xref: /trunk/main/svl/inc/svl/filerec.hxx (revision 39a19a47)
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