LCOV - code coverage report
Current view: top level - include/svl - filerec.hxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 25 55 45.5 %
Date: 2015-06-13 12:38:46 Functions: 7 17 41.2 %
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             : #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: */

Generated by: LCOV version 1.11