| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #ifndef _SFXFILEREC_HXX |
| #define _SFXFILEREC_HXX |
| |
| //========================================================================= |
| |
| #include "svl/svldllapi.h" |
| #include <tools/debug.hxx> |
| #include <tools/stream.hxx> |
| #include <svl/svarray.hxx> |
| |
| SV_DECL_VARARR( SfxUINT32s, sal_uInt32, 8, 8 ) |
| |
| //------------------------------------------------------------------------ |
| |
| #define SFX_BOOL_DONTCARE sal_Bool(2) // Don't-Care-Wert f"ur BOOLs |
| |
| #define SFX_REC_PRETAG_EXT sal_uInt8(0x00) // Pre-Tag f"ur Extended-Records |
| #define SFX_REC_PRETAG_EOR sal_uInt8(0xFF) // Pre-Tag f"ur End-Of-Records |
| |
| #define SFX_REC_TYPE_NONE sal_uInt8(0x00) // unbekannter Record-Typ |
| #define SFX_REC_TYPE_FIRST sal_uInt8(0x01) |
| #define SFX_REC_TYPE_SINGLE sal_uInt8(0x01) // Single-Content-Record |
| #define SFX_REC_TYPE_FIXSIZE sal_uInt8(0x02) // Fix-Size-Multi-Content-Record |
| #define SFX_REC_TYPE_VARSIZE_RELOC sal_uInt8(0x03) // variable Rec-Size |
| #define SFX_REC_TYPE_VARSIZE sal_uInt8(0x04) // alt (nicht verschiebbar) |
| #define SFX_REC_TYPE_MIXTAGS_RELOC sal_uInt8(0x07) // Mixed Tag Content-Record |
| #define SFX_REC_TYPE_MIXTAGS sal_uInt8(0x08) // alt (nicht verschiebbar) |
| #define SFX_REC_TYPE_LAST sal_uInt8(0x08) |
| #define SFX_REC_TYPE_MINI 0x100 // Mini-Record |
| #define SFX_REC_TYPE_DRAWENG 0x400 // Drawing-Engine-Record |
| #define SFX_REC_TYPE_EOR 0xF00 // End-Of-Records |
| |
| //------------------------------------------------------------------------ |
| |
| #define SFX_REC_HEADERSIZE_MINI 4 // Gr"o\se des Mini-Record-Headers |
| #define SFX_REC_HEADERSIZE_SINGLE 4 // zzgl. HEADERSIZE_MINI => 8 |
| #define SFX_REC_HEADERSIZE_MULTI 6 // zzgl. HEADERSIZE_SINGLE => 14 |
| |
| //------------------------------------------------------------------------ |
| |
| #ifndef DBG |
| #ifdef DBG_UTIL |
| #define DBG(x) x |
| #else |
| #define DBG(x) |
| #endif |
| #endif |
| |
| //------------------------------------------------------------------------ |
| |
| /* [Fileformat] |
| |
| Jeder Record beginnt mit einem Byte, dem sogenannten 'Pre-Tag'. |
| |
| Ist dieses 'Pre-Tag' == 0x00, dann handelt es sich um einen Extended- |
| Record, dessen Typ durch ein weiteres Byte an Position 5 n�her |
| beschrieben wird: |
| |
| 0x01: SfxSingleRecord |
| 0x02: SfxMultiFixRecord |
| 0x03+0x04: SfxMultiVarRecord |
| 0x07+0x08: SfxMultiMixRecord |
| (Alle weiteren Record-Typ-Kennungen sind reserviert.) |
| |
| I.d.R. werden File-Formate schon aus Performance-Gr"unden so aufgebaut, |
| da\s beim Lesen jeweils vorher schon feststeht, welcher Record-Typ |
| vorliegt. Diese Kennung dient daher hautps"achlich der "Uberpr"ufung |
| und File-Viewern, die das genaue File-Format (unterhalb der Records) |
| nicht kennen. |
| |
| Der 'SfxMiniRecordReader' verf"ugt dazu auch "uber eine statische |
| Methode 'ScanRecordType()', mit der festgestellt werden kann, welcher |
| Record-Typ in dem "ubergebenen Stream zu finden ist. |
| |
| Ein 'Pre-Tag' mit dem Wert 0xFF ist als Terminator reserviert. |
| Terminatoren werden verwendet, um das Suchen nach einem speziellen |
| Record zu terminieren, d.h. ist er bis dorthin nicht gefunden, wird |
| auch nicht weitergesucht. |
| |
| Bei allen anderen Werten des 'Pre-Tags' (also von 0x01 bis 0xFE) |
| handelt es sich um einen zum SW3 kompatbilen Record, der hier |
| 'SfxMiniRecord' genannt wird, er kann daher mit einem <SfxMiniRecordReader> |
| gelesen werden. |
| |
| Beginnt ein Record mit 0x44 k"onnte es sich um einen Drawing-Engine- |
| Record handeln. Dies ist dann der Fall, wenn die folgenden drei Bytes |
| die Zeichenkette 'RMD' bzw. 'RVW' ergeben (zusammen mit 'D'==0x44 |
| ergibt dies die K"urzel f"ur 'DRaw-MoDel' bzw. 'DRaw-VieW'). Records |
| dieser Art k"onnen von den hier dargestellten Klassen weder gelesen, |
| noch in irgendeiner Weise interpretiert werden. Einzig die Methode |
| 'ScanRecordType()' kann sie erkennen - weitere Behandlung obliegt |
| jedoch der Anwendungsprogrammierung. |
| |
| Diese drei Bytes an den Positionen 2 bis 4 enthalten normalerweise |
| die Gr"o\se des Records ohne Pre-Tag und Gr"o\sen-Bytes selbst, |
| also die Restgr"o\se nach diesem 4-Byte-Header. |
| |
| Struktur des Mini-Records: |
| |
| 1 sal_uInt8 Pre-Tag |
| 3 sal_uInt8 OffsetToEndOfRec |
| OffsetToEndOfRec* 1 sal_uInt8 Content |
| |
| Bei den Extended-Reords folgt auf diesen 4-Byte-Header ein erweiterter |
| Header, der zun"achst den o.g. Record-Typ, dann eine Versions-Kennung |
| sowie ein Tag enth"alt, welches den Inhalt kennzeichnet. |
| |
| Struktur des Extended-Records: |
| |
| 1 sal_uInt8 Pre-Tag (==0x00) |
| 3 sal_uInt8 OffsetToEndOfRec |
| OffsetToEndOfRec* 1 sal_uInt8 Content |
| 1 sal_uInt8 Record-Type |
| 1 sal_uInt8 Version |
| 2 sal_uInt8 Tag |
| ContentSize* 1 sal_uInt8 Content |
| |
| (ContentSize = OffsetToEndOfRec - 8) |
| |
| [Anmerkung] |
| |
| Der Aufbau der Records wird wie folgt begr"undet: |
| |
| Der SW-Record-Typ war zuerst vorhanden, mu\ste also 1:1 "ubernommen |
| werden. Zum Gl"uck wurden einige Record-Tags nicht verwendet, (Z.B. |
| 0x00 und 0xFF). |
| => 1. Byte 0x00 kann als Kennung f"ur erweiterten Record verwendet werden |
| => 1. Byte 0xFF kann f"ur besondere Zwecke verwendet werden |
| |
| Egal welcher Record-Typ vorliegt, sollte eine Erkennung des Typs, ein |
| Auslesen des Headers und ein "uberpspringen des Records m"oglich sein, |
| ohne zu"uck-seeken zu m"ussen und ohne "uberfl"ussige Daten lesen zu |
| m"ussen. |
| => die Bytes 2-4 werden bei allen Records als Offset zum Ende des |
| Records interpretiert, so da\s die Gesamt-Recors-Size sich wie |
| folgt berechnet: sizeof(sal_uInt32) + OffsetToEndOfRec |
| |
| Die Records sollten einfach zu parsen un einheitlich aufgebaut sein. |
| => Sie bauen aufeinander auf, so ist z.B. der SfxMiniRecord in jedem |
| anderen enthalten. |
| |
| Die Records sollten auch von denen der Drawing Enginge unterscheidbar |
| sein. Diese beginnen mit 'DRMD' und 'DRVW'. |
| => Mini-Records mit dem Pre-Tag 'D' d"urfen maximal 4MB gro\s sein, |
| um nicht in diesen Kennungs-Bereich zu reichen. |
| |
| [Erweiterungen] |
| |
| Es ist geplant das File-Format so zu erweitern, da\s das High-Nibble |
| des Record-Typs der erweiterten Records besondere Aufgaben "ubernehmen |
| soll. Zum Beispiel ist geplant, Record-Contents als 'nur aus Records |
| bestehend' zu kennzeichnen. Ein File-Viewer k"onnte sich dann automatisch |
| durch solche Strukturen 'hangeln', ohne Gefahr zu laufen, auf Daten |
| zu sto\sen, die sich zwar als Records interpretieren lassen, aber |
| tats"achlis als 'flache' Daten geschrieben wurden. Die m"ogliche |
| Erweiterung wird schon jetzt insofern vorbereitet, als da\s das |
| High-Nibble des Typs bei Vergleichen nicht ber"ucksichtigt wird. |
| */ |
| |
| //------------------------------------------------------------------------ |
| |
| class SVL_DLLPUBLIC SfxMiniRecordWriter |
| |
| /* [Beschreibung] |
| |
| Mit Instanzen dieser Klasse kann ein einfacher Record in einen Stream |
| geschrieben werden, der sich durch ein sal_uInt8-Tag identifiziert, sowie |
| seine eigene L"ange speichert und somit auch von "alteren Versionen |
| bzw. Readern, die diesen Record-Type (Tag) nicht kennen, "ubersprungen |
| werden kann. Es wird keine Version-Nummer gespeichert. |
| |
| Alternativ kann die Gr"o\se fest angegeben werden oder sie wird |
| automatisch aus der Differenz der Tell()-Angaben vor und nach dem |
| Streamen des Inhalts ermittelt. |
| |
| Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen |
| neue Versionen die Daten der "alteren immer komplett enthalten, |
| es d"urfen allenfalls neue Daten hintenan geh"angt werden! |
| |
| [Fileformat] |
| |
| 1* sal_uInt8 Content-Tag (!= 0) |
| 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes |
| SizeOfContent* sal_uInt8 Content |
| |
| [Beispiel] |
| |
| { |
| SfxMiniRecordWriter aRecord( pStream, MY_TAG_X ); |
| *aRecord << aMember1; |
| *aRecord << aMember2; |
| } |
| */ |
| |
| { |
| protected: |
| SvStream* _pStream; // <SvStream>, in dem der Record liegt |
| sal_uInt32 _nStartPos; // Start-Position des Gesamt-Records im Stream |
| FASTBOOL _bHeaderOk; /* sal_True, wenn der Header schon geschrieben ist; |
| bei DBG_UTIL wird SFX_BOOL_DONTCARE ver- |
| wendet, um die Gr"o\se von Fix-Sized-Records |
| zu pr"ufen. */ |
| sal_uInt8 _nPreTag; // in den Header zu schreibendes 'Pre-Tag' |
| |
| public: |
| inline SfxMiniRecordWriter( SvStream *pStream, |
| sal_uInt8 nTag ); |
| inline SfxMiniRecordWriter( SvStream *pStream, sal_uInt8 nTag, |
| sal_uInt32 nSize ); |
| |
| inline ~SfxMiniRecordWriter(); |
| |
| inline SvStream& operator*() const; |
| |
| inline void Reset(); |
| |
| sal_uInt32 Close( FASTBOOL bSeekToEndOfRec = sal_True ); |
| |
| private: |
| // not implementend, not allowed |
| SfxMiniRecordWriter( const SfxMiniRecordWriter& ); |
| SfxMiniRecordWriter& operator=(const SfxMiniRecordWriter&); |
| }; |
| |
| //------------------------------------------------------------------------ |
| |
| class SVL_DLLPUBLIC SfxMiniRecordReader |
| |
| /* [Beschreibung] |
| |
| Mit Instanzen dieser Klasse kann ein einfacher Record aus einem Stream |
| gelesen werden, der mit der Klasse <SfxRecordWriter> geschrieben wurde. |
| |
| Es ist auch m"oglich, den Record zu "uberspringen, ohne sein internes |
| Format zu kennen. |
| |
| [Beispiel] |
| |
| { |
| SfxMiniRecordReader aRecord( pStream ); |
| switch ( aRecord.GetTag() ) |
| { |
| case MY_TAG_X: |
| *aRecord >> aMember1; |
| *aRecord >> aMember2; |
| break; |
| |
| ... |
| } |
| } |
| */ |
| |
| { |
| protected: |
| SvStream* _pStream; // <SvStream>, aus dem gelesen wird |
| sal_uInt32 _nEofRec; // Position direkt hinter dem Record |
| FASTBOOL _bSkipped; // sal_True: der Record wurde explizit geskippt |
| sal_uInt8 _nPreTag; // aus dem Header gelesenes Pre-Tag |
| |
| // Drei-Phasen-Ctor f"ur Subklassen |
| SfxMiniRecordReader() {} |
| void Construct_Impl( SvStream *pStream, sal_uInt8 nTag ) |
| { |
| _pStream = pStream; |
| _bSkipped = sal_False; |
| _nPreTag = nTag; |
| } |
| inline FASTBOOL SetHeader_Impl( sal_uInt32 nHeader ); |
| |
| // als ung"ultig markieren und zur"uck-seeken |
| void SetInvalid_Impl( sal_uInt32 nRecordStartPos ) |
| { |
| _nPreTag = SFX_REC_PRETAG_EOR; |
| _pStream->Seek( nRecordStartPos ); |
| } |
| |
| public: |
| static sal_uInt16 ScanRecordType( SvStream *pStream ); |
| |
| SfxMiniRecordReader( SvStream *pStream ); |
| SfxMiniRecordReader( SvStream *pStream, sal_uInt8 nTag ); |
| inline ~SfxMiniRecordReader(); |
| |
| inline sal_uInt8 GetTag() const; |
| inline FASTBOOL IsValid() const; |
| |
| inline SvStream& operator*() const; |
| |
| inline void Skip(); |
| |
| private: |
| // not implementend, not allowed |
| SfxMiniRecordReader( const SfxMiniRecordReader& ); |
| SfxMiniRecordReader& operator=(const SfxMiniRecordReader&); |
| }; |
| |
| //------------------------------------------------------------------------ |
| |
| class SVL_DLLPUBLIC SfxSingleRecordWriter: public SfxMiniRecordWriter |
| |
| /* [Beschreibung] |
| |
| Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben |
| werden, dessen einziger Inhalt sich durch ein sal_uInt16-Tag und eine |
| sal_uInt8-Versions-Nummer identifiziert, sowie seine eigene L"ange speichert |
| und somit auch von "alteren Versionen bzw. Readern, die diesen |
| Record-Type (Tag) nicht kennen, "ubersprungen werden kann. |
| |
| Alternativ kann die Gr"o\se fest angegeben werden oder sie wird |
| automatisch aus der Differenz der Tell()-Angaben vor und nach dem |
| Streamen des Inhalts ermittelt. |
| |
| Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen |
| neue Versionen die Daten der "alteren immer komplett enthalten, |
| es d"urfen allenfalls neue Daten hintenan geh"angt werden! |
| |
| [Fileformat] |
| |
| 1* sal_uInt8 Pre-Tag (!= 0) |
| 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes |
| 1* sal_uInt8 Record-Type (==SFX_REC_TYPE_SINGLE) |
| 1* sal_uInt8 Content-Version |
| 1* sal_uInt16 Content-Tag |
| SizeOfContent* sal_uInt8 Content |
| |
| [Beispiel] |
| |
| { |
| SfxSingleRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION ); |
| *aRecord << aMember1; |
| *aRecord << aMember2; |
| } |
| */ |
| |
| { |
| protected: |
| SfxSingleRecordWriter( sal_uInt8 nRecordType, |
| SvStream *pStream, |
| sal_uInt16 nTag, sal_uInt8 nCurVer ); |
| |
| public: |
| SfxSingleRecordWriter( SvStream *pStream, |
| sal_uInt16 nTag, sal_uInt8 nCurVer ); |
| SfxSingleRecordWriter( SvStream *pStream, |
| sal_uInt16 nTag, sal_uInt8 nCurVer, |
| sal_uInt32 nSize ); |
| |
| inline void Reset(); |
| |
| sal_uInt32 Close( FASTBOOL bSeekToEndOfRec = sal_True ); |
| }; |
| |
| //------------------------------------------------------------------------ |
| |
| class SVL_DLLPUBLIC SfxSingleRecordReader: public SfxMiniRecordReader |
| |
| /* [Beschreibung] |
| |
| Mit Instanzen dieser Klasse kann ein einfacher Record aus einem Stream |
| gelesen werden, der mit der Klasse <SfxSingleRecordWriter> geschrieben |
| wurde. |
| |
| Es ist auch m"oglich, den Record zu "uberspringen, ohne sein internes |
| Format zu kennen. |
| |
| [Beispiel] |
| |
| { |
| SfxSingleRecordReader aRecord( pStream ); |
| switch ( aRecord.GetTag() ) |
| { |
| case MY_TAG_X: |
| aRecord >> aMember1; |
| if ( aRecord.HasVersion(2) ) |
| *aRecord >> aMember2; |
| break; |
| |
| ... |
| } |
| } |
| */ |
| |
| { |
| protected: |
| sal_uInt16 _nRecordTag; // Art des Gesamt-Inhalts |
| sal_uInt8 _nRecordVer; // Version des Gesamt-Inhalts |
| sal_uInt8 _nRecordType; // Record Type aus dem Header |
| |
| // Drei-Phasen-Ctor f"ur Subklassen |
| SfxSingleRecordReader() {} |
| void Construct_Impl( SvStream *pStream ) |
| { |
| SfxMiniRecordReader::Construct_Impl( |
| pStream, SFX_REC_PRETAG_EXT ); |
| } |
| FASTBOOL FindHeader_Impl( sal_uInt16 nTypes, sal_uInt16 nTag ); |
| FASTBOOL ReadHeader_Impl( sal_uInt16 nTypes ); |
| |
| public: |
| SfxSingleRecordReader( SvStream *pStream ); |
| SfxSingleRecordReader( SvStream *pStream, sal_uInt16 nTag ); |
| |
| inline sal_uInt16 GetTag() const; |
| |
| inline sal_uInt8 GetVersion() const; |
| inline FASTBOOL HasVersion( sal_uInt16 nVersion ) const; |
| }; |
| |
| //------------------------------------------------------------------------ |
| |
| class SVL_DLLPUBLIC SfxMultiFixRecordWriter: public SfxSingleRecordWriter |
| |
| /* [Beschreibung] |
| |
| Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben |
| werden, der seine eigene L"ange speichert und somit auch von "alteren |
| Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen, |
| "ubersprungen werden kann. |
| |
| Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben |
| Version, die einmalig (stellvertretend f"ur alle) im Header des Records |
| identifiziert werden. Alle Inhalte haben eine vorher bekannte und |
| identische L"ange. |
| |
| Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen |
| neue Versionen die Daten der "alteren immer komplett enthalten, |
| es d"urfen allenfalls neue Daten hinten angeh"angt werden! Hier sind |
| damit selbstverst"andlich nur die Daten der einzelnen Inhalte gemeint, |
| die Anzahl der Inhalte ist selbstverst"andlich variabel und sollte |
| von lesenden Applikationen auch so behandelt werden. |
| |
| [Fileformat] |
| |
| 1* sal_uInt8 Pre-Tag (==0) |
| 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes |
| 1* sal_uInt8 Record-Type (==SFX_REC_TYPE_FIXSIZE) |
| 1* sal_uInt8 Content-Version |
| 1* sal_uInt16 Content-Tag |
| 1* sal_uInt16 NumberOfContents |
| 1* sal_uInt32 SizeOfEachContent |
| NumberOfContents* ( |
| SizeOfEachContent sal_uInt8 Content |
| ) |
| |
| [Beispiel] |
| |
| { |
| SfxMultiFixRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION ); |
| for ( sal_uInt16 n = 0; n < Count(); ++n ) |
| { |
| aRecord.NewContent(); |
| *aRecord << aMember1[n]; |
| *aRecord << aMember2[n]; |
| } |
| } |
| */ |
| |
| { |
| protected: |
| sal_uInt32 _nContentStartPos; /* Startposition des jeweiligen |
| Contents - nur bei DBG_UTIL |
| und f"ur Subklassen */ |
| sal_uInt32 _nContentSize; // Gr"o\se jedes Contents |
| sal_uInt16 _nContentCount; // jeweilige Anzahl der Contents |
| |
| SfxMultiFixRecordWriter( sal_uInt8 nRecordType, |
| SvStream *pStream, |
| sal_uInt16 nTag, sal_uInt8 nCurVer, |
| sal_uInt32 nContentSize ); |
| |
| public: |
| SfxMultiFixRecordWriter( SvStream *pStream, |
| sal_uInt16 nTag, sal_uInt8 nCurVer, |
| sal_uInt32 nContentSize ); |
| inline ~SfxMultiFixRecordWriter(); |
| |
| inline void NewContent(); |
| |
| inline void Reset(); |
| |
| sal_uInt32 Close( FASTBOOL bSeekToEndOfRec = sal_True ); |
| }; |
| |
| //------------------------------------------------------------------------ |
| |
| class SVL_DLLPUBLIC SfxMultiVarRecordWriter: public SfxMultiFixRecordWriter |
| |
| /* [Beschreibung] |
| |
| Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben |
| werden, der seine eigene L"ange speichert und somit auch von "alteren |
| Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen, |
| "ubersprungen werden kann. |
| |
| Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben |
| Version, die einmalig (stellvertretend f"ur alle) im Header des Records |
| identifiziert werden. Die L"ange f"ur jeden einzelnen Inhalt wird |
| automatisch berechnet und gespeichert, so da\s auch einzelne Inhalte |
| "ubersprungen werden k"onnen, ohne sie interpretieren zu m"ussen. |
| |
| Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen |
| neue Versionen die Daten der "alteren immer komplett enthalten, |
| es d"urfen allenfalls neue Daten hinten angeh"angt werden! |
| |
| [Fileformat] |
| |
| 1* sal_uInt8 Pre-Tag (==0) |
| 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes |
| 1* sal_uInt8 Record-Type (==SFX_FILETYPE_TYPE_VARSIZE) |
| 1* sal_uInt8 Content-Version |
| 1* sal_uInt16 Content-Tag |
| 1* sal_uInt16 NumberOfContents |
| 1* sal_uInt32 OffsetToOfsTable |
| NumberOfContents* ( |
| ContentSize* sal_uInt8 Content |
| ) |
| NumberOfContents* sal_uInt32 ContentOfs (je per <<8 verschoben) |
| |
| [Beispiel] |
| |
| { |
| SfxMultiVarRecordWriter aRecord( pStream, MY_TAG_X, MY_VERSION ); |
| for ( sal_uInt16 n = 0; n < Count(); ++n ) |
| { |
| aRecord.NewContent(); |
| *aRecord << aMember1[n]; |
| *aRecord << aMember2[n]; |
| } |
| } |
| */ |
| |
| { |
| protected: |
| SfxUINT32s _aContentOfs; |
| sal_uInt16 _nContentVer; // nur f"ur SfxMultiMixRecordWriter |
| |
| SfxMultiVarRecordWriter( sal_uInt8 nRecordType, |
| SvStream *pStream, |
| sal_uInt16 nRecordTag, |
| sal_uInt8 nRecordVer ); |
| |
| void FlushContent_Impl(); |
| |
| public: |
| SfxMultiVarRecordWriter( SvStream *pStream, |
| sal_uInt16 nRecordTag, |
| sal_uInt8 nRecordVer ); |
| virtual ~SfxMultiVarRecordWriter(); |
| |
| void NewContent(); |
| |
| virtual sal_uInt32 Close( FASTBOOL bSeekToEndOfRec = sal_True ); |
| }; |
| |
| //------------------------------------------------------------------------ |
| |
| class SVL_DLLPUBLIC SfxMultiMixRecordWriter: public SfxMultiVarRecordWriter |
| |
| /* [Beschreibung] |
| |
| Mit Instanzen dieser Klasse kann ein Record in einen Stream geschrieben |
| werden, der seine eigene L"ange speichert und somit auch von "alteren |
| Versionen bzw. Readern, die diesen Record-Type (Tag) nicht kennen, |
| "ubersprungen werden kann. |
| |
| Er enth"alt mehrere Inhalte von demselben Typ (Tag) und derselben |
| Version, die einmalig (stellvertretend f"ur alle) im Header des Records |
| identifiziert werden. Alle Inhalte haben eine vorher bekannte und |
| identische L"ange. |
| |
| Um Auf- und Abw"artskompatiblit"at gew"ahrleisten zu k"onnen, m"ussen |
| neue Versionen die Daten der "alteren immer komplett enthalten, |
| es d"urfen allenfalls neue Daten hinten angeh"angt werden! |
| |
| [Fileformat] |
| |
| 1* sal_uInt8 Pre-Tag (==0) |
| 1* 3-sal_uInt8 OffsetToEndOfRec in Bytes |
| 1* sal_uInt8 Record-Type (==SFX_REC_TYPE_MIXTAGS) |
| 1* sal_uInt8 Content-Version |
| 1* sal_uInt16 Record-Tag |
| 1* sal_uInt16 NumberOfContents |
| 1* sal_uInt32 OffsetToOfsTable |
| NumberOfContents* ( |
| 1* sal_uInt16 Content-Tag |
| ContentSize* sal_uInt8 Content |
| ) |
| NumberOfContents* sal_uInt32 ( ContentOfs << 8 + Version ) |
| */ |
| |
| { |
| public: |
| inline SfxMultiMixRecordWriter( SvStream *pStream, |
| sal_uInt16 nRecordTag, |
| sal_uInt8 nRecordVer ); |
| |
| void NewContent( sal_uInt16 nTag, sal_uInt8 nVersion ); |
| |
| // private: geht nicht, da einige Compiler dann auch vorherige privat machen |
| void NewContent() |
| { DBG_ERROR( "NewContent() only allowed with args" ); } |
| }; |
| |
| //------------------------------------------------------------------------ |
| |
| class SVL_DLLPUBLIC SfxMultiRecordReader: public SfxSingleRecordReader |
| |
| /* [Beschreibung] |
| |
| Mit Instanzen dieser Klasse kann ein aus mehreren Contents bestehender |
| Record aus einem Stream gelesen werden, der mit einer der Klassen |
| <SfxMultiFixRecordWriter>, <SfxMultiVarRecordWriter> oder |
| <SfxMultiMixRecordWriter> geschrieben wurde. |
| |
| Es ist auch m"oglich, den Record oder einzelne Contents zu "uberspringen, |
| ohne das jeweilis interne Format zu kennen. |
| |
| [Beispiel] |
| |
| { |
| SfxMultiRecordReader aRecord( pStream ); |
| for ( sal_uInt16 nRecNo = 0; aRecord.GetContent(); ++nRecNo ) |
| { |
| switch ( aRecord.GetTag() ) |
| { |
| case MY_TAG_X: |
| X *pObj = new X; |
| *aRecord >> pObj.>aMember1; |
| if ( aRecord.HasVersion(2) ) |
| *aRecord >> pObj->aMember2; |
| Append( pObj ); |
| break; |
| |
| ... |
| } |
| } |
| } |
| */ |
| |
| { |
| sal_uInt32 _nStartPos; // Start-Position des Records |
| sal_uInt32* _pContentOfs; // Offsets der Startpositionen |
| sal_uInt32 _nContentSize; // Size jedes einzelnen / Tabellen-Pos |
| sal_uInt16 _nContentCount; // Anzahl der Contents im Record |
| sal_uInt16 _nContentNo; /* der Index des aktuellen Contents |
| enth"alt jeweils den Index des |
| Contents, der beim n"achsten |
| GetContent() geholt wird */ |
| sal_uInt16 _nContentTag; // Art-Kennung des aktuellen Contents |
| sal_uInt8 _nContentVer; // Versions-Kennung des akt. Contents |
| |
| FASTBOOL ReadHeader_Impl(); |
| |
| public: |
| SfxMultiRecordReader( SvStream *pStream ); |
| SfxMultiRecordReader( SvStream *pStream, sal_uInt16 nTag ); |
| ~SfxMultiRecordReader(); |
| |
| FASTBOOL GetContent(); |
| inline sal_uInt16 GetContentTag(); |
| inline sal_uInt8 GetContentVersion() const; |
| inline FASTBOOL HasContentVersion( sal_uInt16 nVersion ) const; |
| |
| inline sal_uInt32 ContentCount() const; |
| }; |
| |
| //========================================================================= |
| |
| inline SfxMiniRecordWriter::SfxMiniRecordWriter |
| ( |
| SvStream* pStream, // Stream, in dem der Record angelegt wird |
| sal_uInt8 nTag // Record-Tag zwischen 0x01 und 0xFE |
| ) |
| |
| /* [Beschreibung] |
| |
| Legt in 'pStream' einen 'SfxMiniRecord' an, dessen Content-Gr"o\se |
| nicht bekannt ist, sondern nach dam Streamen des Contents errechnet |
| werden soll. |
| */ |
| |
| : _pStream( pStream ), |
| _nStartPos( pStream->Tell() ), |
| _bHeaderOk(sal_False), |
| _nPreTag( nTag ) |
| { |
| DBG_ASSERT( _nPreTag != 0xFF, "invalid Tag" ); |
| DBG( DbgOutf( "SfxFileRec: writing record to %ul", pStream->Tell() ) ); |
| |
| pStream->SeekRel( + SFX_REC_HEADERSIZE_MINI ); |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline SfxMiniRecordWriter::SfxMiniRecordWriter |
| ( |
| SvStream* pStream, // Stream, in dem der Record angelegt wird |
| sal_uInt8 nTag, // Record-Tag zwischen 0x01 und 0xFE |
| sal_uInt32 nSize // Gr"o\se der Daten in Bytes |
| ) |
| |
| /* [Beschreibung] |
| |
| Legt in 'pStream' einen 'SfxMiniRecord' an, dessen Content-Gr"o\se |
| von vornherein bekannt ist. |
| */ |
| |
| : _pStream( pStream ), |
| // _nTag( uninitialized ), |
| // _nStarPos( uninitialized ), |
| _bHeaderOk(SFX_BOOL_DONTCARE) |
| { |
| DBG_ASSERT( nTag != 0 && nTag != 0xFF, "invalid Tag" ); |
| DBG(_nStartPos = pStream->Tell()); |
| DBG( DbgOutf( "SfxFileRec: writing record to %ul", _nStartPos ) ); |
| |
| *pStream << ( ( nTag << 24 ) | nSize ); |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline SfxMiniRecordWriter::~SfxMiniRecordWriter() |
| |
| /* [Beschreibung] |
| |
| Der Dtor der Klasse <SfxMiniRecordWriter> schlie\st den Record |
| automatisch, falls <SfxMiniRecordWriter::Close()> nicht bereits |
| explizit gerufen wurde. |
| */ |
| |
| { |
| // wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden |
| if ( !_bHeaderOk DBG(||sal_True) ) |
| Close(); |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline SvStream& SfxMiniRecordWriter::operator*() const |
| |
| /* [Beschreibung] |
| |
| Dieser Operator liefert den Stream, in dem der Record liegt. |
| Der Record darf noch nicht geschlossen worden sein. |
| */ |
| |
| { |
| DBG_ASSERT( !_bHeaderOk, "getting Stream of closed record" ); |
| return *_pStream; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline void SfxMiniRecordWriter::Reset() |
| { |
| _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI ); |
| _bHeaderOk = sal_False; |
| } |
| |
| //========================================================================= |
| |
| inline SfxMiniRecordReader::~SfxMiniRecordReader() |
| |
| /* [Beschreibung] |
| |
| Der Dtor der Klasse <SfxMiniRecordReader> positioniert den Stream |
| automatisch auf die Position direkt hinter dem Record, falls nicht |
| <SfxMiniRecordReader::Skip()> bereits explizit gerufen wurde. |
| */ |
| |
| { |
| // noch nicht explizit ans Ende gesprungen? |
| if ( !_bSkipped ) |
| Skip(); |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline void SfxMiniRecordReader::Skip() |
| |
| /* [Beschreibung] |
| |
| Mit dieser Methode wird der Stream direkt hinter das Ende des Records |
| positioniert. |
| */ |
| |
| { |
| _pStream->Seek(_nEofRec); |
| _bSkipped = sal_True; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline sal_uInt8 SfxMiniRecordReader::GetTag() const |
| |
| /* [Beschreibung] |
| |
| Liefert des aus dem Header gelesene Pre-Tag des Records. Dieses kann |
| auch SFX_REC_PRETAG_EXT oder SFX_REC_PRETAG_EOR sein, im |
| letzteren Fall ist am Stream der Fehlercode ERRCODE_IO_WRONGFORMAT |
| gesetzt. SFX_REC_PRETAG_EXT ist g"ultig, da diese extended-Records |
| nur eine Erweiterung des SfxMiniRecord darstellen. |
| */ |
| |
| { |
| return _nPreTag; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline FASTBOOL SfxMiniRecordReader::IsValid() const |
| |
| /* [Beschreibung] |
| |
| Hiermit kann abgefragt werden, ob der Record erfolgreich aus dem |
| Stream konstruiert werden konnte, der Header also f"ur diesen Record-Typ |
| passend war. |
| */ |
| |
| { |
| return _nPreTag != SFX_REC_PRETAG_EOR; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline SvStream& SfxMiniRecordReader::operator*() const |
| |
| /* [Beschreibung] |
| |
| Dieser Operator liefert den Stream in dem der Record liegt. |
| Die aktuelle Position des Streams mu\s innerhalb des Records liegen. |
| */ |
| |
| { |
| DBG_ASSERT( _pStream->Tell() < _nEofRec, "read behind record" ); |
| return *_pStream; |
| } |
| |
| //========================================================================= |
| |
| inline sal_uInt32 SfxSingleRecordWriter::Close( FASTBOOL bSeekToEndOfRec ) |
| |
| // siehe <SfxMiniRecordWriter::Close(FASTBOOL)> |
| |
| { |
| sal_uInt32 nRet = 0; |
| |
| // wurde der Header noch nicht geschrieben? |
| if ( !_bHeaderOk ) |
| { |
| // Basisklassen-Header schreiben |
| sal_uInt32 nEndPos = SfxMiniRecordWriter::Close( bSeekToEndOfRec ); |
| |
| // ggf. ans Ende des eigenen Headers seeken oder hinter Rec bleiben |
| if ( !bSeekToEndOfRec ) |
| _pStream->SeekRel( SFX_REC_HEADERSIZE_SINGLE ); |
| nRet = nEndPos; |
| } |
| #ifdef DBG_UTIL |
| else |
| // Basisklassen-Header pr"ufen |
| SfxMiniRecordWriter::Close( bSeekToEndOfRec ); |
| #endif |
| |
| // Record war bereits geschlossen |
| // nRet = 0; |
| return nRet; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline void SfxSingleRecordWriter::Reset() |
| { |
| _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI + |
| SFX_REC_HEADERSIZE_SINGLE ); |
| _bHeaderOk = sal_False; |
| } |
| |
| //========================================================================= |
| |
| inline sal_uInt16 SfxSingleRecordReader::GetTag() const |
| |
| /* [Beschreibung] |
| |
| Liefert des aus dem Header gelesene Tag f"ur den Gesamt-Record. |
| */ |
| |
| { |
| return _nRecordTag; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline sal_uInt8 SfxSingleRecordReader::GetVersion() const |
| |
| /* [Beschreibung] |
| |
| Liefert die Version des aus dem Stream gelesenen Records. |
| */ |
| |
| { |
| return _nRecordVer; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline FASTBOOL SfxSingleRecordReader::HasVersion( sal_uInt16 nVersion ) const |
| |
| /* [Beschreibung] |
| |
| Stellt fest, ob der aus dem Stream gelese Record in der Version |
| 'nVersion' oder h"oher vorliegt. |
| */ |
| |
| { |
| return _nRecordVer >= nVersion; |
| } |
| |
| //========================================================================= |
| |
| inline SfxMultiFixRecordWriter::~SfxMultiFixRecordWriter() |
| |
| /* [Beschreibung] |
| |
| Der Dtor der Klasse <SfxMultiFixRecordWriter> schlie\st den Record |
| automatisch, falls <SfxMutiFixRecordWriter::Close()> nicht bereits |
| explizit gerufen wurde. |
| */ |
| |
| { |
| // wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden |
| if ( !_bHeaderOk ) |
| Close(); |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline void SfxMultiFixRecordWriter::NewContent() |
| |
| /* [Beschreibung] |
| |
| Mit dieser Methode wird in den Record ein neuer Content eingef"ugt. |
| Jeder, auch der 1. Record mu\s durch Aufruf dieser Methode eingeleitet |
| werden. |
| */ |
| |
| { |
| #ifdef DBG_UTIL |
| sal_uLong nOldStartPos; |
| // Startposition des aktuellen Contents merken - Achtung Subklassen! |
| nOldStartPos = _nContentStartPos; |
| #endif |
| _nContentStartPos = _pStream->Tell(); |
| |
| #ifdef DBG_UTIL |
| // ist ein vorhergehender Content vorhanden? |
| if ( _nContentCount ) |
| { |
| // pr"ufen, ob der vorhergehende die Soll-Gr"o\se eingehalten hat |
| DBG_ASSERT( _nContentStartPos - nOldStartPos == _nContentSize, |
| "wrong content size detected" ); |
| } |
| #endif |
| |
| // Anzahl mitz"ahlen |
| ++_nContentCount; |
| } |
| |
| //========================================================================= |
| |
| inline SfxMultiMixRecordWriter::SfxMultiMixRecordWriter |
| ( |
| SvStream* pStream, // Stream, in dem der Record angelegt wird |
| sal_uInt16 nRecordTag, // Gesamt-Record-Art-Kennung |
| sal_uInt8 nRecordVer // Gesamt-Record-Versions-Kennung |
| ) |
| |
| /* [Beschreibung] |
| |
| Legt in 'pStream' einen 'SfxMultiMixRecord' an, f"ur dessen Contents |
| je eine separate Kennung f"ur Art (Tag) und Version gespeichert wird. |
| Die Gr"o\sen der einzelnen Contents werden automatisch ermittelt. |
| */ |
| |
| : SfxMultiVarRecordWriter( SFX_REC_TYPE_MIXTAGS, |
| pStream, nRecordTag, nRecordVer ) |
| { |
| } |
| |
| //========================================================================= |
| |
| inline void SfxMultiFixRecordWriter::Reset() |
| { |
| _pStream->Seek( _nStartPos + SFX_REC_HEADERSIZE_MINI + |
| SFX_REC_HEADERSIZE_SINGLE + |
| SFX_REC_HEADERSIZE_MULTI ); |
| _bHeaderOk = sal_False; |
| } |
| |
| //========================================================================= |
| |
| inline sal_uInt16 SfxMultiRecordReader::GetContentTag() |
| |
| /* [Beschreibung] |
| |
| Diese Methode liefert die Art-Kennung des zuletzt mit der Methode |
| <SfxMultiRecordReder::GetContent()> ge"offneten Contents. |
| */ |
| |
| { |
| return _nContentTag; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline sal_uInt8 SfxMultiRecordReader::GetContentVersion() const |
| |
| /* [Beschreibung] |
| |
| Diese Methode liefert die Version-Kennung des zuletzt mit der Methode |
| <SfxMultiRecordReder::GetContent()> ge"offneten Contents. |
| */ |
| |
| { |
| return _nContentVer; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline FASTBOOL SfxMultiRecordReader::HasContentVersion( sal_uInt16 nVersion ) const |
| |
| /* [Beschreibung] |
| |
| Diese Methode stellt fest, ob die Version 'nVersion' in der Version des |
| zuletzt mit der Methode <SfxMultiRecordReder::GetContent()> ge"offneten |
| Contents enthalten ist. |
| */ |
| |
| { |
| return _nContentVer >= nVersion; |
| } |
| |
| //------------------------------------------------------------------------- |
| |
| inline sal_uInt32 SfxMultiRecordReader::ContentCount() const |
| |
| /* [Beschreibung] |
| |
| Diese Methode liefert die Anzahl im Record befindlichen Contents. |
| */ |
| |
| { |
| return _nContentCount; |
| } |
| |
| #endif |
| |