LCOV - code coverage report
Current view: top level - svl/source/filerec - filerec.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 68 169 40.2 %
Date: 2015-06-13 12:38:46 Functions: 12 21 57.1 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.11