Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #ifndef OOX_XLS_BIFFINPUTSTREAM_HXX
21 : #define OOX_XLS_BIFFINPUTSTREAM_HXX
22 :
23 : #include <vector>
24 : #include "oox/helper/binaryinputstream.hxx"
25 : #include "biffhelper.hxx"
26 : #include "biffcodec.hxx"
27 :
28 :
29 : namespace oox {
30 : namespace xls {
31 :
32 : // ============================================================================
33 :
34 : namespace prv {
35 :
36 : /** Buffers the contents of a raw record and encapsulates stream decoding. */
37 0 : class BiffInputRecordBuffer
38 : {
39 : public:
40 : explicit BiffInputRecordBuffer( BinaryInputStream& rInStrm );
41 :
42 : /** Returns the wrapped binary base stream. */
43 : inline const BinaryInputStream& getBaseStream() const { return mrInStrm; }
44 :
45 : /** Sets a decoder object and decrypts buffered record data. */
46 : void setDecoder( const BiffDecoderRef& rxDecoder );
47 : /** Returns the current decoder object. */
48 : inline BiffDecoderRef getDecoder() const { return mxDecoder; }
49 : /** Enables/disables usage of current decoder. */
50 : void enableDecoder( bool bEnable );
51 :
52 : /** Restarts the stream at the passed position. Buffer is invalid until the
53 : next call of startRecord() or startNextRecord(). */
54 : void restartAt( sal_Int64 nPos );
55 :
56 : /** Reads the record header at the passed position. */
57 : bool startRecord( sal_Int64 nHeaderPos );
58 : /** Reads the next record header from the stream. */
59 : bool startNextRecord();
60 : /** Returns the start position of the record header in the core stream. */
61 : sal_uInt16 getNextRecId();
62 :
63 : /** Returns the start position of the record header in the core stream. */
64 0 : inline sal_Int64 getRecHeaderPos() const { return mnHeaderPos; }
65 : /** Returns the current record identifier. */
66 0 : inline sal_uInt16 getRecId() const { return mnRecId; }
67 : /** Returns the current record size. */
68 0 : inline sal_uInt16 getRecSize() const { return mnRecSize; }
69 : /** Returns the current read position in the current record body. */
70 : inline sal_uInt16 getRecPos() const { return mnRecPos; }
71 : /** Returns the number of remaining bytes in the current record body. */
72 0 : inline sal_uInt16 getRecLeft() const { return mnRecSize - mnRecPos; }
73 :
74 : /** Reads nBytes bytes to the existing buffer opData. Must NOT overread the source buffer. */
75 : void read( void* opData, sal_uInt16 nBytes );
76 : /** Ignores nBytes bytes. Must NOT overread the buffer. */
77 : void skip( sal_uInt16 nBytes );
78 :
79 : private:
80 : /** Updates data buffer from stream, if needed. */
81 : void updateBuffer();
82 : /** Updates decoded data from original data. */
83 : void updateDecoded();
84 :
85 : private:
86 : typedef ::std::vector< sal_uInt8 > DataBuffer;
87 :
88 : BinaryInputStream& mrInStrm; /// Core input stream.
89 : DataBuffer maOriginalData; /// Original data read from stream.
90 : DataBuffer maDecodedData; /// Decoded data.
91 : DataBuffer* mpCurrentData; /// Points to data buffer currently in use.
92 : BiffDecoderRef mxDecoder; /// Decoder object.
93 : sal_Int64 mnHeaderPos; /// Stream start position of current record header.
94 : sal_Int64 mnBodyPos; /// Stream start position of current record body.
95 : sal_Int64 mnBufferBodyPos; /// Stream start position of buffered data.
96 : sal_Int64 mnNextHeaderPos; /// Stream start position of next record header.
97 : sal_uInt16 mnRecId; /// Current record identifier.
98 : sal_uInt16 mnRecSize; /// Current record size.
99 : sal_uInt16 mnRecPos; /// Current position in record body.
100 : bool mbValidHeader; /// True = valid record header.
101 : };
102 :
103 : } // namespace prv
104 :
105 : // ============================================================================
106 :
107 : /** This class is used to read BIFF record streams.
108 :
109 : An instance is constructed with a BinaryInputStream object. The passed
110 : stream is reset to its start while constructing this stream.
111 :
112 : To start reading a record call startNextRecord(). Now it is possible to
113 : read all contents of the record using operator>>() or any of the read***()
114 : functions. If some data exceeds the record size limit, the stream looks for
115 : a following CONTINUE record and jumps automatically to it. It is NOT
116 : allowed that an atomic data type is split into two records (e.g. 4 bytes of
117 : a double in one record and the other 4 bytes in a following CONTINUE).
118 :
119 : Trying to read over the record limits results in a stream error. The
120 : isValid() function indicates that by returning false. From now on the data
121 : returned by the read functions is undefined. The error state will be reset,
122 : if the next record is started.
123 :
124 : The import stream supports decrypting the stream data. The contents of a
125 : record (not the record header) will be encrypted by Excel if the file has
126 : been stored with password protection. The functions setDecoder() and
127 : enableDecoder() control the usage of the decryption algorithms.
128 : setDecoder() sets a new decryption algorithm and initially enables it.
129 : enableDecoder( false ) may be used to stop the usage of the decryption
130 : temporarily (sometimes record contents are never encrypted, e.g. all BOF
131 : records or the stream position in SHEET records). Decryption will be
132 : reenabled automatically, if a new record is started with the function
133 : startNextRecord().
134 : */
135 0 : class BiffInputStream : public BinaryInputStream
136 : {
137 : public:
138 : /** Constructs the BIFF record stream using the passed binary stream.
139 :
140 : @param rInStream
141 : The base input stream. Must be seekable. Will be seeked to its
142 : start position.
143 :
144 : @param bContLookup Automatic CONTINUE lookup on/off.
145 : */
146 : explicit BiffInputStream(
147 : BinaryInputStream& rInStream,
148 : bool bContLookup = true );
149 :
150 : // record control ---------------------------------------------------------
151 :
152 : /** Sets stream pointer to the start of the next record content.
153 :
154 : Ignores all CONTINUE records of the current record, if automatic
155 : CONTINUE usage is switched on.
156 :
157 : @return False = no record found (end of stream).
158 : */
159 : bool startNextRecord();
160 :
161 : /** Sets stream pointer to the start of the content of the specified record.
162 :
163 : The handle of the current record can be received and stored using the
164 : function getRecHandle() for later usage with this function. The record
165 : handle is equivalent to the position of the underlying binary stream,
166 : thus the function can be used to perform a hard seek to a specific
167 : position, if it is sure that a record starts exactly at this position.
168 :
169 : @return False = no record found (invalid handle passed).
170 : */
171 : bool startRecordByHandle( sal_Int64 nRecHandle );
172 :
173 : /** Sets stream pointer before current record and invalidates stream.
174 :
175 : The next call to startNextRecord() will start again the current record.
176 : This can be used in situations where a loop or a function leaves on a
177 : specific record, but the parent context expects to start this record by
178 : itself. The stream is invalid as long as the first record has not been
179 : started (it is not allowed to call any other stream operation then).
180 : */
181 : void rewindRecord();
182 :
183 : // decoder ----------------------------------------------------------------
184 :
185 : /** Sets a new decoder object.
186 :
187 : Enables decryption of record contents for the rest of the stream.
188 : */
189 : void setDecoder( const BiffDecoderRef& rxDecoder );
190 :
191 : /** Enables/disables usage of current decoder.
192 :
193 : Decryption is reenabled automatically, if a new record is started using
194 : the function startNextRecord().
195 : */
196 : void enableDecoder( bool bEnable = true );
197 :
198 : // stream/record state and info -------------------------------------------
199 :
200 : /** Returns the current record identifier. */
201 0 : inline sal_uInt16 getRecId() const { return mnRecId; }
202 : /** Returns the record identifier of the following record. */
203 : sal_uInt16 getNextRecId();
204 :
205 : /** Returns a unique handle for the current record that can be used with
206 : the function startRecordByHandle(). */
207 0 : inline sal_Int64 getRecHandle() const { return mnRecHandle; }
208 :
209 : // BinaryStreamBase interface (seeking) -----------------------------------
210 :
211 : /** Returns the data size of the whole record without record headers. */
212 : virtual sal_Int64 size() const;
213 : /** Returns the position inside of the whole record content. */
214 : virtual sal_Int64 tell() const;
215 : /** Seeks in record content to the specified position. */
216 : virtual void seek( sal_Int64 nRecPos );
217 : /** Closes the input stream but not the wrapped stream. */
218 : virtual void close();
219 :
220 : // BinaryInputStream interface (stream read access) -----------------------
221 :
222 : /** Reads nBytes bytes to the passed sequence.
223 : @return Number of bytes really read. */
224 : virtual sal_Int32 readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize = 1 );
225 : /** Reads nBytes bytes and copies them to the passed buffer opMem.
226 : @return Number of bytes really read. */
227 : virtual sal_Int32 readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize = 1 );
228 : /** Seeks forward inside the current record. */
229 : virtual void skip( sal_Int32 nBytes, size_t nAtomSize = 1 );
230 :
231 : /** Stream operator for integral and floating-point types. */
232 : template< typename Type >
233 0 : inline BiffInputStream& operator>>( Type& ornValue ) { readValue( ornValue ); return *this; }
234 :
235 : // byte strings -----------------------------------------------------------
236 :
237 : /** Reads 8/16 bit string length and character array, and returns the string.
238 : @param b16BitLen
239 : True = Read 16-bit string length field before the character array.
240 : False = Read 8-bit string length field before the character array.
241 : @param bAllowNulChars
242 : True = NUL characters are inserted into the imported string.
243 : False = NUL characters are replaced by question marks (default).
244 : */
245 : OString readByteString( bool b16BitLen, bool bAllowNulChars = false );
246 :
247 : /** Reads 8/16 bit string length and character array, and returns a Unicode string.
248 : @param b16BitLen
249 : True = Read 16-bit string length field before the character array.
250 : False = Read 8-bit string length field before the character array.
251 : @param eTextEnc The text encoding used to create the Unicode string.
252 : @param bAllowNulChars
253 : True = NUL characters are inserted into the imported string.
254 : False = NUL characters are replaced by question marks (default).
255 : */
256 : OUString readByteStringUC( bool b16BitLen, rtl_TextEncoding eTextEnc, bool bAllowNulChars = false );
257 :
258 : // Unicode strings --------------------------------------------------------
259 :
260 : /** Reads nChars characters of a BIFF8 string, and returns the string.
261 : @param nChars Number of characters to read from the stream.
262 : @param b16BitChars
263 : True = The character array contains 16-bit characters.
264 : False = The character array contains truncated 8-bit characters.
265 : @param bAllowNulChars
266 : True = NUL characters are inserted into the imported string.
267 : False = NUL characters are replaced by question marks (default).
268 : */
269 : OUString readUniStringChars( sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars = false );
270 :
271 : /** Reads 8-bit flags, extended header, nChar characters, extended data of
272 : a BIFF8 string, and returns the string.
273 : @param nChars Number of characters to read from the stream.
274 : @param bAllowNulChars
275 : True = NUL characters are inserted into the imported string.
276 : False = NUL characters are replaced by question marks (default).
277 : */
278 : OUString readUniStringBody( sal_uInt16 nChars, bool bAllowNulChars = false );
279 :
280 : /** Reads 16-bit character count, 8-bit flags, extended header, character
281 : array, extended data of a BIFF8 string, and returns the string.
282 : @param bAllowNulChars
283 : True = NUL characters are inserted into the imported string.
284 : False = NUL characters are replaced by question marks (default).
285 : */
286 : OUString readUniString( bool bAllowNulChars = false );
287 :
288 : // ------------------------------------------------------------------------
289 : private:
290 : /** Initializes all members after base stream has been seeked to new record. */
291 : void setupRecord();
292 : /** Restarts the current record from the beginning. */
293 : void restartRecord( bool bInvalidateRecSize );
294 : /** Sets stream pointer before specified record and invalidates stream. */
295 : void rewindToRecord( sal_Int64 nRecHandle );
296 : /** Returns true, if stream was able to start a valid record. */
297 0 : inline bool isInRecord() const { return mnRecHandle >= 0; }
298 :
299 : /** Returns true, if the passed ID is real or alternative continuation record ID. */
300 : bool isContinueId( sal_uInt16 nRecId ) const;
301 : /** Goes to start of the next CONTINUE record.
302 : @descr Stream must be located at the end of a raw record, and handling
303 : of CONTINUE records must be enabled.
304 : @return True if next CONTINUE record has been found and initialized. */
305 : bool jumpToNextContinue();
306 : /** Goes to start of the next CONTINUE record while reading strings.
307 : @descr Stream must be located at the end of a raw record. If reading
308 : has been started in a CONTINUE record, jumps to an existing following
309 : CONTINUE record, even if handling of CONTINUE records is disabled (this
310 : is a special handling for TXO string data). Reads additional Unicode
311 : flag byte at start of the new raw record and sets or resets rb16BitChars.
312 : @return True if next CONTINUE record has been found and initialized. */
313 : bool jumpToNextStringContinue( bool& rb16BitChars );
314 : /** Calculates the complete length of the current record including CONTINUE
315 : records, stores the length in mnComplRecSize. */
316 : void calcRecordLength();
317 :
318 : /** Returns the maximum size of raw data possible to read in one block. */
319 : sal_uInt16 getMaxRawReadSize( sal_Int32 nBytes, size_t nAtomSize ) const;
320 :
321 : /** Reads the BIFF8 Unicode string header fields. */
322 : void readUniStringHeader( bool& orb16BitChars, sal_Int32& ornAddSize );
323 :
324 : private:
325 : prv::BiffInputRecordBuffer maRecBuffer; /// Raw record data buffer.
326 :
327 : sal_Int64 mnRecHandle; /// Handle of current record.
328 : sal_uInt16 mnRecId; /// Identifier of current record (not the CONTINUE ID).
329 : sal_uInt16 mnAltContId; /// Alternative identifier for content continuation records.
330 :
331 : sal_Int64 mnCurrRecSize; /// Helper for record size and position.
332 : sal_Int64 mnComplRecSize; /// Size of complete record data (with CONTINUEs).
333 : bool mbHasComplRec; /// True = mnComplRecSize is valid.
334 :
335 : bool mbCont; /// True = automatic CONTINUE lookup enabled.
336 : };
337 :
338 : // ============================================================================
339 :
340 : class BiffInputStreamPos
341 : {
342 : public:
343 : explicit BiffInputStreamPos( BiffInputStream& rStrm );
344 :
345 : bool restorePosition();
346 :
347 0 : inline BiffInputStream& getStream() { return mrStrm; }
348 :
349 : private:
350 : BiffInputStream& mrStrm;
351 : sal_Int64 mnRecHandle;
352 : sal_Int64 mnRecPos;
353 : };
354 :
355 : // ============================================================================
356 :
357 : /** Stores the current position of the passed stream on construction and
358 : restores it automatically on destruction. */
359 : class BiffInputStreamPosGuard : private BiffInputStreamPos
360 : {
361 : public:
362 : explicit BiffInputStreamPosGuard( BiffInputStream& rStrm );
363 : ~BiffInputStreamPosGuard();
364 : };
365 :
366 : // ============================================================================
367 :
368 : } // namespace xls
369 : } // namespace oox
370 :
371 : #endif
372 :
373 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|