xref: /AOO41X/main/svl/inc/svl/filerec.hxx (revision 39a19a47feaddbaa21988da8c7bf801707fd3d48)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef _SFXFILEREC_HXX
25 #define _SFXFILEREC_HXX
26 
27 //=========================================================================
28 
29 #include "svl/svldllapi.h"
30 #include <tools/debug.hxx>
31 #include <tools/stream.hxx>
32 #include <svl/svarray.hxx>
33 
34 SV_DECL_VARARR( SfxUINT32s, sal_uInt32, 8, 8 )
35 
36 //------------------------------------------------------------------------
37 
38 #define SFX_BOOL_DONTCARE               sal_Bool(2)     // Don't-Care-Wert f"ur BOOLs
39 
40 #define SFX_REC_PRETAG_EXT              sal_uInt8(0x00) // Pre-Tag f"ur Extended-Records
41 #define SFX_REC_PRETAG_EOR              sal_uInt8(0xFF) // Pre-Tag f"ur End-Of-Records
42 
43 #define SFX_REC_TYPE_NONE               sal_uInt8(0x00) // unbekannter Record-Typ
44 #define SFX_REC_TYPE_FIRST              sal_uInt8(0x01)
45 #define SFX_REC_TYPE_SINGLE             sal_uInt8(0x01) // Single-Content-Record
46 #define SFX_REC_TYPE_FIXSIZE            sal_uInt8(0x02) // Fix-Size-Multi-Content-Record
47 #define SFX_REC_TYPE_VARSIZE_RELOC      sal_uInt8(0x03) // variable Rec-Size
48 #define SFX_REC_TYPE_VARSIZE            sal_uInt8(0x04) // alt (nicht verschiebbar)
49 #define SFX_REC_TYPE_MIXTAGS_RELOC      sal_uInt8(0x07) // Mixed Tag Content-Record
50 #define SFX_REC_TYPE_MIXTAGS            sal_uInt8(0x08) // alt (nicht verschiebbar)
51 #define SFX_REC_TYPE_LAST               sal_uInt8(0x08)
52 #define SFX_REC_TYPE_MINI                   0x100   // Mini-Record
53 #define SFX_REC_TYPE_DRAWENG                0x400   // Drawing-Engine-Record
54 #define SFX_REC_TYPE_EOR                    0xF00   // End-Of-Records
55 
56 //------------------------------------------------------------------------
57 
58 #define SFX_REC_HEADERSIZE_MINI     4   // Gr"o\se des Mini-Record-Headers
59 #define SFX_REC_HEADERSIZE_SINGLE   4   // zzgl. HEADERSIZE_MINI => 8
60 #define SFX_REC_HEADERSIZE_MULTI    6   // zzgl. HEADERSIZE_SINGLE => 14
61 
62 //------------------------------------------------------------------------
63 
64 #ifndef DBG
65 #ifdef DBG_UTIL
66 #define DBG(x) x
67 #else
68 #define DBG(x)
69 #endif
70 #endif
71 
72 //------------------------------------------------------------------------
73 
74 /*  [Fileformat]
75 
76     Jeder Record beginnt mit einem Byte, dem sogenannten 'Pre-Tag'.
77 
78     Ist dieses 'Pre-Tag' == 0x00, dann handelt es sich um einen Extended-
79     Record, dessen Typ durch ein weiteres Byte an Position 5 n�her
80     beschrieben wird:
81 
82     0x01:       SfxSingleRecord
83     0x02:       SfxMultiFixRecord
84     0x03+0x04:  SfxMultiVarRecord
85     0x07+0x08:  SfxMultiMixRecord
86     (Alle weiteren Record-Typ-Kennungen sind reserviert.)
87 
88     I.d.R. werden File-Formate schon aus Performance-Gr"unden so aufgebaut,
89     da\s beim Lesen jeweils vorher schon feststeht, welcher Record-Typ
90     vorliegt. Diese Kennung dient daher hautps"achlich der "Uberpr"ufung
91     und File-Viewern, die das genaue File-Format (unterhalb der Records)
92     nicht kennen.
93 
94     Der 'SfxMiniRecordReader' verf"ugt dazu auch "uber eine statische
95     Methode 'ScanRecordType()', mit der festgestellt werden kann, welcher
96     Record-Typ in dem "ubergebenen Stream zu finden ist.
97 
98     Ein 'Pre-Tag' mit dem Wert 0xFF ist als Terminator reserviert.
99     Terminatoren werden verwendet, um das Suchen nach einem speziellen
100     Record zu terminieren, d.h. ist er bis dorthin nicht gefunden, wird
101     auch nicht weitergesucht.
102 
103     Bei allen anderen Werten des 'Pre-Tags' (also von 0x01 bis 0xFE)
104     handelt es sich um einen zum SW3 kompatbilen Record, der hier
105     'SfxMiniRecord' genannt wird, er kann daher mit einem <SfxMiniRecordReader>
106     gelesen werden.
107 
108     Beginnt ein Record mit 0x44 k"onnte es sich um einen Drawing-Engine-
109     Record handeln. Dies ist dann der Fall, wenn die folgenden drei Bytes
110     die Zeichenkette 'RMD' bzw. 'RVW' ergeben (zusammen mit 'D'==0x44
111     ergibt dies die K"urzel f"ur 'DRaw-MoDel' bzw. 'DRaw-VieW'). Records
112     dieser Art k"onnen von den hier dargestellten Klassen weder gelesen,
113     noch in irgendeiner Weise interpretiert werden. Einzig die Methode
114     'ScanRecordType()' kann sie erkennen - weitere Behandlung obliegt
115     jedoch der Anwendungsprogrammierung.
116 
117     Diese drei Bytes an den Positionen 2 bis 4 enthalten normalerweise
118     die Gr"o\se des Records ohne Pre-Tag und Gr"o\sen-Bytes selbst,
119     also die Restgr"o\se nach diesem 4-Byte-Header.
120 
121         Struktur des Mini-Records:
122 
123                             1 sal_uInt8         Pre-Tag
124                             3 sal_uInt8         OffsetToEndOfRec
125         OffsetToEndOfRec*   1 sal_uInt8         Content
126 
127     Bei den Extended-Reords folgt auf diesen 4-Byte-Header ein erweiterter
128     Header, der zun"achst den o.g. Record-Typ, dann eine Versions-Kennung
129     sowie ein Tag enth"alt, welches den Inhalt kennzeichnet.
130 
131         Struktur des Extended-Records:
132 
133                             1 sal_uInt8         Pre-Tag (==0x00)
134                             3 sal_uInt8         OffsetToEndOfRec
135         OffsetToEndOfRec*   1 sal_uInt8         Content
136                             1 sal_uInt8         Record-Type
137                             1 sal_uInt8         Version
138                             2 sal_uInt8         Tag
139         ContentSize*        1 sal_uInt8         Content
140 
141         (ContentSize = OffsetToEndOfRec - 8)
142 
143     [Anmerkung]
144 
145     Der Aufbau der Records wird wie folgt begr"undet:
146 
147     Der SW-Record-Typ war zuerst vorhanden, mu\ste also 1:1 "ubernommen
148     werden. Zum Gl"uck wurden einige Record-Tags nicht verwendet, (Z.B.
149     0x00 und 0xFF).
150     =>  1. Byte 0x00 kann als Kennung f"ur erweiterten Record verwendet werden
151     =>  1. Byte 0xFF kann f"ur besondere Zwecke verwendet werden
152 
153     Egal welcher Record-Typ vorliegt, sollte eine Erkennung des Typs, ein
154     Auslesen des Headers und ein "uberpspringen des Records m"oglich sein,
155     ohne zu"uck-seeken zu m"ussen und ohne "uberfl"ussige Daten lesen zu
156     m"ussen.
157     =>  die Bytes 2-4 werden bei allen Records als Offset zum Ende des
158         Records interpretiert, so da\s die Gesamt-Recors-Size sich wie
159         folgt berechnet: sizeof(sal_uInt32) + OffsetToEndOfRec
160 
161     Die Records sollten einfach zu parsen un einheitlich aufgebaut sein.
162     =>  Sie bauen aufeinander auf, so ist z.B. der SfxMiniRecord in jedem
163         anderen enthalten.
164 
165     Die Records sollten auch von denen der Drawing Enginge unterscheidbar
166     sein. Diese beginnen mit 'DRMD' und 'DRVW'.
167     =>  Mini-Records mit dem Pre-Tag 'D' d"urfen maximal 4MB gro\s sein,
168         um nicht in diesen Kennungs-Bereich zu reichen.
169 
170     [Erweiterungen]
171 
172     Es ist geplant das File-Format so zu erweitern, da\s das High-Nibble
173     des Record-Typs der erweiterten Records besondere Aufgaben "ubernehmen
174     soll. Zum Beispiel ist geplant, Record-Contents als 'nur aus Records
175     bestehend' zu kennzeichnen. Ein File-Viewer k"onnte sich dann automatisch
176     durch solche Strukturen 'hangeln', ohne Gefahr zu laufen, auf Daten
177     zu sto\sen, die sich zwar als Records interpretieren lassen, aber
178     tats"achlis als 'flache' Daten geschrieben wurden. Die m"ogliche
179     Erweiterung wird schon jetzt insofern vorbereitet, als da\s das
180     High-Nibble des Typs bei Vergleichen nicht ber"ucksichtigt wird.
181 */
182 
183 //------------------------------------------------------------------------
184 
185 class SVL_DLLPUBLIC SfxMiniRecordWriter
186 
187 /*  [Beschreibung]
188 
189     Mit Instanzen dieser Klasse kann ein einfacher Record in einen Stream
190     geschrieben werden, der sich durch ein sal_uInt8-Tag identifiziert, sowie
191     seine eigene L"ange speichert und somit auch von "alteren Versionen
192     bzw. Readern, die diesen Record-Type (Tag) nicht kennen, "ubersprungen
193     werden kann. Es wird keine Version-Nummer gespeichert.
194 
195     Alternativ kann die Gr"o\se fest angegeben werden oder sie wird
196     automatisch aus der Differenz der Tell()-Angaben vor und nach dem
197     Streamen des Inhalts ermittelt.
198 
199     Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen
200     neue Versionen die Daten der "alteren immer komplett enthalten,
201     es d"urfen allenfalls neue Daten hintenan geh"angt werden!
202 
203     [Fileformat]
204 
205     1*              sal_uInt8       Content-Tag (!= 0)
206     1*              3-sal_uInt8     OffsetToEndOfRec in Bytes
207     SizeOfContent*  sal_uInt8       Content
208 
209     [Beispiel]
210 
211     {
212         SfxMiniRecordWriter aRecord( pStream, MY_TAG_X );
213         *aRecord << aMember1;
214         *aRecord << aMember2;
215     }
216 */
217 
218 {
219 protected:
220     SvStream*       _pStream;   //  <SvStream>, in dem der Record liegt
221     sal_uInt32          _nStartPos; //  Start-Position des Gesamt-Records im Stream
222     FASTBOOL        _bHeaderOk; /*  sal_True, wenn der Header schon geschrieben ist;
223                                     bei DBG_UTIL wird SFX_BOOL_DONTCARE ver-
224                                     wendet, um die Gr"o\se von Fix-Sized-Records
225                                     zu pr"ufen. */
226     sal_uInt8           _nPreTag;   //  in den Header zu schreibendes 'Pre-Tag'
227 
228 public:
229     inline          SfxMiniRecordWriter( SvStream *pStream,
230                                          sal_uInt8 nTag );
231     inline          SfxMiniRecordWriter( SvStream *pStream, sal_uInt8 nTag,
232                                          sal_uInt32 nSize );
233 
234     inline          ~SfxMiniRecordWriter();
235 
236     inline SvStream& operator*() const;
237 
238     inline void     Reset();
239 
240     sal_uInt32          Close( FASTBOOL bSeekToEndOfRec = sal_True );
241 
242 private:
243                     // not implementend, not allowed
244                     SfxMiniRecordWriter( const SfxMiniRecordWriter& );
245     SfxMiniRecordWriter& operator=(const SfxMiniRecordWriter&);
246 };
247 
248 //------------------------------------------------------------------------
249 
250 class SVL_DLLPUBLIC SfxMiniRecordReader
251 
252 /*  [Beschreibung]
253 
254     Mit Instanzen dieser Klasse kann ein einfacher Record aus einem Stream
255     gelesen werden, der mit der Klasse <SfxRecordWriter> geschrieben wurde.
256 
257     Es ist auch m"oglich, den Record zu "uberspringen, ohne sein internes
258     Format zu kennen.
259 
260     [Beispiel]
261 
262     {
263         SfxMiniRecordReader aRecord( pStream );
264         switch ( aRecord.GetTag() )
265         {
266             case MY_TAG_X:
267                 *aRecord >> aMember1;
268                 *aRecord >> aMember2;
269                 break;
270 
271             ...
272         }
273     }
274 */
275 
276 {
277 protected:
278     SvStream*           _pStream;   //  <SvStream>, aus dem gelesen wird
279     sal_uInt32              _nEofRec;   //  Position direkt hinter dem Record
280     FASTBOOL            _bSkipped;  //  sal_True: der Record wurde explizit geskippt
281     sal_uInt8               _nPreTag;   //  aus dem Header gelesenes Pre-Tag
282 
283                         // Drei-Phasen-Ctor f"ur Subklassen
SfxMiniRecordReader()284                         SfxMiniRecordReader() {}
Construct_Impl(SvStream * pStream,sal_uInt8 nTag)285    void                 Construct_Impl( SvStream *pStream, sal_uInt8 nTag )
286                         {
287                             _pStream = pStream;
288                             _bSkipped = sal_False;
289                             _nPreTag = nTag;
290                         }
291     inline FASTBOOL     SetHeader_Impl( sal_uInt32 nHeader );
292 
293                         // als ung"ultig markieren und zur"uck-seeken
SetInvalid_Impl(sal_uInt32 nRecordStartPos)294     void                SetInvalid_Impl( sal_uInt32 nRecordStartPos )
295                         {
296                             _nPreTag = SFX_REC_PRETAG_EOR;
297                             _pStream->Seek( nRecordStartPos );
298                         }
299 
300 public:
301     static sal_uInt16       ScanRecordType( SvStream *pStream );
302 
303                         SfxMiniRecordReader( SvStream *pStream );
304                         SfxMiniRecordReader( SvStream *pStream, sal_uInt8 nTag );
305     inline              ~SfxMiniRecordReader();
306 
307     inline sal_uInt8        GetTag() const;
308     inline FASTBOOL     IsValid() const;
309 
310     inline SvStream&    operator*() const;
311 
312     inline void         Skip();
313 
314 private:
315                         // not implementend, not allowed
316                         SfxMiniRecordReader( const SfxMiniRecordReader& );
317     SfxMiniRecordReader& operator=(const SfxMiniRecordReader&);
318 };
319 
320 //------------------------------------------------------------------------
321 
322 class SVL_DLLPUBLIC SfxSingleRecordWriter: public SfxMiniRecordWriter
323 
324 /*  [Beschreibung]
325 
326     Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben
327     werden, dessen einziger Inhalt sich durch ein sal_uInt16-Tag und eine
328     sal_uInt8-Versions-Nummer identifiziert, sowie seine eigene L"ange speichert
329     und somit auch von "alteren Versionen bzw. Readern, die diesen
330     Record-Type (Tag) nicht kennen, "ubersprungen werden kann.
331 
332     Alternativ kann die Gr"o\se fest angegeben werden oder sie wird
333     automatisch aus der Differenz der Tell()-Angaben vor und nach dem
334     Streamen des Inhalts ermittelt.
335 
336     Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen
337     neue Versionen die Daten der "alteren immer komplett enthalten,
338     es d"urfen allenfalls neue Daten hintenan geh"angt werden!
339 
340     [Fileformat]
341 
342     1*              sal_uInt8       Pre-Tag (!= 0)
343     1*              3-sal_uInt8     OffsetToEndOfRec in Bytes
344     1*              sal_uInt8       Record-Type (==SFX_REC_TYPE_SINGLE)
345     1*              sal_uInt8       Content-Version
346     1*              sal_uInt16      Content-Tag
347     SizeOfContent*  sal_uInt8       Content
348 
349     [Beispiel]
350 
351     {
352         SfxSingleRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION );
353         *aRecord << aMember1;
354         *aRecord << aMember2;
355     }
356 */
357 
358 {
359 protected:
360                     SfxSingleRecordWriter( sal_uInt8 nRecordType,
361                                            SvStream *pStream,
362                                            sal_uInt16 nTag, sal_uInt8 nCurVer );
363 
364 public:
365                     SfxSingleRecordWriter( SvStream *pStream,
366                                            sal_uInt16 nTag, sal_uInt8 nCurVer );
367                     SfxSingleRecordWriter( SvStream *pStream,
368                                            sal_uInt16 nTag, sal_uInt8 nCurVer,
369                                            sal_uInt32 nSize );
370 
371     inline void     Reset();
372 
373     sal_uInt32          Close( FASTBOOL bSeekToEndOfRec = sal_True );
374 };
375 
376 //------------------------------------------------------------------------
377 
378 class SVL_DLLPUBLIC SfxSingleRecordReader: public SfxMiniRecordReader
379 
380 /*  [Beschreibung]
381 
382     Mit Instanzen dieser Klasse kann ein einfacher Record aus einem Stream
383     gelesen werden, der mit der Klasse <SfxSingleRecordWriter> geschrieben
384     wurde.
385 
386     Es ist auch m"oglich, den Record zu "uberspringen, ohne sein internes
387     Format zu kennen.
388 
389     [Beispiel]
390 
391     {
392         SfxSingleRecordReader aRecord( pStream );
393         switch ( aRecord.GetTag() )
394         {
395             case MY_TAG_X:
396                 aRecord >> aMember1;
397                 if ( aRecord.HasVersion(2) )
398                     *aRecord >> aMember2;
399                 break;
400 
401             ...
402         }
403     }
404 */
405 
406 {
407 protected:
408     sal_uInt16              _nRecordTag;    // Art des Gesamt-Inhalts
409     sal_uInt8               _nRecordVer;    // Version des Gesamt-Inhalts
410     sal_uInt8               _nRecordType;   // Record Type aus dem Header
411 
412                         // Drei-Phasen-Ctor f"ur Subklassen
SfxSingleRecordReader()413                         SfxSingleRecordReader() {}
Construct_Impl(SvStream * pStream)414     void                Construct_Impl( SvStream *pStream )
415                         {
416                             SfxMiniRecordReader::Construct_Impl(
417                                     pStream, SFX_REC_PRETAG_EXT );
418                         }
419     FASTBOOL            FindHeader_Impl( sal_uInt16 nTypes, sal_uInt16 nTag );
420     FASTBOOL            ReadHeader_Impl( sal_uInt16 nTypes );
421 
422 public:
423                         SfxSingleRecordReader( SvStream *pStream );
424                         SfxSingleRecordReader( SvStream *pStream, sal_uInt16 nTag );
425 
426     inline sal_uInt16       GetTag() const;
427 
428     inline sal_uInt8        GetVersion() const;
429     inline FASTBOOL     HasVersion( sal_uInt16 nVersion ) const;
430 };
431 
432 //------------------------------------------------------------------------
433 
434 class SVL_DLLPUBLIC SfxMultiFixRecordWriter: public SfxSingleRecordWriter
435 
436 /*  [Beschreibung]
437 
438     Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben
439     werden, der seine eigene L"ange speichert und somit auch von "alteren
440     Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen,
441     "ubersprungen werden kann.
442 
443     Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben
444     Version, die einmalig (stellvertretend f"ur alle) im Header des Records
445     identifiziert werden. Alle Inhalte haben eine vorher bekannte und
446     identische L"ange.
447 
448     Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen
449     neue Versionen die Daten der "alteren immer komplett enthalten,
450     es d"urfen allenfalls neue Daten hinten angeh"angt werden! Hier sind
451     damit selbstverst"andlich nur die Daten der einzelnen Inhalte gemeint,
452     die Anzahl der Inhalte ist selbstverst"andlich variabel und sollte
453     von lesenden Applikationen auch so behandelt werden.
454 
455     [Fileformat]
456 
457     1*                  sal_uInt8       Pre-Tag (==0)
458     1*                  3-sal_uInt8     OffsetToEndOfRec in Bytes
459     1*                  sal_uInt8       Record-Type (==SFX_REC_TYPE_FIXSIZE)
460     1*                  sal_uInt8       Content-Version
461     1*                  sal_uInt16      Content-Tag
462     1*                  sal_uInt16      NumberOfContents
463     1*                  sal_uInt32      SizeOfEachContent
464     NumberOfContents*   (
465     SizeOfEachContent   sal_uInt8       Content
466                         )
467 
468     [Beispiel]
469 
470     {
471         SfxMultiFixRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION );
472         for ( sal_uInt16 n = 0; n < Count(); ++n )
473         {
474             aRecord.NewContent();
475             *aRecord << aMember1[n];
476             *aRecord << aMember2[n];
477         }
478     }
479 */
480 
481 {
482 protected:
483     sal_uInt32          _nContentStartPos;  /*  Startposition des jeweiligen
484                                             Contents - nur bei DBG_UTIL
485                                             und f"ur Subklassen */
486     sal_uInt32          _nContentSize;      //  Gr"o\se jedes Contents
487     sal_uInt16          _nContentCount;     //  jeweilige Anzahl der Contents
488 
489                     SfxMultiFixRecordWriter( sal_uInt8 nRecordType,
490                                              SvStream *pStream,
491                                              sal_uInt16 nTag, sal_uInt8 nCurVer,
492                                              sal_uInt32 nContentSize );
493 
494 public:
495                     SfxMultiFixRecordWriter( SvStream *pStream,
496                                              sal_uInt16 nTag, sal_uInt8 nCurVer,
497                                              sal_uInt32 nContentSize );
498     inline          ~SfxMultiFixRecordWriter();
499 
500     inline void     NewContent();
501 
502     inline void     Reset();
503 
504     sal_uInt32          Close( FASTBOOL bSeekToEndOfRec = sal_True );
505 };
506 
507 //------------------------------------------------------------------------
508 
509 class SVL_DLLPUBLIC SfxMultiVarRecordWriter: public SfxMultiFixRecordWriter
510 
511 /*  [Beschreibung]
512 
513     Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben
514     werden, der seine eigene L"ange speichert und somit auch von "alteren
515     Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen,
516     "ubersprungen werden kann.
517 
518     Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben
519     Version, die einmalig (stellvertretend f"ur alle) im Header des Records
520     identifiziert werden. Die L"ange f"ur jeden einzelnen Inhalt wird
521     automatisch berechnet und gespeichert, so da\s auch einzelne Inhalte
522     "ubersprungen werden k"onnen, ohne sie interpretieren zu m"ussen.
523 
524     Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen
525     neue Versionen die Daten der "alteren immer komplett enthalten,
526     es d"urfen allenfalls neue Daten hinten angeh"angt werden!
527 
528     [Fileformat]
529 
530     1*                  sal_uInt8       Pre-Tag (==0)
531     1*                  3-sal_uInt8     OffsetToEndOfRec in Bytes
532     1*                  sal_uInt8       Record-Type (==SFX_FILETYPE_TYPE_VARSIZE)
533     1*                  sal_uInt8       Content-Version
534     1*                  sal_uInt16      Content-Tag
535     1*                  sal_uInt16      NumberOfContents
536     1*                  sal_uInt32      OffsetToOfsTable
537     NumberOfContents*   (
538     ContentSize*        sal_uInt8       Content
539                         )
540     NumberOfContents*   sal_uInt32      ContentOfs (je per <<8 verschoben)
541 
542     [Beispiel]
543 
544     {
545         SfxMultiVarRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION );
546         for ( sal_uInt16 n = 0; n < Count(); ++n )
547         {
548             aRecord.NewContent();
549             *aRecord << aMember1[n];
550             *aRecord << aMember2[n];
551         }
552     }
553 */
554 
555 {
556 protected:
557     SfxUINT32s          _aContentOfs;
558     sal_uInt16              _nContentVer;   // nur f"ur SfxMultiMixRecordWriter
559 
560                         SfxMultiVarRecordWriter( sal_uInt8 nRecordType,
561                                                  SvStream *pStream,
562                                                  sal_uInt16 nRecordTag,
563                                                  sal_uInt8 nRecordVer );
564 
565     void                FlushContent_Impl();
566 
567 public:
568                         SfxMultiVarRecordWriter( SvStream *pStream,
569                                                  sal_uInt16 nRecordTag,
570                                                  sal_uInt8 nRecordVer );
571     virtual             ~SfxMultiVarRecordWriter();
572 
573     void                NewContent();
574 
575     virtual sal_uInt32      Close( FASTBOOL bSeekToEndOfRec = sal_True );
576 };
577 
578 //------------------------------------------------------------------------
579 
580 class SVL_DLLPUBLIC SfxMultiMixRecordWriter: public SfxMultiVarRecordWriter
581 
582 /*  [Beschreibung]
583 
584     Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben
585     werden, der seine eigene L"ange speichert und somit auch von "alteren
586     Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen,
587     "ubersprungen werden kann.
588 
589     Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben
590     Version, die einmalig (stellvertretend f"ur alle) im Header des Records
591     identifiziert werden. Alle Inhalte haben eine vorher bekannte und
592     identische L"ange.
593 
594     Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen
595     neue Versionen die Daten der "alteren immer komplett enthalten,
596     es d"urfen allenfalls neue Daten hinten angeh"angt werden!
597 
598     [Fileformat]
599 
600     1*                  sal_uInt8       Pre-Tag (==0)
601     1*                  3-sal_uInt8     OffsetToEndOfRec in Bytes
602     1*                  sal_uInt8       Record-Type (==SFX_REC_TYPE_MIXTAGS)
603     1*                  sal_uInt8       Content-Version
604     1*                  sal_uInt16      Record-Tag
605     1*                  sal_uInt16      NumberOfContents
606     1*                  sal_uInt32      OffsetToOfsTable
607     NumberOfContents*   (
608     1*                  sal_uInt16      Content-Tag
609     ContentSize*        sal_uInt8        Content
610                         )
611     NumberOfContents*   sal_uInt32      ( ContentOfs << 8 + Version )
612 */
613 
614 {
615 public:
616     inline              SfxMultiMixRecordWriter( SvStream *pStream,
617                                                  sal_uInt16 nRecordTag,
618                                                  sal_uInt8 nRecordVer );
619 
620     void                NewContent( sal_uInt16 nTag, sal_uInt8 nVersion );
621 
622 // private: geht nicht, da einige Compiler dann auch vorherige privat machen
NewContent()623     void                NewContent()
624                         { DBG_ERROR( "NewContent() only allowed with args" ); }
625 };
626 
627 //------------------------------------------------------------------------
628 
629 class SVL_DLLPUBLIC SfxMultiRecordReader: public SfxSingleRecordReader
630 
631 /*  [Beschreibung]
632 
633     Mit Instanzen dieser Klasse kann ein aus mehreren Contents bestehender
634     Record aus einem Stream gelesen werden, der mit einer der Klassen
635     <SfxMultiFixRecordWriter>, <SfxMultiVarRecordWriter> oder
636     <SfxMultiMixRecordWriter> geschrieben wurde.
637 
638     Es ist auch m"oglich, den Record oder einzelne Contents zu "uberspringen,
639     ohne das jeweilis interne Format zu kennen.
640 
641     [Beispiel]
642 
643     {
644         SfxMultiRecordReader aRecord( pStream );
645         for ( sal_uInt16 nRecNo = 0; aRecord.GetContent(); ++nRecNo )
646         {
647             switch ( aRecord.GetTag() )
648             {
649                 case MY_TAG_X:
650                     X *pObj = new X;
651                     *aRecord >> pObj.>aMember1;
652                     if ( aRecord.HasVersion(2) )
653                         *aRecord >> pObj->aMember2;
654                     Append( pObj );
655                     break;
656 
657                 ...
658             }
659         }
660     }
661 */
662 
663 {
664     sal_uInt32              _nStartPos;     //  Start-Position des Records
665     sal_uInt32*             _pContentOfs;   //  Offsets der Startpositionen
666     sal_uInt32              _nContentSize;  //  Size jedes einzelnen / Tabellen-Pos
667     sal_uInt16              _nContentCount; //  Anzahl der Contents im Record
668     sal_uInt16              _nContentNo;    /*  der Index des aktuellen Contents
669                                             enth"alt jeweils den Index des
670                                             Contents, der beim n"achsten
671                                             GetContent() geholt wird */
672     sal_uInt16              _nContentTag;   //  Art-Kennung des aktuellen Contents
673     sal_uInt8               _nContentVer;   //  Versions-Kennung des akt. Contents
674 
675     FASTBOOL            ReadHeader_Impl();
676 
677 public:
678                         SfxMultiRecordReader( SvStream *pStream );
679                         SfxMultiRecordReader( SvStream *pStream, sal_uInt16 nTag );
680                         ~SfxMultiRecordReader();
681 
682     FASTBOOL            GetContent();
683     inline sal_uInt16       GetContentTag();
684     inline sal_uInt8        GetContentVersion() const;
685     inline FASTBOOL     HasContentVersion( sal_uInt16 nVersion ) const;
686 
687     inline sal_uInt32       ContentCount() const;
688 };
689 
690 //=========================================================================
691 
SfxMiniRecordWriter(SvStream * pStream,sal_uInt8 nTag)692 inline SfxMiniRecordWriter::SfxMiniRecordWriter
693 (
694     SvStream*       pStream,        // Stream, in dem der Record angelegt wird
695     sal_uInt8            nTag            // Record-Tag zwischen 0x01 und 0xFE
696 )
697 
698 /*  [Beschreibung]
699 
700     Legt in 'pStream' einen 'SfxMiniRecord' an, dessen Content-Gr"o\se
701     nicht bekannt ist, sondern nach dam Streamen des Contents errechnet
702     werden soll.
703 */
704 
705 :   _pStream( pStream ),
706     _nStartPos( pStream->Tell() ),
707     _bHeaderOk(sal_False),
708     _nPreTag( nTag )
709 {
710     DBG_ASSERT( _nPreTag != 0xFF, "invalid Tag" );
711     DBG( DbgOutf( "SfxFileRec: writing record to %ul", pStream->Tell() ) );
712 
713     pStream->SeekRel( + SFX_REC_HEADERSIZE_MINI );
714 }
715 
716 //-------------------------------------------------------------------------
717 
SfxMiniRecordWriter(SvStream * pStream,sal_uInt8 nTag,sal_uInt32 nSize)718 inline SfxMiniRecordWriter::SfxMiniRecordWriter
719 (
720     SvStream*       pStream,        // Stream, in dem der Record angelegt wird
721     sal_uInt8           nTag,           // Record-Tag zwischen 0x01 und 0xFE
722     sal_uInt32          nSize           // Gr"o\se der Daten in Bytes
723 )
724 
725 /*  [Beschreibung]
726 
727     Legt in 'pStream' einen 'SfxMiniRecord' an, dessen Content-Gr"o\se
728     von vornherein bekannt ist.
729 */
730 
731 :   _pStream( pStream ),
732     // _nTag( uninitialized ),
733     // _nStarPos( uninitialized ),
734     _bHeaderOk(SFX_BOOL_DONTCARE)
735 {
736     DBG_ASSERT( nTag != 0 && nTag != 0xFF, "invalid Tag" );
737     DBG(_nStartPos = pStream->Tell());
738     DBG( DbgOutf( "SfxFileRec: writing record to %ul", _nStartPos ) );
739 
740     *pStream << ( ( nTag << 24 ) | nSize );
741 }
742 
743 //-------------------------------------------------------------------------
744 
~SfxMiniRecordWriter()745 inline SfxMiniRecordWriter::~SfxMiniRecordWriter()
746 
747 /*  [Beschreibung]
748 
749     Der Dtor der Klasse <SfxMiniRecordWriter> schlie\st den Record
750     automatisch, falls <SfxMiniRecordWriter::Close()> nicht bereits
751     explizit gerufen wurde.
752 */
753 
754 {
755     // wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden
756     if ( !_bHeaderOk DBG(||sal_True) )
757         Close();
758 }
759 
760 //-------------------------------------------------------------------------
761 
operator *() const762 inline SvStream& SfxMiniRecordWriter::operator*() const
763 
764 /*  [Beschreibung]
765 
766     Dieser Operator liefert den Stream, in dem der Record liegt.
767     Der Record darf noch nicht geschlossen worden sein.
768 */
769 
770 {
771     DBG_ASSERT( !_bHeaderOk, "getting Stream of closed record" );
772     return *_pStream;
773 }
774 
775 //-------------------------------------------------------------------------
776 
Reset()777 inline void SfxMiniRecordWriter::Reset()
778 {
779     _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI );
780     _bHeaderOk = sal_False;
781 }
782 
783 //=========================================================================
784 
~SfxMiniRecordReader()785 inline SfxMiniRecordReader::~SfxMiniRecordReader()
786 
787 /*  [Beschreibung]
788 
789     Der Dtor der Klasse <SfxMiniRecordReader> positioniert den Stream
790     automatisch auf die Position direkt hinter dem Record, falls nicht
791     <SfxMiniRecordReader::Skip()> bereits explizit gerufen wurde.
792 */
793 
794 {
795     // noch nicht explizit ans Ende gesprungen?
796     if ( !_bSkipped )
797         Skip();
798 }
799 
800 //-------------------------------------------------------------------------
801 
Skip()802 inline void SfxMiniRecordReader::Skip()
803 
804 /*  [Beschreibung]
805 
806     Mit dieser Methode wird der Stream direkt hinter das Ende des Records
807     positioniert.
808 */
809 
810 {
811     _pStream->Seek(_nEofRec);
812     _bSkipped = sal_True;
813 }
814 
815 //-------------------------------------------------------------------------
816 
GetTag() const817 inline sal_uInt8 SfxMiniRecordReader::GetTag() const
818 
819 /*  [Beschreibung]
820 
821     Liefert des aus dem Header gelesene Pre-Tag des Records. Dieses kann
822     auch SFX_REC_PRETAG_EXT oder SFX_REC_PRETAG_EOR sein, im
823     letzteren Fall ist am Stream der Fehlercode ERRCODE_IO_WRONGFORMAT
824     gesetzt. SFX_REC_PRETAG_EXT ist g"ultig, da diese extended-Records
825     nur eine Erweiterung des SfxMiniRecord darstellen.
826 */
827 
828 {
829     return _nPreTag;
830 }
831 
832 //-------------------------------------------------------------------------
833 
IsValid() const834 inline FASTBOOL SfxMiniRecordReader::IsValid() const
835 
836 /*  [Beschreibung]
837 
838     Hiermit kann abgefragt werden, ob der Record erfolgreich aus dem
839     Stream konstruiert werden konnte, der Header also f"ur diesen Record-Typ
840     passend war.
841 */
842 
843 {
844     return _nPreTag != SFX_REC_PRETAG_EOR;
845 }
846 
847 //-------------------------------------------------------------------------
848 
operator *() const849 inline SvStream& SfxMiniRecordReader::operator*() const
850 
851 /*  [Beschreibung]
852 
853     Dieser Operator liefert den Stream in dem der Record liegt.
854     Die aktuelle Position des Streams mu\s innerhalb des Records liegen.
855 */
856 
857 {
858     DBG_ASSERT( _pStream->Tell() < _nEofRec, "read behind record" );
859     return *_pStream;
860 }
861 
862 //=========================================================================
863 
Close(FASTBOOL bSeekToEndOfRec)864 inline sal_uInt32 SfxSingleRecordWriter::Close( FASTBOOL bSeekToEndOfRec )
865 
866 //  siehe <SfxMiniRecordWriter::Close(FASTBOOL)>
867 
868 {
869     sal_uInt32 nRet = 0;
870 
871     // wurde der Header noch nicht geschrieben?
872     if ( !_bHeaderOk )
873     {
874         // Basisklassen-Header schreiben
875         sal_uInt32 nEndPos = SfxMiniRecordWriter::Close( bSeekToEndOfRec );
876 
877         // ggf. ans Ende des eigenen Headers seeken oder hinter Rec bleiben
878         if ( !bSeekToEndOfRec )
879             _pStream->SeekRel( SFX_REC_HEADERSIZE_SINGLE );
880         nRet = nEndPos;
881     }
882 #ifdef DBG_UTIL
883     else
884         // Basisklassen-Header pr"ufen
885         SfxMiniRecordWriter::Close( bSeekToEndOfRec );
886 #endif
887 
888     // Record war bereits geschlossen
889 //  nRet = 0;
890     return nRet;
891 }
892 
893 //-------------------------------------------------------------------------
894 
Reset()895 inline void SfxSingleRecordWriter::Reset()
896 {
897     _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI +
898                                  SFX_REC_HEADERSIZE_SINGLE );
899     _bHeaderOk = sal_False;
900 }
901 
902 //=========================================================================
903 
GetTag() const904 inline sal_uInt16 SfxSingleRecordReader::GetTag() const
905 
906 /*  [Beschreibung]
907 
908     Liefert des aus dem Header gelesene Tag f"ur den Gesamt-Record.
909 */
910 
911 {
912     return _nRecordTag;
913 }
914 
915 //-------------------------------------------------------------------------
916 
GetVersion() const917 inline sal_uInt8 SfxSingleRecordReader::GetVersion() const
918 
919 /*  [Beschreibung]
920 
921     Liefert die Version des aus dem Stream gelesenen Records.
922 */
923 
924 {
925     return _nRecordVer;
926 }
927 
928 //-------------------------------------------------------------------------
929 
HasVersion(sal_uInt16 nVersion) const930 inline FASTBOOL SfxSingleRecordReader::HasVersion( sal_uInt16 nVersion ) const
931 
932 /*  [Beschreibung]
933 
934     Stellt fest, ob der aus dem Stream gelese Record in der Version
935     'nVersion' oder h"oher vorliegt.
936 */
937 
938 {
939     return _nRecordVer >= nVersion;
940 }
941 
942 //=========================================================================
943 
~SfxMultiFixRecordWriter()944 inline SfxMultiFixRecordWriter::~SfxMultiFixRecordWriter()
945 
946 /*  [Beschreibung]
947 
948     Der Dtor der Klasse <SfxMultiFixRecordWriter> schlie\st den Record
949     automatisch, falls <SfxMutiFixRecordWriter::Close()> nicht bereits
950     explizit gerufen wurde.
951 */
952 
953 {
954     // wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden
955     if ( !_bHeaderOk )
956         Close();
957 }
958 
959 //-------------------------------------------------------------------------
960 
NewContent()961 inline void SfxMultiFixRecordWriter::NewContent()
962 
963 /*  [Beschreibung]
964 
965     Mit dieser Methode wird in den Record ein neuer Content eingef"ugt.
966     Jeder, auch der 1. Record mu\s durch Aufruf dieser Methode eingeleitet
967     werden.
968 */
969 
970 {
971     #ifdef DBG_UTIL
972     sal_uLong nOldStartPos;
973     // Startposition des aktuellen Contents merken - Achtung Subklassen!
974     nOldStartPos = _nContentStartPos;
975     #endif
976     _nContentStartPos = _pStream->Tell();
977 
978 #ifdef DBG_UTIL
979     // ist ein vorhergehender Content vorhanden?
980     if ( _nContentCount )
981     {
982         // pr"ufen, ob der vorhergehende die Soll-Gr"o\se eingehalten hat
983         DBG_ASSERT( _nContentStartPos - nOldStartPos == _nContentSize,
984                     "wrong content size detected" );
985     }
986 #endif
987 
988     // Anzahl mitz"ahlen
989     ++_nContentCount;
990 }
991 
992 //=========================================================================
993 
SfxMultiMixRecordWriter(SvStream * pStream,sal_uInt16 nRecordTag,sal_uInt8 nRecordVer)994 inline SfxMultiMixRecordWriter::SfxMultiMixRecordWriter
995 (
996     SvStream*       pStream,    // Stream, in dem der Record angelegt wird
997     sal_uInt16          nRecordTag, // Gesamt-Record-Art-Kennung
998     sal_uInt8           nRecordVer  // Gesamt-Record-Versions-Kennung
999 )
1000 
1001 /*  [Beschreibung]
1002 
1003     Legt in 'pStream' einen 'SfxMultiMixRecord' an, f"ur dessen Contents
1004     je eine separate Kennung f"ur Art (Tag) und Version gespeichert wird.
1005     Die Gr"o\sen der einzelnen Contents werden automatisch ermittelt.
1006 */
1007 
1008 :   SfxMultiVarRecordWriter( SFX_REC_TYPE_MIXTAGS,
1009                              pStream, nRecordTag, nRecordVer )
1010 {
1011 }
1012 
1013 //=========================================================================
1014 
Reset()1015 inline void SfxMultiFixRecordWriter::Reset()
1016 {
1017     _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI +
1018                                  SFX_REC_HEADERSIZE_SINGLE +
1019                                  SFX_REC_HEADERSIZE_MULTI );
1020     _bHeaderOk = sal_False;
1021 }
1022 
1023 //=========================================================================
1024 
GetContentTag()1025 inline sal_uInt16 SfxMultiRecordReader::GetContentTag()
1026 
1027 /*  [Beschreibung]
1028 
1029     Diese Methode liefert die Art-Kennung des zuletzt mit der Methode
1030     <SfxMultiRecordReder::GetContent()> ge"offneten Contents.
1031 */
1032 
1033 {
1034     return _nContentTag;
1035 }
1036 
1037 //-------------------------------------------------------------------------
1038 
GetContentVersion() const1039 inline sal_uInt8 SfxMultiRecordReader::GetContentVersion() const
1040 
1041 /*  [Beschreibung]
1042 
1043     Diese Methode liefert die Version-Kennung des zuletzt mit der Methode
1044     <SfxMultiRecordReder::GetContent()> ge"offneten Contents.
1045 */
1046 
1047 {
1048     return _nContentVer;
1049 }
1050 
1051 //-------------------------------------------------------------------------
1052 
HasContentVersion(sal_uInt16 nVersion) const1053 inline FASTBOOL SfxMultiRecordReader::HasContentVersion( sal_uInt16 nVersion ) const
1054 
1055 /*  [Beschreibung]
1056 
1057     Diese Methode stellt fest, ob die Version 'nVersion' in der Version des
1058     zuletzt mit der Methode <SfxMultiRecordReder::GetContent()> ge"offneten
1059     Contents enthalten ist.
1060 */
1061 
1062 {
1063     return _nContentVer >= nVersion;
1064 }
1065 
1066 //-------------------------------------------------------------------------
1067 
ContentCount() const1068 inline sal_uInt32 SfxMultiRecordReader::ContentCount() const
1069 
1070 /*  [Beschreibung]
1071 
1072     Diese Methode liefert die Anzahl im Record befindlichen Contents.
1073 */
1074 
1075 {
1076     return _nContentCount;
1077 }
1078 
1079 #endif
1080 
1081