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

Generated by: LCOV version 1.10