LCOV - code coverage report
Current view: top level - include/svl - filerec.hxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 25 55 45.5 %
Date: 2014-04-11 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-Typ
      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             : #ifndef DBG
      49             : #ifdef DBG_UTIL
      50             : #define DBG(x) x
      51             : #else
      52             : #define DBG(x)
      53             : #endif
      54             : #endif
      55             : 
      56             : /*  [Fileformat]
      57             : 
      58             :     Jeder Record beginnt mit einem Byte, dem sogenannten 'Pre-Tag'.
      59             : 
      60             :     Ist dieses 'Pre-Tag' == 0x00, dann handelt es sich um einen Extended-
      61             :     Record, dessen Typ durch ein weiteres Byte an Position 5 n?her
      62             :     beschrieben wird:
      63             : 
      64             :     0x01:       SfxSingleRecord
      65             :     0x02:       SfxMultiFixRecord
      66             :     0x03+0x04:  SfxMultiVarRecord
      67             :     0x07+0x08:  SfxMultiMixRecord
      68             :     (Alle weiteren Record-Typ-Kennungen sind reserviert.)
      69             : 
      70             :     I.d.R. werden File-Formate schon aus Performance-Gr"unden so aufgebaut,
      71             :     da\s beim Lesen jeweils vorher schon feststeht, welcher Record-Typ
      72             :     vorliegt. Diese Kennung dient daher hautps"achlich der "Uberpr"ufung
      73             :     und File-Viewern, die das genaue File-Format (unterhalb der Records)
      74             :     nicht kennen.
      75             : 
      76             :     Der 'SfxMiniRecordReader' verf"ugt dazu auch "uber eine statische
      77             :     Methode 'ScanRecordType()', mit der festgestellt werden kann, welcher
      78             :     Record-Typ in dem "ubergebenen Stream zu finden ist.
      79             : 
      80             :     Ein 'Pre-Tag' mit dem Wert 0xFF ist als Terminator reserviert.
      81             :     Terminatoren werden verwendet, um das Suchen nach einem speziellen
      82             :     Record zu terminieren, d.h. ist er bis dorthin nicht gefunden, wird
      83             :     auch nicht weitergesucht.
      84             : 
      85             :     Bei allen anderen Werten des 'Pre-Tags' (also von 0x01 bis 0xFE)
      86             :     handelt es sich um einen zum SW3 kompatbilen Record, der hier
      87             :     'SfxMiniRecord' genannt wird, er kann daher mit einem <SfxMiniRecordReader>
      88             :     gelesen werden.
      89             : 
      90             :     Beginnt ein Record mit 0x44 k"onnte es sich um einen Drawing-Engine-
      91             :     Record handeln. Dies ist dann der Fall, wenn die folgenden drei Bytes
      92             :     die Zeichenkette 'RMD' bzw. 'RVW' ergeben (zusammen mit 'D'==0x44
      93             :     ergibt dies die K"urzel f"ur 'DRaw-MoDel' bzw. 'DRaw-VieW'). Records
      94             :     dieser Art k"onnen von den hier dargestellten Klassen weder gelesen,
      95             :     noch in irgendeiner Weise interpretiert werden. Einzig die Methode
      96             :     'ScanRecordType()' kann sie erkennen - weitere Behandlung obliegt
      97             :     jedoch der Anwendungsprogrammierung.
      98             : 
      99             :     Diese drei Bytes an den Positionen 2 bis 4 enthalten normalerweise
     100             :     die Gr"o\se des Records ohne Pre-Tag und Gr"o\sen-Bytes selbst,
     101             :     also die Restgr"o\se nach diesem 4-Byte-Header.
     102             : 
     103             :         Struktur des Mini-Records:
     104             : 
     105             :                             1 sal_uInt8         Pre-Tag
     106             :                             3 sal_uInt8         OffsetToEndOfRec
     107             :         OffsetToEndOfRec*   1 sal_uInt8         Content
     108             : 
     109             :     Bei den Extended-Reords folgt auf diesen 4-Byte-Header ein erweiterter
     110             :     Header, der zun"achst den o.g. Record-Typ, dann eine Versions-Kennung
     111             :     sowie ein Tag enth"alt, welches den Inhalt kennzeichnet.
     112             : 
     113             :         Struktur des Extended-Records:
     114             : 
     115             :                             1 sal_uInt8         Pre-Tag (==0x00)
     116             :                             3 sal_uInt8         OffsetToEndOfRec
     117             :         OffsetToEndOfRec*   1 sal_uInt8         Content
     118             :                             1 sal_uInt8         Record-Type
     119             :                             1 sal_uInt8         Version
     120             :                             2 sal_uInt8         Tag
     121             :         ContentSize*        1 sal_uInt8         Content
     122             : 
     123             :         (ContentSize = OffsetToEndOfRec - 8)
     124             : 
     125             :     [Anmerkung]
     126             : 
     127             :     Der Aufbau der Records wird wie folgt begr"undet:
     128             : 
     129             :     Der SW-Record-Typ war zuerst vorhanden, mu\ste also 1:1 "ubernommen
     130             :     werden. Zum Gl"uck wurden einige Record-Tags nicht verwendet, (Z.B.
     131             :     0x00 und 0xFF).
     132             :     =>  1. Byte 0x00 kann als Kennung f"ur erweiterten Record verwendet werden
     133             :     =>  1. Byte 0xFF kann f"ur besondere Zwecke verwendet werden
     134             : 
     135             :     Egal welcher Record-Typ vorliegt, sollte eine Erkennung des Typs, ein
     136             :     Auslesen des Headers und ein "uberpspringen des Records m"oglich sein,
     137             :     ohne zu"uck-seeken zu m"ussen und ohne "uberfl"ussige Daten lesen zu
     138             :     m"ussen.
     139             :     =>  die Bytes 2-4 werden bei allen Records als Offset zum Ende des
     140             :         Records interpretiert, so da\s die Gesamt-Recors-Size sich wie
     141             :         folgt berechnet: sizeof(sal_uInt32) + OffsetToEndOfRec
     142             : 
     143             :     Die Records sollten einfach zu parsen un einheitlich aufgebaut sein.
     144             :     =>  Sie bauen aufeinander auf, so ist z.B. der SfxMiniRecord in jedem
     145             :         anderen enthalten.
     146             : 
     147             :     Die Records sollten auch von denen der Drawing Enginge unterscheidbar
     148             :     sein. Diese beginnen mit 'DRMD' und 'DRVW'.
     149             :     =>  Mini-Records mit dem Pre-Tag 'D' d"urfen maximal 4MB gro\s sein,
     150             :         um nicht in diesen Kennungs-Bereich zu reichen.
     151             : 
     152             :     [Erweiterungen]
     153             : 
     154             :     Es ist geplant das File-Format so zu erweitern, da\s das High-Nibble
     155             :     des Record-Typs der erweiterten Records besondere Aufgaben "ubernehmen
     156             :     soll. Zum Beispiel ist geplant, Record-Contents als 'nur aus Records
     157             :     bestehend' zu kennzeichnen. Ein File-Viewer k"onnte sich dann automatisch
     158             :     durch solche Strukturen 'hangeln', ohne Gefahr zu laufen, auf Daten
     159             :     zu sto\sen, die sich zwar als Records interpretieren lassen, aber
     160             :     tats"achlis als 'flache' Daten geschrieben wurden. Die m"ogliche
     161             :     Erweiterung wird schon jetzt insofern vorbereitet, als da\s das
     162             :     High-Nibble des Typs bei Vergleichen nicht ber"ucksichtigt wird.
     163             : */
     164             : 
     165             : /** Writes simple records in a stream
     166             :  *
     167             :  * An instance of this class can write a simple record into a stream. It identifies itself
     168             :  * with a sal_uInt8 and stores its own size. This allows it to be skipped with old versions or
     169             :  * readers if they do not know the record type (= tag). No version number will be stored.
     170             :  *
     171             :  * One can either provide the size or the latter will be automatically calculated based on the
     172             :  * difference of Tell() before and after streaming the content.
     173             :  *
     174             :  * [File Format]
     175             :  * 1*              sal_uInt8    Content-Tag (!= 0)
     176             :  * 1*              3-sal_uInt8  OffsetToEndOfRec in Bytes
     177             :  * SizeOfContent*  sal_uInt8    Content
     178             :  *
     179             :  * @example
     180             :  * {
     181             :  *     SfxMiniRecordWriter aRecord( pStream, MY_TAG_X );
     182             :  *     *aRecord << aMember1;
     183             :  *     *aRecord << aMember2;
     184             :  * }
     185             :  * @note To ensure up- and downwards compatibility, new versions need to include
     186             :  * the data of the older ones and are only allowed to add data afterwards.
     187             :  * @see SfxMiniRecordReader
     188             :  */
     189             : class SVL_DLLPUBLIC SfxMiniRecordWriter
     190             : {
     191             : protected:
     192             :     SvStream*       _pStream;   // <SvStream> with the record
     193             :     sal_uInt32      _nStartPos; // starting position of the total record in the stream
     194             :     bool            _bHeaderOk; /* TRUE, if header already written */
     195             :     sal_uInt8       _nPreTag;   // 'pre-Tag' to write to header
     196             : 
     197             : public:
     198             :     inline          SfxMiniRecordWriter( SvStream *pStream, sal_uInt8 nTag );
     199             :     inline          ~SfxMiniRecordWriter();
     200             : 
     201             :     inline SvStream& operator*() const;
     202             : 
     203             :     inline void     Reset();
     204             :     sal_uInt32      Close( bool bSeekToEndOfRec = true );
     205             : 
     206             : private:
     207             :     /// not implementend, not allowed
     208             :     SfxMiniRecordWriter( const SfxMiniRecordWriter& );
     209             :     SfxMiniRecordWriter& operator=(const SfxMiniRecordWriter&);
     210             : };
     211             : 
     212             : /** Reads simple record from a stream
     213             :  *
     214             :  * An instance of this class allows to read a simple record from a stream that was written by
     215             :  * SfxMiniRecordWriter. It is also possible to skip a record, even without knowing its internal
     216             :  * format.
     217             :  *
     218             :  * @example
     219             :  * {
     220             :  *      SfxMiniRecordReader aRecord( pStream );
     221             :  *      switch ( aRecord.GetTag() )
     222             :  *      {
     223             :  *          case MY_TAG_X:
     224             :  *              *aRecord >> aMember1;
     225             :  *              *aRecord >> aMember2;
     226             :  *              break;
     227             :  *
     228             :  *          ...
     229             :  *      }
     230             :  * }
     231             :  * @see SfxMiniRecordWriter
     232             :  */
     233             : class SVL_DLLPUBLIC SfxMiniRecordReader
     234             : {
     235             : protected:
     236             :     SvStream*           _pStream;   //  <SvStream> to read from
     237             :     sal_uInt32          _nEofRec;   //  Position direkt hinter dem Record
     238             :     bool                _bSkipped;  //  TRUE: der Record wurde explizit geskippt
     239             :     sal_uInt8           _nPreTag;   //  aus dem Header gelesenes Pre-Tag
     240             : 
     241             :                         // Drei-Phasen-Ctor f"ur Subklassen
     242           0 :     SfxMiniRecordReader()
     243             :         : _pStream(NULL)
     244             :         , _nEofRec(0)
     245             :         , _bSkipped(false)
     246           0 :         , _nPreTag(0)
     247             :     {
     248           0 :     }
     249           0 :     void                 Construct_Impl( SvStream *pStream, sal_uInt8 nTag )
     250             :                         {
     251           0 :                             _pStream = pStream;
     252           0 :                             _bSkipped = false;
     253           0 :                             _nPreTag = nTag;
     254           0 :                         }
     255             :     inline bool         SetHeader_Impl( sal_uInt32 nHeader );
     256             : 
     257             :                         // als ung"ultig markieren und zur"uck-seeken
     258           0 :     void                SetInvalid_Impl( sal_uInt32 nRecordStartPos )
     259             :                         {
     260           0 :                             _nPreTag = SFX_REC_PRETAG_EOR;
     261           0 :                             _pStream->Seek( nRecordStartPos );
     262           0 :                         }
     263             : 
     264             : public:
     265             :     SfxMiniRecordReader( SvStream *pStream, sal_uInt8 nTag );
     266             :     inline              ~SfxMiniRecordReader();
     267             : 
     268             :     inline sal_uInt8    GetTag() const;
     269             :     inline bool         IsValid() const;
     270             : 
     271             :     inline SvStream&    operator*() const;
     272             : 
     273             :     inline void         Skip();
     274             : 
     275             : private:
     276             :     /// not implementend, not allowed
     277             :     SfxMiniRecordReader( const SfxMiniRecordReader& );
     278             :     SfxMiniRecordReader& operator=(const SfxMiniRecordReader&);
     279             : };
     280             : 
     281             : /*  [Beschreibung]
     282             : 
     283             :     Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben
     284             :     werden, dessen einziger Inhalt sich durch ein sal_uInt16-Tag und eine
     285             :     sal_uInt8-Versions-Nummer identifiziert, sowie seine eigene L"ange speichert
     286             :     und somit auch von "alteren Versionen bzw. Readern, die diesen
     287             :     Record-Type (Tag) nicht kennen, "ubersprungen werden kann.
     288             : 
     289             :     Alternativ kann die Gr"o\se fest angegeben werden oder sie wird
     290             :     automatisch aus der Differenz der Tell()-Angaben vor und nach dem
     291             :     Streamen des Inhalts ermittelt.
     292             : 
     293             :     Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen
     294             :     neue Versionen die Daten der "alteren immer komplett enthalten,
     295             :     es d"urfen allenfalls neue Daten hintenan geh"angt werden!
     296             : 
     297             :     [Fileformat]
     298             : 
     299             :     1*              sal_uInt8       Pre-Tag (!= 0)
     300             :     1*              3-sal_uInt8     OffsetToEndOfRec in Bytes
     301             :     1*              sal_uInt8       Record-Type (==SFX_REC_TYPE_SINGLE)
     302             :     1*              sal_uInt8       Content-Version
     303             :     1*              sal_uInt16      Content-Tag
     304             :     SizeOfContent*  sal_uInt8       Content
     305             : */
     306       18794 : class SVL_DLLPUBLIC SfxSingleRecordWriter: public SfxMiniRecordWriter
     307             : {
     308             : protected:
     309             :                     SfxSingleRecordWriter( sal_uInt8 nRecordType,
     310             :                                            SvStream *pStream,
     311             :                                            sal_uInt16 nTag, sal_uInt8 nCurVer );
     312             : 
     313             : public:
     314             :     inline void     Reset();
     315             : 
     316             :     sal_uInt32          Close( bool bSeekToEndOfRec = true );
     317             : };
     318             : 
     319             : /*  [Beschreibung]
     320             : 
     321             :     Mit Instanzen dieser Klasse kann ein einfacher Record aus einem Stream
     322             :     gelesen werden, der mit der Klasse <SfxSingleRecordWriter> geschrieben
     323             :     wurde.
     324             : 
     325             :     Es ist auch m"oglich, den Record zu "uberspringen, ohne sein internes
     326             :     Format zu kennen.
     327             : */
     328           0 : class SVL_DLLPUBLIC SfxSingleRecordReader: public SfxMiniRecordReader
     329             : {
     330             : protected:
     331             :     sal_uInt16              _nRecordTag;    // Art des Gesamt-Inhalts
     332             :     sal_uInt8               _nRecordVer;    // Version des Gesamt-Inhalts
     333             :     sal_uInt8               _nRecordType;   // Record Type aus dem Header
     334             : 
     335             :     // Drei-Phasen-Ctor f"ur Subklassen
     336           0 :     SfxSingleRecordReader()
     337             :         : _nRecordTag(0)
     338             :         , _nRecordVer(0)
     339           0 :         , _nRecordType(0)
     340             :     {
     341           0 :     }
     342           0 :     void                Construct_Impl( SvStream *pStream )
     343             :                         {
     344             :                             SfxMiniRecordReader::Construct_Impl(
     345           0 :                                     pStream, SFX_REC_PRETAG_EXT );
     346           0 :                         }
     347             :     bool                FindHeader_Impl( sal_uInt16 nTypes, sal_uInt16 nTag );
     348             :     bool                ReadHeader_Impl( sal_uInt16 nTypes );
     349             : 
     350             : public:
     351             : 
     352             :     inline sal_uInt16       GetTag() const;
     353             : 
     354             :     inline sal_uInt8        GetVersion() const;
     355             :     inline bool         HasVersion( sal_uInt16 nVersion ) const;
     356             : };
     357             : 
     358             : /*  [Beschreibung]
     359             : 
     360             :     Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben
     361             :     werden, der seine eigene L"ange speichert und somit auch von "alteren
     362             :     Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen,
     363             :     "ubersprungen werden kann.
     364             : 
     365             :     Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben
     366             :     Version, die einmalig (stellvertretend f"ur alle) im Header des Records
     367             :     identifiziert werden. Alle Inhalte haben eine vorher bekannte und
     368             :     identische L"ange.
     369             : 
     370             :     Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen
     371             :     neue Versionen die Daten der "alteren immer komplett enthalten,
     372             :     es d"urfen allenfalls neue Daten hinten angeh"angt werden! Hier sind
     373             :     damit selbstverst"andlich nur die Daten der einzelnen Inhalte gemeint,
     374             :     die Anzahl der Inhalte ist selbstverst"andlich variabel und sollte
     375             :     von lesenden Applikationen auch so behandelt werden.
     376             : 
     377             :     [Fileformat]
     378             : 
     379             :     1*                  sal_uInt8       Pre-Tag (==0)
     380             :     1*                  3-sal_uInt8     OffsetToEndOfRec in Bytes
     381             :     1*                  sal_uInt8       Record-Type (==SFX_REC_TYPE_FIXSIZE)
     382             :     1*                  sal_uInt8       Content-Version
     383             :     1*                  sal_uInt16      Content-Tag
     384             :     1*                  sal_uInt16      NumberOfContents
     385             :     1*                  sal_uInt32      SizeOfEachContent
     386             :     NumberOfContents*   (
     387             :     SizeOfEachContent   sal_uInt8       Content
     388             :                         )
     389             : 
     390             :     [Beispiel]
     391             : 
     392             :     {
     393             :         SfxMultiFixRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION );
     394             :         for ( sal_uInt16 n = 0; n < Count(); ++n )
     395             :         {
     396             :             aRecord.NewContent();
     397             :             *aRecord << aMember1[n];
     398             :             *aRecord << aMember2[n];
     399             :         }
     400             :     }
     401             : */
     402             : class SVL_DLLPUBLIC SfxMultiFixRecordWriter: public SfxSingleRecordWriter
     403             : {
     404             : protected:
     405             :     sal_uInt32          _nContentStartPos;  /*  Startposition des jeweiligen
     406             :                                             Contents - nur bei DBG_UTIL
     407             :                                             und f"ur Subklassen */
     408             :     sal_uInt32          _nContentSize;      //  Gr"o\se jedes Contents
     409             :     sal_uInt16          _nContentCount;     //  jeweilige Anzahl der Contents
     410             : 
     411             :                     SfxMultiFixRecordWriter( sal_uInt8 nRecordType,
     412             :                                              SvStream *pStream,
     413             :                                              sal_uInt16 nTag,
     414             :                                              sal_uInt8 nCurVer );
     415             : 
     416             : public:
     417             :     inline          ~SfxMultiFixRecordWriter();
     418             : 
     419             :     inline void     NewContent();
     420             : 
     421             :     inline void     Reset();
     422             : 
     423             :     sal_uInt32          Close( bool bSeekToEndOfRec = true );
     424             : };
     425             : 
     426             : /** write record with multiple content items
     427             :  *
     428             :  * Write a record into a stream that stores its own size. This allows it to be
     429             :  * skipped with old versions or readers if they do not know the record type (= tag).
     430             :  *
     431             :  * It contains multiple content items of the same tag and version, that are both
     432             :  * stored in the header of the record. The size of each content will be calculated
     433             :  * automatically and stored so that single content items can be skipped without
     434             :  * having to read them.
     435             :  *
     436             :  * [Fileformat]
     437             :  * 1*                  sal_uInt8       Pre-Tag (==0)
     438             :  * 1*                  3-sal_uInt8     OffsetToEndOfRec in Bytes
     439             :  * 1*                  sal_uInt8       Record-Type (==SFX_FILETYPE_TYPE_VARSIZE)
     440             :  * 1*                  sal_uInt8       Content-Version
     441             :  * 1*                  sal_uInt16      Content-Tag
     442             :  * 1*                  sal_uInt16      NumberOfContents
     443             :  * 1*                  sal_uInt32      OffsetToOfsTable
     444             :  * NumberOfContents*   (
     445             :  * ContentSize*        sal_uInt8       Content
     446             :  *                     )
     447             :  * NumberOfContents*   sal_uInt32      ContentOfs (je per <<8 verschoben)
     448             :  * @example
     449             :  * {
     450             :  *      SfxMultiVarRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION );
     451             :  *      for ( sal_uInt16 n = 0; n < Count(); ++n )
     452             :  *      {
     453             :  *          aRecord.NewContent();
     454             :  *          *aRecord << aMember1[n];
     455             :  *          *aRecord << aMember2[n];
     456             :  *      }
     457             :  *  }
     458             :  * @note To ensure up- and downwards compatibility, new versions need to include
     459             :  * the data of the older ones and are only allowed to add data afterwards.
     460             :  */
     461             : class SVL_DLLPUBLIC SfxMultiVarRecordWriter: public SfxMultiFixRecordWriter
     462             : {
     463             : protected:
     464             :     std::vector<sal_uInt32> _aContentOfs;
     465             :     sal_uInt16              _nContentVer;   // only for SfxMultiMixRecordWriter
     466             : 
     467             :                         SfxMultiVarRecordWriter( sal_uInt8 nRecordType,
     468             :                                                  SvStream *pStream,
     469             :                                                  sal_uInt16 nRecordTag,
     470             :                                                  sal_uInt8 nRecordVer );
     471             : 
     472             :     void                FlushContent_Impl();
     473             : 
     474             : public:
     475             :                         SfxMultiVarRecordWriter( SvStream *pStream,
     476             :                                                  sal_uInt16 nRecordTag,
     477             :                                                  sal_uInt8 nRecordVer );
     478             :     virtual             ~SfxMultiVarRecordWriter();
     479             : 
     480             :     void                NewContent();
     481             : 
     482             :     virtual sal_uInt32  Close( bool bSeekToEndOfRec = true );
     483             : };
     484             : 
     485             : /** write record with multiple content items with identical size
     486             :  *
     487             :  * Write a record into a stream that stores its own size. This allows it to be
     488             :  * skipped with old versions or readers if they do not know the record type (= tag).
     489             :  *
     490             :  * It contains multiple content items of the same tag and version, that are both
     491             :  * stored in the header of the record. All content items have a known identical
     492             :  * size.
     493             :  *
     494             :  * [Fileformat]
     495             :  * 1*                  sal_uInt8       Pre-Tag (==0)
     496             :  * 1*                  3-sal_uInt8     OffsetToEndOfRec in Bytes
     497             :  * 1*                  sal_uInt8       record type (==SFX_REC_TYPE_MIXTAGS)
     498             :  * 1*                  sal_uInt8       content version
     499             :  * 1*                  sal_uInt16      record tag
     500             :  * 1*                  sal_uInt16      NumberOfContents
     501             :  * 1*                  sal_uInt32      OffsetToOfsTable
     502             :  * NumberOfContents*   (
     503             :  * 1*                  sal_uInt16      content tag
     504             :  * ContentSize*        sal_uInt8       content
     505             :  *                     )
     506             :  * NumberOfContents*   sal_uInt32      ( ContentOfs << 8 + Version )
     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       15350 : 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             :  * @example
     535             :  * {
     536             :  *      SfxMultiRecordReader aRecord( pStream );
     537             :  *      for ( sal_uInt16 nRecNo = 0; aRecord.GetContent(); ++nRecNo )
     538             :  *      {
     539             :  *          switch ( aRecord.GetTag() )
     540             :  *          {
     541             :  *              case MY_TAG_X:
     542             :  *                  X *pObj = new X;
     543             :  *                  *aRecord >> pObj.>aMember1;
     544             :  *                  if ( aRecord.HasVersion(2) )
     545             :  *                      *aRecord >> pObj->aMember2;
     546             :  *                  Append( pObj );
     547             :  *                  break;
     548             :  *
     549             :  *              ...
     550             :  *          }
     551             :  *      }
     552             :  *  }
     553             :  */
     554             : class SVL_DLLPUBLIC SfxMultiRecordReader: public SfxSingleRecordReader
     555             : {
     556             :     sal_uInt32          _nStartPos;     //  start position of this record
     557             :     sal_uInt32*         _pContentOfs;   //  offsets of the start positions
     558             :     sal_uInt32          _nContentSize;  //  size of each record or table position
     559             :     sal_uInt16          _nContentCount; //  number of content items
     560             :     sal_uInt16          _nContentNo;    /*  the index of the current content
     561             :                                             contains the next content's index
     562             :                                             for GetContent() */
     563             :     sal_uInt16          _nContentTag;   //  tag of the current content
     564             :     sal_uInt8           _nContentVer;   //  version of the current content
     565             : 
     566             :     bool                ReadHeader_Impl();
     567             : 
     568             : public:
     569             :                         SfxMultiRecordReader( SvStream *pStream, sal_uInt16 nTag );
     570             :                         ~SfxMultiRecordReader();
     571             : 
     572             :     bool                GetContent();
     573             :     inline sal_uInt16   GetContentTag();
     574             :     inline sal_uInt8    GetContentVersion() const;
     575             :     inline bool         HasContentVersion( sal_uInt16 nVersion ) const;
     576             : 
     577             :     inline sal_uInt32   ContentCount() const;
     578             : };
     579             : 
     580             : /** create a mini record
     581             :  *
     582             :  * The content size is calculated automatically after streaming.
     583             :  *
     584             :  * @param pStream the stream that will contain the record
     585             :  * @param nTag    a record tag between 0x01 and 0xFE
     586             :  */
     587       25682 : inline SfxMiniRecordWriter::SfxMiniRecordWriter( SvStream* pStream, sal_uInt8 nTag )
     588             : :   _pStream( pStream ),
     589       25682 :     _nStartPos( pStream->Tell() ),
     590             :     _bHeaderOk(false),
     591       51364 :     _nPreTag( nTag )
     592             : {
     593             :     DBG_ASSERT( _nPreTag != 0xFF, "invalid Tag" );
     594             :     SAL_INFO("svl", "SfxFileRec: writing record to " << pStream->Tell());
     595             : 
     596       25682 :     pStream->SeekRel( + SFX_REC_HEADERSIZE_MINI );
     597       25682 : }
     598             : 
     599             : /** The destructor closes the record automatically if not done earlier */
     600       25682 : inline SfxMiniRecordWriter::~SfxMiniRecordWriter()
     601             : {
     602             :     // the header was not written, yet, or needs to be checked
     603       25682 :     if ( !_bHeaderOk )
     604        3444 :         Close();
     605       25682 : }
     606             : 
     607             : /** Get the record's stream
     608             :  * @return The stream containing the record
     609             :  * @note The record must not be already closed!
     610             :  */
     611             : inline SvStream& SfxMiniRecordWriter::operator*() const
     612             : {
     613             :     DBG_ASSERT( !_bHeaderOk, "getting Stream of closed record" );
     614             :     return *_pStream;
     615             : }
     616             : 
     617             : inline void SfxMiniRecordWriter::Reset()
     618             : {
     619             :     _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI );
     620             :     _bHeaderOk = false;
     621             : }
     622             : 
     623             : /** The dtor moves the stream automatically to the position directly behind the record */
     624           0 : inline SfxMiniRecordReader::~SfxMiniRecordReader()
     625             : {
     626           0 :     if ( !_bSkipped )
     627           0 :         Skip();
     628           0 : }
     629             : 
     630             : /** position the stream directly behind the record's end */
     631           0 : inline void SfxMiniRecordReader::Skip()
     632             : {
     633           0 :     _pStream->Seek(_nEofRec);
     634           0 :     _bSkipped = true;
     635           0 : }
     636             : 
     637             : /** Get the pre-tag of this record
     638             :  *
     639             :  * The pre-tag might also be SFX_REC_PRETAG_EXT or SFX_REC_PRETAG_EOR.
     640             :  * The latter means that in the stream the error code ERRCODE_IO_WRONGFORMAT
     641             :  * is set. The former is valid, since extended records are just building on
     642             :  * top of SfxMiniRecord.
     643             :  *
     644             :  * @return The pre-tag
     645             :  */
     646             : inline sal_uInt8 SfxMiniRecordReader::GetTag() const
     647             : {
     648             :     return _nPreTag;
     649             : }
     650             : 
     651             : /** This method allows to check if the record could be recreated successfully
     652             :  *  from the stream and, hence, was correct for this record type.
     653             :  */
     654             : inline bool SfxMiniRecordReader::IsValid() const
     655             : {
     656             :     return _nPreTag != SFX_REC_PRETAG_EOR;
     657             : }
     658             : 
     659             : /** get the owning stream
     660             :  *
     661             :  * This method returns the stream in which the record is contained.
     662             :  * The current position of the stream must be inside the record.
     663             :  */
     664             : inline SvStream& SfxMiniRecordReader::operator*() const
     665             : {
     666             :     DBG_ASSERT( _pStream->Tell() < _nEofRec, "read behind record" );
     667             :     return *_pStream;
     668             : }
     669             : 
     670             : /// @see SfxMiniRecordWriter::Close()
     671       18794 : inline sal_uInt32 SfxSingleRecordWriter::Close( bool bSeekToEndOfRec )
     672             : {
     673       18794 :     sal_uInt32 nRet = 0;
     674             : 
     675             :     // was the header already written?
     676       18794 :     if ( !_bHeaderOk )
     677             :     {
     678             :         // write base class header
     679       18794 :         sal_uInt32 nEndPos = SfxMiniRecordWriter::Close( bSeekToEndOfRec );
     680             : 
     681             :         // seek the end of the own header if needed or stay behind the record
     682       18794 :         if ( !bSeekToEndOfRec )
     683       18794 :             _pStream->SeekRel( SFX_REC_HEADERSIZE_SINGLE );
     684       18794 :         nRet = nEndPos;
     685             :     }
     686             : #ifdef DBG_UTIL
     687             :     else
     688             :         // check base class header
     689             :         SfxMiniRecordWriter::Close( bSeekToEndOfRec );
     690             : #endif
     691             : 
     692       18794 :     return nRet;
     693             : }
     694             : 
     695             : inline void SfxSingleRecordWriter::Reset()
     696             : {
     697             :     _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI +
     698             :                                  SFX_REC_HEADERSIZE_SINGLE );
     699             :     _bHeaderOk = false;
     700             : }
     701             : 
     702             : /** @returns the tag for the overall record (stored in the record's head) */
     703             : inline sal_uInt16 SfxSingleRecordReader::GetTag() const
     704             : {
     705             :     return _nRecordTag;
     706             : }
     707             : 
     708             : /** @returns version of the record */
     709             : inline sal_uInt8 SfxSingleRecordReader::GetVersion() const
     710             : {
     711             :     return _nRecordVer;
     712             : }
     713             : 
     714             : /** determine if the read record has at least the given version */
     715             : inline bool SfxSingleRecordReader::HasVersion( sal_uInt16 nVersion ) const
     716             : {
     717             :     return _nRecordVer >= nVersion;
     718             : }
     719             : 
     720             : /** The destructor closes the record automatically if not done earlier */
     721       37588 : inline SfxMultiFixRecordWriter::~SfxMultiFixRecordWriter()
     722             : {
     723             :     // the header was not written, yet, or needs to be checked
     724       18794 :     if ( !_bHeaderOk )
     725           0 :         Close();
     726       18794 : }
     727             : 
     728             : /** add a new content into a record
     729             :  *
     730             :  * @note each, also the first record, must be initialized by this method
     731             :  */
     732             : inline void SfxMultiFixRecordWriter::NewContent()
     733             : {
     734             :     #ifdef DBG_UTIL
     735             :     sal_uLong nOldStartPos;
     736             :     // store starting position of the current content - CAUTION: sub classes!
     737             :     nOldStartPos = _nContentStartPos;
     738             :     #endif
     739             :     _nContentStartPos = _pStream->Tell();
     740             : 
     741             : #ifdef DBG_UTIL
     742             :     // is there a previous content?
     743             :     if ( _nContentCount )
     744             :     {
     745             :         // check if the previous content stays in specified max. size
     746             :         DBG_ASSERT( _nContentStartPos - nOldStartPos == _nContentSize,
     747             :                     "wrong content size detected" );
     748             :     }
     749             : #endif
     750             : 
     751             :     // count how many
     752             :     ++_nContentCount;
     753             : }
     754             : 
     755             : /**
     756             :  * Creates a SfxMultiMixRecord in the given stream with a seperate tags and
     757             :  * versions of its content parts. The sizes of each part are calculated
     758             :  * automatically.
     759             :  *
     760             :  * @param pStream    target stream in which the record will be created
     761             :  * @param nRecordTag tag for the total record
     762             :  * @param nRecordVer version for the total record
     763             :  */
     764       15350 : inline SfxMultiMixRecordWriter::SfxMultiMixRecordWriter( SvStream* pStream,
     765             :                                                          sal_uInt16 nRecordTag,
     766             :                                                          sal_uInt8 nRecordVer )
     767       15350 : : SfxMultiVarRecordWriter( SFX_REC_TYPE_MIXTAGS, pStream, nRecordTag, nRecordVer )
     768             : {
     769       15350 : }
     770             : 
     771             : inline void SfxMultiFixRecordWriter::Reset()
     772             : {
     773             :     _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI +
     774             :                                  SFX_REC_HEADERSIZE_SINGLE +
     775             :                                  SFX_REC_HEADERSIZE_MULTI );
     776             :     _bHeaderOk = false;
     777             : }
     778             : 
     779             : /** @returns the tag of the last opened content
     780             :  *  @see SfxMultiRecordReder::GetContent()
     781             :  */
     782           0 : inline sal_uInt16 SfxMultiRecordReader::GetContentTag()
     783             : {
     784           0 :     return _nContentTag;
     785             : }
     786             : 
     787             : /** @returns the version of the last opened content
     788             :  *  @see SfxMultiRecordReder::GetContent()
     789             :  */
     790             : inline sal_uInt8 SfxMultiRecordReader::GetContentVersion() const
     791             : {
     792             :     return _nContentVer;
     793             : }
     794             : 
     795             : /** Determines if the given version is in the last opened content
     796             :  *
     797             :  * This method checks if the version is contained in the last version of the
     798             :  * content that was opened with SfxMultiRecordReder::GetContent().
     799             :  *
     800             :  * @param nVersion The version to find
     801             :  * @return true, if found
     802             :  * @see SfxMultiRecordReder::GetContent()
     803             :  */
     804             : inline bool SfxMultiRecordReader::HasContentVersion( sal_uInt16 nVersion ) const
     805             : {
     806             :     return _nContentVer >= nVersion;
     807             : }
     808             : 
     809             : /** @returns number of this record's contents */
     810             : inline sal_uInt32 SfxMultiRecordReader::ContentCount() const
     811             : {
     812             :     return _nContentCount;
     813             : }
     814             : 
     815             : #endif
     816             : 
     817             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10