| /************************************************************** |
| * |
| * 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 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 sought 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 the data size of the whole record without record headers. */ |
| virtual sal_Int64 size() const; |
| /** Returns the position inside of the whole record content. */ |
| virtual sal_Int64 tell() const; |
| /** Seeks in record content to the specified position. */ |
| virtual void seek( sal_Int64 nRecPos ); |
| /** Closes the input stream but not the wrapped stream. */ |
| virtual void close(); |
| |
| /** Returns the absolute position in the wrapped binary stream. */ |
| sal_Int64 tellBase() const; |
| /** Returns the total size of the wrapped binary stream. */ |
| sal_Int64 sizeBase() 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, size_t nAtomSize = 1 ); |
| /** 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, size_t nAtomSize = 1 ); |
| /** Seeks forward inside the current record. */ |
| virtual void skip( sal_Int32 nBytes, size_t nAtomSize = 1 ); |
| |
| /** 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: |
| /** Initializes all members after base stream has been sought 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(); |
| |
| /** Returns the maximum size of raw data possible to read in one block. */ |
| sal_uInt16 getMaxRawReadSize( sal_Int32 nBytes, size_t nAtomSize ) const; |
| |
| /** 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 |