Update ooo320-m1
[ooovba.git] / svtools / source / filerec / filerec.cxx
blob40de424c8303136f91d78d7e3f9b3cb5da2c6121
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: filerec.cxx,v $
10 * $Revision: 1.13 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
33 #include <svtools/filerec.hxx>
34 #include <osl/endian.h>
36 //========================================================================
38 SV_IMPL_VARARR( SfxUINT32s, UINT32 );
40 //========================================================================
42 /* Die folgenden Makros extrahieren Teilbereiche aus einem UINT32 Wert.
43 Diese UINT32-Werte werden anstelle der einzelnen Werte gestreamt,
44 um Calls zu sparen.
47 #define SFX_REC_PRE(n) ( ((n) & 0x000000FF) )
48 #define SFX_REC_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
49 #define SFX_REC_TYP(n) ( ((n) & 0x000000FF) )
50 #define SFX_REC_VER(n) ( ((n) & 0x0000FF00) >> 8 )
51 #define SFX_REC_TAG(n) ( ((n) & 0xFFFF0000) >> 16 )
53 #define SFX_REC_CONTENT_VER(n) ( ((n) & 0x000000FF) )
54 #define SFX_REC_CONTENT_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
56 //-------------------------------------------------------------------------
58 /* Die folgenden Makros setzen Teilbereiche zu einem UINT32 Wert zusammen.
59 Diese UINT32-Werte werden anstelle der einzelnen Werte gestreamt,
60 um Calls zu sparen.
63 #define SFX_REC_MINI_HEADER(nPreTag,nStartPos,nEndPos) \
64 ( UINT32(nPreTag) | \
65 UINT32(nEndPos-nStartPos-SFX_REC_HEADERSIZE_MINI) << 8 )
67 #define SFX_REC_HEADER(nRecType,nContentTag,nContentVer) \
68 ( UINT32(nRecType) | \
69 ( UINT32(nContentVer) << 8 ) | \
70 ( UINT32(nContentTag) << 16 ) )
72 #define SFX_REC_CONTENT_HEADER(nContentVer,n1StStartPos,nCurStartPos) \
73 ( UINT32(nContentVer) | \
74 UINT32( nCurStartPos - n1StStartPos ) << 8 )
76 //=========================================================================
78 UINT32 SfxMiniRecordWriter::Close
80 FASTBOOL bSeekToEndOfRec /* TRUE (default)
81 Der Stream wird an das Ende des Records
82 positioniert.
84 FALSE
85 Der Stream wird an den Anfang des
86 Contents (also hinter den Header)
87 positioniert.
91 /* [Beschreibung]
93 Diese Methode schlie\st den Record. Dabei wird haupts"achlich der
94 Header geschrieben.
96 Wurde der Header bereits geschrieben, hat der Aufruf keine Wirkung.
99 [R"uckgabewert]
101 UINT32 != 0
102 Position im Stream, die direkt hinter dem Record liegt.
103 'bSeekToEndOfRecord==TRUE'
104 => R"uckgabewert == aktuelle Stream-Position nach Aufruf
106 == 0
107 Der Header war bereits geschrieben worden.
111 // wurde der Header noch nicht geschrieben?
112 if ( !_bHeaderOk )
114 // Header an den Anfang des Records schreiben
115 UINT32 nEndPos = _pStream->Tell();
116 _pStream->Seek( _nStartPos );
117 *_pStream << SFX_REC_MINI_HEADER( _nPreTag, _nStartPos, nEndPos );
119 // je nachdem ans Ende des Records seeken oder hinter Header bleiben
120 if ( bSeekToEndOfRec )
121 _pStream->Seek( nEndPos );
123 // Header wurde JETZT geschrieben
124 _bHeaderOk = TRUE;
125 return nEndPos;
127 #ifdef DBG_UTIL
128 // mu\s Fix-Size-Record gepr"uft werden?
129 else if ( SFX_BOOL_DONTCARE == _bHeaderOk )
131 // Header auslesen, um Soll-Gr"o\se zu bestimmen
132 UINT32 nEndPos = _pStream->Tell();
133 _pStream->Seek( _nStartPos );
134 UINT32 nHeader;
135 *_pStream >> nHeader;
136 _pStream->Seek( nEndPos );
138 // Soll-Gr"o\se mit Ist-Gr"o\se vergleichen
139 DBG_ASSERT( nEndPos - SFX_REC_OFS(nHeader) == _nStartPos + sizeof(UINT32),
140 "fixed record size incorrect" );
141 DbgOutf( "SfxFileRec: written record until %ul", nEndPos );
143 #endif
145 // Record war bereits geschlossen
146 return 0;
149 //=========================================================================
151 USHORT SfxMiniRecordReader::ScanRecordType
153 SvStream* pStream /* <SvStream> an dessen aktueller Position
154 ein Record liegt, dessen Typ erkannt werden
155 soll.
159 /* [Beschreibung]
161 Mit dieser statischen Methode kann ermittelt werden, ob sich an der
162 aktuellen Position in einem Stream ein Record befindet, und der Typ
163 des Records kann ermittelt werden.
165 Die Position im Stream ist nach dem Aufruf aufver"andert.
168 [Anmerkung]
170 Die Record-Typen k"onnen zwar (abgesehen vom Drawing-Enginge-Record)
171 untereinander eindeutig erkannt werden, es besteht jedoch die Gefahr
172 der Verwechslung von Records mit normalen Daten. File-Formate sollten
173 darauf R"ucksicht nehmen. Handelt es sich um keinen Record, wird
174 am wahrscheinlichsten SFX_REC_TYPE_MINI zur"uckgeliefert, da dieser
175 Typ sich aufgrund seines sparsam kurzen Headers durch die k"urzeste
176 Kennung auszeichnet.
179 [R"uckgabewert]
181 USHORT SFX_REC_TYPE_EOR
182 An der aktuellen Position des Streams
183 steht eine End-Of-Records-Kennung.
185 SFX_REC_TYPE_MINI
186 Es handelt sich um einen SW3 kompatiblen
187 Mini-Record, dessen einzige Kennung sein
188 'Mini-Tag' ist.
190 SFX_REC_TYPE_SINGLE
191 Es handelt sich um einen Extended-Record
192 mit einem einzigen Content, der durch eine
193 Version und ein Tag n"aher gekennzeichnet
194 ist.
196 SFX_REC_TYPE_FIXSIZE
197 Es handelt sich um einen Extended-Record
198 mit mehreren Contents gleicher Gr"o\se,
199 die gemeinsam durch eine einzige Version
200 und ein einziges gemeinsames Tag n"aher
201 gekennzeichnet sind.
203 SFX_REC_TYPE_VARSIZE
204 Es handelt sich um einen Extended-Record
205 mit mehreren Contents variabler Gr"o\se,
206 die gemeinsam durch eine einzige Version
207 und ein einziges gemeinsames Tag n"aher
208 gekennzeichnet sind.
210 SFX_REC_TYPE_MIXTAGS
211 Es handelt sich um einen Extended-Record
212 mit mehreren Contents variabler Gr"o\se,
213 die jeweils durch ein eignes Tag und
214 eine eigene Versions-Nummer n"aher
215 gekennzeichnet sind.
217 SFX_REC_TYPE_DRAWENG
218 Es handelt sich wahrscheinlich um einen
219 Drawing-Engine-Record. Dieser Record-Typ
220 kann von den Klassen dieser Gruppe nicht
221 interpretiert werden.
225 // die ersten 4 Bytes als Mini-Header lesen
226 sal_uInt32 nHeader;
227 *pStream >> nHeader;
229 // k"onnte es sich um einen extended-Record handeln?
230 USHORT nPreTag = sal::static_int_cast< USHORT >(SFX_REC_PRE(nHeader));
231 if ( SFX_REC_PRETAG_EXT == nPreTag )
233 // die n"achsten 4 Bytes als extended-Header lesen
234 *pStream >> nHeader;
236 // Stream-Position restaurieren
237 pStream->SeekRel(-8);
239 // liegt eine g"ultige Record-Kennung vor?
240 USHORT nType = sal::static_int_cast< USHORT >(SFX_REC_TYP(nHeader));
241 if ( nType >= SFX_REC_TYPE_FIRST && nType <= SFX_REC_TYPE_LAST )
242 // entsprechenden extended-Record-Typ zur"uckliefern
243 return nType;
245 // sonst ist der Record-Typ unbekannt
246 return SFX_REC_TYPE_NONE;
249 // Stream-Position restaurieren
250 pStream->SeekRel(-4);
252 // liegt eine End-Of-Record-Kennung vor?
253 if ( SFX_REC_PRETAG_EOR == nPreTag )
254 return nPreTag;
256 // liegt ein Drawin-Engine-Record vor?
257 if ( nHeader == UINT32(*"DRMD") || nHeader == UINT32(*"DRVW") )
258 return SFX_REC_TYPE_DRAWENG;
260 // alle anderen sind grunds"atzlich g"ultige Mini-Records
261 return SFX_REC_TYPE_MINI;
264 //-------------------------------------------------------------------------
266 FASTBOOL SfxMiniRecordReader::SetHeader_Impl( UINT32 nHeader )
268 /* [Beschreibung]
270 Interne Methode zum nachtr"aglichen Verarbeiten eines extern gelesenen
271 Headers. Falls der Header eine End-Of-Records-Kennung darstellt,
272 wird am Stream ein Errorcode gesetzt und FALSE zur"uckgeliefert. Im
273 Fehlerfall wird der Stream jedoch nicht auf den Record-Anfang zur"uck-
274 gesetzt.
278 FASTBOOL bRet = TRUE;
280 // Record-Ende und Pre-Tag aus dem Header ermitteln
281 _nEofRec = _pStream->Tell() + SFX_REC_OFS(nHeader);
282 _nPreTag = sal::static_int_cast< BYTE >(SFX_REC_PRE(nHeader));
284 // wenn End-Of-Record-Kennung, dann Fehler
285 if ( _nPreTag == SFX_REC_PRETAG_EOR )
287 _pStream->SetError( ERRCODE_IO_WRONGFORMAT );
288 bRet = FALSE;
290 return bRet;
293 //-------------------------------------------------------------------------
295 SfxMiniRecordReader::SfxMiniRecordReader
297 SvStream* pStream /* <SvStream>, an dessen aktueller
298 Position sich ein <SfxMiniRecord>
299 befindet.
303 /* [Beschreibung]
305 Dieser Ctor liest den Header eines <SfxMiniRecord> ab der aktuellen
306 Position von 'pStream'. Da grunds"atzlich fast 4-Byte Kombination ein
307 g"ultiger SfxMiniRecord-Header ist, bleiben die einzig m"oglichen
308 Fehler der EOF-Status des Streams, und ein SFX_REC_PRETAG_EOR
309 als Pre-Tag. Ein entsprechender Error-Code (ERRCODE_IO_EOF bzw.
310 ERRCODE_IO_WRONGFORMAT) ist dann am Stream gesetzt, dessen Position
311 dann au\serdem unver"andert ist.
314 : _pStream( pStream ),
315 _bSkipped( FALSE )
317 // Header einlesen
318 UINT32 nStartPos = pStream->Tell(); // um im Fehlerfall zur"uck zu-seeken
319 DBG( DbgOutf( "SfxFileRec: reading record at %ul", nStartPos ) );
320 UINT32 nHeader;
321 *pStream >> nHeader;
323 // Headerdaten extrahieren
324 SetHeader_Impl( nHeader );
326 // Fehlerbehandlung
327 if ( pStream->IsEof() )
328 _nPreTag = SFX_REC_PRETAG_EOR;
329 else if ( _nPreTag == SFX_REC_PRETAG_EOR )
330 pStream->SetError( ERRCODE_IO_WRONGFORMAT );
331 if ( !IsValid() )
332 pStream->Seek( nStartPos );
335 //-------------------------------------------------------------------------
337 SfxMiniRecordReader::SfxMiniRecordReader
339 SvStream* pStream, /* <SvStream>, an dessen aktueller
340 Position sich ein <SfxMiniRecord>
341 befindet.
343 BYTE nTag // Pre-Tag des gew"unschten Records
346 /* [Beschreibung]
348 Dieser Ctor interpretiert 'pStream' ab der aktuellen Position als
349 eine l"uckenlose Folge von, von dieser Klassen-Gruppe interpretierbaren,
350 Records. Der in dieser Folge erste als <SfxMiniRecord> interpretierbare
351 (also ggf. auch ein extended-Record) mit dem PreTag 'nTag' wird ge"offnet
352 und durch diese Instanz repr"asentiert.
354 Wird das Ende des Streams oder die Kennung SFX_REC_PRETAG_EOR
355 erreicht, bevor ein Record mit dem ge"unschten Pre-Tag gefunden wird,
356 ist die erzeugte Instanz ung"ultig ('IsValid() == FALSE'). Ein ent-
357 sprechender Error-Code (ERRCODE_IO_EOF bzw. ERRCODE_IO_WRONGFORMAT)
358 ist dann am Stream gesetzt, dessen Position ist dann au\serdem unver-
359 "andert.
361 Bei 'nTag==SFX_FILEREC_PRETAG_EOR' wird nicht versucht, einen Record
362 zu lesen, es wird sofort 'IsValid()' auf FALSE gesetzt und kein Error-Code
363 am Stream gesetzt. Dies ist dauzu gedacht, ohne 'new' und 'delete'
364 abw"rtskompatibel SfxMiniRecords einbauen zu k"onnen. Siehe dazu
365 <SfxItemSet::Load()>.
368 [Anwendungsvorschlag]
370 Wird dieser Ctor in einer bereits ausgelieferten Programmversion
371 verwendet, k"onnen in das File-Format jeweils davor kompatibel neue
372 Records mit einer anderen Kennung eingef"ugt werden. Diese werden
373 schlie\slich automatisch "uberlesen. Erkauft wird diese M"oglichkeit
374 allerdings mit etwas schlechterem Laufzeitverhalten im Vergleich mit
375 direktem 'drauf-los-lesen', der sich jedoch auf einen Vergleich zweier
376 Bytes reduziert, falls der gesuchte Record der erste in der Folge ist.
379 : _pStream( pStream ),
380 _bSkipped( nTag == SFX_REC_PRETAG_EOR )
382 // ggf. ignorieren (s.o.)
383 if ( _bSkipped )
385 _nPreTag = nTag;
386 return;
389 // StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
390 UINT32 nStartPos = pStream->Tell();
392 // passenden Record suchen
393 while(TRUE)
395 // Header lesen
396 DBG( DbgOutf( "SfxFileRec: searching record at %ul", pStream->Tell() ) );
397 UINT32 nHeader;
398 *pStream >> nHeader;
400 // Headerdaten von Basisklasse extrahieren lassen
401 SetHeader_Impl( nHeader );
403 // ggf. Fehler behandeln
404 if ( pStream->IsEof() )
405 _nPreTag = SFX_REC_PRETAG_EOR;
406 else if ( _nPreTag == SFX_REC_PRETAG_EOR )
407 pStream->SetError( ERRCODE_IO_WRONGFORMAT );
408 else
410 // wenn gefunden, dann Schleife abbrechen
411 if ( _nPreTag == nTag )
412 break;
414 // sonst skippen und weitersuchen
415 pStream->Seek( _nEofRec );
416 continue;
419 // Fehler => zur"uck-seeken
420 pStream->Seek( nStartPos );
421 break;
425 //=========================================================================
427 SfxSingleRecordWriter::SfxSingleRecordWriter
429 BYTE nRecordType, // f"ur Subklassen
430 SvStream* pStream, // Stream, in dem der Record angelegt wird
431 UINT16 nContentTag, // Inhalts-Art-Kennung
432 BYTE nContentVer // Inhalts-Versions-Kennung
435 /* [Beschreibung]
437 Interner Ctor f"ur Subklassen.
440 : SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT )
442 // Erweiterten Header hiner den des SfxMiniRec schreiben
443 *pStream << SFX_REC_HEADER(nRecordType, nContentTag, nContentVer);
446 //-------------------------------------------------------------------------
448 SfxSingleRecordWriter::SfxSingleRecordWriter
450 SvStream* pStream, // Stream, in dem der Record angelegt wird
451 UINT16 nContentTag, // Inhalts-Art-Kennung
452 BYTE nContentVer // Inhalts-Versions-Kennung
455 /* [Beschreibung]
457 Legt in 'pStream' einen 'SfxSingleRecord' an, dessen Content-Gr"o\se
458 nicht bekannt ist, sondern nach dam Streamen des Contents errechnet
459 werden soll.
462 : SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT )
464 // Erweiterten Header hiner den des SfxMiniRec schreiben
465 *pStream << SFX_REC_HEADER( SFX_REC_TYPE_SINGLE, nContentTag, nContentVer);
468 //-------------------------------------------------------------------------
470 SfxSingleRecordWriter::SfxSingleRecordWriter
472 SvStream* pStream, // Stream, in dem der Record angelegt wird
473 UINT16 nContentTag, // Inhalts-Art-Kennung
474 BYTE nContentVer, // Inhalts-Versions-Kennung
475 UINT32 nContentSize // Gr"o\se des Inhalts in Bytes
478 /* [Beschreibung]
480 Legt in 'pStream' einen 'SfxSingleRecord' an, dessen Content-Gr"o\se
481 von vornherein bekannt ist.
484 : SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT,
485 nContentSize + SFX_REC_HEADERSIZE_SINGLE )
487 // Erweiterten Header hinter den des SfxMiniRec schreiben
488 *pStream << SFX_REC_HEADER( SFX_REC_TYPE_SINGLE, nContentTag, nContentVer);
491 //=========================================================================
493 inline FASTBOOL SfxSingleRecordReader::ReadHeader_Impl( USHORT nTypes )
495 /* [Beschreibung]
497 Interne Methode zum Einlesen eines SfxMultiRecord-Headers, nachdem
498 die Basisklasse bereits initialisiert und deren Header gelesen ist.
499 Ggf. ist ein Error-Code am Stream gesetzt, im Fehlerfall wird jedoch
500 nicht zur"uckge-seekt.
504 FASTBOOL bRet;
506 // Basisklassen-Header einlesen
507 UINT32 nHeader=0;
508 *_pStream >> nHeader;
509 if ( !SetHeader_Impl( nHeader ) )
510 bRet = FALSE;
511 else
513 // eigenen Header einlesen
514 *_pStream >> nHeader;
515 _nRecordVer = sal::static_int_cast< BYTE >(SFX_REC_VER(nHeader));
516 _nRecordTag = sal::static_int_cast< UINT16 >(SFX_REC_TAG(nHeader));
518 // falscher Record-Typ?
519 _nRecordType = sal::static_int_cast< BYTE >(SFX_REC_TYP(nHeader));
520 bRet = 0 != ( nTypes & _nRecordType);
522 return bRet;
525 //-------------------------------------------------------------------------
527 SfxSingleRecordReader::SfxSingleRecordReader( SvStream *pStream )
528 : SfxMiniRecordReader()
530 // Startposition merken, um im Fehlerfall zur"uck-seeken zu k"onnen
531 #ifdef DBG_UTIL
532 UINT32 nStartPos = pStream->Tell();
533 DBG( DbgOutf( "SfxFileRec: reading record at %ul", nStartPos ) );
534 #endif
536 // Basisklasse initialisieren (nicht via Ctor, da der nur MiniRecs akzept.)
537 Construct_Impl( pStream );
539 // nur Header mit korrektem Record-Type akzeptieren
540 if ( !ReadHeader_Impl( SFX_REC_TYPE_SINGLE ) )
542 // Error-Code setzen und zur"uck-seeken
543 pStream->SeekRel( - SFX_REC_HEADERSIZE_SINGLE );
544 pStream->SetError( ERRCODE_IO_WRONGFORMAT );
548 //-------------------------------------------------------------------------
550 SfxSingleRecordReader::SfxSingleRecordReader( SvStream *pStream, USHORT nTag )
552 // StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
553 UINT32 nStartPos = pStream->Tell();
555 // richtigen Record suchen, ggf. Error-Code setzen und zur"uck-seeken
556 Construct_Impl( pStream );
557 if ( !FindHeader_Impl( SFX_REC_TYPE_SINGLE, nTag ) )
559 // Error-Code setzen und zur"uck-seeken
560 pStream->Seek( nStartPos );
561 pStream->SetError( ERRCODE_IO_WRONGFORMAT );
565 //-------------------------------------------------------------------------
567 FASTBOOL SfxSingleRecordReader::FindHeader_Impl
569 UINT16 nTypes, // arithm. Veroderung erlaubter Record-Typen
570 UINT16 nTag // zu findende Record-Art-Kennung
573 /* [Beschreibung]
575 Interne Methode zum lesen des Headers des ersten Record, der einem
576 der Typen in 'nTypes' entspricht und mit der Art-Kennung 'nTag'
577 gekennzeichnet ist.
579 Kann ein solcher Record nicht gefunden werden, wird am Stream ein
580 Errorcode gesetzt, zur"uck-geseekt und FALSE zur"uckgeliefert.
584 // StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
585 UINT32 nStartPos = _pStream->Tell();
587 // richtigen Record suchen
588 while ( !_pStream->IsEof() )
590 // Header lesen
591 UINT32 nHeader;
592 DBG( DbgOutf( "SfxFileRec: searching record at %ul", _pStream->Tell() ) );
593 *_pStream >> nHeader;
594 if ( !SetHeader_Impl( nHeader ) )
595 // EOR => Such-Schleife abbreichen
596 break;
598 // Extended Record gefunden?
599 if ( _nPreTag == SFX_REC_PRETAG_EXT )
601 // Extended Header lesen
602 *_pStream >> nHeader;
603 _nRecordTag = sal::static_int_cast< UINT16 >(SFX_REC_TAG(nHeader));
605 // richtigen Record gefunden?
606 if ( _nRecordTag == nTag )
608 // gefundener Record-Typ passend?
609 _nRecordType = sal::static_int_cast< BYTE >(
610 SFX_REC_TYP(nHeader));
611 if ( nTypes & _nRecordType )
612 // ==> gefunden
613 return TRUE;
615 // error => Such-Schleife abbrechen
616 break;
620 // sonst skippen
621 if ( !_pStream->IsEof() )
622 _pStream->Seek( _nEofRec );
625 // Fehler setzen und zur"uck-seeken
626 _pStream->SetError( ERRCODE_IO_WRONGFORMAT );
627 _pStream->Seek( nStartPos );
628 return FALSE;
631 //=========================================================================
633 SfxMultiFixRecordWriter::SfxMultiFixRecordWriter
635 BYTE nRecordType, // Subklassen Record-Kennung
636 SvStream* pStream, // Stream, in dem der Record angelegt wird
637 UINT16 nContentTag, // Content-Art-Kennung
638 BYTE nContentVer, // Content-Versions-Kennung
639 UINT32 // Gr"o\se jedes einzelnen Contents in Bytes
642 /* [Beschreibung]
644 Interne Methode f"ur Subklassen.
647 : SfxSingleRecordWriter( nRecordType, pStream, nContentTag, nContentVer ),
648 _nContentCount( 0 )
650 // Platz f"ur eigenen Header
651 pStream->SeekRel( + SFX_REC_HEADERSIZE_MULTI );
654 //------------------------------------------------------------------------
656 SfxMultiFixRecordWriter::SfxMultiFixRecordWriter
658 SvStream* pStream, // Stream, in dem der Record angelegt wird
659 UINT16 nContentTag, // Content-Art-Kennung
660 BYTE nContentVer, // Content-Versions-Kennung
661 UINT32 // Gr"o\se jedes einzelnen Contents in Bytes
664 /* [Beschreibung]
666 Legt in 'pStream' einen 'SfxMultiFixRecord' an, dessen Content-Gr"o\se
667 konstant und von vornherein bekannt ist.
670 : SfxSingleRecordWriter( SFX_REC_TYPE_FIXSIZE,
671 pStream, nContentTag, nContentVer ),
672 _nContentCount( 0 )
674 // Platz f"ur eigenen Header
675 pStream->SeekRel( + SFX_REC_HEADERSIZE_MULTI );
678 //------------------------------------------------------------------------
680 UINT32 SfxMultiFixRecordWriter::Close( FASTBOOL bSeekToEndOfRec )
682 // siehe <SfxMiniRecordWriter>
685 // Header noch nicht geschrieben?
686 if ( !_bHeaderOk )
688 // Position hinter Record merken, um sie restaurieren zu k"onnen
689 UINT32 nEndPos = SfxSingleRecordWriter::Close( FALSE );
691 // gegen"uber SfxSingleRecord erweiterten Header schreiben
692 *_pStream << _nContentCount;
693 *_pStream << _nContentSize;
695 // je nachdem ans Ende des Records seeken oder hinter Header bleiben
696 if ( bSeekToEndOfRec )
697 _pStream->Seek(nEndPos);
698 return nEndPos;
701 // Record war bereits geschlossen
702 return 0;
705 //=========================================================================
707 SfxMultiVarRecordWriter::SfxMultiVarRecordWriter
709 BYTE nRecordType, // Record-Kennung der Subklasse
710 SvStream* pStream, // Stream, in dem der Record angelegt wird
711 UINT16 nRecordTag, // Gesamt-Art-Kennung
712 BYTE nRecordVer // Gesamt-Versions-Kennung
715 /* [Beschreibung]
717 Interner Ctor f"ur Subklassen.
720 : SfxMultiFixRecordWriter( nRecordType, pStream, nRecordTag, nRecordVer, 0 ),
721 _nContentVer( 0 )
725 //-------------------------------------------------------------------------
727 SfxMultiVarRecordWriter::SfxMultiVarRecordWriter
729 SvStream* pStream, // Stream, in dem der Record angelegt wird
730 UINT16 nRecordTag, // Gesamt-Art-Kennung
731 BYTE nRecordVer // Gesamt-Versions-Kennung
734 /* [Beschreibung]
736 Legt in 'pStream' einen 'SfxMultiVarRecord' an, dessen Content-Gr"o\sen
737 weder bekannt sind noch identisch sein m"ussen, sondern jeweils nach dem
738 Streamen jedes einzelnen Contents errechnet werden sollen.
741 [Anmerkung]
743 Diese Methode ist nicht inline, da f"ur die Initialisierung eines
744 <SvULongs>-Members zu viel Code generiert werden w"urde.
747 : SfxMultiFixRecordWriter( SFX_REC_TYPE_VARSIZE,
748 pStream, nRecordTag, nRecordVer, 0 ),
749 _nContentVer( 0 )
753 //-------------------------------------------------------------------------
755 SfxMultiVarRecordWriter::~SfxMultiVarRecordWriter()
757 /* [Beschreibung]
759 Der Dtor der Klasse <SfxMultiVarRecordWriter> schlie\st den Record
760 automatisch, falls <SfxMultiVarRecordWriter::Close()> nicht bereits
761 explizit gerufen wurde.
765 // wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden
766 if ( !_bHeaderOk )
767 Close();
770 //-------------------------------------------------------------------------
772 void SfxMultiVarRecordWriter::FlushContent_Impl()
774 /* [Beschreibung]
776 Interne Methode zum Abschlie\sen eines einzelnen Contents.
780 // Versions-Kennung und Positions-Offset des aktuellen Contents merken;
781 // das Positions-Offset ist relativ zur Startposition des ersten Contents
782 _aContentOfs.Insert(
783 SFX_REC_CONTENT_HEADER(_nContentVer,_nStartPos,_nContentStartPos),
784 _nContentCount-1 );
787 //-------------------------------------------------------------------------
789 void SfxMultiVarRecordWriter::NewContent()
791 // siehe <SfxMultiFixRecordWriter>
794 // schon ein Content geschrieben?
795 if ( _nContentCount )
796 FlushContent_Impl();
798 // neuen Content beginnen
799 _nContentStartPos = _pStream->Tell();
800 ++_nContentCount;
803 //-------------------------------------------------------------------------
805 UINT32 SfxMultiVarRecordWriter::Close( FASTBOOL bSeekToEndOfRec )
807 // siehe <SfxMiniRecordWriter>
810 // Header noch nicht geschrieben?
811 if ( !_bHeaderOk )
813 // ggf. letzten Content abschlie\sen
814 if ( _nContentCount )
815 FlushContent_Impl();
817 // Content-Offset-Tabelle schreiben
818 UINT32 nContentOfsPos = _pStream->Tell();
819 //! darf man das so einr"ucken?
820 #if defined(OSL_LITENDIAN)
821 _pStream->Write( _aContentOfs.GetData(),
822 sizeof(UINT32)*_nContentCount );
823 #else
824 for ( USHORT n = 0; n < _nContentCount; ++n )
825 *_pStream << UINT32(_aContentOfs[n]);
826 #endif
828 // SfxMultiFixRecordWriter::Close() "uberspringen!
829 UINT32 nEndPos = SfxSingleRecordWriter::Close( FALSE );
831 // eigenen Header schreiben
832 *_pStream << _nContentCount;
833 if ( SFX_REC_TYPE_VARSIZE_RELOC == _nPreTag ||
834 SFX_REC_TYPE_MIXTAGS_RELOC == _nPreTag )
835 *_pStream << static_cast<UINT32>(nContentOfsPos - ( _pStream->Tell() + sizeof(UINT32) ));
836 else
837 *_pStream << nContentOfsPos;
839 // ans Ende des Records seeken bzw. am Ende des Headers bleiben
840 if ( bSeekToEndOfRec )
841 _pStream->Seek(nEndPos);
842 return nEndPos;
845 // Record war bereits vorher geschlossen
846 return 0;
849 //=========================================================================
851 void SfxMultiMixRecordWriter::NewContent
853 UINT16 nContentTag, // Kennung f"ur die Art des Contents
854 BYTE nContentVer // Kennung f"ur die Version des Contents
857 /* [Beschreibung]
859 Mit dieser Methode wird in den Record ein neuer Content eingef"ugt
860 und dessen Content-Tag sowie dessen Content-Version angegeben. Jeder,
861 auch der 1. Record mu\s durch Aufruf dieser Methode eingeleitet werden.
865 // ggf. vorherigen Record abschlie\sen
866 if ( _nContentCount )
867 FlushContent_Impl();
869 // Tag vor den Content schreiben, Version und Startposition merken
870 _nContentStartPos = _pStream->Tell();
871 ++_nContentCount;
872 *_pStream << nContentTag;
873 _nContentVer = nContentVer;
876 //=========================================================================
878 FASTBOOL SfxMultiRecordReader::ReadHeader_Impl()
880 /* [Beschreibung]
882 Interne Methode zum Einlesen eines SfxMultiRecord-Headers, nachdem
883 die Basisklasse bereits initialisiert und deren Header gelesen ist.
884 Ggf. ist ein Error-Code am Stream gesetzt, im Fehlerfall wird jedoch
885 nicht zur"uckge-seekt.
889 // eigenen Header lesen
890 *_pStream >> _nContentCount;
891 *_pStream >> _nContentSize; // Fix: jedes einzelnen, Var|Mix: Tabellen-Pos.
893 // mu\s noch eine Tabelle mit Content-Offsets geladen werden?
894 if ( _nRecordType != SFX_REC_TYPE_FIXSIZE )
896 // Tabelle aus dem Stream einlesen
897 UINT32 nContentPos = _pStream->Tell();
898 if ( _nRecordType == SFX_REC_TYPE_VARSIZE_RELOC ||
899 _nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
900 _pStream->SeekRel( + _nContentSize );
901 else
902 _pStream->Seek( _nContentSize );
903 _pContentOfs = new UINT32[_nContentCount];
904 //! darf man jetzt so einr"ucken
905 #if defined(OSL_LITENDIAN)
906 _pStream->Read( _pContentOfs, sizeof(UINT32)*_nContentCount );
907 #else
908 for ( USHORT n = 0; n < _nContentCount; ++n )
909 *_pStream >> _pContentOfs[n];
910 #endif
911 _pStream->Seek( nContentPos );
914 // Header konnte gelesen werden, wenn am Stream kein Error gesetzt ist
915 return !_pStream->GetError();
918 //-------------------------------------------------------------------------
920 SfxMultiRecordReader::SfxMultiRecordReader( SvStream *pStream )
921 : _pContentOfs( NULL ), _nContentNo(0)
923 // Position im Stream merken, um im Fehlerfall zur"uck-seeken zu k"onnen
924 _nStartPos = pStream->Tell();
926 // Basisklasse konstruieren (normaler Ctor w"urde nur SingleRecs lesen)
927 SfxSingleRecordReader::Construct_Impl( pStream );
929 // Header der Basisklasse lesen
930 if ( !SfxSingleRecordReader::ReadHeader_Impl( SFX_REC_TYPE_FIXSIZE |
931 SFX_REC_TYPE_VARSIZE | SFX_REC_TYPE_VARSIZE_RELOC |
932 SFX_REC_TYPE_MIXTAGS | SFX_REC_TYPE_MIXTAGS_RELOC ) ||
933 !ReadHeader_Impl() )
934 // als ung"ultig markieren und zur"uck-seeken
935 SetInvalid_Impl( _nStartPos );
938 //-------------------------------------------------------------------------
940 SfxMultiRecordReader::SfxMultiRecordReader( SvStream *pStream, UINT16 nTag )
941 : _nContentNo(0)
943 // Position im Stream merken, um im Fehlerfall zur"uck-seeken zu k"onnen
944 _nStartPos = pStream->Tell();
946 // passenden Record suchen und Basisklasse initialisieren
947 SfxSingleRecordReader::Construct_Impl( pStream );
948 if ( SfxSingleRecordReader::FindHeader_Impl( SFX_REC_TYPE_FIXSIZE |
949 SFX_REC_TYPE_VARSIZE | SFX_REC_TYPE_VARSIZE_RELOC |
950 SFX_REC_TYPE_MIXTAGS | SFX_REC_TYPE_MIXTAGS_RELOC,
951 nTag ) )
953 // eigenen Header dazu-lesen
954 if ( !ReadHeader_Impl() )
955 // nicht lesbar => als ung"ultig markieren und zur"uck-seeken
956 SetInvalid_Impl( _nStartPos);
960 //-------------------------------------------------------------------------
962 SfxMultiRecordReader::~SfxMultiRecordReader()
964 delete[] _pContentOfs;
967 //-------------------------------------------------------------------------
969 FASTBOOL SfxMultiRecordReader::GetContent()
971 /* [Beschreibung]
973 Positioniert den Stream an den Anfang des n"chsten bzw. beim 1. Aufruf
974 auf den Anfang des ersten Contents im Record und liest ggf. dessen
975 Header ein.
977 Liegt laut Record-Header kein Content mehr vor, wird FALSE zur"uck-
978 gegeben. Trotz einem TRUE-Returnwert kann am Stream ein Fehlercode
979 gesetzt sein, z.B. falls er unvorhergesehenerweise (kaputtes File)
980 zuende ist.
984 // noch ein Content vorhanden?
985 if ( _nContentNo < _nContentCount )
987 // den Stream an den Anfang des Contents positionieren
988 UINT32 nOffset = _nRecordType == SFX_REC_TYPE_FIXSIZE
989 ? _nContentNo * _nContentSize
990 : SFX_REC_CONTENT_OFS(_pContentOfs[_nContentNo]);
991 UINT32 nNewPos = _nStartPos + nOffset;
992 DBG_ASSERT( nNewPos >= _pStream->Tell(), "SfxMultiRecordReader::GetContent() - New position before current, to much data red!" );
994 // #99366#: correct stream pos in every case;
995 // the if clause was added by MT a long time ago,
996 // maybe to 'repair' other corrupt documents; but this
997 // gives errors when writing with 5.1 and reading with current
998 // versions, so we decided to remove the if clause (KA-05/17/2002)
999 // if ( nNewPos > _pStream->Tell() )
1000 _pStream->Seek( nNewPos );
1002 // ggf. Content-Header lesen
1003 if ( _nRecordType == SFX_REC_TYPE_MIXTAGS ||
1004 _nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
1006 _nContentVer = sal::static_int_cast< BYTE >(
1007 SFX_REC_CONTENT_VER(_pContentOfs[_nContentNo]));
1008 *_pStream >> _nContentTag;
1011 // ContentNo weiterz"ahlen
1012 ++_nContentNo;
1013 return TRUE;
1016 return FALSE;