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