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