fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / oox / biffinputstream.cxx
blob49450cf52f2dcbb38881d868400d5ba25d7f6a47
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "biffinputstream.hxx"
22 #include <algorithm>
23 #include <rtl/ustrbuf.hxx>
24 #include <osl/diagnose.h>
26 namespace oox {
27 namespace xls {
29 namespace prv {
31 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 mbValidHeader( false )
43 OSL_ENSURE( mrInStrm.isSeekable(), "BiffInputRecordBuffer::BiffInputRecordBuffer - stream must be seekable" );
44 mrInStrm.seekToStart();
45 maOriginalData.reserve( SAL_MAX_UINT16 );
46 maDecodedData.reserve( SAL_MAX_UINT16 );
47 enableDecoder( false ); // updates mpCurrentData
50 void BiffInputRecordBuffer::restartAt( sal_Int64 nPos )
52 mnHeaderPos = -1;
53 mnBodyPos = mnBufferBodyPos = 0;
54 mnNextHeaderPos = nPos;
55 mnRecId = BIFF_ID_UNKNOWN;
56 mnRecSize = mnRecPos = 0;
57 mbValidHeader = false;
60 void BiffInputRecordBuffer::setDecoder( const BiffDecoderRef& rxDecoder )
62 mxDecoder = rxDecoder;
63 enableDecoder( true );
64 updateDecoded();
67 void BiffInputRecordBuffer::enableDecoder( bool bEnable )
69 mpCurrentData = (bEnable && mxDecoder.get() && mxDecoder->isValid()) ? &maDecodedData : &maOriginalData;
72 bool BiffInputRecordBuffer::startRecord( sal_Int64 nHeaderPos )
74 mbValidHeader = (0 <= nHeaderPos) && (nHeaderPos + 4 <= mrInStrm.size());
75 if( mbValidHeader )
77 mnHeaderPos = nHeaderPos;
78 mrInStrm.seek( nHeaderPos );
79 mnRecId = mrInStrm.readuInt16();
80 mnRecSize = mrInStrm.readuInt16();
81 mnBodyPos = mrInStrm.tell();
82 mnNextHeaderPos = mnBodyPos + mnRecSize;
83 mbValidHeader = !mrInStrm.isEof() && (mnNextHeaderPos <= mrInStrm.size());
85 if( !mbValidHeader )
87 mnHeaderPos = mnBodyPos = -1;
88 mnNextHeaderPos = 0;
89 mnRecId = BIFF_ID_UNKNOWN;
90 mnRecSize = 0;
92 mnRecPos = 0;
93 return mbValidHeader;
96 bool BiffInputRecordBuffer::startNextRecord()
98 return startRecord( mnNextHeaderPos );
101 sal_uInt16 BiffInputRecordBuffer::getNextRecId()
103 sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
104 if( mbValidHeader && (mnNextHeaderPos + 4 <= mrInStrm.size()) )
106 mrInStrm.seek( mnNextHeaderPos );
107 nRecId = mrInStrm.readuInt16();
109 return nRecId;
112 void BiffInputRecordBuffer::read( void* opData, sal_uInt16 nBytes )
114 updateBuffer();
115 OSL_ENSURE( nBytes > 0, "BiffInputRecordBuffer::read - nothing to read" );
116 OSL_ENSURE( nBytes <= getRecLeft(), "BiffInputRecordBuffer::read - buffer overflow" );
117 memcpy( opData, &(*mpCurrentData)[ mnRecPos ], nBytes );
118 mnRecPos = mnRecPos + nBytes;
121 void BiffInputRecordBuffer::skip( sal_uInt16 nBytes )
123 OSL_ENSURE( nBytes > 0, "BiffInputRecordBuffer::skip - nothing to skip" );
124 OSL_ENSURE( nBytes <= getRecLeft(), "BiffInputRecordBuffer::skip - buffer overflow" );
125 mnRecPos = mnRecPos + nBytes;
128 void BiffInputRecordBuffer::updateBuffer()
130 OSL_ENSURE( mbValidHeader, "BiffInputRecordBuffer::updateBuffer - invalid access" );
131 if( mnBodyPos != mnBufferBodyPos )
133 mrInStrm.seek( mnBodyPos );
134 maOriginalData.resize( mnRecSize );
135 if( mnRecSize > 0 )
136 mrInStrm.readMemory( &maOriginalData.front(), static_cast< sal_Int32 >( mnRecSize ) );
137 mnBufferBodyPos = mnBodyPos;
138 updateDecoded();
142 void BiffInputRecordBuffer::updateDecoded()
144 if( mxDecoder.get() && mxDecoder->isValid() )
146 maDecodedData.resize( mnRecSize );
147 if( mnRecSize > 0 )
148 mxDecoder->decode( &maDecodedData.front(), &maOriginalData.front(), mnBodyPos, mnRecSize );
152 } // namespace prv
154 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 mbCont( bContLookup )
165 mbEof = true; // EOF will be true if stream is not inside a record
168 // record control -------------------------------------------------------------
170 bool BiffInputStream::startNextRecord()
172 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 bool bIsZeroRec = false;
178 // record header is never encrypted
179 maRecBuffer.enableDecoder( false );
180 // read header of next raw record, returns false at end of stream
181 bValidRec = maRecBuffer.startNextRecord();
182 // ignore record, if identifier and size are zero
183 bIsZeroRec = (maRecBuffer.getRecId() == 0) && (maRecBuffer.getRecSize() == 0);
185 while( bValidRec && ((mbCont && isContinueId( maRecBuffer.getRecId() )) || bIsZeroRec) );
187 // setup other class members
188 setupRecord();
189 return isInRecord();
192 bool BiffInputStream::startRecordByHandle( sal_Int64 nRecHandle )
194 rewindToRecord( nRecHandle );
195 return startNextRecord();
198 void BiffInputStream::rewindRecord()
200 rewindToRecord( mnRecHandle );
203 // decoder --------------------------------------------------------------------
205 void BiffInputStream::setDecoder( const BiffDecoderRef& rxDecoder )
207 maRecBuffer.setDecoder( rxDecoder );
210 void BiffInputStream::enableDecoder( bool bEnable )
212 maRecBuffer.enableDecoder( bEnable );
215 // stream/record state and info -----------------------------------------------
217 sal_uInt16 BiffInputStream::getNextRecId()
219 sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
220 if( isInRecord() )
222 sal_Int64 nCurrPos = tell(); // save current position in record
223 while( jumpToNextContinue() ) {} // skip following CONTINUE records
224 if( maRecBuffer.startNextRecord() ) // read header of next record
225 nRecId = maRecBuffer.getRecId();
226 seek( nCurrPos ); // restore position, seek() resets old mbValid state
228 return nRecId;
231 // BinaryStreamBase interface (seeking) ---------------------------------------
233 sal_Int64 BiffInputStream::size() const
235 if( !mbHasComplRec )
236 const_cast< BiffInputStream* >( this )->calcRecordLength();
237 return mnComplRecSize;
240 sal_Int64 BiffInputStream::tell() const
242 return mbEof ? -1 : (mnCurrRecSize - maRecBuffer.getRecLeft());
245 void BiffInputStream::seek( sal_Int64 nRecPos )
247 if( isInRecord() )
249 if( mbEof || (nRecPos < tell()) )
250 restartRecord( false );
251 if( !mbEof && (nRecPos > tell()) )
252 skip( static_cast< sal_Int32 >( nRecPos - tell() ) );
256 void BiffInputStream::close()
260 // BinaryInputStream interface (stream read access) ---------------------------
262 sal_Int32 BiffInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
264 sal_Int32 nRet = 0;
265 if( !mbEof )
267 orData.realloc( ::std::max< sal_Int32 >( nBytes, 0 ) );
268 if( nBytes > 0 )
269 nRet = readMemory( orData.getArray(), nBytes, nAtomSize );
271 return nRet;
274 sal_Int32 BiffInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
276 sal_Int32 nRet = 0;
277 if( !mbEof && opMem && (nBytes > 0) )
279 sal_uInt8* pnBuffer = static_cast< sal_uInt8* >( opMem );
280 sal_Int32 nBytesLeft = nBytes;
282 while( !mbEof && (nBytesLeft > 0) )
284 sal_uInt16 nReadSize = getMaxRawReadSize( nBytesLeft, nAtomSize );
285 // check nReadSize, stream may already be located at end of a raw record
286 if( nReadSize > 0 )
288 maRecBuffer.read( pnBuffer, nReadSize );
289 nRet += nReadSize;
290 pnBuffer += nReadSize;
291 nBytesLeft -= nReadSize;
293 if( nBytesLeft > 0 )
294 jumpToNextContinue();
295 OSL_ENSURE( !mbEof, "BiffInputStream::readMemory - record overread" );
298 return nRet;
301 void BiffInputStream::skip( sal_Int32 nBytes, size_t nAtomSize )
303 sal_Int32 nBytesLeft = nBytes;
304 while( !mbEof && (nBytesLeft > 0) )
306 sal_uInt16 nSkipSize = getMaxRawReadSize( nBytesLeft, nAtomSize );
307 // check nSkipSize, stream may already be located at end of a raw record
308 if( nSkipSize > 0 )
310 maRecBuffer.skip( nSkipSize );
311 nBytesLeft -= nSkipSize;
313 if( nBytesLeft > 0 )
314 jumpToNextContinue();
315 OSL_ENSURE( !mbEof, "BiffInputStream::skip - record overread" );
319 // byte strings ---------------------------------------------------------------
321 OString BiffInputStream::readByteString( bool b16BitLen, bool bAllowNulChars )
323 sal_Int32 nStrLen = b16BitLen ? readuInt16() : readuInt8();
324 return readCharArray( nStrLen, bAllowNulChars );
327 OUString BiffInputStream::readByteStringUC( bool b16BitLen, rtl_TextEncoding eTextEnc, bool bAllowNulChars )
329 return OStringToOUString( readByteString( b16BitLen, bAllowNulChars ), eTextEnc );
332 // Unicode strings ------------------------------------------------------------
334 OUString BiffInputStream::readUniStringChars( sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars )
336 OUStringBuffer aBuffer;
337 aBuffer.ensureCapacity( nChars );
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 sal_Int32 nCharsLeft = nChars;
343 while( !mbEof && (nCharsLeft > 0) )
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 sal_Int32 nRawChars = b16BitChars ? (getMaxRawReadSize( nCharsLeft * 2, 2 ) / 2) : getMaxRawReadSize( nCharsLeft, 1 );
349 aBuffer.append( readCompressedUnicodeArray( nRawChars, !b16BitChars, bAllowNulChars ) );
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 nCharsLeft -= nRawChars;
355 if( nCharsLeft > 0 )
356 jumpToNextStringContinue( b16BitChars );
359 return aBuffer.makeStringAndClear();
362 OUString BiffInputStream::readUniStringBody( sal_uInt16 nChars, bool bAllowNulChars )
364 bool b16BitChars;
365 sal_Int32 nAddSize;
366 readUniStringHeader( b16BitChars, nAddSize );
367 OUString aString = readUniStringChars( nChars, b16BitChars, bAllowNulChars );
368 skip( nAddSize );
369 return aString;
372 OUString BiffInputStream::readUniString( bool bAllowNulChars )
374 return readUniStringBody( readuInt16(), bAllowNulChars );
377 // private --------------------------------------------------------------------
379 void BiffInputStream::setupRecord()
381 // initialize class members
382 mnRecHandle = maRecBuffer.getRecHeaderPos();
383 mnRecId = maRecBuffer.getRecId();
384 mnAltContId = BIFF_ID_UNKNOWN;
385 mnCurrRecSize = mnComplRecSize = maRecBuffer.getRecSize();
386 mbHasComplRec = !mbCont;
387 mbEof = !isInRecord();
388 // enable decoder in new record
389 enableDecoder( true );
392 void BiffInputStream::restartRecord( bool bInvalidateRecSize )
394 if( isInRecord() )
396 maRecBuffer.startRecord( getRecHandle() );
397 mnCurrRecSize = maRecBuffer.getRecSize();
398 if( bInvalidateRecSize )
400 mnComplRecSize = mnCurrRecSize;
401 mbHasComplRec = !mbCont;
403 mbEof = false;
407 void BiffInputStream::rewindToRecord( sal_Int64 nRecHandle )
409 if( nRecHandle >= 0 )
411 maRecBuffer.restartAt( nRecHandle );
412 mnRecHandle = -1;
413 mbEof = true; // as long as the record is not started
417 bool BiffInputStream::isContinueId( sal_uInt16 nRecId ) const
419 return (nRecId == BIFF_ID_CONT) || (nRecId == mnAltContId);
422 bool BiffInputStream::jumpToNextContinue()
424 mbEof = mbEof || !mbCont || !isContinueId( maRecBuffer.getNextRecId() ) || !maRecBuffer.startNextRecord();
425 if( !mbEof )
426 mnCurrRecSize += maRecBuffer.getRecSize();
427 return !mbEof;
430 bool BiffInputStream::jumpToNextStringContinue( bool& rb16BitChars )
432 OSL_ENSURE( maRecBuffer.getRecLeft() == 0, "BiffInputStream::jumpToNextStringContinue - alignment error" );
434 if( mbCont && (getRemaining() > 0) )
436 jumpToNextContinue();
438 else if( mnRecId == BIFF_ID_CONT )
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 mbEof = mbEof || (maRecBuffer.getNextRecId() != BIFF_ID_CONT) || !maRecBuffer.startNextRecord();
444 if( !mbEof )
445 setupRecord();
448 // trying to read the flags invalidates stream, if no CONTINUE record has been found
449 sal_uInt8 nFlags = readuInt8();
450 rb16BitChars = getFlag( nFlags, BIFF_STRF_16BIT );
451 return !mbEof;
454 void BiffInputStream::calcRecordLength()
456 sal_Int64 nCurrPos = tell(); // save current position in record
457 while( jumpToNextContinue() ) {} // jumpToNextContinue() adds up mnCurrRecSize
458 mnComplRecSize = mnCurrRecSize;
459 mbHasComplRec = true;
460 seek( nCurrPos ); // restore position, seek() resets old mbValid state
463 sal_uInt16 BiffInputStream::getMaxRawReadSize( sal_Int32 nBytes, size_t nAtomSize ) const
465 sal_uInt16 nMaxSize = getLimitedValue< sal_uInt16, sal_Int32 >( nBytes, 0, maRecBuffer.getRecLeft() );
466 if( (0 < nMaxSize) && (nMaxSize < nBytes) && (nAtomSize > 1) )
468 // check that remaining data in record buffer is a multiple of the passed atom size
469 sal_uInt16 nPadding = static_cast< sal_uInt16 >( nMaxSize % nAtomSize );
470 OSL_ENSURE( nPadding == 0, "BiffInputStream::getMaxRawReadSize - alignment error" );
471 nMaxSize = nMaxSize - nPadding;
473 return nMaxSize;
476 void BiffInputStream::readUniStringHeader( bool& orb16BitChars, sal_Int32& ornAddSize )
478 sal_uInt8 nFlags = readuInt8();
479 OSL_ENSURE( !getFlag( nFlags, BIFF_STRF_UNKNOWN ), "BiffInputStream::readUniStringHeader - unknown flags" );
480 orb16BitChars = getFlag( nFlags, BIFF_STRF_16BIT );
481 sal_uInt16 nFontCount = getFlag( nFlags, BIFF_STRF_RICH ) ? readuInt16() : 0;
482 sal_Int32 nPhoneticSize = getFlag( nFlags, BIFF_STRF_PHONETIC ) ? readInt32() : 0;
483 ornAddSize = 4 * nFontCount + ::std::max< sal_Int32 >( 0, nPhoneticSize );
486 BiffInputStreamPos::BiffInputStreamPos( BiffInputStream& rStrm ) :
487 mrStrm( rStrm ),
488 mnRecHandle( rStrm.getRecHandle() ),
489 mnRecPos( rStrm.tell() )
493 bool BiffInputStreamPos::restorePosition()
495 bool bValidRec = mrStrm.startRecordByHandle( mnRecHandle );
496 if( bValidRec )
497 mrStrm.seek( mnRecPos );
498 return bValidRec && !mrStrm.isEof();
501 BiffInputStreamPosGuard::BiffInputStreamPosGuard( BiffInputStream& rStrm ) :
502 BiffInputStreamPos( rStrm )
506 BiffInputStreamPosGuard::~BiffInputStreamPosGuard()
508 restorePosition();
511 } // namespace xls
512 } // namespace oox
514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */