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