Branch data 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 : 0 : SfxMiniRecordReader() {}
274 : 0 : void Construct_Impl( SvStream *pStream, sal_uInt8 nTag )
275 : : {
276 : 0 : _pStream = pStream;
277 : 0 : _bSkipped = sal_False;
278 : 0 : _nPreTag = nTag;
279 : 0 : }
280 : : inline bool SetHeader_Impl( sal_uInt32 nHeader );
281 : :
282 : : // als ung"ultig markieren und zur"uck-seeken
283 : 0 : void SetInvalid_Impl( sal_uInt32 nRecordStartPos )
284 : : {
285 : 0 : _nPreTag = SFX_REC_PRETAG_EOR;
286 : 0 : _pStream->Seek( nRecordStartPos );
287 : 0 : }
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 : 36736 : 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 : 0 : 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 : 0 : SfxSingleRecordReader() {}
370 : 0 : void Construct_Impl( SvStream *pStream )
371 : : {
372 : : SfxMiniRecordReader::Construct_Impl(
373 : 0 : pStream, SFX_REC_PRETAG_EXT );
374 : 0 : }
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 [ - + ]: 31606 : 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 : 46996 : 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 : 46996 : _nStartPos( pStream->Tell() ),
657 : : _bHeaderOk(false),
658 : 93992 : _nPreTag( nTag )
659 : : {
660 : : DBG_ASSERT( _nPreTag != 0xFF, "invalid Tag" );
661 : : DBG( DbgOutf( "SfxFileRec: writing record to %ul", pStream->Tell() ) );
662 : :
663 : 46996 : pStream->SeekRel( + SFX_REC_HEADERSIZE_MINI );
664 : 46996 : }
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 : 46996 : 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 [ + + ]: 46996 : if ( !_bHeaderOk )
707 : 5130 : Close();
708 : 46996 : }
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 : 0 : 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 [ # # ]: 0 : if ( !_bSkipped )
747 : 0 : Skip();
748 : 0 : }
749 : :
750 : : //-------------------------------------------------------------------------
751 : :
752 : 0 : 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 : 0 : _pStream->Seek(_nEofRec);
762 : 0 : _bSkipped = sal_True;
763 : 0 : }
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 : 36736 : inline sal_uInt32 SfxSingleRecordWriter::Close( bool bSeekToEndOfRec )
815 : :
816 : : // siehe <SfxMiniRecordWriter::Close(bool)>
817 : :
818 : : {
819 : 36736 : sal_uInt32 nRet = 0;
820 : :
821 : : // wurde der Header noch nicht geschrieben?
822 [ + - ]: 36736 : if ( !_bHeaderOk )
823 : : {
824 : : // Basisklassen-Header schreiben
825 : 36736 : sal_uInt32 nEndPos = SfxMiniRecordWriter::Close( bSeekToEndOfRec );
826 : :
827 : : // ggf. ans Ende des eigenen Headers seeken oder hinter Rec bleiben
828 [ + - ]: 36736 : if ( !bSeekToEndOfRec )
829 : 36736 : _pStream->SeekRel( SFX_REC_HEADERSIZE_SINGLE );
830 : 36736 : 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 : 36736 : 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 : 36736 : 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 [ - + ]: 36736 : if ( !_bHeaderOk )
906 [ # # ]: 0 : Close();
907 : 36736 : }
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 : 31606 : 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 : 31606 : pStream, nRecordTag, nRecordVer )
960 : : {
961 : 31606 : }
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 : 0 : 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 : 0 : 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: */
|