573edd503b
in SfxMultiRecordReader::dtor().
1045 lines
34 KiB
C++
1045 lines
34 KiB
C++
/*************************************************************************
|
|
*
|
|
* $RCSfile: filerec.cxx,v $
|
|
*
|
|
* $Revision: 1.3 $
|
|
*
|
|
* last change: $Author: mhu $ $Date: 2002-06-28 17:48:20 $
|
|
*
|
|
* The Contents of this file are made available subject to the terms of
|
|
* either of the following licenses
|
|
*
|
|
* - GNU Lesser General Public License Version 2.1
|
|
* - Sun Industry Standards Source License Version 1.1
|
|
*
|
|
* Sun Microsystems Inc., October, 2000
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2000 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
*
|
|
* Sun Industry Standards Source License Version 1.1
|
|
* =================================================
|
|
* The contents of this file are subject to the Sun Industry Standards
|
|
* Source License Version 1.1 (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.openoffice.org/license.html.
|
|
*
|
|
* Software provided under this License is provided on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
|
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
|
|
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
|
|
* See the License for the specific provisions governing your rights and
|
|
* obligations concerning the Software.
|
|
*
|
|
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
|
|
*
|
|
* Copyright: 2000 by Sun Microsystems, Inc.
|
|
*
|
|
* All Rights Reserved.
|
|
*
|
|
* Contributor(s): _______________________________________
|
|
*
|
|
*
|
|
************************************************************************/
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "filerec.hxx"
|
|
|
|
//========================================================================
|
|
|
|
SV_IMPL_VARARR( SfxUINT32s, UINT32 );
|
|
|
|
//========================================================================
|
|
|
|
/* Die folgenden Makros extrahieren Teilbereiche aus einem UINT32 Wert.
|
|
Diese UINT32-Werte werden anstelle der einzelnen Werte gestreamt,
|
|
um Calls zu sparen.
|
|
*/
|
|
|
|
#define SFX_REC_PRE(n) ( ((n) & 0x000000FF) )
|
|
#define SFX_REC_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
|
|
#define SFX_REC_TYP(n) ( ((n) & 0x000000FF) )
|
|
#define SFX_REC_VER(n) ( ((n) & 0x0000FF00) >> 8 )
|
|
#define SFX_REC_TAG(n) ( ((n) & 0xFFFF0000) >> 16 )
|
|
|
|
#define SFX_REC_CONTENT_VER(n) ( ((n) & 0x000000FF) )
|
|
#define SFX_REC_CONTENT_OFS(n) ( ((n) & 0xFFFFFF00) >> 8 )
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/* Die folgenden Makros setzen Teilbereiche zu einem UINT32 Wert zusammen.
|
|
Diese UINT32-Werte werden anstelle der einzelnen Werte gestreamt,
|
|
um Calls zu sparen.
|
|
*/
|
|
|
|
#define SFX_REC_MINI_HEADER(nPreTag,nStartPos,nEndPos) \
|
|
( UINT32(nPreTag) | \
|
|
UINT32(nEndPos-nStartPos-SFX_REC_HEADERSIZE_MINI) << 8 )
|
|
|
|
#define SFX_REC_HEADER(nRecType,nContentTag,nContentVer) \
|
|
( UINT32(nRecType) | \
|
|
( UINT32(nContentVer) << 8 ) | \
|
|
( UINT32(nContentTag) << 16 ) )
|
|
|
|
#define SFX_REC_CONTENT_HEADER(nContentVer,n1StStartPos,nCurStartPos) \
|
|
( UINT32(nContentVer) | \
|
|
UINT32( nCurStartPos - n1StStartPos ) << 8 )
|
|
|
|
//=========================================================================
|
|
|
|
UINT32 SfxMiniRecordWriter::Close
|
|
(
|
|
FASTBOOL bSeekToEndOfRec /* TRUE (default)
|
|
Der Stream wird an das Ende des Records
|
|
positioniert.
|
|
|
|
FALSE
|
|
Der Stream wird an den Anfang des
|
|
Contents (also hinter den Header)
|
|
positioniert.
|
|
*/
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Diese Methode schlie\st den Record. Dabei wird haupts"achlich der
|
|
Header geschrieben.
|
|
|
|
Wurde der Header bereits geschrieben, hat der Aufruf keine Wirkung.
|
|
|
|
|
|
[R"uckgabewert]
|
|
|
|
UINT32 != 0
|
|
Position im Stream, die direkt hinter dem Record liegt.
|
|
'bSeekToEndOfRecord==TRUE'
|
|
=> R"uckgabewert == aktuelle Stream-Position nach Aufruf
|
|
|
|
== 0
|
|
Der Header war bereits geschrieben worden.
|
|
*/
|
|
|
|
{
|
|
// wurde der Header noch nicht geschrieben?
|
|
if ( !_bHeaderOk )
|
|
{
|
|
// Header an den Anfang des Records schreiben
|
|
UINT32 nEndPos = _pStream->Tell();
|
|
_pStream->Seek( _nStartPos );
|
|
*_pStream << SFX_REC_MINI_HEADER( _nPreTag, _nStartPos, nEndPos );
|
|
|
|
// je nachdem ans Ende des Records seeken oder hinter Header bleiben
|
|
if ( bSeekToEndOfRec )
|
|
_pStream->Seek( nEndPos );
|
|
|
|
// Header wurde JETZT geschrieben
|
|
_bHeaderOk = TRUE;
|
|
return nEndPos;
|
|
}
|
|
#ifdef DBG_UTIL
|
|
// mu\s Fix-Size-Record gepr"uft werden?
|
|
else if ( SFX_BOOL_DONTCARE == _bHeaderOk )
|
|
{
|
|
// Header auslesen, um Soll-Gr"o\se zu bestimmen
|
|
UINT32 nEndPos = _pStream->Tell();
|
|
_pStream->Seek( _nStartPos );
|
|
ULONG nHeader;
|
|
*_pStream >> nHeader;
|
|
_pStream->Seek( nEndPos );
|
|
|
|
// Soll-Gr"o\se mit Ist-Gr"o\se vergleichen
|
|
DBG_ASSERT( nEndPos - SFX_REC_OFS(nHeader) == _nStartPos + sizeof(UINT32),
|
|
"fixed record size incorrect" );
|
|
DbgOutf( "SfxFileRec: written record until %ul", nEndPos );
|
|
}
|
|
#endif
|
|
|
|
// Record war bereits geschlossen
|
|
return 0;
|
|
}
|
|
|
|
//=========================================================================
|
|
|
|
USHORT SfxMiniRecordReader::ScanRecordType
|
|
(
|
|
SvStream* pStream /* <SvStream> an dessen aktueller Position
|
|
ein Record liegt, dessen Typ erkannt werden
|
|
soll.
|
|
*/
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Mit dieser statischen Methode kann ermittelt werden, ob sich an der
|
|
aktuellen Position in einem Stream ein Record befindet, und der Typ
|
|
des Records kann ermittelt werden.
|
|
|
|
Die Position im Stream ist nach dem Aufruf aufver"andert.
|
|
|
|
|
|
[Anmerkung]
|
|
|
|
Die Record-Typen k"onnen zwar (abgesehen vom Drawing-Enginge-Record)
|
|
untereinander eindeutig erkannt werden, es besteht jedoch die Gefahr
|
|
der Verwechslung von Records mit normalen Daten. File-Formate sollten
|
|
darauf R"ucksicht nehmen. Handelt es sich um keinen Record, wird
|
|
am wahrscheinlichsten SFX_REC_TYPE_MINI zur"uckgeliefert, da dieser
|
|
Typ sich aufgrund seines sparsam kurzen Headers durch die k"urzeste
|
|
Kennung auszeichnet.
|
|
|
|
|
|
[R"uckgabewert]
|
|
|
|
USHORT SFX_REC_TYPE_EOR
|
|
An der aktuellen Position des Streams
|
|
steht eine End-Of-Records-Kennung.
|
|
|
|
SFX_REC_TYPE_MINI
|
|
Es handelt sich um einen SW3 kompatiblen
|
|
Mini-Record, dessen einzige Kennung sein
|
|
'Mini-Tag' ist.
|
|
|
|
SFX_REC_TYPE_SINGLE
|
|
Es handelt sich um einen Extended-Record
|
|
mit einem einzigen Content, der durch eine
|
|
Version und ein Tag n"aher gekennzeichnet
|
|
ist.
|
|
|
|
SFX_REC_TYPE_FIXSIZE
|
|
Es handelt sich um einen Extended-Record
|
|
mit mehreren Contents gleicher Gr"o\se,
|
|
die gemeinsam durch eine einzige Version
|
|
und ein einziges gemeinsames Tag n"aher
|
|
gekennzeichnet sind.
|
|
|
|
SFX_REC_TYPE_VARSIZE
|
|
Es handelt sich um einen Extended-Record
|
|
mit mehreren Contents variabler Gr"o\se,
|
|
die gemeinsam durch eine einzige Version
|
|
und ein einziges gemeinsames Tag n"aher
|
|
gekennzeichnet sind.
|
|
|
|
SFX_REC_TYPE_MIXTAGS
|
|
Es handelt sich um einen Extended-Record
|
|
mit mehreren Contents variabler Gr"o\se,
|
|
die jeweils durch ein eignes Tag und
|
|
eine eigene Versions-Nummer n"aher
|
|
gekennzeichnet sind.
|
|
|
|
SFX_REC_TYPE_DRAWENG
|
|
Es handelt sich wahrscheinlich um einen
|
|
Drawing-Engine-Record. Dieser Record-Typ
|
|
kann von den Klassen dieser Gruppe nicht
|
|
interpretiert werden.
|
|
*/
|
|
|
|
{
|
|
// die ersten 4 Bytes als Mini-Header lesen
|
|
ULONG nHeader;
|
|
*pStream >> nHeader;
|
|
|
|
// k"onnte es sich um einen extended-Record handeln?
|
|
USHORT nPreTag = SFX_REC_PRE(nHeader);
|
|
if ( SFX_REC_PRETAG_EXT == nPreTag )
|
|
{
|
|
// die n"achsten 4 Bytes als extended-Header lesen
|
|
*pStream >> nHeader;
|
|
|
|
// Stream-Position restaurieren
|
|
pStream->SeekRel(-8);
|
|
|
|
// liegt eine g"ultige Record-Kennung vor?
|
|
USHORT nType = SFX_REC_TYP(nHeader);
|
|
if ( nType >= SFX_REC_TYPE_FIRST && nType <= SFX_REC_TYPE_LAST )
|
|
// entsprechenden extended-Record-Typ zur"uckliefern
|
|
return nType;
|
|
|
|
// sonst ist der Record-Typ unbekannt
|
|
return SFX_REC_TYPE_NONE;
|
|
}
|
|
|
|
// Stream-Position restaurieren
|
|
pStream->SeekRel(-4);
|
|
|
|
// liegt eine End-Of-Record-Kennung vor?
|
|
if ( SFX_REC_PRETAG_EOR == nPreTag )
|
|
return nPreTag;
|
|
|
|
// liegt ein Drawin-Engine-Record vor?
|
|
if ( nHeader == UINT32(*"DRMD") || nHeader == UINT32(*"DRVW") )
|
|
return SFX_REC_TYPE_DRAWENG;
|
|
|
|
// alle anderen sind grunds"atzlich g"ultige Mini-Records
|
|
return SFX_REC_TYPE_MINI;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
FASTBOOL SfxMiniRecordReader::SetHeader_Impl( UINT32 nHeader )
|
|
|
|
/* [Beschreibung]
|
|
|
|
Interne Methode zum nachtr"aglichen Verarbeiten eines extern gelesenen
|
|
Headers. Falls der Header eine End-Of-Records-Kennung darstellt,
|
|
wird am Stream ein Errorcode gesetzt und FALSE zur"uckgeliefert. Im
|
|
Fehlerfall wird der Stream jedoch nicht auf den Record-Anfang zur"uck-
|
|
gesetzt.
|
|
*/
|
|
|
|
{
|
|
FASTBOOL bRet = TRUE;
|
|
|
|
// Record-Ende und Pre-Tag aus dem Header ermitteln
|
|
_nEofRec = _pStream->Tell() + SFX_REC_OFS(nHeader);
|
|
_nPreTag = SFX_REC_PRE(nHeader);
|
|
|
|
// wenn End-Of-Record-Kennung, dann Fehler
|
|
if ( _nPreTag == SFX_REC_PRETAG_EOR )
|
|
{
|
|
_pStream->SetError( ERRCODE_IO_WRONGFORMAT );
|
|
bRet = FALSE;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxMiniRecordReader::SfxMiniRecordReader
|
|
(
|
|
SvStream* pStream /* <SvStream>, an dessen aktueller
|
|
Position sich ein <SfxMiniRecord>
|
|
befindet.
|
|
*/
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Dieser Ctor liest den Header eines <SfxMiniRecord> ab der aktuellen
|
|
Position von 'pStream'. Da grunds"atzlich fast 4-Byte Kombination ein
|
|
g"ultiger SfxMiniRecord-Header ist, bleiben die einzig m"oglichen
|
|
Fehler der EOF-Status des Streams, und ein SFX_REC_PRETAG_EOR
|
|
als Pre-Tag. Ein entsprechender Error-Code (ERRCODE_IO_EOF bzw.
|
|
ERRCODE_IO_WRONGFORMAT) ist dann am Stream gesetzt, dessen Position
|
|
dann au\serdem unver"andert ist.
|
|
*/
|
|
|
|
: _pStream( pStream ),
|
|
_bSkipped( FALSE )
|
|
{
|
|
// Header einlesen
|
|
UINT32 nStartPos = pStream->Tell(); // um im Fehlerfall zur"uck zu-seeken
|
|
DBG( DbgOutf( "SfxFileRec: reading record at %ul", nStartPos ) );
|
|
UINT32 nHeader;
|
|
*pStream >> nHeader;
|
|
|
|
// Headerdaten extrahieren
|
|
SetHeader_Impl( nHeader );
|
|
|
|
// Fehlerbehandlung
|
|
if ( pStream->IsEof() )
|
|
_nPreTag = SFX_REC_PRETAG_EOR;
|
|
else if ( _nPreTag == SFX_REC_PRETAG_EOR )
|
|
pStream->SetError( ERRCODE_IO_WRONGFORMAT );
|
|
if ( !IsValid() )
|
|
pStream->Seek( nStartPos );
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxMiniRecordReader::SfxMiniRecordReader
|
|
(
|
|
SvStream* pStream, /* <SvStream>, an dessen aktueller
|
|
Position sich ein <SfxMiniRecord>
|
|
befindet.
|
|
*/
|
|
BYTE nTag // Pre-Tag des gew"unschten Records
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Dieser Ctor interpretiert 'pStream' ab der aktuellen Position als
|
|
eine l"uckenlose Folge von, von dieser Klassen-Gruppe interpretierbaren,
|
|
Records. Der in dieser Folge erste als <SfxMiniRecord> interpretierbare
|
|
(also ggf. auch ein extended-Record) mit dem PreTag 'nTag' wird ge"offnet
|
|
und durch diese Instanz repr"asentiert.
|
|
|
|
Wird das Ende des Streams oder die Kennung SFX_REC_PRETAG_EOR
|
|
erreicht, bevor ein Record mit dem ge"unschten Pre-Tag gefunden wird,
|
|
ist die erzeugte Instanz ung"ultig ('IsValid() == FALSE'). Ein ent-
|
|
sprechender Error-Code (ERRCODE_IO_EOF bzw. ERRCODE_IO_WRONGFORMAT)
|
|
ist dann am Stream gesetzt, dessen Position ist dann au\serdem unver-
|
|
"andert.
|
|
|
|
Bei 'nTag==SFX_FILEREC_PRETAG_EOR' wird nicht versucht, einen Record
|
|
zu lesen, es wird sofort 'IsValid()' auf FALSE gesetzt und kein Error-Code
|
|
am Stream gesetzt. Dies ist dauzu gedacht, ohne 'new' und 'delete'
|
|
abw"rtskompatibel SfxMiniRecords einbauen zu k"onnen. Siehe dazu
|
|
<SfxItemSet::Load()>.
|
|
|
|
|
|
[Anwendungsvorschlag]
|
|
|
|
Wird dieser Ctor in einer bereits ausgelieferten Programmversion
|
|
verwendet, k"onnen in das File-Format jeweils davor kompatibel neue
|
|
Records mit einer anderen Kennung eingef"ugt werden. Diese werden
|
|
schlie\slich automatisch "uberlesen. Erkauft wird diese M"oglichkeit
|
|
allerdings mit etwas schlechterem Laufzeitverhalten im Vergleich mit
|
|
direktem 'drauf-los-lesen', der sich jedoch auf einen Vergleich zweier
|
|
Bytes reduziert, falls der gesuchte Record der erste in der Folge ist.
|
|
*/
|
|
|
|
: _pStream( pStream ),
|
|
_bSkipped( nTag == SFX_REC_PRETAG_EOR )
|
|
{
|
|
// ggf. ignorieren (s.o.)
|
|
if ( _bSkipped )
|
|
{
|
|
_nPreTag = nTag;
|
|
return;
|
|
}
|
|
|
|
// StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
|
|
UINT32 nStartPos = pStream->Tell();
|
|
|
|
// passenden Record suchen
|
|
while(TRUE)
|
|
{
|
|
// Header lesen
|
|
DBG( DbgOutf( "SfxFileRec: searching record at %ul", pStream->Tell() ) );
|
|
UINT32 nHeader;
|
|
*pStream >> nHeader;
|
|
|
|
// Headerdaten von Basisklasse extrahieren lassen
|
|
SetHeader_Impl( nHeader );
|
|
|
|
// ggf. Fehler behandeln
|
|
if ( pStream->IsEof() )
|
|
_nPreTag = SFX_REC_PRETAG_EOR;
|
|
else if ( _nPreTag == SFX_REC_PRETAG_EOR )
|
|
pStream->SetError( ERRCODE_IO_WRONGFORMAT );
|
|
else
|
|
{
|
|
// wenn gefunden, dann Schleife abbrechen
|
|
if ( _nPreTag == nTag )
|
|
break;
|
|
|
|
// sonst skippen und weitersuchen
|
|
pStream->Seek( _nEofRec );
|
|
continue;
|
|
}
|
|
|
|
// Fehler => zur"uck-seeken
|
|
pStream->Seek( nStartPos );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//=========================================================================
|
|
|
|
SfxSingleRecordWriter::SfxSingleRecordWriter
|
|
(
|
|
BYTE nRecordType, // f"ur Subklassen
|
|
SvStream* pStream, // Stream, in dem der Record angelegt wird
|
|
UINT16 nContentTag, // Inhalts-Art-Kennung
|
|
BYTE nContentVer // Inhalts-Versions-Kennung
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Interner Ctor f"ur Subklassen.
|
|
*/
|
|
|
|
: SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT )
|
|
{
|
|
// Erweiterten Header hiner den des SfxMiniRec schreiben
|
|
*pStream << SFX_REC_HEADER(nRecordType, nContentTag, nContentVer);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxSingleRecordWriter::SfxSingleRecordWriter
|
|
(
|
|
SvStream* pStream, // Stream, in dem der Record angelegt wird
|
|
UINT16 nContentTag, // Inhalts-Art-Kennung
|
|
BYTE nContentVer // Inhalts-Versions-Kennung
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Legt in 'pStream' einen 'SfxSingleRecord' an, dessen Content-Gr"o\se
|
|
nicht bekannt ist, sondern nach dam Streamen des Contents errechnet
|
|
werden soll.
|
|
*/
|
|
|
|
: SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT )
|
|
{
|
|
// Erweiterten Header hiner den des SfxMiniRec schreiben
|
|
*pStream << SFX_REC_HEADER( SFX_REC_TYPE_SINGLE, nContentTag, nContentVer);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxSingleRecordWriter::SfxSingleRecordWriter
|
|
(
|
|
SvStream* pStream, // Stream, in dem der Record angelegt wird
|
|
UINT16 nContentTag, // Inhalts-Art-Kennung
|
|
BYTE nContentVer, // Inhalts-Versions-Kennung
|
|
UINT32 nContentSize // Gr"o\se des Inhalts in Bytes
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Legt in 'pStream' einen 'SfxSingleRecord' an, dessen Content-Gr"o\se
|
|
von vornherein bekannt ist.
|
|
*/
|
|
|
|
: SfxMiniRecordWriter( pStream, SFX_REC_PRETAG_EXT,
|
|
nContentSize + SFX_REC_HEADERSIZE_SINGLE )
|
|
{
|
|
// Erweiterten Header hinter den des SfxMiniRec schreiben
|
|
*pStream << SFX_REC_HEADER( SFX_REC_TYPE_SINGLE, nContentTag, nContentVer);
|
|
}
|
|
|
|
//=========================================================================
|
|
|
|
inline FASTBOOL SfxSingleRecordReader::ReadHeader_Impl( USHORT nTypes )
|
|
|
|
/* [Beschreibung]
|
|
|
|
Interne Methode zum Einlesen eines SfxMultiRecord-Headers, nachdem
|
|
die Basisklasse bereits initialisiert und deren Header gelesen ist.
|
|
Ggf. ist ein Error-Code am Stream gesetzt, im Fehlerfall wird jedoch
|
|
nicht zur"uckge-seekt.
|
|
*/
|
|
|
|
{
|
|
FASTBOOL bRet;
|
|
|
|
// Basisklassen-Header einlesen
|
|
UINT32 nHeader;
|
|
*_pStream >> nHeader;
|
|
if ( !SetHeader_Impl( nHeader ) )
|
|
bRet = FALSE;
|
|
else
|
|
{
|
|
// eigenen Header einlesen
|
|
*_pStream >> nHeader;
|
|
_nRecordVer = SFX_REC_VER(nHeader);
|
|
_nRecordTag = SFX_REC_TAG(nHeader);
|
|
|
|
// falscher Record-Typ?
|
|
_nRecordType = SFX_REC_TYP(nHeader);
|
|
bRet = 0 != ( nTypes & _nRecordType);
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxSingleRecordReader::SfxSingleRecordReader( SvStream *pStream )
|
|
: SfxMiniRecordReader()
|
|
{
|
|
// Startposition merken, um im Fehlerfall zur"uck-seeken zu k"onnen
|
|
UINT32 nStartPos = pStream->Tell();
|
|
DBG( DbgOutf( "SfxFileRec: reading record at %ul", nStartPos ) );
|
|
|
|
// Basisklasse initialisieren (nicht via Ctor, da der nur MiniRecs akzept.)
|
|
Construct_Impl( pStream );
|
|
|
|
// nur Header mit korrektem Record-Type akzeptieren
|
|
if ( !ReadHeader_Impl( SFX_REC_TYPE_SINGLE ) )
|
|
{
|
|
// Error-Code setzen und zur"uck-seeken
|
|
pStream->SeekRel( - SFX_REC_HEADERSIZE_SINGLE );
|
|
pStream->SetError( ERRCODE_IO_WRONGFORMAT );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxSingleRecordReader::SfxSingleRecordReader( SvStream *pStream, USHORT nTag )
|
|
{
|
|
// StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
|
|
UINT32 nStartPos = pStream->Tell();
|
|
|
|
// richtigen Record suchen, ggf. Error-Code setzen und zur"uck-seeken
|
|
Construct_Impl( pStream );
|
|
if ( !FindHeader_Impl( SFX_REC_TYPE_SINGLE, nTag ) )
|
|
{
|
|
// Error-Code setzen und zur"uck-seeken
|
|
pStream->Seek( nStartPos );
|
|
pStream->SetError( ERRCODE_IO_WRONGFORMAT );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
FASTBOOL SfxSingleRecordReader::FindHeader_Impl
|
|
(
|
|
UINT16 nTypes, // arithm. Veroderung erlaubter Record-Typen
|
|
UINT16 nTag // zu findende Record-Art-Kennung
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Interne Methode zum lesen des Headers des ersten Record, der einem
|
|
der Typen in 'nTypes' entspricht und mit der Art-Kennung 'nTag'
|
|
gekennzeichnet ist.
|
|
|
|
Kann ein solcher Record nicht gefunden werden, wird am Stream ein
|
|
Errorcode gesetzt, zur"uck-geseekt und FALSE zur"uckgeliefert.
|
|
*/
|
|
|
|
{
|
|
// StartPos merken, um im Fehlerfall zur"uck-seeken zu k"onnen
|
|
UINT32 nStartPos = _pStream->Tell();
|
|
|
|
// richtigen Record suchen
|
|
while ( !_pStream->IsEof() )
|
|
{
|
|
// Header lesen
|
|
UINT32 nHeader;
|
|
DBG( DbgOutf( "SfxFileRec: searching record at %ul", _pStream->Tell() ) );
|
|
*_pStream >> nHeader;
|
|
if ( !SetHeader_Impl( nHeader ) )
|
|
// EOR => Such-Schleife abbreichen
|
|
break;
|
|
|
|
// Extended Record gefunden?
|
|
if ( _nPreTag == SFX_REC_PRETAG_EXT )
|
|
{
|
|
// Extended Header lesen
|
|
*_pStream >> nHeader;
|
|
_nRecordTag = SFX_REC_TAG(nHeader);
|
|
|
|
// richtigen Record gefunden?
|
|
if ( _nRecordTag == nTag )
|
|
{
|
|
// gefundener Record-Typ passend?
|
|
_nRecordType = SFX_REC_TYP(nHeader);
|
|
if ( nTypes & _nRecordType )
|
|
// ==> gefunden
|
|
return TRUE;
|
|
|
|
// error => Such-Schleife abbrechen
|
|
break;
|
|
}
|
|
}
|
|
|
|
// sonst skippen
|
|
if ( !_pStream->IsEof() )
|
|
_pStream->Seek( _nEofRec );
|
|
}
|
|
|
|
// Fehler setzen und zur"uck-seeken
|
|
_pStream->SetError( ERRCODE_IO_WRONGFORMAT );
|
|
_pStream->Seek( nStartPos );
|
|
return FALSE;
|
|
}
|
|
|
|
//=========================================================================
|
|
|
|
SfxMultiFixRecordWriter::SfxMultiFixRecordWriter
|
|
(
|
|
BYTE nRecordType, // Subklassen Record-Kennung
|
|
SvStream* pStream, // Stream, in dem der Record angelegt wird
|
|
UINT16 nContentTag, // Content-Art-Kennung
|
|
BYTE nContentVer, // Content-Versions-Kennung
|
|
UINT32 nContentSize // Gr"o\se jedes einzelnen Contents in Bytes
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Interne Methode f"ur Subklassen.
|
|
*/
|
|
|
|
: SfxSingleRecordWriter( nRecordType, pStream, nContentTag, nContentVer ),
|
|
_nContentCount( 0 )
|
|
{
|
|
// Platz f"ur eigenen Header
|
|
pStream->SeekRel( + SFX_REC_HEADERSIZE_MULTI );
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
SfxMultiFixRecordWriter::SfxMultiFixRecordWriter
|
|
(
|
|
SvStream* pStream, // Stream, in dem der Record angelegt wird
|
|
UINT16 nContentTag, // Content-Art-Kennung
|
|
BYTE nContentVer, // Content-Versions-Kennung
|
|
UINT32 nContentSize // Gr"o\se jedes einzelnen Contents in Bytes
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Legt in 'pStream' einen 'SfxMultiFixRecord' an, dessen Content-Gr"o\se
|
|
konstant und von vornherein bekannt ist.
|
|
*/
|
|
|
|
: SfxSingleRecordWriter( SFX_REC_TYPE_FIXSIZE,
|
|
pStream, nContentTag, nContentVer ),
|
|
_nContentCount( 0 )
|
|
{
|
|
// Platz f"ur eigenen Header
|
|
pStream->SeekRel( + SFX_REC_HEADERSIZE_MULTI );
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
UINT32 SfxMultiFixRecordWriter::Close( FASTBOOL bSeekToEndOfRec )
|
|
|
|
// siehe <SfxMiniRecordWriter>
|
|
|
|
{
|
|
// Header noch nicht geschrieben?
|
|
if ( !_bHeaderOk )
|
|
{
|
|
// Position hinter Record merken, um sie restaurieren zu k"onnen
|
|
UINT32 nEndPos = SfxSingleRecordWriter::Close( FALSE );
|
|
|
|
// gegen"uber SfxSingleRecord erweiterten Header schreiben
|
|
*_pStream << _nContentCount;
|
|
*_pStream << _nContentSize;
|
|
|
|
// je nachdem ans Ende des Records seeken oder hinter Header bleiben
|
|
if ( bSeekToEndOfRec )
|
|
_pStream->Seek(nEndPos);
|
|
return nEndPos;
|
|
}
|
|
|
|
// Record war bereits geschlossen
|
|
return 0;
|
|
}
|
|
|
|
//=========================================================================
|
|
|
|
SfxMultiVarRecordWriter::SfxMultiVarRecordWriter
|
|
(
|
|
BYTE nRecordType, // Record-Kennung der Subklasse
|
|
SvStream* pStream, // Stream, in dem der Record angelegt wird
|
|
UINT16 nRecordTag, // Gesamt-Art-Kennung
|
|
BYTE nRecordVer // Gesamt-Versions-Kennung
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Interner Ctor f"ur Subklassen.
|
|
*/
|
|
|
|
: SfxMultiFixRecordWriter( nRecordType, pStream, nRecordTag, nRecordVer, 0 ),
|
|
_nContentVer( 0 )
|
|
{
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxMultiVarRecordWriter::SfxMultiVarRecordWriter
|
|
(
|
|
SvStream* pStream, // Stream, in dem der Record angelegt wird
|
|
UINT16 nRecordTag, // Gesamt-Art-Kennung
|
|
BYTE nRecordVer // Gesamt-Versions-Kennung
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Legt in 'pStream' einen 'SfxMultiVarRecord' an, dessen Content-Gr"o\sen
|
|
weder bekannt sind noch identisch sein m"ussen, sondern jeweils nach dem
|
|
Streamen jedes einzelnen Contents errechnet werden sollen.
|
|
|
|
|
|
[Anmerkung]
|
|
|
|
Diese Methode ist nicht inline, da f"ur die Initialisierung eines
|
|
<SvULongs>-Members zu viel Code generiert werden w"urde.
|
|
*/
|
|
|
|
: SfxMultiFixRecordWriter( SFX_REC_TYPE_VARSIZE,
|
|
pStream, nRecordTag, nRecordVer, 0 ),
|
|
_nContentVer( 0 )
|
|
{
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxMultiVarRecordWriter::~SfxMultiVarRecordWriter()
|
|
|
|
/* [Beschreibung]
|
|
|
|
Der Dtor der Klasse <SfxMultiVarRecordWriter> schlie\st den Record
|
|
automatisch, falls <SfxMultiVarRecordWriter::Close()> nicht bereits
|
|
explizit gerufen wurde.
|
|
*/
|
|
|
|
{
|
|
// wurde der Header noch nicht geschrieben oder mu\s er gepr"uft werden
|
|
if ( !_bHeaderOk )
|
|
Close();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
void SfxMultiVarRecordWriter::FlushContent_Impl()
|
|
|
|
/* [Beschreibung]
|
|
|
|
Interne Methode zum Abschlie\sen eines einzelnen Contents.
|
|
*/
|
|
|
|
{
|
|
// Versions-Kennung und Positions-Offset des aktuellen Contents merken;
|
|
// das Positions-Offset ist relativ zur Startposition des ersten Contents
|
|
_aContentOfs.Insert(
|
|
SFX_REC_CONTENT_HEADER(_nContentVer,_nStartPos,_nContentStartPos),
|
|
_nContentCount-1 );
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
void SfxMultiVarRecordWriter::NewContent()
|
|
|
|
// siehe <SfxMultiFixRecordWriter>
|
|
|
|
{
|
|
// schon ein Content geschrieben?
|
|
if ( _nContentCount )
|
|
FlushContent_Impl();
|
|
|
|
// neuen Content beginnen
|
|
_nContentStartPos = _pStream->Tell();
|
|
++_nContentCount;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
UINT32 SfxMultiVarRecordWriter::Close( FASTBOOL bSeekToEndOfRec )
|
|
|
|
// siehe <SfxMiniRecordWriter>
|
|
|
|
{
|
|
// Header noch nicht geschrieben?
|
|
if ( !_bHeaderOk )
|
|
{
|
|
// ggf. letzten Content abschlie\sen
|
|
if ( _nContentCount )
|
|
FlushContent_Impl();
|
|
|
|
// Content-Offset-Tabelle schreiben
|
|
UINT32 nContentOfsPos = _pStream->Tell();
|
|
//! darf man das so einr"ucken?
|
|
#if defined(__LITTLEENDIAN)
|
|
_pStream->Write( _aContentOfs.GetData(),
|
|
sizeof(UINT32)*_nContentCount );
|
|
#else
|
|
for ( USHORT n = 0; n < _nContentCount; ++n )
|
|
*_pStream << UINT32(_aContentOfs[n]);
|
|
#endif
|
|
|
|
// SfxMultiFixRecordWriter::Close() "uberspringen!
|
|
UINT32 nEndPos = SfxSingleRecordWriter::Close( FALSE );
|
|
|
|
// eigenen Header schreiben
|
|
*_pStream << _nContentCount;
|
|
if ( SFX_REC_TYPE_VARSIZE_RELOC == _nPreTag ||
|
|
SFX_REC_TYPE_MIXTAGS_RELOC == _nPreTag )
|
|
*_pStream << nContentOfsPos - ( _pStream->Tell() + sizeof(UINT32) );
|
|
else
|
|
*_pStream << nContentOfsPos;
|
|
|
|
// ans Ende des Records seeken bzw. am Ende des Headers bleiben
|
|
if ( bSeekToEndOfRec )
|
|
_pStream->Seek(nEndPos);
|
|
return nEndPos;
|
|
}
|
|
|
|
// Record war bereits vorher geschlossen
|
|
return 0;
|
|
}
|
|
|
|
//=========================================================================
|
|
|
|
void SfxMultiMixRecordWriter::NewContent
|
|
(
|
|
UINT16 nContentTag, // Kennung f"ur die Art des Contents
|
|
BYTE nContentVer // Kennung f"ur die Version des Contents
|
|
)
|
|
|
|
/* [Beschreibung]
|
|
|
|
Mit dieser Methode wird in den Record ein neuer Content eingef"ugt
|
|
und dessen Content-Tag sowie dessen Content-Version angegeben. Jeder,
|
|
auch der 1. Record mu\s durch Aufruf dieser Methode eingeleitet werden.
|
|
*/
|
|
|
|
{
|
|
// ggf. vorherigen Record abschlie\sen
|
|
if ( _nContentCount )
|
|
FlushContent_Impl();
|
|
|
|
// Tag vor den Content schreiben, Version und Startposition merken
|
|
_nContentStartPos = _pStream->Tell();
|
|
++_nContentCount;
|
|
*_pStream << nContentTag;
|
|
_nContentVer = nContentVer;
|
|
}
|
|
|
|
//=========================================================================
|
|
|
|
FASTBOOL SfxMultiRecordReader::ReadHeader_Impl()
|
|
|
|
/* [Beschreibung]
|
|
|
|
Interne Methode zum Einlesen eines SfxMultiRecord-Headers, nachdem
|
|
die Basisklasse bereits initialisiert und deren Header gelesen ist.
|
|
Ggf. ist ein Error-Code am Stream gesetzt, im Fehlerfall wird jedoch
|
|
nicht zur"uckge-seekt.
|
|
*/
|
|
|
|
{
|
|
// eigenen Header lesen
|
|
*_pStream >> _nContentCount;
|
|
*_pStream >> _nContentSize; // Fix: jedes einzelnen, Var|Mix: Tabellen-Pos.
|
|
|
|
// mu\s noch eine Tabelle mit Content-Offsets geladen werden?
|
|
if ( _nRecordType != SFX_REC_TYPE_FIXSIZE )
|
|
{
|
|
// Tabelle aus dem Stream einlesen
|
|
UINT32 nContentPos = _pStream->Tell();
|
|
if ( _nRecordType == SFX_REC_TYPE_VARSIZE_RELOC ||
|
|
_nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
|
|
_pStream->SeekRel( + _nContentSize );
|
|
else
|
|
_pStream->Seek( _nContentSize );
|
|
_pContentOfs = new UINT32[_nContentCount];
|
|
//! darf man jetzt so einr"ucken
|
|
#if defined(__LITTLEENDIAN)
|
|
_pStream->Read( _pContentOfs, sizeof(UINT32)*_nContentCount );
|
|
#else
|
|
for ( USHORT n = 0; n < _nContentCount; ++n )
|
|
*_pStream >> _pContentOfs[n];
|
|
#endif
|
|
_pStream->Seek( nContentPos );
|
|
}
|
|
|
|
// Header konnte gelesen werden, wenn am Stream kein Error gesetzt ist
|
|
return !_pStream->GetError();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxMultiRecordReader::SfxMultiRecordReader( SvStream *pStream )
|
|
: _nContentNo(0), _pContentOfs( NULL )
|
|
{
|
|
// Position im Stream merken, um im Fehlerfall zur"uck-seeken zu k"onnen
|
|
_nStartPos = pStream->Tell();
|
|
|
|
// Basisklasse konstruieren (normaler Ctor w"urde nur SingleRecs lesen)
|
|
SfxSingleRecordReader::Construct_Impl( pStream );
|
|
|
|
// Header der Basisklasse lesen
|
|
if ( !SfxSingleRecordReader::ReadHeader_Impl( SFX_REC_TYPE_FIXSIZE |
|
|
SFX_REC_TYPE_VARSIZE | SFX_REC_TYPE_VARSIZE_RELOC |
|
|
SFX_REC_TYPE_MIXTAGS | SFX_REC_TYPE_MIXTAGS_RELOC ) ||
|
|
!ReadHeader_Impl() )
|
|
// als ung"ultig markieren und zur"uck-seeken
|
|
SetInvalid_Impl( _nStartPos );
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxMultiRecordReader::SfxMultiRecordReader( SvStream *pStream, UINT16 nTag )
|
|
: _nContentNo(0)
|
|
{
|
|
// Position im Stream merken, um im Fehlerfall zur"uck-seeken zu k"onnen
|
|
_nStartPos = pStream->Tell();
|
|
|
|
// passenden Record suchen und Basisklasse initialisieren
|
|
SfxSingleRecordReader::Construct_Impl( pStream );
|
|
if ( SfxSingleRecordReader::FindHeader_Impl( SFX_REC_TYPE_FIXSIZE |
|
|
SFX_REC_TYPE_VARSIZE | SFX_REC_TYPE_VARSIZE_RELOC |
|
|
SFX_REC_TYPE_MIXTAGS | SFX_REC_TYPE_MIXTAGS_RELOC,
|
|
nTag ) )
|
|
{
|
|
// eigenen Header dazu-lesen
|
|
if ( !ReadHeader_Impl() )
|
|
// nicht lesbar => als ung"ultig markieren und zur"uck-seeken
|
|
SetInvalid_Impl( _nStartPos);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
SfxMultiRecordReader::~SfxMultiRecordReader()
|
|
{
|
|
delete[] _pContentOfs;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
FASTBOOL SfxMultiRecordReader::GetContent()
|
|
|
|
/* [Beschreibung]
|
|
|
|
Positioniert den Stream an den Anfang des n"chsten bzw. beim 1. Aufruf
|
|
auf den Anfang des ersten Contents im Record und liest ggf. dessen
|
|
Header ein.
|
|
|
|
Liegt laut Record-Header kein Content mehr vor, wird FALSE zur"uck-
|
|
gegeben. Trotz einem TRUE-Returnwert kann am Stream ein Fehlercode
|
|
gesetzt sein, z.B. falls er unvorhergesehenerweise (kaputtes File)
|
|
zuende ist.
|
|
*/
|
|
|
|
{
|
|
// noch ein Content vorhanden?
|
|
if ( _nContentNo < _nContentCount )
|
|
{
|
|
// den Stream an den Anfang des Contents positionieren
|
|
UINT32 nOffset = _nRecordType == SFX_REC_TYPE_FIXSIZE
|
|
? _nContentNo * _nContentSize
|
|
: SFX_REC_CONTENT_OFS(_pContentOfs[_nContentNo]);
|
|
UINT32 nNewPos = _nStartPos + nOffset;
|
|
DBG_ASSERT( nNewPos >= _pStream->Tell(), "SfxMultiRecordReader::GetContent() - New position before current, to much data red!" );
|
|
|
|
// #99366#: correct stream pos in every case;
|
|
// the if clause was added by MT a long time ago,
|
|
// maybe to 'repair' other corrupt documents; but this
|
|
// gives errors when writing with 5.1 and reading with current
|
|
// versions, so we decided to remove the if clause (KA-05/17/2002)
|
|
// if ( nNewPos > _pStream->Tell() )
|
|
_pStream->Seek( nNewPos );
|
|
|
|
// ggf. Content-Header lesen
|
|
if ( _nRecordType == SFX_REC_TYPE_MIXTAGS ||
|
|
_nRecordType == SFX_REC_TYPE_MIXTAGS_RELOC )
|
|
{
|
|
_nContentVer = SFX_REC_CONTENT_VER(_pContentOfs[_nContentNo]);
|
|
*_pStream >> _nContentTag;
|
|
}
|
|
|
|
// ContentNo weiterz"ahlen
|
|
++_nContentNo;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|