diff options
Diffstat (limited to 'sc/source/filter/inc/xistream.hxx')
-rw-r--r-- | sc/source/filter/inc/xistream.hxx | 529 |
1 files changed, 529 insertions, 0 deletions
diff --git a/sc/source/filter/inc/xistream.hxx b/sc/source/filter/inc/xistream.hxx new file mode 100644 index 000000000000..9b27077d78e7 --- /dev/null +++ b/sc/source/filter/inc/xistream.hxx @@ -0,0 +1,529 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_XISTREAM_HXX +#define SC_XISTREAM_HXX + +#include <comphelper/docpasswordhelper.hxx> +#include <filter/msfilter/mscodec.hxx> +#include "xlstream.hxx" +#include "xlconst.hxx" + +class XclImpRoot; + +/* ============================================================================ +Input stream class for Excel import +- CONTINUE record handling +- ByteString and UniString support +- Decryption +============================================================================ */ + +// ============================================================================ +// Decryption +// ============================================================================ + +class XclImpDecrypter; +typedef ScfRef< XclImpDecrypter > XclImpDecrypterRef; + +/** Base class for BIFF stream decryption. */ +class XclImpDecrypter : public ::comphelper::IDocPasswordVerifier +{ +public: + explicit XclImpDecrypter(); + virtual ~XclImpDecrypter(); + + /** Returns the current error code of the decrypter. */ + inline ErrCode GetError() const { return mnError; } + /** Returns true, if the decoder has been initialized correctly. */ + inline bool IsValid() const { return mnError == ERRCODE_NONE; } + + /** Creates a (ref-counted) copy of this decrypter object. */ + XclImpDecrypterRef Clone() const; + + /** Implementation of the ::comphelper::IDocPasswordVerifier interface, + calls the new virtual function implVerify(). */ + virtual ::comphelper::DocPasswordVerifierResult + verifyPassword( const ::rtl::OUString& rPassword ); + + /** Updates the decrypter on start of a new record or after seeking stream. */ + void Update( SvStream& rStrm, sal_uInt16 nRecSize ); + /** Reads and decrypts nBytes bytes and stores data into the existing(!) buffer pData. + @return Count of bytes really read. */ + sal_uInt16 Read( SvStream& rStrm, void* pData, sal_uInt16 nBytes ); + +protected: + /** Protected copy c'tor for OnClone(). */ + explicit XclImpDecrypter( const XclImpDecrypter& rSrc ); + +private: + /** Implementation of cloning this object. */ + virtual XclImpDecrypter* OnClone() const = 0; + /** Derived classes implement password verification and initialization of + the decoder. */ + virtual bool OnVerify( const ::rtl::OUString& rPassword ) = 0; + /** Implementation of updating the decrypter. */ + virtual void OnUpdate( sal_Size nOldStrmPos, sal_Size nNewStrmPos, sal_uInt16 nRecSize ) = 0; + /** Implementation of the decryption. */ + virtual sal_uInt16 OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes ) = 0; + +private: + ErrCode mnError; /// Decrypter error code. + sal_Size mnOldPos; /// Last known stream position. + sal_uInt16 mnRecSize; /// Current record size. +}; + +// ---------------------------------------------------------------------------- + +/** Decrypts BIFF5 stream contents. */ +class XclImpBiff5Decrypter : public XclImpDecrypter +{ +public: + explicit XclImpBiff5Decrypter( sal_uInt16 nKey, sal_uInt16 nHash ); + +private: + /** Private copy c'tor for OnClone(). */ + explicit XclImpBiff5Decrypter( const XclImpBiff5Decrypter& rSrc ); + + /** Implementation of cloning this object. */ + virtual XclImpBiff5Decrypter* OnClone() const; + /** Implements password verification and initialization of the decoder. */ + virtual bool OnVerify( const ::rtl::OUString& rPassword ); + /** Implementation of updating the decrypter. */ + virtual void OnUpdate( sal_Size nOldStrmPos, sal_Size nNewStrmPos, sal_uInt16 nRecSize ); + /** Implementation of the decryption. */ + virtual sal_uInt16 OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes ); + +private: + ::msfilter::MSCodec_XorXLS95 maCodec; /// Crypto algorithm implementation. + ::std::vector< sal_uInt8 > maPassword; + sal_uInt16 mnKey; + sal_uInt16 mnHash; +}; + +// ---------------------------------------------------------------------------- + +/** Decrypts BIFF8 stream contents using the given document identifier. */ +class XclImpBiff8Decrypter : public XclImpDecrypter +{ +public: + explicit XclImpBiff8Decrypter( sal_uInt8 pnSalt[ 16 ], + sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ); + +private: + /** Private copy c'tor for OnClone(). */ + explicit XclImpBiff8Decrypter( const XclImpBiff8Decrypter& rSrc ); + + /** Implementation of cloning this object. */ + virtual XclImpBiff8Decrypter* OnClone() const; + /** Implements password verification and initialization of the decoder. */ + virtual bool OnVerify( const ::rtl::OUString& rPassword ); + /** Implementation of updating the decrypter. */ + virtual void OnUpdate( sal_Size nOldStrmPos, sal_Size nNewStrmPos, sal_uInt16 nRecSize ); + /** Implementation of the decryption. */ + virtual sal_uInt16 OnRead( SvStream& rStrm, sal_uInt8* pnData, sal_uInt16 nBytes ); + + /** Returns the block number corresponding to the passed stream position. */ + sal_uInt32 GetBlock( sal_Size nStrmPos ) const; + /** Returns the block offset corresponding to the passed stream position. */ + sal_uInt16 GetOffset( sal_Size nStrmPos ) const; + +private: + ::msfilter::MSCodec_Std97 maCodec; /// Crypto algorithm implementation. + ::std::vector< sal_uInt16 > maPassword; + ::std::vector< sal_uInt8 > maSalt; + ::std::vector< sal_uInt8 > maVerifier; + ::std::vector< sal_uInt8 > maVerifierHash; +}; + +// ============================================================================ +// Stream +// ============================================================================ + +/** This class represents an Excel stream position. + @descr It contains the relevant data for a stream position inside of a record + (including CONTINUE records). */ +class XclImpStreamPos +{ +public: + /** Constructs an invalid stream position data object. */ + explicit XclImpStreamPos(); + + /** Sets the stream position data to the passed values. */ + void Set( const SvStream& rStrm, sal_Size nNextPos, sal_Size nCurrSize, + sal_uInt16 nRawRecId, sal_uInt16 nRawRecSize, sal_uInt16 nRawRecLeft, + bool bValid ); + + /** Writes the contained stream position data to the given variables. */ + void Get( SvStream& rStrm, sal_Size& rnNextPos, sal_Size& rnCurrSize, + sal_uInt16& rnRawRecId, sal_uInt16& rnRawRecSize, sal_uInt16& rnRawRecLeft, + bool& rbValid ) const; + +private: + sal_Size mnPos; /// Absolute position of the stream. + sal_Size mnNextPos; /// Absolute position of next record. + sal_Size mnCurrSize; /// Current calculated size of the record. + sal_uInt16 mnRawRecId; /// Current raw record ID (including CONTINUEs). + sal_uInt16 mnRawRecSize; /// Current raw record size (without following CONTINUEs). + sal_uInt16 mnRawRecLeft; /// Bytes left in current raw record (without following CONTINUEs). + bool mbValid; /// Read state: false = record overread. +}; + +// ============================================================================ + +/** This class is used to import record oriented streams. + @descr An instance is constructed with an SvStream. The SvStream stream is + reset to its start while constructing this stream. + + To start reading a record call StartNextRecord(). Now it is possible to + read all contents of the record using operator>>() or any of the Read***() + functions. If some data exceeds the record size limit, the stream looks for + a following CONTINUE record and jumps automatically to it. It is NOT + allowed that an atomic data type is split into two records (i.e. 4 bytes of + a double in one record and the other 4 bytes in a following CONTINUE). + + Trying to read over the record limits results in a stream error. The + IsValid() function indicates that with returning false. From now on it is + undefined what data the read functions will return. The error state will be + reset, if the record is reset (with the method ResetRecord()) or if the + next record is started. + + To switch off the automatic lookup of CONTINUE records, use ResetRecord() + with false parameter. This is useful i.e. on import of Escher objects, + where sometimes solely CONTINUE records will occur. The automatic lookup + keeps switched off until the method ResetRecord() is called with parameter + true. All other settings done on the stream (i.e. alternative CONTINUE + record identifier, enabled decryption, NUL substitution character) will be + reset to default values, if a new record is started. + + The import stream supports decrypting the stream data. The contents of a + record (not the record header) will be encrypted by Excel if the file has + been stored with password protection. The functions SetDecrypter(), + EnableDecryption(), and DisableDecryption() control the usage of the + decryption algorithms. SetDecrypter() sets a new decryption algorithm and + initially enables it. DisableDecryption() may be used to stop the usage of + the decryption temporarily (sometimes record contents are never encrypted, + i.e. all BOF records or the stream position in BOUNDSHEET). Decryption will + be reenabled automatically, if a new record is started with the function + StartNextRecord(). + + It is possible to store several stream positions inside a record (including + its CONTINUE records). The positions are stored on a stack, which can be + controlled with the functions PushPosition(), PopPosition() and + RejectPosition(). The stack will be cleared whenever a new record is + started with the function StartNextRecord(). + + Additionally a single global stream position can be stored which keeps + valid during the whole import process (methods StoreGlobalPosition(), + SeekGlobalPosition() and DeleteGlobalPosition()). This is the only way to + jump back to a previous record (that is a real jump without return). +*/ +class XclImpStream +{ +public: + /** Detects the BIFF version of the passed workbook stream. */ + static XclBiff DetectBiffVersion( SvStream& rStrm ); + + /** Constructs the Excel record import stream using a TOOLS stream object. + @param rInStrm The system input stream. Will be set to its start position. + Must exist as long as this object exists. + @param bContLookup Automatic CONTINUE lookup on/off. */ + explicit XclImpStream( + SvStream& rInStrm, + const XclImpRoot& rRoot, + bool bContLookup = true ); + + ~XclImpStream(); + + /** Returns the filter root data. */ + inline const XclImpRoot& GetRoot() const { return mrRoot; } + + /** Sets stream pointer to the start of the next record content. + @descr Ignores all CONTINUE records of the current record, if automatic + CONTINUE usage is switched on. + @return false = no record found (end of stream). */ + bool StartNextRecord(); + /** Sets stream pointer to the start of the record content for the record + at the passed absolute stream position. + @return false = no record found (end of stream). */ + bool StartNextRecord( sal_Size nNextRecPos ); + /** Sets stream pointer to begin of record content. + @param bContLookup Automatic CONTINUE lookup on/off. In difference + to other stream settings, this setting is persistent until next call of + this function (because it is wanted to receive the next CONTINUE + records separately). + @param nAltContId Sets an alternative record ID for content + continuation. This value is reset automatically when a new record is + started with StartNextRecord(). */ + void ResetRecord( bool bContLookup, + sal_uInt16 nAltContId = EXC_ID_UNKNOWN ); + + /** Enables decryption of record contents for the rest of the stream. */ + void SetDecrypter( XclImpDecrypterRef xDecrypter ); + /** Sets decrypter from another stream. */ + void CopyDecrypterFrom( const XclImpStream& rStrm ); + /** Returns true, if a valid decrypter is set at the stream. */ + bool HasValidDecrypter() const; + /** Switches usage of current decryption algorithm on/off. + @descr Encryption is re-enabled automatically, if a new record is + started using the function StartNextRecord(). */ + void EnableDecryption( bool bEnable = true ); + /** Switches usage of current decryption algorithm off. + @descr This is a record-local setting. The function StartNextRecord() + always enables decryption. */ + inline void DisableDecryption() { EnableDecryption( false ); } + + /** Pushes current position on user position stack. + @descr This stack is emptied when starting a new record with + StartNextRecord(). The decryption state (enabled/disabled) is not + pushed onto the stack. */ + void PushPosition(); + /** Seeks to last position from user position stack. + @descr This position will be removed from the stack. */ + void PopPosition(); +//UNUSED2008-05 /** Removes last position from user position stack, but does not seek to it. */ +//UNUSED2008-05 void RejectPosition(); + + /** Stores current position. This position keeps valid in all records. */ + void StoreGlobalPosition(); + /** Seeks to the stored global user position. */ + void SeekGlobalPosition(); + /** Invalidates global user position. */ + inline void DeleteGlobalPosition() { mbHasGlobPos = false; } + + /** Returns record reading state: false = record overread. */ + inline bool IsValid() const { return mbValid; } + /** Returns the current record ID. */ + inline sal_uInt16 GetRecId() const { return mnRecId; } + /** Returns the position inside of the whole record content. */ + sal_Size GetRecPos() const; + /** Returns the data size of the whole record without record headers. */ + sal_Size GetRecSize(); + /** Returns remaining data size of the whole record without record headers. */ + sal_Size GetRecLeft(); + /** Returns the record ID of the following record. */ + sal_uInt16 GetNextRecId(); + + XclImpStream& operator>>( sal_Int8& rnValue ); + XclImpStream& operator>>( sal_uInt8& rnValue ); + XclImpStream& operator>>( sal_Int16& rnValue ); + XclImpStream& operator>>( sal_uInt16& rnValue ); + XclImpStream& operator>>( sal_Int32& rnValue ); + XclImpStream& operator>>( sal_uInt32& rnValue ); + XclImpStream& operator>>( float& rfValue ); + XclImpStream& operator>>( double& rfValue ); + + sal_Int8 ReadInt8(); + sal_uInt8 ReaduInt8(); + sal_Int16 ReadInt16(); + sal_uInt16 ReaduInt16(); + sal_Int32 ReadInt32(); + sal_uInt32 ReaduInt32(); + float ReadFloat(); + double ReadDouble(); + + /** Reads nBytes bytes to the existing(!) buffer pData. + @return Count of bytes really read. */ + sal_Size Read( void* pData, sal_Size nBytes ); + /** Copies nBytes bytes to rOutStrm. + @return Count of bytes really written. */ + sal_Size CopyToStream( SvStream& rOutStrm, sal_Size nBytes ); + + /** Copies the entire record to rOutStrm. The current record position keeps unchanged. + @return Count of bytes really written. */ + sal_Size CopyRecordToStream( SvStream& rOutStrm ); + + /** Seeks absolute in record content to the specified position. + @descr The value 0 means start of record, independent from physical stream position. */ + void Seek( sal_Size nPos ); + /** Seeks forward inside the current record. */ + void Ignore( sal_Size nBytes ); + + // *** special string functions *** --------------------------------------- + + // *** read/ignore unicode strings *** ------------------------------------ + /* - look for CONTINUE records even if CONTINUE handling disabled + (only if inside of a CONTINUE record - for TXO import) + - no overread assertions (for Applix wrong string length export bug) + + structure of an Excel unicode string: + (1) 2 byte character count + (2) 1 byte flags (16-bit-characters, rich string, far east string) + (3) [2 byte rich string format run count] + (4) [4 byte far east data size] + (5) character array + (6) [4 * (rich string format run count) byte] + (7) [(far east data size) byte] + header = (1), (2) + ext. header = (3), (4) + ext. data = (6), (7) + */ + + /** Reads ext. header, detects 8/16 bit mode, sets all ext. info. + @return Total size of ext. data. */ + sal_Size ReadUniStringExtHeader( + bool& rb16Bit, bool& rbRich, bool& rbFareast, + sal_uInt16& rnFormatRuns, sal_uInt32& rnExtInf, sal_uInt8 nFlags ); + /** Seeks to begin of character array, detects 8/16 bit mode. + @return Total size of ext. data. */ + sal_Size ReadUniStringExtHeader( bool& rb16Bit, sal_uInt8 nFlags ); + + /** Sets a replacement character for NUL characters. + @descr NUL characters must be replaced, because Tools strings cannot + handle them. The substitution character is reset to '?' automatically, + if a new record is started using the function StartNextRecord(). + @param cNulSubst The character to use for NUL replacement. It is + possible to specify NUL here. in this case strings are terminated when + the first NUL occurs during string import. */ + inline void SetNulSubstChar( sal_Unicode cNulSubst = '?' ) { mcNulSubst = cNulSubst; } + + /** Reads nChars characters and returns the string. */ + String ReadRawUniString( sal_uInt16 nChars, bool b16Bit ); + /** Reads ext. header, nChar characters, ext. data and returns the string. */ + String ReadUniString( sal_uInt16 nChars, sal_uInt8 nFlags ); + /** Reads 8 bit flags, ext. header, nChar characters, ext. data and returns the string. */ + String ReadUniString( sal_uInt16 nChars ); + /** Reads 16 bit character count, 8 bit flags, ext. header, character array, + ext. data and returns the string. */ + String ReadUniString(); + + /** Ignores nChars characters. */ + void IgnoreRawUniString( sal_uInt16 nChars, bool b16Bit ); + /** Ignores ext. header, nChar characters, ext. data. */ + void IgnoreUniString( sal_uInt16 nChars, sal_uInt8 nFlags ); + /** Ignores 8 bit flags, ext. header, nChar characters, ext. data. */ + void IgnoreUniString( sal_uInt16 nChars ); + /** Ignores 16 bit character count, 8 bit flags, ext. header, character array, ext. data. */ + void IgnoreUniString(); + + // *** read/ignore 8-bit-strings, store in String *** --------------------- + + /** Reads nChar byte characters and returns the string. */ + String ReadRawByteString( sal_uInt16 nChars ); + /** Reads 8/16 bit string length, character array and returns the string. */ + String ReadByteString( bool b16BitLen ); + + // *** SvStream functions *** --------------------------------------------- + + /** Returns the absolute stream position. */ + inline sal_Size GetSvStreamPos() const { return mrStrm.Tell(); } + /** Returns the stream size. */ + inline sal_Size GetSvStreamSize() const { return mnStreamSize; } + +private: + /** Stores current stream position into rPos. */ + void StorePosition( XclImpStreamPos& rPos ); + /** Restores stream position contained in rPos. */ + void RestorePosition( const XclImpStreamPos& rPos ); + + /** Seeks to next raw record header and reads record ID and size. + @descr This is a "raw" function, means that stream members are + inconsistent after return. Does only change mnRawRecId, mnRawRecSize, + and the base stream position, but no other members. + @return false = No record header found (end of stream). */ + bool ReadNextRawRecHeader(); + + /** Initializes the decrypter to read a new record. */ + void SetupDecrypter(); + /** Initializes all members after base stream has been seeked to new raw record. */ + void SetupRawRecord(); + /** Initializes all members after base stream has been seeked to new record. */ + void SetupRecord(); + + /** Returns true, if the passed ID is real or alternative continuation record ID. */ + bool IsContinueId( sal_uInt16 nRecId ) const; + + /** Goes to start of the next CONTINUE record. + @descr Stream must be located at the end of a raw record, and handling + of CONTINUE records must be enabled. + @return Copy of mbValid. */ + bool JumpToNextContinue(); + /** Goes to start of the next CONTINUE record while reading strings. + @descr Stream must be located at the end of a raw record. If reading + has been started in a CONTINUE record, jumps to an existing following + CONTINUE record, even if handling of CONTINUE records is disabled (This + is a special handling for TXO string data). Reads additional Unicode + flag byte at start of the new raw record and sets or resets rb16Bit. + @return Copy of mbValid. */ + bool JumpToNextStringContinue( bool& rb16Bit ); + + /** Ensures that reading nBytes bytes is possible with next stream access. + @descr Stream must be located at the end of a raw record, and handling + of CONTINUE records must be enabled. + @return Copy of mbValid. */ + bool EnsureRawReadSize( sal_uInt16 nBytes ); + /** Returns the maximum size of raw data possible to read in one block. */ + sal_uInt16 GetMaxRawReadSize( sal_Size nBytes ) const; + + /** Reads and decrypts nBytes bytes to the existing(!) buffer pData. + @return Count of bytes really read. */ + sal_uInt16 ReadRawData( void* pData, sal_uInt16 nBytes ); + + /** Reads 8 bit/16 bit string length. */ + inline sal_uInt16 ReadByteStrLen( bool b16BitLen ) + { return b16BitLen ? ReaduInt16() : ReaduInt8(); } + +private: + typedef ::std::vector< XclImpStreamPos > XclImpStreamPosStack; + + SvStream& mrStrm; /// Reference to the system input stream. + const XclImpRoot& mrRoot; /// Filter root data. + + XclImpDecrypterRef mxDecrypter; /// Provides methods to decrypt data. + + XclImpStreamPos maFirstRec; /// Start position of current record. + XclImpStreamPosStack maPosStack; /// Stack for record positions. + + XclImpStreamPos maGlobPos; /// User defined position elsewhere in stream. + sal_uInt16 mnGlobRecId; /// Record ID for user defined position. + bool mbGlobValidRec; /// Was user position a valid record? + bool mbHasGlobPos; /// Is user position defined? + + sal_Size mnStreamSize; /// Size of system stream. + sal_Size mnNextRecPos; /// Start of next record header. + sal_Size mnCurrRecSize; /// Helper for record position. + sal_Size mnComplRecSize; /// Size of complete record data (with CONTINUEs). + bool mbHasComplRec; /// true = mnComplRecSize is valid. + + sal_uInt16 mnRecId; /// Current record ID (not the CONTINUE ID). + sal_uInt16 mnAltContId; /// Alternative record ID for content continuation. + + sal_uInt16 mnRawRecId; /// Current raw record ID (including CONTINUEs). + sal_uInt16 mnRawRecSize; /// Current raw record size (without following CONTINUEs). + sal_uInt16 mnRawRecLeft; /// Bytes left in current raw record (without following CONTINUEs). + + sal_Unicode mcNulSubst; /// Replacement for NUL characters. + + bool mbCont; /// Automatic CONTINUE lookup on/off. + bool mbUseDecr; /// Usage of decryption. + bool mbValidRec; /// false = No more records to read. + bool mbValid; /// false = Record overread. +}; + +// ============================================================================ + +#endif + |