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 : #include <svl/filerec.hxx>
21 : #include <osl/endian.h>
22 :
23 :
24 : /* The following macros extract parts from a sal_uInt32 value.
25 : These sal_uInt32 values are written out instead of the individual
26 : values to reduce the number of calls.
27 : */
28 :
29 : #define SFX_REC_PRE(n) ( ((n) & 0x000000FF) )
30 : #define SFX_REC_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
31 : #define SFX_REC_TYP(n) ( ((n) & 0x000000FF) )
32 : #define SFX_REC_VER(n) ( ((n) & 0x0000FF00) >> 8 )
33 : #define SFX_REC_TAG(n) ( ((n) & 0xFFFF0000) >> 16 )
34 :
35 : #define SFX_REC_CONTENT_VER(n) ( ((n) & 0x000000FF) )
36 : #define SFX_REC_CONTENT_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
37 :
38 :
39 : /* The following macros combine parts to a sal_uInt32 value.
40 : This sal_uInt32 value is written instead of the individual values
41 : to reduce the number of calls.
42 : */
43 :
44 71788 : static void lclWriteMiniHeader(SvStream *p, sal_uInt32 nPreTag, sal_uInt32 nStartPos, sal_uInt32 nEndPos)
45 : {
46 : (*p).WriteUInt32( sal_uInt32(nPreTag) |
47 71788 : sal_uInt32(nEndPos-nStartPos-SFX_REC_HEADERSIZE_MINI) << 8 );
48 71788 : }
49 :
50 50380 : static void lclWriteHeader(SvStream *p, sal_uInt32 nRecType, sal_uInt32 nContentTag, sal_uInt32 nContentVer)
51 : {
52 50380 : (*p).WriteUInt32( sal_uInt32(nRecType) |
53 50380 : ( sal_uInt32(nContentVer) << 8 ) |
54 50380 : ( sal_uInt32(nContentTag) << 16 ) );
55 50380 : }
56 :
57 : #define SFX_REC_CONTENT_HEADER(nContentVer,n1StStartPos,nCurStartPos) \
58 : ( sal_uInt32(nContentVer) | \
59 : sal_uInt32( nCurStartPos - n1StStartPos ) << 8 )
60 :
61 : /** Close the record; write the header
62 : *
63 : * @param bSeekToEndOfRec
64 : * if true (default) the stream is positioned at the end of the record;
65 : * if false the stream at the start of the content (so after the header).
66 : *
67 : * This method closes the record. The main function is to write the header.
68 : * If the header was written already this method is a no-op.
69 : *
70 : * @return sal_uInt32 != 0: Position im the stream immediately after the record.
71 : * If 'bSeekToEndOfRecord==sal_True' this will be equal to the current stream position.
72 : * == 0: The header was already written.
73 : */
74 71788 : sal_uInt32 SfxMiniRecordWriter::Close(bool bSeekToEndOfRec)
75 : {
76 : // The header wasn't written yet?
77 71788 : if ( !_bHeaderOk )
78 : {
79 : // Write header at the start of the record
80 71788 : sal_uInt32 nEndPos = _pStream->Tell();
81 71788 : _pStream->Seek( _nStartPos );
82 71788 : lclWriteMiniHeader(_pStream, _nPreTag, _nStartPos, nEndPos );
83 :
84 : // seek to the end of the record or stay where we are
85 71788 : if ( bSeekToEndOfRec )
86 21408 : _pStream->Seek( nEndPos );
87 :
88 : // the header has been written NOW
89 71788 : _bHeaderOk = true;
90 71788 : return nEndPos;
91 : }
92 :
93 : // Record was closed already
94 0 : return 0;
95 : }
96 :
97 : /**
98 : Internal method for belatedly processsing a header read externally.
99 : If the header corresponds to an End-Of-Record tag, an error
100 : code is set on the stream and sal_False is returned.
101 : But the stream will not be reset to the record start in case of an error.
102 : */
103 0 : bool SfxMiniRecordReader::SetHeader_Impl( sal_uInt32 nHeader )
104 : {
105 0 : bool bRet = true;
106 :
107 : // determine reord end and PreTag from the header
108 0 : _nEofRec = _pStream->Tell() + SFX_REC_OFS(nHeader);
109 0 : _nPreTag = sal::static_int_cast< sal_uInt8 >(SFX_REC_PRE(nHeader));
110 :
111 : // Errror in cae of End of Record tag
112 0 : if ( _nPreTag == SFX_REC_PRETAG_EOR )
113 : {
114 0 : _pStream->SetError( ERRCODE_IO_WRONGFORMAT );
115 0 : bRet = true;
116 : }
117 0 : return bRet;
118 : }
119 :
120 : /**
121 : *
122 : * @param pstream
123 : * an \a SvStream, which has an \a SfxMiniRecord at the current position
124 : * @param nTag
125 : * Pre-Tag of the wanted record
126 : *
127 : * This constructor interprets a 'pStream' from the current position
128 : * as a continuous sequence of records that should be parsable by
129 : * this group of classes. The first record that is an <SfxMiniRecord>
130 : * (possibly an extened-Record> that has the PreTag 'nTag' will be opened
131 : * and represented by this instance.
132 : *
133 : * If the end of stream is reached or a record with tag
134 : * SFX_REC_PRETAG_EOR is seen before a record with the wanted 'nTag'
135 : * tag is found, the created instance is invalid ('IsValid() ==
136 : * sal_False'). The ERRCODE_IO_WRONGFORMAT error code will be set on
137 : * the stream,and the current position will be unchanged.
138 : *
139 : * If (the wanted tag) 'nTag==SFX_FILEREC_PRETAG_EOR' no attempt is
140 : * made to read a record, but 'IsValid()' is set to sal_False immediately.
141 : * This gives the possibility to include backward compatible SfxMiniRecords
142 : * without 'new' or 'delete'. See <SfxItemSet::Load()>.
143 : *
144 : * Suggested usage:
145 : *
146 : * This constructor allows for adding new record types in a backward
147 : * compatible way by writing out a record with a new tag followed
148 : * by one with an old tag. In that case previous versions of the program
149 : * that do not recognise the new tag will skip the new record
150 : * automatically. This does cause a slight run time inefficiency,
151 : * compared just starting reading, but if the first record
152 : * is the wanted one the difference is just a comparision of 2 bytes.
153 : */
154 :
155 0 : SfxMiniRecordReader::SfxMiniRecordReader(SvStream* pStream, sal_uInt8 nTag)
156 : : _pStream(pStream)
157 : , _nEofRec(0)
158 0 : , _bSkipped(nTag == SFX_REC_PRETAG_EOR)
159 : {
160 : // ignore if we are looking for SFX_REC_PRETAG_EOR
161 0 : if ( _bSkipped )
162 : {
163 0 : _nPreTag = nTag;
164 0 : return;
165 : }
166 :
167 : // remember StartPos to be able to seek back in case of error
168 0 : sal_uInt32 nStartPos = pStream->Tell();
169 :
170 : // look for the matching record
171 : while(true)
172 : {
173 : // read header
174 : SAL_INFO("svl", "SfxFileRec: searching record at " << pStream->Tell());
175 : sal_uInt32 nHeader;
176 0 : pStream->ReadUInt32( nHeader );
177 :
178 : // let the base class extract the header data
179 0 : SetHeader_Impl( nHeader );
180 :
181 : // handle error, if any
182 0 : if ( pStream->IsEof() )
183 0 : _nPreTag = SFX_REC_PRETAG_EOR;
184 0 : else if ( _nPreTag == SFX_REC_PRETAG_EOR )
185 0 : pStream->SetError( ERRCODE_IO_WRONGFORMAT );
186 : else
187 : {
188 : // stop the loop if the right tag is found
189 0 : if ( _nPreTag == nTag )
190 0 : break;
191 :
192 : // or else skip the record and continue
193 0 : pStream->Seek( _nEofRec );
194 0 : continue;
195 : }
196 :
197 : // seek back in case of error
198 0 : pStream->Seek( nStartPos );
199 0 : break;
200 0 : }
201 : }
202 :
203 : /**
204 : *
205 : * @param nRecordType for sub classes
206 : * @param pStream stream to write the record to
207 : * @param nContentTag record type
208 : * @param nContentVer record version
209 : *
210 : * internal constructor for sub classes
211 : */
212 50380 : SfxSingleRecordWriter::SfxSingleRecordWriter(sal_uInt8 nRecordType,
213 : SvStream* pStream,
214 : sal_uInt16 nContentTag,
215 : sal_uInt8 nContentVer)
216 50380 : : SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT )
217 : {
218 : // write extend header after the SfxMiniRec
219 50380 : lclWriteHeader(pStream, nRecordType, nContentTag, nContentVer);
220 50380 : }
221 :
222 : /**
223 : *
224 : * Internal method for reading an SfxMultiRecord header, after
225 : * the base class has been initialized and its header has been read.
226 : * Set an error code on the stream if needed, but don't seek back
227 : * in case of error.
228 : */
229 : inline bool SfxSingleRecordReader::ReadHeader_Impl( sal_uInt16 nTypes )
230 : {
231 : bool bRet;
232 :
233 : // read header of the base class
234 : sal_uInt32 nHeader=0;
235 : _pStream->ReadUInt32( nHeader );
236 : if ( !SetHeader_Impl( nHeader ) )
237 : bRet = false;
238 : else
239 : {
240 : // read own header
241 : _pStream->ReadUInt32( nHeader );
242 : _nRecordVer = sal::static_int_cast< sal_uInt8 >(SFX_REC_VER(nHeader));
243 : _nRecordTag = sal::static_int_cast< sal_uInt16 >(SFX_REC_TAG(nHeader));
244 :
245 : // wrong record type?
246 : _nRecordType = sal::static_int_cast< sal_uInt8 >(SFX_REC_TYP(nHeader));
247 : bRet = 0 != ( nTypes & _nRecordType);
248 : }
249 : return bRet;
250 : }
251 :
252 :
253 : /**
254 : *
255 : * @param nTypes arithmetic OR of allowed record types
256 : * @param nTag record tag to find
257 : *
258 : * Internal method for reading the header of the first record
259 : * that has the tag 'nTag', for which then the type should be
260 : * one of the types in 'nTypes'.
261 : *
262 : * If such a record is not found an error code is set, the stream
263 : * position is seek-ed back and sal_False is returned.
264 : */
265 0 : bool SfxSingleRecordReader::FindHeader_Impl(sal_uInt16 nTypes, sal_uInt16 nTag)
266 : {
267 : // remember StartPos to be able to seek back in case of error
268 0 : sal_uInt32 nStartPos = _pStream->Tell();
269 :
270 : // look for the right record
271 0 : while ( !_pStream->IsEof() )
272 : {
273 : // read header
274 : sal_uInt32 nHeader;
275 : SAL_INFO("svl", "SfxFileRec: searching record at " << _pStream->Tell());
276 0 : _pStream->ReadUInt32( nHeader );
277 0 : if ( !SetHeader_Impl( nHeader ) )
278 : // EOR => abort loop
279 0 : break;
280 :
281 : // found extended record?
282 0 : if ( _nPreTag == SFX_REC_PRETAG_EXT )
283 : {
284 : // read extended header
285 0 : _pStream->ReadUInt32( nHeader );
286 0 : _nRecordTag = sal::static_int_cast< sal_uInt16 >(SFX_REC_TAG(nHeader));
287 :
288 : // found right record?
289 0 : if ( _nRecordTag == nTag )
290 : {
291 : // record type matches as well?
292 : _nRecordType = sal::static_int_cast< sal_uInt8 >(
293 0 : SFX_REC_TYP(nHeader));
294 0 : if ( nTypes & _nRecordType )
295 : // ==> found it
296 0 : return true;
297 :
298 : // error => abort loop
299 0 : break;
300 : }
301 : }
302 :
303 : // else skip
304 0 : if ( !_pStream->IsEof() )
305 0 : _pStream->Seek( _nEofRec );
306 : }
307 :
308 : // set error and seek back
309 0 : _pStream->SetError( ERRCODE_IO_WRONGFORMAT );
310 0 : _pStream->Seek( nStartPos );
311 0 : return false;
312 : }
313 :
314 : /**
315 : *
316 : * @param nRecordType sub class record type
317 : * @param pStream Stream to write the record to
318 : * @param nContentTag Content type
319 : * @param nContentVer Content version
320 : *
321 : * Internal method for sub classes
322 : */
323 50380 : SfxMultiFixRecordWriter::SfxMultiFixRecordWriter(sal_uInt8 nRecordType,
324 : SvStream* pStream,
325 : sal_uInt16 nContentTag,
326 : sal_uInt8 nContentVer)
327 : : SfxSingleRecordWriter( nRecordType, pStream, nContentTag, nContentVer )
328 : , _nContentStartPos(0)
329 : , _nContentSize(0)
330 50380 : , _nContentCount(0)
331 : {
332 : // space for own header
333 50380 : pStream->SeekRel( + SFX_REC_HEADERSIZE_MULTI );
334 50380 : }
335 :
336 : /**
337 : * @see SfxMiniRecordWriter
338 : */
339 0 : sal_uInt32 SfxMultiFixRecordWriter::Close( bool bSeekToEndOfRec )
340 : {
341 : // Header not written yet?
342 0 : if ( !_bHeaderOk )
343 : {
344 : // remember position after header, to be able to seek back to it
345 0 : sal_uInt32 nEndPos = SfxSingleRecordWriter::Close( false );
346 :
347 : // write extended header after SfxSingleRecord
348 0 : _pStream->WriteUInt16( _nContentCount );
349 0 : _pStream->WriteUInt32( _nContentSize );
350 :
351 : // seek to end of record or stay after the header
352 0 : if ( bSeekToEndOfRec )
353 0 : _pStream->Seek(nEndPos);
354 0 : return nEndPos;
355 : }
356 :
357 : // Record was closed already
358 0 : return 0;
359 : }
360 :
361 : /**
362 : *
363 : * @param nRecordType Record type of the sub class
364 : * @param pStream stream to write the record to
365 : * @param nRecordTag record base type
366 : * @param nRecordVer record base version
367 : *
368 : * Internal constructor for sub classes
369 : */
370 39676 : SfxMultiVarRecordWriter::SfxMultiVarRecordWriter(sal_uInt8 nRecordType,
371 : SvStream* pStream,
372 : sal_uInt16 nRecordTag,
373 : sal_uInt8 nRecordVer)
374 : : SfxMultiFixRecordWriter( nRecordType, pStream, nRecordTag, nRecordVer ),
375 39676 : _nContentVer( 0 )
376 : {
377 39676 : }
378 :
379 : /**
380 : *
381 : * @param pStream, stream to write the record to
382 : * @param nRecordTag record base type
383 : * @param nRecordVer record base version
384 : *
385 : * Starts an SfxMultiVarRecord in \a pStream, for which the size
386 : * of the content does not have to be known or identical;
387 : * after streaming a record its size will be calculated.
388 : *
389 : * Note:
390 : *
391 : * This method is not inline since too much code was generated
392 : * for initializing the <SvULong> members.
393 : */
394 10704 : SfxMultiVarRecordWriter::SfxMultiVarRecordWriter(SvStream* pStream,
395 : sal_uInt16 nRecordTag,
396 : sal_uInt8 nRecordVer)
397 : : SfxMultiFixRecordWriter( SFX_REC_TYPE_VARSIZE,
398 : pStream, nRecordTag, nRecordVer ),
399 10704 : _nContentVer( 0 )
400 : {
401 10704 : }
402 :
403 :
404 : /**
405 : *
406 : * The destructor of class <SfxMultiVarRecordWriter> closes the
407 : * record automatically, in case <SfxMultiVarRecordWriter::Close()>
408 : * has not been called explicitly yet.
409 : */
410 100760 : SfxMultiVarRecordWriter::~SfxMultiVarRecordWriter()
411 : {
412 : // close if the header has not been written yet
413 50380 : if ( !_bHeaderOk )
414 50380 : Close();
415 50380 : }
416 :
417 : /**
418 : *
419 : * Internal method for finishing individual content
420 : */
421 102576 : void SfxMultiVarRecordWriter::FlushContent_Impl()
422 : {
423 : // record the version and position offset of the current content;
424 : // the position offset is relative ot the start position of the
425 : // first content.
426 : assert(_aContentOfs.size() == static_cast<size_t>(_nContentCount)-1);
427 102576 : _aContentOfs.resize(_nContentCount-1);
428 : _aContentOfs.push_back(
429 102576 : SFX_REC_CONTENT_HEADER(_nContentVer,_nStartPos,_nContentStartPos));
430 102576 : }
431 :
432 : /**
433 : * @see SfxMultiFixRecordWriter
434 : */
435 64224 : void SfxMultiVarRecordWriter::NewContent()
436 : {
437 : // written Content already?
438 64224 : if ( _nContentCount )
439 53520 : FlushContent_Impl();
440 :
441 : // start new Content
442 64224 : _nContentStartPos = _pStream->Tell();
443 64224 : ++_nContentCount;
444 64224 : }
445 :
446 : /**
447 : * @see SfxMiniRecordWriter
448 : */
449 50380 : sal_uInt32 SfxMultiVarRecordWriter::Close( bool bSeekToEndOfRec )
450 : {
451 : // Header not written yet?
452 50380 : if ( !_bHeaderOk )
453 : {
454 : // finish content if needed
455 50380 : if ( _nContentCount )
456 29604 : FlushContent_Impl();
457 :
458 : // write out content offset table
459 50380 : sal_uInt32 nContentOfsPos = _pStream->Tell();
460 : //! (loop without braces)
461 152956 : for ( sal_uInt16 n = 0; n < _nContentCount; ++n )
462 102576 : _pStream->WriteUInt32( _aContentOfs[n] );
463 :
464 : // skip SfxMultiFixRecordWriter::Close()!
465 50380 : sal_uInt32 nEndPos = SfxSingleRecordWriter::Close( false );
466 :
467 : // write own header
468 50380 : _pStream->WriteUInt16( _nContentCount );
469 100760 : if ( SFX_REC_TYPE_VARSIZE_RELOC == _nPreTag ||
470 50380 : SFX_REC_TYPE_MIXTAGS_RELOC == _nPreTag )
471 0 : _pStream->WriteUInt32( static_cast<sal_uInt32>(nContentOfsPos - ( _pStream->Tell() + sizeof(sal_uInt32) )) );
472 : else
473 50380 : _pStream->WriteUInt32( nContentOfsPos );
474 :
475 : // seek to the end of the record or stay where we are
476 50380 : if ( bSeekToEndOfRec )
477 50380 : _pStream->Seek(nEndPos);
478 50380 : return nEndPos;
479 : }
480 :
481 : // Record was closed already
482 0 : return 0;
483 : }
484 :
485 : /**
486 : *
487 : * @param nContentTag tag for this content type
488 : * @param nContentVer content version
489 : *
490 : * With this method new Content is added to a record and
491 : * its tag and version are regorded. This method must be called
492 : * to start each content, including the first record.
493 : */
494 38352 : void SfxMultiMixRecordWriter::NewContent(sal_uInt16 nContentTag, sal_uInt8 nContentVer)
495 : {
496 : // Finish the previous record if necessary
497 38352 : if ( _nContentCount )
498 19452 : FlushContent_Impl();
499 :
500 : // Write the content tag, and record the version and starting position
501 38352 : _nContentStartPos = _pStream->Tell();
502 38352 : ++_nContentCount;
503 38352 : _pStream->WriteUInt16( nContentTag );
504 38352 : _nContentVer = nContentVer;
505 38352 : }
506 :
507 : /**
508 : *
509 : * Internal method for reading an SfxMultiRecord-Headers, after
510 : * the base class has been initialized and its header has been read.
511 : * If an error occurs an error code is set on the stream, but
512 : * the stream position will not be seek-ed back in that case.
513 : */
514 0 : bool SfxMultiRecordReader::ReadHeader_Impl()
515 : {
516 : // read own header
517 0 : _pStream->ReadUInt16( _nContentCount );
518 0 : _pStream->ReadUInt32( _nContentSize ); // Fix: each on its own, Var|Mix: table position
519 :
520 : // do we still need to rade a table with Content offsets?
521 0 : if ( _nRecordType != SFX_REC_TYPE_FIXSIZE )
522 : {
523 : // read table from the stream
524 0 : sal_uInt32 nContentPos = _pStream->Tell();
525 0 : if ( _nRecordType == SFX_REC_TYPE_VARSIZE_RELOC ||
526 0 : _nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
527 0 : _pStream->SeekRel( + _nContentSize );
528 : else
529 0 : _pStream->Seek( _nContentSize );
530 0 : _pContentOfs = new sal_uInt32[_nContentCount];
531 0 : memset(_pContentOfs, 0, _nContentCount*sizeof(sal_uInt32));
532 : #if defined(OSL_LITENDIAN)
533 0 : _pStream->Read( _pContentOfs, sizeof(sal_uInt32)*_nContentCount );
534 : #else
535 : // (loop without braces)
536 : for ( sal_uInt16 n = 0; n < _nContentCount; ++n )
537 : _pStream->ReadUInt32( _pContentOfs[n] );
538 : #endif
539 0 : _pStream->Seek( nContentPos );
540 : }
541 :
542 : // It was possible to read the error if no error is set on the stream
543 0 : return !_pStream->GetError();
544 : }
545 :
546 :
547 0 : SfxMultiRecordReader::SfxMultiRecordReader( SvStream *pStream, sal_uInt16 nTag )
548 : : _pContentOfs(0)
549 : , _nContentSize(0)
550 : , _nContentCount(0)
551 : , _nContentNo(0)
552 : , _nContentTag( 0 )
553 0 : , _nContentVer( 0 )
554 : {
555 : // remember position in the stream to be able seek back in case of error
556 0 : _nStartPos = pStream->Tell();
557 :
558 : // look for matching record and initialize base class
559 0 : SfxSingleRecordReader::Construct_Impl( pStream );
560 0 : if ( SfxSingleRecordReader::FindHeader_Impl( SFX_REC_TYPE_FIXSIZE |
561 : SFX_REC_TYPE_VARSIZE | SFX_REC_TYPE_VARSIZE_RELOC |
562 : SFX_REC_TYPE_MIXTAGS | SFX_REC_TYPE_MIXTAGS_RELOC,
563 0 : nTag ) )
564 : {
565 : // also read own header
566 0 : if ( !ReadHeader_Impl() )
567 : // not readable => mark as invalid and reset stream position
568 0 : SetInvalid_Impl( _nStartPos);
569 : }
570 0 : }
571 :
572 :
573 0 : SfxMultiRecordReader::~SfxMultiRecordReader()
574 : {
575 0 : delete[] _pContentOfs;
576 0 : }
577 :
578 : /**
579 : *
580 : * Positions the stream at the start of the next Content, or
581 : * for the first call at the start of the first Content in the record,
582 : * and reads its header if necessary.
583 : *
584 : * @return sal_False if there is no further Content according to
585 : * the record header. Even if sal_True is returned an error can
586 : * be set on the stream, for instance if the record finished prematurely
587 : * in a broken file.
588 : */
589 0 : bool SfxMultiRecordReader::GetContent()
590 : {
591 : // more Content available?
592 0 : if ( _nContentNo < _nContentCount )
593 : {
594 : // position the stream at the start of the Content
595 0 : sal_uInt32 nOffset = _nRecordType == SFX_REC_TYPE_FIXSIZE
596 0 : ? _nContentNo * _nContentSize
597 0 : : SFX_REC_CONTENT_OFS(_pContentOfs[_nContentNo]);
598 0 : sal_uInt32 nNewPos = _nStartPos + nOffset;
599 : DBG_ASSERT( nNewPos >= _pStream->Tell(), "SfxMultiRecordReader::GetContent() - New position before current, to much data red!" );
600 :
601 : // #99366#: correct stream pos in every case;
602 : // the if clause was added by MT a long time ago,
603 : // maybe to 'repair' other corrupt documents; but this
604 : // gives errors when writing with 5.1 and reading with current
605 : // versions, so we decided to remove the if clause (KA-05/17/2002)
606 : // if ( nNewPos > _pStream->Tell() )
607 0 : _pStream->Seek( nNewPos );
608 :
609 : // Read Content Header if available
610 0 : if ( _nRecordType == SFX_REC_TYPE_MIXTAGS ||
611 0 : _nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
612 : {
613 : _nContentVer = sal::static_int_cast< sal_uInt8 >(
614 0 : SFX_REC_CONTENT_VER(_pContentOfs[_nContentNo]));
615 0 : _pStream->ReadUInt16( _nContentTag );
616 : }
617 :
618 : // Increment ContentNo
619 0 : ++_nContentNo;
620 0 : return true;
621 : }
622 :
623 0 : return false;
624 : }
625 :
626 :
627 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|