1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: filerec.cxx,v $
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,
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,
63 #define SFX_REC_MINI_HEADER(nPreTag,nStartPos,nEndPos) \
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
85 Der Stream wird an den Anfang des
86 Contents (also hinter den Header)
93 Diese Methode schlie\st den Record. Dabei wird haupts"achlich der
96 Wurde der Header bereits geschrieben, hat der Aufruf keine Wirkung.
102 Position im Stream, die direkt hinter dem Record liegt.
103 'bSeekToEndOfRecord==TRUE'
104 => R"uckgabewert == aktuelle Stream-Position nach Aufruf
107 Der Header war bereits geschrieben worden.
111 // wurde der Header noch nicht geschrieben?
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
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
);
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
);
145 // Record war bereits geschlossen
149 //=========================================================================
151 USHORT
SfxMiniRecordReader::ScanRecordType
153 SvStream
* pStream
/* <SvStream> an dessen aktueller Position
154 ein Record liegt, dessen Typ erkannt werden
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.
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
181 USHORT SFX_REC_TYPE_EOR
182 An der aktuellen Position des Streams
183 steht eine End-Of-Records-Kennung.
186 Es handelt sich um einen SW3 kompatiblen
187 Mini-Record, dessen einzige Kennung sein
191 Es handelt sich um einen Extended-Record
192 mit einem einzigen Content, der durch eine
193 Version und ein Tag n"aher gekennzeichnet
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
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
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
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
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
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
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
)
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
)
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-
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
);
293 //-------------------------------------------------------------------------
295 SfxMiniRecordReader::SfxMiniRecordReader
297 SvStream
* pStream
/* <SvStream>, an dessen aktueller
298 Position sich ein <SfxMiniRecord>
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
),
318 UINT32 nStartPos
= pStream
->Tell(); // um im Fehlerfall zur"uck zu-seeken
319 DBG( DbgOutf( "SfxFileRec: reading record at %ul", nStartPos
) );
323 // Headerdaten extrahieren
324 SetHeader_Impl( nHeader
);
327 if ( pStream
->IsEof() )
328 _nPreTag
= SFX_REC_PRETAG_EOR
;
329 else if ( _nPreTag
== SFX_REC_PRETAG_EOR
)
330 pStream
->SetError( ERRCODE_IO_WRONGFORMAT
);
332 pStream
->Seek( nStartPos
);
335 //-------------------------------------------------------------------------
337 SfxMiniRecordReader::SfxMiniRecordReader
339 SvStream
* pStream
, /* <SvStream>, an dessen aktueller
340 Position sich ein <SfxMiniRecord>
343 BYTE nTag
// Pre-Tag des gew"unschten Records
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-
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.)
389 // StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
390 UINT32 nStartPos
= pStream
->Tell();
392 // passenden Record suchen
396 DBG( DbgOutf( "SfxFileRec: searching record at %ul", pStream
->Tell() ) );
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
);
410 // wenn gefunden, dann Schleife abbrechen
411 if ( _nPreTag
== nTag
)
414 // sonst skippen und weitersuchen
415 pStream
->Seek( _nEofRec
);
419 // Fehler => zur"uck-seeken
420 pStream
->Seek( nStartPos
);
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
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
457 Legt in 'pStream' einen 'SfxSingleRecord' an, dessen Content-Gr"o\se
458 nicht bekannt ist, sondern nach dam Streamen des Contents errechnet
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
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
)
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.
506 // Basisklassen-Header einlesen
508 *_pStream
>> nHeader
;
509 if ( !SetHeader_Impl( nHeader
) )
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
);
525 //-------------------------------------------------------------------------
527 SfxSingleRecordReader::SfxSingleRecordReader( SvStream
*pStream
)
528 : SfxMiniRecordReader()
530 // Startposition merken, um im Fehlerfall zur"uck-seeken zu k"onnen
532 UINT32 nStartPos
= pStream
->Tell();
533 DBG( DbgOutf( "SfxFileRec: reading record at %ul", nStartPos
) );
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
575 Interne Methode zum lesen des Headers des ersten Record, der einem
576 der Typen in 'nTypes' entspricht und mit der Art-Kennung 'nTag'
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() )
592 DBG( DbgOutf( "SfxFileRec: searching record at %ul", _pStream
->Tell() ) );
593 *_pStream
>> nHeader
;
594 if ( !SetHeader_Impl( nHeader
) )
595 // EOR => Such-Schleife abbreichen
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
)
615 // error => Such-Schleife abbrechen
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
);
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
644 Interne Methode f"ur Subklassen.
647 : SfxSingleRecordWriter( nRecordType
, pStream
, nContentTag
, nContentVer
),
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
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
),
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?
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
);
701 // Record war bereits geschlossen
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
717 Interner Ctor f"ur Subklassen.
720 : SfxMultiFixRecordWriter( nRecordType
, pStream
, nRecordTag
, nRecordVer
, 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
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.
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 ),
753 //-------------------------------------------------------------------------
755 SfxMultiVarRecordWriter::~SfxMultiVarRecordWriter()
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
770 //-------------------------------------------------------------------------
772 void SfxMultiVarRecordWriter::FlushContent_Impl()
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
783 SFX_REC_CONTENT_HEADER(_nContentVer
,_nStartPos
,_nContentStartPos
),
787 //-------------------------------------------------------------------------
789 void SfxMultiVarRecordWriter::NewContent()
791 // siehe <SfxMultiFixRecordWriter>
794 // schon ein Content geschrieben?
795 if ( _nContentCount
)
798 // neuen Content beginnen
799 _nContentStartPos
= _pStream
->Tell();
803 //-------------------------------------------------------------------------
805 UINT32
SfxMultiVarRecordWriter::Close( FASTBOOL bSeekToEndOfRec
)
807 // siehe <SfxMiniRecordWriter>
810 // Header noch nicht geschrieben?
813 // ggf. letzten Content abschlie\sen
814 if ( _nContentCount
)
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
);
824 for ( USHORT n
= 0; n
< _nContentCount
; ++n
)
825 *_pStream
<< UINT32(_aContentOfs
[n
]);
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
) ));
837 *_pStream
<< nContentOfsPos
;
839 // ans Ende des Records seeken bzw. am Ende des Headers bleiben
840 if ( bSeekToEndOfRec
)
841 _pStream
->Seek(nEndPos
);
845 // Record war bereits vorher geschlossen
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
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
)
869 // Tag vor den Content schreiben, Version und Startposition merken
870 _nContentStartPos
= _pStream
->Tell();
872 *_pStream
<< nContentTag
;
873 _nContentVer
= nContentVer
;
876 //=========================================================================
878 FASTBOOL
SfxMultiRecordReader::ReadHeader_Impl()
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
);
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
);
908 for ( USHORT n
= 0; n
< _nContentCount
; ++n
)
909 *_pStream
>> _pContentOfs
[n
];
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
) ||
934 // als ung"ultig markieren und zur"uck-seeken
935 SetInvalid_Impl( _nStartPos
);
938 //-------------------------------------------------------------------------
940 SfxMultiRecordReader::SfxMultiRecordReader( SvStream
*pStream
, UINT16 nTag
)
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
,
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()
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
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)
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