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 INCLUDED_SVL_FILEREC_HXX
21 : #define INCLUDED_SVL_FILEREC_HXX
22 :
23 : #include <svl/svldllapi.h>
24 : #include <tools/debug.hxx>
25 : #include <tools/stream.hxx>
26 : #include <vector>
27 :
28 : #define SFX_REC_PRETAG_EXT sal_uInt8(0x00) // Pre-Tag for Extended-Records
29 : #define SFX_REC_PRETAG_EOR sal_uInt8(0xFF) // Pre-Tag for End-Of-Records
30 :
31 : #define SFX_REC_TYPE_NONE sal_uInt8(0x00) // unknown Record type
32 : #define SFX_REC_TYPE_FIRST sal_uInt8(0x01)
33 : #define SFX_REC_TYPE_SINGLE sal_uInt8(0x01) // Single-Content-Record
34 : #define SFX_REC_TYPE_FIXSIZE sal_uInt8(0x02) // Fix-Size-Multi-Content-Record
35 : #define SFX_REC_TYPE_VARSIZE_RELOC sal_uInt8(0x03) // variable Rec-Size
36 : #define SFX_REC_TYPE_VARSIZE sal_uInt8(0x04) // old (not movable)
37 : #define SFX_REC_TYPE_MIXTAGS_RELOC sal_uInt8(0x07) // Mixed Tag Content-Record
38 : #define SFX_REC_TYPE_MIXTAGS sal_uInt8(0x08) // old (not movable)
39 : #define SFX_REC_TYPE_LAST sal_uInt8(0x08)
40 : #define SFX_REC_TYPE_MINI 0x100 // Mini-Record
41 : #define SFX_REC_TYPE_DRAWENG 0x400 // Drawing-Engine-Record
42 : #define SFX_REC_TYPE_EOR 0xF00 // End-Of-Records
43 :
44 : #define SFX_REC_HEADERSIZE_MINI 4 // size of the Mini-Record-Header
45 : #define SFX_REC_HEADERSIZE_SINGLE 4 // additional HEADERSIZE_MINI => 8
46 : #define SFX_REC_HEADERSIZE_MULTI 6 // additional HEADERSIZE_SINGLE => 14
47 :
48 :
49 : // General file format: documented at class SfxMiniRecordReader below
50 :
51 : /** Writes simple records in a stream
52 : *
53 : * An instance of this class can write a simple record into a stream. It identifies itself
54 : * with a sal_uInt8 and stores its own size. This allows it to be skipped with old versions or
55 : * readers if they do not know the record type (= tag). No version number will be stored.
56 : *
57 : * One can either provide the size or the latter will be automatically calculated based on the
58 : * difference of Tell() before and after streaming the content.
59 : *
60 : * @par File format
61 : *
62 : * 1* sal_uInt8 Content-Tag (!= 0)
63 : * 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes
64 : * SizeOfContent* sal_uInt8 Content
65 : *
66 : * @par Example
67 : * @code
68 : * {
69 : * SfxMiniRecordWriter aRecord( pStream, MY_TAG_X );
70 : * *aRecord << aMember1;
71 : * *aRecord << aMember2;
72 : * }
73 : * @endcode
74 : *
75 : * @note To ensure up- and downwards compatibility, new versions need to include
76 : * the data of the older ones and are only allowed to add data afterwards.
77 : * @see SfxMiniRecordReader
78 : */
79 : class SVL_DLLPUBLIC SfxMiniRecordWriter
80 : {
81 : protected:
82 : SvStream* _pStream; // <SvStream> with the record
83 : sal_uInt32 _nStartPos; // starting position of the total record in the stream
84 : bool _bHeaderOk; /* TRUE, if header already written */
85 : sal_uInt8 _nPreTag; // 'pre-Tag' to write to header
86 :
87 : public:
88 : inline SfxMiniRecordWriter( SvStream *pStream, sal_uInt8 nTag );
89 : inline ~SfxMiniRecordWriter();
90 :
91 : inline SvStream& operator*() const;
92 :
93 : inline void Reset();
94 : sal_uInt32 Close( bool bSeekToEndOfRec = true );
95 :
96 : private:
97 : /// not implementend, not allowed
98 : SfxMiniRecordWriter( const SfxMiniRecordWriter& );
99 : SfxMiniRecordWriter& operator=(const SfxMiniRecordWriter&);
100 : };
101 :
102 : /** Reads simple record from a stream
103 : *
104 : * An instance of this class allows to read a simple record from a stream that was written by
105 : * SfxMiniRecordWriter. It is also possible to skip a record, even without knowing its internal
106 : * format.
107 : *
108 : * @par Example
109 : * @code
110 : * {
111 : * SfxMiniRecordReader aRecord( pStream );
112 : * switch ( aRecord.GetTag() )
113 : * {
114 : * case MY_TAG_X:
115 : * *aRecord >> aMember1;
116 : * *aRecord >> aMember2;
117 : * break;
118 : *
119 : * ...
120 : * }
121 : * }
122 : * @endcode
123 : *
124 : * @par General file format
125 : *
126 : * Each record begins with one byte, the so called 'Pre-Tag'.
127 : *
128 : * If this 'Pre-Tag' == 0x00, then the record is a extended record,
129 : * whose type is further determined by another byte at position 5:
130 : *
131 : * 0x01: SfxSingleRecord
132 : * 0x02: SfxMultiFixRecord
133 : * 0x03+0x04: SfxMultiVarRecord
134 : * 0x07+0x08: SfxMultiMixRecord
135 : * (All other possible record types are reserved.)
136 : *
137 : * Normally, if only for performance reasons, the file formats are
138 : * constructed in such a way, that when loading the record type
139 : * is predetermined. So the record type serves mainly for checks
140 : * and for file viewers that do not know the exact file format.
141 : *
142 : * For that purpse 'SfxMiniRecordReader' provides a static method
143 : * 'ScanRecordType()', with which it is possible to find out what
144 : * Record type can be found in the stream that was passed.
145 : *
146 : * A 'Pre-Tag' with value 0xFF is reserved for a terminator.
147 : * Terminators are used to stop looking for a particular record,
148 : * i.e. if it was not found until then the search will not be continued.
149 : *
150 : * For all other values of the 'Pre-Tag' (so 0x01 to 0xFE) the record
151 : * is one that is compatible with SW3, called 'SfxMiniRecord' here,
152 : * and therefore it can be read with an <SfxMiniRecordReader>.
153 : *
154 : * If the record starts with 0x44 it could be a Drawing-Engine-Record.
155 : * This is the case if the following 3 bytes spell 'RMD' or 'RVW'
156 : * (which together with 'D'==0x44 form an abbreviation for 'DRaw-MoDel'
157 : * or 'DRaw-VieW'). Records of this type cannot be readby the classes
158 : * represented here, nor interpreted in any way. Only the
159 : * 'ScanRecordType()' method can recognise it - but further processing
160 : * is impossible.
161 : *
162 : * The 3 bytes in postion 2 to 4 normally contain the size of the
163 : * record without the pre-tag and the size field itself,
164 : * so the remaining size after the 4 byte header.
165 : *
166 : * Structure of the Mini-Records:
167 : *
168 : * 1 sal_uInt8 Pre-Tag
169 : * 3 sal_uInt8 OffsetToEndOfRec
170 : * OffsetToEndOfRec* 1 sal_uInt8 Content
171 : *
172 : * For Extended-Reords the 4 byte header is followed by an extended header,
173 : * which contains first the record type, than a version number
174 : * and a tag, which indicates the kind of content.
175 : *
176 : * Structure of the extended record:
177 : *
178 : * 1 sal_uInt8 Pre-Tag (==0x00)
179 : * 3 sal_uInt8 OffsetToEndOfRec
180 : * OffsetToEndOfRec* 1 sal_uInt8 Content
181 : * 1 sal_uInt8 Record-Type
182 : * 1 sal_uInt8 Version
183 : * 2 sal_uInt8 Tag
184 : * ContentSize* 1 sal_uInt8 Content
185 : *
186 : * (ContentSize = OffsetToEndOfRec - 8)
187 : *
188 : * @note
189 : * The reason for the structure of the record is as follows:
190 : *
191 : * The SW record type came first, and so had to be kept 1:1.
192 : * Fortunately some record tags had not been used (like 0x00 and 0xFF).
193 : * <BR>
194 : * => 1st byte 0x00 can be used to identify extended records
195 : * <BR>
196 : * => 1st byte 0xFF can be used for special purposes.
197 : *
198 : * Whatever record type is present, it should be possible to recognise
199 : * the type, read the header and skip the record without having to
200 : * seek back or read superfluous data.
201 : * <BR>
202 : * => Bytes 2-4 are interpreted as the offset to the end of the record
203 : * whatever the record, so that the total record size is equal
204 : * to sizeof(sal_uInt32) + OffsetToEndOfRec
205 : *
206 : * The records should be easy to parse and constructed uniformly
207 : * <BR>
208 : * => They build on each, for instance the SfxMiniRecord is contained
209 : * in all others
210 : *
211 : * It should be possible to distinguish the record from Drawing Enginge
212 : * ones. These start with 'DRMD' und 'DRVW'.
213 : * <BR>
214 : * => Mini-Records with Pre-Tag 'D' can only be up to 4MB in size,
215 : * to avoid confusion.
216 : *
217 : * @par Extensions
218 : * Plans are to extend the file format in such a way that the high nibble
219 : * of the record type has special duties. For instance it is planned
220 : * to mark Record-Contents als 'consisting only of Records'. That way
221 : * a file viewer could automatically parse these structures without
222 : * risking encountering data that looks like records, but actually is
223 : * flat data. Those further extensions are prepared to the extent
224 : * that in type comparisons the high nibble is not taken into account.
225 : *
226 : * @see SfxMiniRecordWriter
227 : */
228 : class SVL_DLLPUBLIC SfxMiniRecordReader
229 : {
230 : protected:
231 : SvStream* _pStream; // <SvStream> to read from
232 : sal_uInt32 _nEofRec; // Position direcly after the record
233 : bool _bSkipped; // TRUE: the record was skipped explicitly
234 : sal_uInt8 _nPreTag; // Pre-Tag read from the heather
235 :
236 : // three phase constructor for sub-classes
237 0 : SfxMiniRecordReader()
238 : : _pStream(NULL)
239 : , _nEofRec(0)
240 : , _bSkipped(false)
241 0 : , _nPreTag(0)
242 : {
243 0 : }
244 0 : void Construct_Impl( SvStream *pStream, sal_uInt8 nTag )
245 : {
246 0 : _pStream = pStream;
247 0 : _bSkipped = false;
248 0 : _nPreTag = nTag;
249 0 : }
250 : inline bool SetHeader_Impl( sal_uInt32 nHeader );
251 :
252 : // mark as invalid and seek back
253 0 : void SetInvalid_Impl( sal_uInt32 nRecordStartPos )
254 : {
255 0 : _nPreTag = SFX_REC_PRETAG_EOR;
256 0 : _pStream->Seek( nRecordStartPos );
257 0 : }
258 :
259 : public:
260 : SfxMiniRecordReader( SvStream *pStream, sal_uInt8 nTag );
261 : inline ~SfxMiniRecordReader();
262 :
263 : inline sal_uInt8 GetTag() const;
264 : inline bool IsValid() const;
265 :
266 : inline SvStream& operator*() const;
267 :
268 : inline void Skip();
269 :
270 : private:
271 : /// not implementend, not allowed
272 : SfxMiniRecordReader( const SfxMiniRecordReader& );
273 : SfxMiniRecordReader& operator=(const SfxMiniRecordReader&);
274 : };
275 :
276 : /**
277 : *
278 : * With instances of this class a record ban be written to a stream,
279 : * whose only contents is identified by a sal_uInt16 tag and a
280 : * sal_uInt8 version number. Also the length of the record is stored
281 : * so that older versions or readers that do not known the
282 : * record type (tag) can skip it.
283 : *
284 : * The size can be given directly or calculated automatically from
285 : * the difference between the tell() return values before and
286 : * after streaming the conntents.
287 : *
288 : * To allow for forward and backward compatibility, newer versions
289 : * of the data must always inclode the older versions completely,
290 : * it is only allowed to append new data!
291 : *
292 : * @par File Format
293 : *
294 : * 1* sal_uInt8 Pre-Tag (!= 0)
295 : * 1* 3-sal_uInt8 OffsetToEndOfRec in bytes
296 : * 1* sal_uInt8 Record-Type (==SFX_REC_TYPE_SINGLE)
297 : * 1* sal_uInt8 Content-Version
298 : * 1* sal_uInt16 Content-Tag
299 : * SizeOfContent* sal_uInt8 Content
300 : */
301 50380 : class SVL_DLLPUBLIC SfxSingleRecordWriter: public SfxMiniRecordWriter
302 : {
303 : protected:
304 : SfxSingleRecordWriter( sal_uInt8 nRecordType,
305 : SvStream *pStream,
306 : sal_uInt16 nTag, sal_uInt8 nCurVer );
307 :
308 : public:
309 : inline void Reset();
310 :
311 : sal_uInt32 Close( bool bSeekToEndOfRec = true );
312 : };
313 :
314 : /**
315 : *
316 : * With instances of this class simple records can be read from a stream,
317 : * that were written with class <SfxSingleRecordWriter>.
318 : *
319 : * It is also possible to skip the record without knowing the internal format.
320 : */
321 0 : class SVL_DLLPUBLIC SfxSingleRecordReader: public SfxMiniRecordReader
322 : {
323 : protected:
324 : sal_uInt16 _nRecordTag; // type of the complete contents
325 : sal_uInt8 _nRecordVer; // version of the complete contents
326 : sal_uInt8 _nRecordType; // Record Type from the header
327 :
328 : // Three phase constructor for derived classes
329 0 : SfxSingleRecordReader()
330 : : _nRecordTag(0)
331 : , _nRecordVer(0)
332 0 : , _nRecordType(0)
333 : {
334 0 : }
335 0 : void Construct_Impl( SvStream *pStream )
336 : {
337 : SfxMiniRecordReader::Construct_Impl(
338 0 : pStream, SFX_REC_PRETAG_EXT );
339 0 : }
340 : bool FindHeader_Impl( sal_uInt16 nTypes, sal_uInt16 nTag );
341 : bool ReadHeader_Impl( sal_uInt16 nTypes );
342 :
343 : public:
344 :
345 : inline sal_uInt16 GetTag() const;
346 :
347 : inline sal_uInt8 GetVersion() const;
348 : inline bool HasVersion( sal_uInt16 nVersion ) const;
349 : };
350 :
351 : /**
352 : *
353 : * Instances of this class can be used to write a record to a stream,
354 : * which stores its own length so that it can be skipped by
355 : * older versions and readers that do not known the record type (tag).
356 : *
357 : * It contains multipl contents of the same type (tag) and the same
358 : * version, which have been identified once and for all in the
359 : * header of the reacord. All contents have a length which is
360 : * known in advance and identical.
361 : *
362 : * To be able to guarantee forward and backwards compatibility,
363 : * newer versions of the that must always completely contain
364 : * the old version, so it is only allowed to append data!
365 : * Obviously, only the data of the individual contents are meant,
366 : * the number of contents is naturally variable, and should be
367 : * treated as such by the reading application.
368 : *
369 : * @par File format
370 : *
371 : * 1* sal_uInt8 Pre-Tag (==0)
372 : * 1* 3-sal_uInt8 OffsetToEndOfRec in bytes
373 : * 1* sal_uInt8 Record-Type (==SFX_REC_TYPE_FIXSIZE)
374 : * 1* sal_uInt8 Content-Version
375 : * 1* sal_uInt16 Content-Tag
376 : * 1* sal_uInt16 NumberOfContents
377 : * 1* sal_uInt32 SizeOfEachContent
378 : * NumberOfContents* (
379 : * SizeOfEachContent sal_uInt8 Content
380 : * )
381 : *
382 : * @par Example
383 : * @code
384 : * {
385 : * SfxMultiFixRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION );
386 : * for ( sal_uInt16 n = 0; n < Count(); ++n )
387 : * {
388 : * aRecord.NewContent();
389 : * *aRecord << aMember1[n];
390 : * *aRecord << aMember2[n];
391 : * }
392 : * }
393 : * @endcode
394 : */
395 : class SVL_DLLPUBLIC SfxMultiFixRecordWriter: public SfxSingleRecordWriter
396 : {
397 : protected:
398 : sal_uInt32 _nContentStartPos; /* Startposition des jeweiligen
399 : Contents - nur bei DBG_UTIL
400 : und f"ur Subklassen */
401 : sal_uInt32 _nContentSize; // Gr"o\se jedes Contents
402 : sal_uInt16 _nContentCount; // jeweilige Anzahl der Contents
403 :
404 : SfxMultiFixRecordWriter( sal_uInt8 nRecordType,
405 : SvStream *pStream,
406 : sal_uInt16 nTag,
407 : sal_uInt8 nCurVer );
408 :
409 : public:
410 : inline ~SfxMultiFixRecordWriter();
411 :
412 : inline void NewContent();
413 :
414 : inline void Reset();
415 :
416 : sal_uInt32 Close( bool bSeekToEndOfRec = true );
417 : };
418 :
419 : /** write record with multiple content items
420 : *
421 : * Write a record into a stream that stores its own size. This allows it to be
422 : * skipped with old versions or readers if they do not know the record type (= tag).
423 : *
424 : * It contains multiple content items of the same tag and version, that are both
425 : * stored in the header of the record. The size of each content will be calculated
426 : * automatically and stored so that single content items can be skipped without
427 : * having to read them.
428 : *
429 : * @par File Format
430 : *
431 : * 1* sal_uInt8 Pre-Tag (==0)
432 : * 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes
433 : * 1* sal_uInt8 Record-Type (==SFX_FILETYPE_TYPE_VARSIZE)
434 : * 1* sal_uInt8 Content-Version
435 : * 1* sal_uInt16 Content-Tag
436 : * 1* sal_uInt16 NumberOfContents
437 : * 1* sal_uInt32 OffsetToOfsTable
438 : * NumberOfContents* (
439 : * ContentSize* sal_uInt8 Content
440 : * )
441 : * NumberOfContents* sal_uInt32 ContentOfs (shifted each <<8)
442 : *
443 : * @par Example
444 : * @code
445 : * {
446 : * SfxMultiVarRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION );
447 : * for ( sal_uInt16 n = 0; n < Count(); ++n )
448 : * {
449 : * aRecord.NewContent();
450 : * *aRecord << aMember1[n];
451 : * *aRecord << aMember2[n];
452 : * }
453 : * }
454 : * @endcode
455 : *
456 : * @note To ensure up- and downwards compatibility, new versions need to include
457 : * the data of the older ones and are only allowed to add data afterwards.
458 : */
459 : class SVL_DLLPUBLIC SfxMultiVarRecordWriter: public SfxMultiFixRecordWriter
460 : {
461 : protected:
462 : std::vector<sal_uInt32> _aContentOfs;
463 : sal_uInt16 _nContentVer; // only for SfxMultiMixRecordWriter
464 :
465 : SfxMultiVarRecordWriter( sal_uInt8 nRecordType,
466 : SvStream *pStream,
467 : sal_uInt16 nRecordTag,
468 : sal_uInt8 nRecordVer );
469 :
470 : void FlushContent_Impl();
471 :
472 : public:
473 : SfxMultiVarRecordWriter( SvStream *pStream,
474 : sal_uInt16 nRecordTag,
475 : sal_uInt8 nRecordVer );
476 : virtual ~SfxMultiVarRecordWriter();
477 :
478 : void NewContent();
479 :
480 : virtual sal_uInt32 Close( bool bSeekToEndOfRec = true );
481 : };
482 :
483 : /** write record with multiple content items with identical size
484 : *
485 : * Write a record into a stream that stores its own size. This allows it to be
486 : * skipped with old versions or readers if they do not know the record type (= tag).
487 : *
488 : * It contains multiple content items of the same tag and version, that are both
489 : * stored in the header of the record. All content items have a known identical
490 : * size.
491 : *
492 : * @par File Format
493 : *
494 : * 1* sal_uInt8 Pre-Tag (==0)
495 : * 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes
496 : * 1* sal_uInt8 record type (==SFX_REC_TYPE_MIXTAGS)
497 : * 1* sal_uInt8 content version
498 : * 1* sal_uInt16 record tag
499 : * 1* sal_uInt16 NumberOfContents
500 : * 1* sal_uInt32 OffsetToOfsTable
501 : * NumberOfContents* (
502 : * 1* sal_uInt16 content tag
503 : * ContentSize* sal_uInt8 content
504 : * )
505 : * NumberOfContents* sal_uInt32 ( ContentOfs << 8 + Version )
506 : *
507 : * @note To ensure up- and downwards compatibility, new versions need to include
508 : * the data of the older ones and are only allowed to add data afterwards.
509 : */
510 39676 : class SVL_DLLPUBLIC SfxMultiMixRecordWriter: public SfxMultiVarRecordWriter
511 : {
512 : public:
513 : inline SfxMultiMixRecordWriter( SvStream *pStream,
514 : sal_uInt16 nRecordTag,
515 : sal_uInt8 nRecordVer );
516 :
517 : void NewContent( sal_uInt16 nTag, sal_uInt8 nVersion );
518 : // private: not possible, since some compilers then make the previous also private
519 : void NewContent()
520 : { OSL_FAIL( "NewContent() only allowed with args" ); }
521 : };
522 :
523 : /** Read multiple content items of an existing record
524 : *
525 : * Instances of this class allow to read multiple content items of a record
526 : * that was written with
527 : * - SfxMultiFixRecordWriter
528 : * - SfxMultiVarRecordWriter
529 : * - SfxMultiMixRecordWriter
530 : *
531 : * It is possible to skip single content or the whole record without knowing
532 : * its internal format.
533 : *
534 : * @par Example
535 : * @code
536 : * {
537 : * SfxMultiRecordReader aRecord( pStream );
538 : * for ( sal_uInt16 nRecNo = 0; aRecord.GetContent(); ++nRecNo )
539 : * {
540 : * switch ( aRecord.GetTag() )
541 : * {
542 : * case MY_TAG_X:
543 : * X *pObj = new X;
544 : * *aRecord >> pObj.>aMember1;
545 : * if ( aRecord.HasVersion(2) )
546 : * *aRecord >> pObj->aMember2;
547 : * Append( pObj );
548 : * break;
549 : *
550 : * ...
551 : * }
552 : * }
553 : * }
554 : * @endcode
555 : */
556 : class SVL_DLLPUBLIC SfxMultiRecordReader: public SfxSingleRecordReader
557 : {
558 : sal_uInt32 _nStartPos; // start position of this record
559 : sal_uInt32* _pContentOfs; // offsets of the start positions
560 : sal_uInt32 _nContentSize; // size of each record or table position
561 : sal_uInt16 _nContentCount; // number of content items
562 : sal_uInt16 _nContentNo; /* the index of the current content
563 : contains the next content's index
564 : for GetContent() */
565 : sal_uInt16 _nContentTag; // tag of the current content
566 : sal_uInt8 _nContentVer; // version of the current content
567 :
568 : bool ReadHeader_Impl();
569 :
570 : public:
571 : SfxMultiRecordReader( SvStream *pStream, sal_uInt16 nTag );
572 : ~SfxMultiRecordReader();
573 :
574 : bool GetContent();
575 : inline sal_uInt16 GetContentTag();
576 : inline sal_uInt8 GetContentVersion() const;
577 : inline bool HasContentVersion( sal_uInt16 nVersion ) const;
578 :
579 : inline sal_uInt32 ContentCount() const;
580 : };
581 :
582 : /** create a mini record
583 : *
584 : * The content size is calculated automatically after streaming.
585 : *
586 : * @param pStream the stream that will contain the record
587 : * @param nTag a record tag between 0x01 and 0xFE
588 : */
589 71788 : inline SfxMiniRecordWriter::SfxMiniRecordWriter( SvStream* pStream, sal_uInt8 nTag )
590 : : _pStream( pStream ),
591 71788 : _nStartPos( pStream->Tell() ),
592 : _bHeaderOk(false),
593 143576 : _nPreTag( nTag )
594 : {
595 : DBG_ASSERT( _nPreTag != 0xFF, "invalid Tag" );
596 : SAL_INFO("svl", "SfxFileRec: writing record to " << pStream->Tell());
597 :
598 71788 : pStream->SeekRel( + SFX_REC_HEADERSIZE_MINI );
599 71788 : }
600 :
601 : /** The destructor closes the record automatically if not done earlier */
602 71788 : inline SfxMiniRecordWriter::~SfxMiniRecordWriter()
603 : {
604 : // the header was not written, yet, or needs to be checked
605 71788 : if ( !_bHeaderOk )
606 10704 : Close();
607 71788 : }
608 :
609 : /** Get the record's stream
610 : * @return The stream containing the record
611 : * @note The record must not be already closed!
612 : */
613 : inline SvStream& SfxMiniRecordWriter::operator*() const
614 : {
615 : DBG_ASSERT( !_bHeaderOk, "getting Stream of closed record" );
616 : return *_pStream;
617 : }
618 :
619 : inline void SfxMiniRecordWriter::Reset()
620 : {
621 : _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI );
622 : _bHeaderOk = false;
623 : }
624 :
625 : /** The dtor moves the stream automatically to the position directly behind the record */
626 0 : inline SfxMiniRecordReader::~SfxMiniRecordReader()
627 : {
628 0 : if ( !_bSkipped )
629 0 : Skip();
630 0 : }
631 :
632 : /** position the stream directly behind the record's end */
633 0 : inline void SfxMiniRecordReader::Skip()
634 : {
635 0 : _pStream->Seek(_nEofRec);
636 0 : _bSkipped = true;
637 0 : }
638 :
639 : /** Get the pre-tag of this record
640 : *
641 : * The pre-tag might also be SFX_REC_PRETAG_EXT or SFX_REC_PRETAG_EOR.
642 : * The latter means that in the stream the error code ERRCODE_IO_WRONGFORMAT
643 : * is set. The former is valid, since extended records are just building on
644 : * top of SfxMiniRecord.
645 : *
646 : * @return The pre-tag
647 : */
648 : inline sal_uInt8 SfxMiniRecordReader::GetTag() const
649 : {
650 : return _nPreTag;
651 : }
652 :
653 : /** This method allows to check if the record could be recreated successfully
654 : * from the stream and, hence, was correct for this record type.
655 : */
656 : inline bool SfxMiniRecordReader::IsValid() const
657 : {
658 : return _nPreTag != SFX_REC_PRETAG_EOR;
659 : }
660 :
661 : /** get the owning stream
662 : *
663 : * This method returns the stream in which the record is contained.
664 : * The current position of the stream must be inside the record.
665 : */
666 : inline SvStream& SfxMiniRecordReader::operator*() const
667 : {
668 : DBG_ASSERT( _pStream->Tell() < _nEofRec, "read behind record" );
669 : return *_pStream;
670 : }
671 :
672 : /// @see SfxMiniRecordWriter::Close()
673 50380 : inline sal_uInt32 SfxSingleRecordWriter::Close( bool bSeekToEndOfRec )
674 : {
675 50380 : sal_uInt32 nRet = 0;
676 :
677 : // was the header already written?
678 50380 : if ( !_bHeaderOk )
679 : {
680 : // write base class header
681 50380 : sal_uInt32 nEndPos = SfxMiniRecordWriter::Close( bSeekToEndOfRec );
682 :
683 : // seek the end of the own header if needed or stay behind the record
684 50380 : if ( !bSeekToEndOfRec )
685 50380 : _pStream->SeekRel( SFX_REC_HEADERSIZE_SINGLE );
686 50380 : nRet = nEndPos;
687 : }
688 : #ifdef DBG_UTIL
689 : else
690 : // check base class header
691 : SfxMiniRecordWriter::Close( bSeekToEndOfRec );
692 : #endif
693 :
694 50380 : return nRet;
695 : }
696 :
697 : inline void SfxSingleRecordWriter::Reset()
698 : {
699 : _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI +
700 : SFX_REC_HEADERSIZE_SINGLE );
701 : _bHeaderOk = false;
702 : }
703 :
704 : /** @returns the tag for the overall record (stored in the record's head) */
705 : inline sal_uInt16 SfxSingleRecordReader::GetTag() const
706 : {
707 : return _nRecordTag;
708 : }
709 :
710 : /** @returns version of the record */
711 : inline sal_uInt8 SfxSingleRecordReader::GetVersion() const
712 : {
713 : return _nRecordVer;
714 : }
715 :
716 : /** determine if the read record has at least the given version */
717 : inline bool SfxSingleRecordReader::HasVersion( sal_uInt16 nVersion ) const
718 : {
719 : return _nRecordVer >= nVersion;
720 : }
721 :
722 : /** The destructor closes the record automatically if not done earlier */
723 100760 : inline SfxMultiFixRecordWriter::~SfxMultiFixRecordWriter()
724 : {
725 : // the header was not written, yet, or needs to be checked
726 50380 : if ( !_bHeaderOk )
727 0 : Close();
728 50380 : }
729 :
730 : /** add a new content into a record
731 : *
732 : * @note each, also the first record, must be initialized by this method
733 : */
734 : inline void SfxMultiFixRecordWriter::NewContent()
735 : {
736 : #ifdef DBG_UTIL
737 : sal_uLong nOldStartPos;
738 : // store starting position of the current content - CAUTION: sub classes!
739 : nOldStartPos = _nContentStartPos;
740 : #endif
741 : _nContentStartPos = _pStream->Tell();
742 :
743 : #ifdef DBG_UTIL
744 : // is there a previous content?
745 : if ( _nContentCount )
746 : {
747 : // check if the previous content stays in specified max. size
748 : DBG_ASSERT( _nContentStartPos - nOldStartPos == _nContentSize,
749 : "wrong content size detected" );
750 : }
751 : #endif
752 :
753 : // count how many
754 : ++_nContentCount;
755 : }
756 :
757 : /**
758 : * Creates a SfxMultiMixRecord in the given stream with a separate tags and
759 : * versions of its content parts. The sizes of each part are calculated
760 : * automatically.
761 : *
762 : * @param pStream target stream in which the record will be created
763 : * @param nRecordTag tag for the total record
764 : * @param nRecordVer version for the total record
765 : */
766 39676 : inline SfxMultiMixRecordWriter::SfxMultiMixRecordWriter( SvStream* pStream,
767 : sal_uInt16 nRecordTag,
768 : sal_uInt8 nRecordVer )
769 39676 : : SfxMultiVarRecordWriter( SFX_REC_TYPE_MIXTAGS, pStream, nRecordTag, nRecordVer )
770 : {
771 39676 : }
772 :
773 : inline void SfxMultiFixRecordWriter::Reset()
774 : {
775 : _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI +
776 : SFX_REC_HEADERSIZE_SINGLE +
777 : SFX_REC_HEADERSIZE_MULTI );
778 : _bHeaderOk = false;
779 : }
780 :
781 : /** @returns the tag of the last opened content
782 : * @see SfxMultiRecordReder::GetContent()
783 : */
784 0 : inline sal_uInt16 SfxMultiRecordReader::GetContentTag()
785 : {
786 0 : return _nContentTag;
787 : }
788 :
789 : /** @returns the version of the last opened content
790 : * @see SfxMultiRecordReder::GetContent()
791 : */
792 : inline sal_uInt8 SfxMultiRecordReader::GetContentVersion() const
793 : {
794 : return _nContentVer;
795 : }
796 :
797 : /** Determines if the given version is in the last opened content
798 : *
799 : * This method checks if the version is contained in the last version of the
800 : * content that was opened with SfxMultiRecordReder::GetContent().
801 : *
802 : * @param nVersion The version to find
803 : * @return true, if found
804 : * @see SfxMultiRecordReder::GetContent()
805 : */
806 : inline bool SfxMultiRecordReader::HasContentVersion( sal_uInt16 nVersion ) const
807 : {
808 : return _nContentVer >= nVersion;
809 : }
810 :
811 : /** @returns number of this record's contents */
812 : inline sal_uInt32 SfxMultiRecordReader::ContentCount() const
813 : {
814 : return _nContentCount;
815 : }
816 :
817 : #endif
818 :
819 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|