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