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