diff options
Diffstat (limited to 'oox/inc/oox/xls/biffinputstream.hxx')
-rw-r--r-- | oox/inc/oox/xls/biffinputstream.hxx | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/oox/inc/oox/xls/biffinputstream.hxx b/oox/inc/oox/xls/biffinputstream.hxx new file mode 100644 index 000000000000..c804d2c9c6e0 --- /dev/null +++ b/oox/inc/oox/xls/biffinputstream.hxx @@ -0,0 +1,447 @@ +/************************************************************************* + * + * 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 OOX_XLS_BIFFINPUTSTREAM_HXX +#define OOX_XLS_BIFFINPUTSTREAM_HXX + +#include <vector> +#include "oox/helper/binaryinputstream.hxx" +#include "oox/xls/biffhelper.hxx" +#include "oox/xls/biffcodec.hxx" + +namespace rtl { class OUStringBuffer; } + +namespace oox { +namespace xls { + +// ============================================================================ + +namespace prv { + +/** Buffers the contents of a raw record and encapsulates stream decoding. */ +class BiffInputRecordBuffer +{ +public: + explicit BiffInputRecordBuffer( BinaryInputStream& rInStrm ); + + /** Returns the wrapped binary base stream. */ + inline const BinaryInputStream& getBaseStream() const { return mrInStrm; } + + /** Sets a decoder object and decrypts buffered record data. */ + void setDecoder( const BiffDecoderRef& rxDecoder ); + /** Returns the current decoder object. */ + inline BiffDecoderRef getDecoder() const { return mxDecoder; } + /** Enables/disables usage of current decoder. */ + void enableDecoder( bool bEnable ); + + /** Restarts the stream at the passed position. Buffer is invalid until the + next call of startRecord() or startNextRecord(). */ + void restartAt( sal_Int64 nPos ); + + /** Reads the record header at the passed position. */ + bool startRecord( sal_Int64 nHeaderPos ); + /** Reads the next record header from the stream. */ + bool startNextRecord(); + /** Returns the start position of the record header in the core stream. */ + sal_uInt16 getNextRecId(); + + /** Returns the start position of the record header in the core stream. */ + inline sal_Int64 getRecHeaderPos() const { return mnHeaderPos; } + /** Returns the current record identifier. */ + inline sal_uInt16 getRecId() const { return mnRecId; } + /** Returns the current record size. */ + inline sal_uInt16 getRecSize() const { return mnRecSize; } + /** Returns the current read position in the current record body. */ + inline sal_uInt16 getRecPos() const { return mnRecPos; } + /** Returns the number of remaining bytes in the current record body. */ + inline sal_uInt16 getRecLeft() const { return mnRecSize - mnRecPos; } + + /** Reads nBytes bytes to the existing buffer opData. Must NOT overread the source buffer. */ + void read( void* opData, sal_uInt16 nBytes ); + /** Ignores nBytes bytes. Must NOT overread the buffer. */ + void skip( sal_uInt16 nBytes ); + +private: + /** Updates data buffer from stream, if needed. */ + void updateBuffer(); + /** Updates decoded data from original data. */ + void updateDecoded(); + +private: + typedef ::std::vector< sal_uInt8 > DataBuffer; + + BinaryInputStream& mrInStrm; /// Core input stream. + DataBuffer maOriginalData; /// Original data read from stream. + DataBuffer maDecodedData; /// Decoded data. + DataBuffer* mpCurrentData; /// Points to data buffer currently in use. + BiffDecoderRef mxDecoder; /// Decoder object. + sal_Int64 mnHeaderPos; /// Stream start position of current record header. + sal_Int64 mnBodyPos; /// Stream start position of current record body. + sal_Int64 mnBufferBodyPos; /// Stream start position of buffered data. + sal_Int64 mnNextHeaderPos; /// Stream start position of next record header. + sal_uInt16 mnRecId; /// Current record identifier. + sal_uInt16 mnRecSize; /// Current record size. + sal_uInt16 mnRecPos; /// Current position in record body. + bool mbValidHeader; /// True = valid record header. +}; + +} // namespace prv + +// ============================================================================ + +/** This class is used to read BIFF record streams. + + An instance is constructed with a BinaryInputStream object. The passed + 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 (e.g. 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 by returning false. From now on the data + returned by the read functions is undefined. The error state will be reset, + if the record is reset (with the function 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 e.g. on import of drawing layer data, + 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 (e.g. 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 setDecoder() and + enableDecoder() control the usage of the decryption algorithms. + setDecoder() sets a new decryption algorithm and initially enables it. + enableDecoder( false ) may be used to stop the usage of the decryption + temporarily (sometimes record contents are never encrypted, e.g. all BOF + records or the stream position in SHEET records). Decryption will be + reenabled automatically, if a new record is started with the function + startNextRecord(). +*/ +class BiffInputStream : public BinaryInputStream +{ +public: + /** Constructs the BIFF record stream using the passed binary stream. + + @param rInStream + The base input stream. Must be seekable. Will be seeked to its + start position. + + @param bContLookup Automatic CONTINUE lookup on/off. + */ + explicit BiffInputStream( + BinaryInputStream& rInStream, + bool bContLookup = true ); + + // record control --------------------------------------------------------- + + /** Sets stream pointer to the start of the next record content. + + 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 content of the specified record. + + The handle of the current record can be received and stored using the + function getRecHandle() for later usage with this function. The record + handle is equivalent to the position of the underlying binary stream, + thus the function can be used to perform a hard seek to a specific + position, if it is sure that a record starts exactly at this position. + + @return False = no record found (invalid handle passed). + */ + bool startRecordByHandle( sal_Int64 nRecHandle ); + + /** 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 identifier for content continuation. + This value is reset automatically when a new record is started with + startNextRecord(). + */ + void resetRecord( + bool bContLookup, + sal_uInt16 nAltContId = BIFF_ID_UNKNOWN ); + + /** Sets stream pointer before current record and invalidates stream. + + The next call to startNextRecord() will start again the current record. + This can be used in situations where a loop or a function leaves on a + specific record, but the parent context expects to start this record by + itself. The stream is invalid as long as the first record has not been + started (it is not allowed to call any other stream operation then). + */ + void rewindRecord(); + + // decoder ---------------------------------------------------------------- + + /** Sets a new decoder object. + + Enables decryption of record contents for the rest of the stream. + */ + void setDecoder( const BiffDecoderRef& rxDecoder ); + + /** Enables/disables usage of current decoder. + + Decryption is reenabled automatically, if a new record is started using + the function startNextRecord(). + */ + void enableDecoder( bool bEnable = true ); + + // stream/record state and info ------------------------------------------- + + /** Returns the current record identifier. */ + inline sal_uInt16 getRecId() const { return mnRecId; } + /** Returns the record identifier of the following record. */ + sal_uInt16 getNextRecId(); + + /** Returns a unique handle for the current record that can be used with + the function startRecordByHandle(). */ + inline sal_Int64 getRecHandle() const { return mnRecHandle; } + + // BinaryStreamBase interface (seeking) ----------------------------------- + + /** Returns true, as the BIFF input stream is required to be seekable. */ + virtual bool isSeekable() const; + /** Returns the position inside of the whole record content. */ + virtual sal_Int64 tell() const; + /** Returns the data size of the whole record without record headers. */ + virtual sal_Int64 getLength() const; + /** Seeks in record content to the specified position. */ + virtual void seek( sal_Int64 nRecPos ); + + /** Returns the absolute position in the wrapped binary stream. */ + sal_Int64 tellBase() const; + /** Returns the total size of the wrapped binary stream. */ + sal_Int64 getBaseLength() const; + + // BinaryInputStream interface (stream read access) ----------------------- + + /** Reads nBytes bytes to the passed sequence. + @return Number of bytes really read. */ + virtual sal_Int32 readData( StreamDataSequence& orData, sal_Int32 nBytes ); + /** Reads nBytes bytes and copies them to the passed buffer opMem. + @return Number of bytes really read. */ + virtual sal_Int32 readMemory( void* opMem, sal_Int32 nBytes ); + /** Seeks forward inside the current record. */ + virtual void skip( sal_Int32 nBytes ); + + /** Stream operator for integral and floating-point types. */ + template< typename Type > + inline BiffInputStream& operator>>( Type& ornValue ) { readValue( ornValue ); return *this; } + + // byte strings ----------------------------------------------------------- + + /** Reads 8/16 bit string length and character array, and returns the string. + @param b16BitLen + True = Read 16-bit string length field before the character array. + False = Read 8-bit string length field before the character array. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OString readByteString( bool b16BitLen, bool bAllowNulChars = false ); + + /** Reads 8/16 bit string length and character array, and returns a Unicode string. + @param b16BitLen + True = Read 16-bit string length field before the character array. + False = Read 8-bit string length field before the character array. + @param eTextEnc The text encoding used to create the Unicode string. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OUString readByteStringUC( bool b16BitLen, rtl_TextEncoding eTextEnc, bool bAllowNulChars = false ); + + /** Ignores 8/16 bit string length and character array. + @param b16BitLen + True = Read 16-bit string length field before the character array. + False = Read 8-bit string length field before the character array. + */ + void skipByteString( bool b16BitLen ); + + // Unicode strings -------------------------------------------------------- + + /** Reads nChars characters of a BIFF8 string, and returns the string. + @param nChars Number of characters to read from the stream. + @param b16BitChars + True = The character array contains 16-bit characters. + False = The character array contains truncated 8-bit characters. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OUString readUniStringChars( sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars = false ); + + /** Reads 8-bit flags, extended header, nChar characters, extended data of + a BIFF8 string, and returns the string. + @param nChars Number of characters to read from the stream. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OUString readUniStringBody( sal_uInt16 nChars, bool bAllowNulChars = false ); + + /** Reads 16-bit character count, 8-bit flags, extended header, character + array, extended data of a BIFF8 string, and returns the string. + @param bAllowNulChars + True = NUL characters are inserted into the imported string. + False = NUL characters are replaced by question marks (default). + */ + ::rtl::OUString readUniString( bool bAllowNulChars = false ); + + /** Ignores nChars characters of a BIFF8 string. + @param nChars Number of characters to skip in the stream. + @param b16BitChars + True = The character array contains 16-bit characters. + False = The character array contains truncated 8-bit characters. + */ + void skipUniStringChars( sal_uInt16 nChars, bool b16BitChars ); + + /** Ignores 8-bit flags, extended header, nChar characters, extended data + of a BIFF8 string. + @param nChars Number of characters to skip in the stream. + */ + void skipUniStringBody( sal_uInt16 nChars ); + + /** Ignores 16-bit character count, 8-bit flags, extended header, character + array, extended data of a BIFF8 string. + */ + void skipUniString(); + + // ------------------------------------------------------------------------ +private: + /** Forwards calls of readValue() template functions to the record buffer. */ + virtual void readAtom( void* opMem, sal_uInt8 nSize ); + + /** Initializes all members after base stream has been seeked to new record. */ + void setupRecord(); + /** Restarts the current record from the beginning. */ + void restartRecord( bool bInvalidateRecSize ); + /** Sets stream pointer before specified record and invalidates stream. */ + void rewindToRecord( sal_Int64 nRecHandle ); + /** Returns true, if stream was able to start a valid record. */ + inline bool isInRecord() const { return mnRecHandle >= 0; } + + /** 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 True if next CONTINUE record has been found and initialized. */ + 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 rb16BitChars. + @return True if next CONTINUE record has been found and initialized. */ + bool jumpToNextStringContinue( bool& rb16BitChars ); + /** Calculates the complete length of the current record including CONTINUE + records, stores the length in mnComplRecSize. */ + void calcRecordLength(); + + /** 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 True if nBytes can be read from stream. */ + bool ensureRawReadSize( sal_uInt16 nBytes ); + /** Returns the maximum size of raw data possible to read in one block. */ + sal_uInt16 getMaxRawReadSize( sal_Int32 nBytes ) const; + + /** Reads an array of Unicode characters and appends them to the passed buffer. */ + void appendUnicodeArray( ::rtl::OUStringBuffer& orBuffer, sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars ); + /** Reads the BIFF8 Unicode string header fields. */ + void readUniStringHeader( bool& orb16BitChars, sal_Int32& ornAddSize ); + +private: + prv::BiffInputRecordBuffer maRecBuffer; /// Raw record data buffer. + + sal_Int64 mnRecHandle; /// Handle of current record. + sal_uInt16 mnRecId; /// Identifier of current record (not the CONTINUE ID). + sal_uInt16 mnAltContId; /// Alternative identifier for content continuation records. + + sal_Int64 mnCurrRecSize; /// Helper for record size and position. + sal_Int64 mnComplRecSize; /// Size of complete record data (with CONTINUEs). + bool mbHasComplRec; /// True = mnComplRecSize is valid. + + bool mbCont; /// True = automatic CONTINUE lookup enabled. +}; + +// ============================================================================ + +class BiffInputStreamPos +{ +public: + explicit BiffInputStreamPos( BiffInputStream& rStrm ); + + bool restorePosition(); + + inline BiffInputStream& getStream() { return mrStrm; } + +private: + BiffInputStream& mrStrm; + sal_Int64 mnRecHandle; + sal_Int64 mnRecPos; +}; + +// ============================================================================ + +/** Stores the current position of the passed stream on construction and + restores it automatically on destruction. */ +class BiffInputStreamPosGuard : private BiffInputStreamPos +{ +public: + explicit BiffInputStreamPosGuard( BiffInputStream& rStrm ); + ~BiffInputStreamPosGuard(); +}; + +// ============================================================================ + +} // namespace xls +} // namespace oox + +#endif + |