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 : #include "biffinputstream.hxx"
21 :
22 : #include <algorithm>
23 : #include <rtl/ustrbuf.hxx>
24 : #include <osl/diagnose.h>
25 :
26 : namespace oox {
27 : namespace xls {
28 :
29 : namespace prv {
30 :
31 0 : BiffInputRecordBuffer::BiffInputRecordBuffer( BinaryInputStream& rInStrm ) :
32 : mrInStrm( rInStrm ),
33 : mpCurrentData( 0 ),
34 : mnHeaderPos( -1 ),
35 : mnBodyPos( 0 ),
36 : mnBufferBodyPos( 0 ),
37 : mnNextHeaderPos( 0 ),
38 : mnRecId( BIFF_ID_UNKNOWN ),
39 : mnRecSize( 0 ),
40 : mnRecPos( 0 ),
41 0 : mbValidHeader( false )
42 : {
43 : OSL_ENSURE( mrInStrm.isSeekable(), "BiffInputRecordBuffer::BiffInputRecordBuffer - stream must be seekable" );
44 0 : mrInStrm.seekToStart();
45 0 : maOriginalData.reserve( SAL_MAX_UINT16 );
46 0 : maDecodedData.reserve( SAL_MAX_UINT16 );
47 0 : enableDecoder( false ); // updates mpCurrentData
48 0 : }
49 :
50 0 : void BiffInputRecordBuffer::restartAt( sal_Int64 nPos )
51 : {
52 0 : mnHeaderPos = -1;
53 0 : mnBodyPos = mnBufferBodyPos = 0;
54 0 : mnNextHeaderPos = nPos;
55 0 : mnRecId = BIFF_ID_UNKNOWN;
56 0 : mnRecSize = mnRecPos = 0;
57 0 : mbValidHeader = false;
58 0 : }
59 :
60 0 : void BiffInputRecordBuffer::setDecoder( const BiffDecoderRef& rxDecoder )
61 : {
62 0 : mxDecoder = rxDecoder;
63 0 : enableDecoder( true );
64 0 : updateDecoded();
65 0 : }
66 :
67 0 : void BiffInputRecordBuffer::enableDecoder( bool bEnable )
68 : {
69 0 : mpCurrentData = (bEnable && mxDecoder.get() && mxDecoder->isValid()) ? &maDecodedData : &maOriginalData;
70 0 : }
71 :
72 0 : bool BiffInputRecordBuffer::startRecord( sal_Int64 nHeaderPos )
73 : {
74 0 : mbValidHeader = (0 <= nHeaderPos) && (nHeaderPos + 4 <= mrInStrm.size());
75 0 : if( mbValidHeader )
76 : {
77 0 : mnHeaderPos = nHeaderPos;
78 0 : mrInStrm.seek( nHeaderPos );
79 0 : mnRecId = mrInStrm.readuInt16();
80 0 : mnRecSize = mrInStrm.readuInt16();
81 0 : mnBodyPos = mrInStrm.tell();
82 0 : mnNextHeaderPos = mnBodyPos + mnRecSize;
83 0 : mbValidHeader = !mrInStrm.isEof() && (mnNextHeaderPos <= mrInStrm.size());
84 : }
85 0 : if( !mbValidHeader )
86 : {
87 0 : mnHeaderPos = mnBodyPos = -1;
88 0 : mnNextHeaderPos = 0;
89 0 : mnRecId = BIFF_ID_UNKNOWN;
90 0 : mnRecSize = 0;
91 : }
92 0 : mnRecPos = 0;
93 0 : return mbValidHeader;
94 : }
95 :
96 0 : bool BiffInputRecordBuffer::startNextRecord()
97 : {
98 0 : return startRecord( mnNextHeaderPos );
99 : }
100 :
101 0 : sal_uInt16 BiffInputRecordBuffer::getNextRecId()
102 : {
103 0 : sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
104 0 : if( mbValidHeader && (mnNextHeaderPos + 4 <= mrInStrm.size()) )
105 : {
106 0 : mrInStrm.seek( mnNextHeaderPos );
107 0 : nRecId = mrInStrm.readuInt16();
108 : }
109 0 : return nRecId;
110 : }
111 :
112 0 : void BiffInputRecordBuffer::read( void* opData, sal_uInt16 nBytes )
113 : {
114 0 : updateBuffer();
115 : OSL_ENSURE( nBytes > 0, "BiffInputRecordBuffer::read - nothing to read" );
116 : OSL_ENSURE( nBytes <= getRecLeft(), "BiffInputRecordBuffer::read - buffer overflow" );
117 0 : memcpy( opData, &(*mpCurrentData)[ mnRecPos ], nBytes );
118 0 : mnRecPos = mnRecPos + nBytes;
119 0 : }
120 :
121 0 : void BiffInputRecordBuffer::skip( sal_uInt16 nBytes )
122 : {
123 : OSL_ENSURE( nBytes > 0, "BiffInputRecordBuffer::skip - nothing to skip" );
124 : OSL_ENSURE( nBytes <= getRecLeft(), "BiffInputRecordBuffer::skip - buffer overflow" );
125 0 : mnRecPos = mnRecPos + nBytes;
126 0 : }
127 :
128 0 : void BiffInputRecordBuffer::updateBuffer()
129 : {
130 : OSL_ENSURE( mbValidHeader, "BiffInputRecordBuffer::updateBuffer - invalid access" );
131 0 : if( mnBodyPos != mnBufferBodyPos )
132 : {
133 0 : mrInStrm.seek( mnBodyPos );
134 0 : maOriginalData.resize( mnRecSize );
135 0 : if( mnRecSize > 0 )
136 0 : mrInStrm.readMemory( &maOriginalData.front(), static_cast< sal_Int32 >( mnRecSize ) );
137 0 : mnBufferBodyPos = mnBodyPos;
138 0 : updateDecoded();
139 : }
140 0 : }
141 :
142 0 : void BiffInputRecordBuffer::updateDecoded()
143 : {
144 0 : if( mxDecoder.get() && mxDecoder->isValid() )
145 : {
146 0 : maDecodedData.resize( mnRecSize );
147 0 : if( mnRecSize > 0 )
148 0 : mxDecoder->decode( &maDecodedData.front(), &maOriginalData.front(), mnBodyPos, mnRecSize );
149 : }
150 0 : }
151 :
152 : } // namespace prv
153 :
154 0 : BiffInputStream::BiffInputStream( BinaryInputStream& rInStream, bool bContLookup ) :
155 : BinaryStreamBase( true ),
156 : maRecBuffer( rInStream ),
157 : mnRecHandle( -1 ),
158 : mnRecId( BIFF_ID_UNKNOWN ),
159 : mnAltContId( BIFF_ID_UNKNOWN ),
160 : mnCurrRecSize( 0 ),
161 : mnComplRecSize( 0 ),
162 : mbHasComplRec( false ),
163 0 : mbCont( bContLookup )
164 : {
165 0 : mbEof = true; // EOF will be true if stream is not inside a record
166 0 : }
167 :
168 : // record control -------------------------------------------------------------
169 :
170 0 : bool BiffInputStream::startNextRecord()
171 : {
172 0 : bool bValidRec = false;
173 : /* #i4266# ignore zero records (id==len==0) (e.g. the application
174 : "Crystal Report" writes zero records between other records) */
175 0 : bool bIsZeroRec = false;
176 0 : do
177 : {
178 : // record header is never encrypted
179 0 : maRecBuffer.enableDecoder( false );
180 : // read header of next raw record, returns false at end of stream
181 0 : bValidRec = maRecBuffer.startNextRecord();
182 : // ignore record, if identifier and size are zero
183 0 : bIsZeroRec = (maRecBuffer.getRecId() == 0) && (maRecBuffer.getRecSize() == 0);
184 : }
185 0 : while( bValidRec && ((mbCont && isContinueId( maRecBuffer.getRecId() )) || bIsZeroRec) );
186 :
187 : // setup other class members
188 0 : setupRecord();
189 0 : return isInRecord();
190 : }
191 :
192 0 : bool BiffInputStream::startRecordByHandle( sal_Int64 nRecHandle )
193 : {
194 0 : rewindToRecord( nRecHandle );
195 0 : return startNextRecord();
196 : }
197 :
198 0 : void BiffInputStream::rewindRecord()
199 : {
200 0 : rewindToRecord( mnRecHandle );
201 0 : }
202 :
203 : // decoder --------------------------------------------------------------------
204 :
205 0 : void BiffInputStream::setDecoder( const BiffDecoderRef& rxDecoder )
206 : {
207 0 : maRecBuffer.setDecoder( rxDecoder );
208 0 : }
209 :
210 0 : void BiffInputStream::enableDecoder( bool bEnable )
211 : {
212 0 : maRecBuffer.enableDecoder( bEnable );
213 0 : }
214 :
215 : // stream/record state and info -----------------------------------------------
216 :
217 0 : sal_uInt16 BiffInputStream::getNextRecId()
218 : {
219 0 : sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
220 0 : if( isInRecord() )
221 : {
222 0 : sal_Int64 nCurrPos = tell(); // save current position in record
223 0 : while( jumpToNextContinue() ) {} // skip following CONTINUE records
224 0 : if( maRecBuffer.startNextRecord() ) // read header of next record
225 0 : nRecId = maRecBuffer.getRecId();
226 0 : seek( nCurrPos ); // restore position, seek() resets old mbValid state
227 : }
228 0 : return nRecId;
229 : }
230 :
231 : // BinaryStreamBase interface (seeking) ---------------------------------------
232 :
233 0 : sal_Int64 BiffInputStream::size() const
234 : {
235 0 : if( !mbHasComplRec )
236 0 : const_cast< BiffInputStream* >( this )->calcRecordLength();
237 0 : return mnComplRecSize;
238 : }
239 :
240 0 : sal_Int64 BiffInputStream::tell() const
241 : {
242 0 : return mbEof ? -1 : (mnCurrRecSize - maRecBuffer.getRecLeft());
243 : }
244 :
245 0 : void BiffInputStream::seek( sal_Int64 nRecPos )
246 : {
247 0 : if( isInRecord() )
248 : {
249 0 : if( mbEof || (nRecPos < tell()) )
250 0 : restartRecord( false );
251 0 : if( !mbEof && (nRecPos > tell()) )
252 0 : skip( static_cast< sal_Int32 >( nRecPos - tell() ) );
253 : }
254 0 : }
255 :
256 0 : void BiffInputStream::close()
257 : {
258 0 : }
259 :
260 : // BinaryInputStream interface (stream read access) ---------------------------
261 :
262 0 : sal_Int32 BiffInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
263 : {
264 0 : sal_Int32 nRet = 0;
265 0 : if( !mbEof )
266 : {
267 0 : orData.realloc( ::std::max< sal_Int32 >( nBytes, 0 ) );
268 0 : if( nBytes > 0 )
269 0 : nRet = readMemory( orData.getArray(), nBytes, nAtomSize );
270 : }
271 0 : return nRet;
272 : }
273 :
274 0 : sal_Int32 BiffInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
275 : {
276 0 : sal_Int32 nRet = 0;
277 0 : if( !mbEof && opMem && (nBytes > 0) )
278 : {
279 0 : sal_uInt8* pnBuffer = static_cast< sal_uInt8* >( opMem );
280 0 : sal_Int32 nBytesLeft = nBytes;
281 :
282 0 : while( !mbEof && (nBytesLeft > 0) )
283 : {
284 0 : sal_uInt16 nReadSize = getMaxRawReadSize( nBytesLeft, nAtomSize );
285 : // check nReadSize, stream may already be located at end of a raw record
286 0 : if( nReadSize > 0 )
287 : {
288 0 : maRecBuffer.read( pnBuffer, nReadSize );
289 0 : nRet += nReadSize;
290 0 : pnBuffer += nReadSize;
291 0 : nBytesLeft -= nReadSize;
292 : }
293 0 : if( nBytesLeft > 0 )
294 0 : jumpToNextContinue();
295 : OSL_ENSURE( !mbEof, "BiffInputStream::readMemory - record overread" );
296 : }
297 : }
298 0 : return nRet;
299 : }
300 :
301 0 : void BiffInputStream::skip( sal_Int32 nBytes, size_t nAtomSize )
302 : {
303 0 : sal_Int32 nBytesLeft = nBytes;
304 0 : while( !mbEof && (nBytesLeft > 0) )
305 : {
306 0 : sal_uInt16 nSkipSize = getMaxRawReadSize( nBytesLeft, nAtomSize );
307 : // check nSkipSize, stream may already be located at end of a raw record
308 0 : if( nSkipSize > 0 )
309 : {
310 0 : maRecBuffer.skip( nSkipSize );
311 0 : nBytesLeft -= nSkipSize;
312 : }
313 0 : if( nBytesLeft > 0 )
314 0 : jumpToNextContinue();
315 : OSL_ENSURE( !mbEof, "BiffInputStream::skip - record overread" );
316 : }
317 0 : }
318 :
319 : // byte strings ---------------------------------------------------------------
320 :
321 0 : OString BiffInputStream::readByteString( bool b16BitLen, bool bAllowNulChars )
322 : {
323 0 : sal_Int32 nStrLen = b16BitLen ? readuInt16() : readuInt8();
324 0 : return readCharArray( nStrLen, bAllowNulChars );
325 : }
326 :
327 0 : OUString BiffInputStream::readByteStringUC( bool b16BitLen, rtl_TextEncoding eTextEnc, bool bAllowNulChars )
328 : {
329 0 : return OStringToOUString( readByteString( b16BitLen, bAllowNulChars ), eTextEnc );
330 : }
331 :
332 : // Unicode strings ------------------------------------------------------------
333 :
334 0 : OUString BiffInputStream::readUniStringChars( sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars )
335 : {
336 0 : OUStringBuffer aBuffer;
337 0 : aBuffer.ensureCapacity( nChars );
338 :
339 : /* This function has to react on CONTINUE records which repeat the flags
340 : field in their first byte and may change the 8bit/16bit character mode,
341 : thus a plain call to readCompressedUnicodeArray() cannot be used here. */
342 0 : sal_Int32 nCharsLeft = nChars;
343 0 : while( !mbEof && (nCharsLeft > 0) )
344 : {
345 : /* Read the character array from the remaining part of the current raw
346 : record. First, calculate the maximum number of characters that can
347 : be read without triggering to start a following CONTINUE record. */
348 0 : sal_Int32 nRawChars = b16BitChars ? (getMaxRawReadSize( nCharsLeft * 2, 2 ) / 2) : getMaxRawReadSize( nCharsLeft, 1 );
349 0 : aBuffer.append( readCompressedUnicodeArray( nRawChars, !b16BitChars, bAllowNulChars ) );
350 :
351 : /* Prepare for next CONTINUE record. Calling jumpToNextStringContinue()
352 : reads the leading byte in the following CONTINUE record and updates
353 : the b16BitChars flag. */
354 0 : nCharsLeft -= nRawChars;
355 0 : if( nCharsLeft > 0 )
356 0 : jumpToNextStringContinue( b16BitChars );
357 : }
358 :
359 0 : return aBuffer.makeStringAndClear();
360 : }
361 :
362 0 : OUString BiffInputStream::readUniStringBody( sal_uInt16 nChars, bool bAllowNulChars )
363 : {
364 : bool b16BitChars;
365 : sal_Int32 nAddSize;
366 0 : readUniStringHeader( b16BitChars, nAddSize );
367 0 : OUString aString = readUniStringChars( nChars, b16BitChars, bAllowNulChars );
368 0 : skip( nAddSize );
369 0 : return aString;
370 : }
371 :
372 0 : OUString BiffInputStream::readUniString( bool bAllowNulChars )
373 : {
374 0 : return readUniStringBody( readuInt16(), bAllowNulChars );
375 : }
376 :
377 : // private --------------------------------------------------------------------
378 :
379 0 : void BiffInputStream::setupRecord()
380 : {
381 : // initialize class members
382 0 : mnRecHandle = maRecBuffer.getRecHeaderPos();
383 0 : mnRecId = maRecBuffer.getRecId();
384 0 : mnAltContId = BIFF_ID_UNKNOWN;
385 0 : mnCurrRecSize = mnComplRecSize = maRecBuffer.getRecSize();
386 0 : mbHasComplRec = !mbCont;
387 0 : mbEof = !isInRecord();
388 : // enable decoder in new record
389 0 : enableDecoder( true );
390 0 : }
391 :
392 0 : void BiffInputStream::restartRecord( bool bInvalidateRecSize )
393 : {
394 0 : if( isInRecord() )
395 : {
396 0 : maRecBuffer.startRecord( getRecHandle() );
397 0 : mnCurrRecSize = maRecBuffer.getRecSize();
398 0 : if( bInvalidateRecSize )
399 : {
400 0 : mnComplRecSize = mnCurrRecSize;
401 0 : mbHasComplRec = !mbCont;
402 : }
403 0 : mbEof = false;
404 : }
405 0 : }
406 :
407 0 : void BiffInputStream::rewindToRecord( sal_Int64 nRecHandle )
408 : {
409 0 : if( nRecHandle >= 0 )
410 : {
411 0 : maRecBuffer.restartAt( nRecHandle );
412 0 : mnRecHandle = -1;
413 0 : mbEof = true; // as long as the record is not started
414 : }
415 0 : }
416 :
417 0 : bool BiffInputStream::isContinueId( sal_uInt16 nRecId ) const
418 : {
419 0 : return (nRecId == BIFF_ID_CONT) || (nRecId == mnAltContId);
420 : }
421 :
422 0 : bool BiffInputStream::jumpToNextContinue()
423 : {
424 0 : mbEof = mbEof || !mbCont || !isContinueId( maRecBuffer.getNextRecId() ) || !maRecBuffer.startNextRecord();
425 0 : if( !mbEof )
426 0 : mnCurrRecSize += maRecBuffer.getRecSize();
427 0 : return !mbEof;
428 : }
429 :
430 0 : bool BiffInputStream::jumpToNextStringContinue( bool& rb16BitChars )
431 : {
432 : OSL_ENSURE( maRecBuffer.getRecLeft() == 0, "BiffInputStream::jumpToNextStringContinue - alignment error" );
433 :
434 0 : if( mbCont && (getRemaining() > 0) )
435 : {
436 0 : jumpToNextContinue();
437 : }
438 0 : else if( mnRecId == BIFF_ID_CONT )
439 : {
440 : /* CONTINUE handling is off, but we have started reading in a CONTINUE
441 : record -> start next CONTINUE for TXO import. We really start a new
442 : record here - no chance to return to string origin. */
443 0 : mbEof = mbEof || (maRecBuffer.getNextRecId() != BIFF_ID_CONT) || !maRecBuffer.startNextRecord();
444 0 : if( !mbEof )
445 0 : setupRecord();
446 : }
447 :
448 : // trying to read the flags invalidates stream, if no CONTINUE record has been found
449 0 : sal_uInt8 nFlags = readuInt8();
450 0 : rb16BitChars = getFlag( nFlags, BIFF_STRF_16BIT );
451 0 : return !mbEof;
452 : }
453 :
454 0 : void BiffInputStream::calcRecordLength()
455 : {
456 0 : sal_Int64 nCurrPos = tell(); // save current position in record
457 0 : while( jumpToNextContinue() ) {} // jumpToNextContinue() adds up mnCurrRecSize
458 0 : mnComplRecSize = mnCurrRecSize;
459 0 : mbHasComplRec = true;
460 0 : seek( nCurrPos ); // restore position, seek() resets old mbValid state
461 0 : }
462 :
463 0 : sal_uInt16 BiffInputStream::getMaxRawReadSize( sal_Int32 nBytes, size_t nAtomSize ) const
464 : {
465 0 : sal_uInt16 nMaxSize = getLimitedValue< sal_uInt16, sal_Int32 >( nBytes, 0, maRecBuffer.getRecLeft() );
466 0 : if( (0 < nMaxSize) && (nMaxSize < nBytes) && (nAtomSize > 1) )
467 : {
468 : // check that remaining data in record buffer is a multiple of the passed atom size
469 0 : sal_uInt16 nPadding = static_cast< sal_uInt16 >( nMaxSize % nAtomSize );
470 : OSL_ENSURE( nPadding == 0, "BiffInputStream::getMaxRawReadSize - alignment error" );
471 0 : nMaxSize = nMaxSize - nPadding;
472 : }
473 0 : return nMaxSize;
474 : }
475 :
476 0 : void BiffInputStream::readUniStringHeader( bool& orb16BitChars, sal_Int32& ornAddSize )
477 : {
478 0 : sal_uInt8 nFlags = readuInt8();
479 : OSL_ENSURE( !getFlag( nFlags, BIFF_STRF_UNKNOWN ), "BiffInputStream::readUniStringHeader - unknown flags" );
480 0 : orb16BitChars = getFlag( nFlags, BIFF_STRF_16BIT );
481 0 : sal_uInt16 nFontCount = getFlag( nFlags, BIFF_STRF_RICH ) ? readuInt16() : 0;
482 0 : sal_Int32 nPhoneticSize = getFlag( nFlags, BIFF_STRF_PHONETIC ) ? readInt32() : 0;
483 0 : ornAddSize = 4 * nFontCount + ::std::max< sal_Int32 >( 0, nPhoneticSize );
484 0 : }
485 :
486 0 : BiffInputStreamPos::BiffInputStreamPos( BiffInputStream& rStrm ) :
487 : mrStrm( rStrm ),
488 0 : mnRecHandle( rStrm.getRecHandle() ),
489 0 : mnRecPos( rStrm.tell() )
490 : {
491 0 : }
492 :
493 0 : bool BiffInputStreamPos::restorePosition()
494 : {
495 0 : bool bValidRec = mrStrm.startRecordByHandle( mnRecHandle );
496 0 : if( bValidRec )
497 0 : mrStrm.seek( mnRecPos );
498 0 : return bValidRec && !mrStrm.isEof();
499 : }
500 :
501 0 : BiffInputStreamPosGuard::BiffInputStreamPosGuard( BiffInputStream& rStrm ) :
502 0 : BiffInputStreamPos( rStrm )
503 : {
504 0 : }
505 :
506 0 : BiffInputStreamPosGuard::~BiffInputStreamPosGuard()
507 : {
508 0 : restorePosition();
509 0 : }
510 :
511 : } // namespace xls
512 30 : } // namespace oox
513 :
514 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|