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