Update ooo320-m1
[ooovba.git] / oox / source / xls / biffinputstream.cxx
blob681b751279fcdd24aa5f96c639c35e2200f9425b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: biffinputstream.cxx,v $
10 * $Revision: 1.4.20.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "oox/xls/biffinputstream.hxx"
32 #include <algorithm>
33 #include <rtl/ustrbuf.hxx>
35 using ::rtl::OString;
36 using ::rtl::OStringToOUString;
37 using ::rtl::OUString;
38 using ::rtl::OUStringBuffer;
40 namespace oox {
41 namespace xls {
43 // ============================================================================
45 namespace prv {
47 BiffInputRecordBuffer::BiffInputRecordBuffer( BinaryInputStream& rInStrm ) :
48 mrInStrm( rInStrm ),
49 mpCurrentData( 0 ),
50 mnHeaderPos( -1 ),
51 mnBodyPos( 0 ),
52 mnBufferBodyPos( 0 ),
53 mnNextHeaderPos( 0 ),
54 mnRecId( BIFF_ID_UNKNOWN ),
55 mnRecSize( 0 ),
56 mnRecPos( 0 ),
57 mbValidHeader( false )
59 OSL_ENSURE( mrInStrm.isSeekable(), "BiffInputRecordBuffer::BiffInputRecordBuffer - stream must be seekable" );
60 mrInStrm.seekToStart();
61 maOriginalData.reserve( SAL_MAX_UINT16 );
62 maDecodedData.reserve( SAL_MAX_UINT16 );
63 enableDecoder( false ); // updates mpCurrentData
66 void BiffInputRecordBuffer::restartAt( sal_Int64 nPos )
68 mnHeaderPos = -1;
69 mnBodyPos = mnBufferBodyPos = 0;
70 mnNextHeaderPos = nPos;
71 mnRecId = BIFF_ID_UNKNOWN;
72 mnRecSize = mnRecPos = 0;
73 mbValidHeader = false;
76 void BiffInputRecordBuffer::setDecoder( const BiffDecoderRef& rxDecoder )
78 mxDecoder = rxDecoder;
79 enableDecoder( true );
80 updateDecoded();
83 void BiffInputRecordBuffer::enableDecoder( bool bEnable )
85 mpCurrentData = (bEnable && mxDecoder.get() && mxDecoder->isValid()) ? &maDecodedData : &maOriginalData;
88 bool BiffInputRecordBuffer::startRecord( sal_Int64 nHeaderPos )
90 mbValidHeader = (0 <= nHeaderPos) && (nHeaderPos + 4 <= mrInStrm.getLength());
91 if( mbValidHeader )
93 mnHeaderPos = nHeaderPos;
94 mrInStrm.seek( nHeaderPos );
95 mrInStrm >> mnRecId >> mnRecSize;
96 mnBodyPos = mrInStrm.tell();
97 mnNextHeaderPos = mnBodyPos + mnRecSize;
98 mbValidHeader = !mrInStrm.isEof() && (mnNextHeaderPos <= mrInStrm.getLength());
100 if( !mbValidHeader )
102 mnHeaderPos = mnBodyPos = -1;
103 mnNextHeaderPos = 0;
104 mnRecId = BIFF_ID_UNKNOWN;
105 mnRecSize = 0;
107 mnRecPos = 0;
108 return mbValidHeader;
111 bool BiffInputRecordBuffer::startNextRecord()
113 return startRecord( mnNextHeaderPos );
116 sal_uInt16 BiffInputRecordBuffer::getNextRecId()
118 sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
119 if( mbValidHeader && (mnNextHeaderPos + 4 <= mrInStrm.getLength()) )
121 mrInStrm.seek( mnNextHeaderPos );
122 mrInStrm >> nRecId;
124 return nRecId;
127 void BiffInputRecordBuffer::read( void* opData, sal_uInt16 nBytes )
129 updateBuffer();
130 OSL_ENSURE( nBytes > 0, "BiffInputRecordBuffer::read - nothing to read" );
131 OSL_ENSURE( nBytes <= getRecLeft(), "BiffInputRecordBuffer::read - buffer overflow" );
132 memcpy( opData, &(*mpCurrentData)[ mnRecPos ], nBytes );
133 mnRecPos = mnRecPos + nBytes;
136 void BiffInputRecordBuffer::skip( sal_uInt16 nBytes )
138 OSL_ENSURE( nBytes > 0, "BiffInputRecordBuffer::skip - nothing to skip" );
139 OSL_ENSURE( nBytes <= getRecLeft(), "BiffInputRecordBuffer::skip - buffer overflow" );
140 mnRecPos = mnRecPos + nBytes;
143 void BiffInputRecordBuffer::updateBuffer()
145 OSL_ENSURE( mbValidHeader, "BiffInputRecordBuffer::updateBuffer - invalid access" );
146 if( mnBodyPos != mnBufferBodyPos )
148 mrInStrm.seek( mnBodyPos );
149 maOriginalData.resize( mnRecSize );
150 if( mnRecSize > 0 )
151 mrInStrm.readMemory( &maOriginalData.front(), static_cast< sal_Int32 >( mnRecSize ) );
152 mnBufferBodyPos = mnBodyPos;
153 updateDecoded();
157 void BiffInputRecordBuffer::updateDecoded()
159 if( mxDecoder.get() && mxDecoder->isValid() )
161 maDecodedData.resize( mnRecSize );
162 if( mnRecSize > 0 )
163 mxDecoder->decode( &maDecodedData.front(), &maOriginalData.front(), mnBodyPos, mnRecSize );
167 } // namespace prv
169 // ============================================================================
171 BiffInputStream::BiffInputStream( BinaryInputStream& rInStream, bool bContLookup ) :
172 maRecBuffer( rInStream ),
173 mnRecHandle( -1 ),
174 mnRecId( BIFF_ID_UNKNOWN ),
175 mnAltContId( BIFF_ID_UNKNOWN ),
176 mnCurrRecSize( 0 ),
177 mnComplRecSize( 0 ),
178 mbHasComplRec( false ),
179 mbCont( bContLookup )
181 mbEof = true; // EOF will be true if stream is not inside a record
184 // record control -------------------------------------------------------------
186 bool BiffInputStream::startNextRecord()
188 bool bValidRec = false;
189 /* #i4266# ignore zero records (id==len==0) (e.g. the application
190 "Crystal Report" writes zero records between other records) */
191 bool bIsZeroRec = false;
194 // record header is never encrypted
195 maRecBuffer.enableDecoder( false );
196 // read header of next raw record, returns false at end of stream
197 bValidRec = maRecBuffer.startNextRecord();
198 // ignore record, if identifier and size are zero
199 bIsZeroRec = (maRecBuffer.getRecId() == 0) && (maRecBuffer.getRecSize() == 0);
201 while( bValidRec && ((mbCont && isContinueId( maRecBuffer.getRecId() )) || bIsZeroRec) );
203 // setup other class members
204 setupRecord();
205 return isInRecord();
208 bool BiffInputStream::startRecordByHandle( sal_Int64 nRecHandle )
210 rewindToRecord( nRecHandle );
211 return startNextRecord();
214 void BiffInputStream::resetRecord( bool bContLookup, sal_uInt16 nAltContId )
216 if( isInRecord() )
218 mbCont = bContLookup;
219 mnAltContId = nAltContId;
220 restartRecord( true );
221 maRecBuffer.enableDecoder( true );
225 void BiffInputStream::rewindRecord()
227 rewindToRecord( mnRecHandle );
230 // decoder --------------------------------------------------------------------
232 void BiffInputStream::setDecoder( const BiffDecoderRef& rxDecoder )
234 maRecBuffer.setDecoder( rxDecoder );
237 void BiffInputStream::enableDecoder( bool bEnable )
239 maRecBuffer.enableDecoder( bEnable );
242 // stream/record state and info -----------------------------------------------
244 sal_uInt16 BiffInputStream::getNextRecId()
246 sal_uInt16 nRecId = BIFF_ID_UNKNOWN;
247 if( isInRecord() )
249 sal_Int64 nCurrPos = tell(); // save current position in record
250 while( jumpToNextContinue() ) {} // skip following CONTINUE records
251 if( maRecBuffer.startNextRecord() ) // read header of next record
252 nRecId = maRecBuffer.getRecId();
253 seek( nCurrPos ); // restore position, seek() resets old mbValid state
255 return nRecId;
258 // BinaryStreamBase interface (seeking) ---------------------------------------
260 bool BiffInputStream::isSeekable() const
262 return true;
265 sal_Int64 BiffInputStream::tell() const
267 return mbEof ? -1 : (mnCurrRecSize - maRecBuffer.getRecLeft());
270 sal_Int64 BiffInputStream::getLength() const
272 if( !mbHasComplRec )
273 const_cast< BiffInputStream* >( this )->calcRecordLength();
274 return mnComplRecSize;
277 void BiffInputStream::seek( sal_Int64 nRecPos )
279 if( isInRecord() )
281 if( mbEof || (nRecPos < tell()) )
282 restartRecord( false );
283 if( !mbEof && (nRecPos > tell()) )
284 skip( static_cast< sal_Int32 >( nRecPos - tell() ) );
288 sal_Int64 BiffInputStream::tellBase() const
290 return maRecBuffer.getBaseStream().tell();
293 sal_Int64 BiffInputStream::getBaseLength() const
295 return maRecBuffer.getBaseStream().getLength();
298 // BinaryInputStream interface (stream read access) ---------------------------
300 sal_Int32 BiffInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes )
302 sal_Int32 nRet = 0;
303 if( !mbEof )
305 orData.realloc( ::std::max< sal_Int32 >( nBytes, 0 ) );
306 if( nBytes > 0 )
308 nRet = readMemory( orData.getArray(), nBytes );
309 if( nRet < nBytes )
310 orData.realloc( nRet );
313 return nRet;
316 sal_Int32 BiffInputStream::readMemory( void* opMem, sal_Int32 nBytes )
318 sal_Int32 nRet = 0;
319 if( !mbEof && opMem && (nBytes > 0) )
321 sal_uInt8* pnBuffer = reinterpret_cast< sal_uInt8* >( opMem );
322 sal_Int32 nBytesLeft = nBytes;
324 while( !mbEof && (nBytesLeft > 0) )
326 sal_uInt16 nReadSize = getMaxRawReadSize( nBytesLeft );
327 // check nReadSize, stream may already be located at end of a raw record
328 if( nReadSize > 0 )
330 maRecBuffer.read( pnBuffer, nReadSize );
331 nRet += nReadSize;
332 pnBuffer += nReadSize;
333 nBytesLeft -= nReadSize;
335 if( nBytesLeft > 0 )
336 jumpToNextContinue();
337 OSL_ENSURE( !mbEof, "BiffInputStream::readMemory - record overread" );
340 return nRet;
343 void BiffInputStream::skip( sal_Int32 nBytes )
345 sal_Int32 nBytesLeft = nBytes;
346 while( !mbEof && (nBytesLeft > 0) )
348 sal_uInt16 nSkipSize = getMaxRawReadSize( nBytesLeft );
349 // check nSkipSize, stream may already be located at end of a raw record
350 if( nSkipSize > 0 )
352 maRecBuffer.skip( nSkipSize );
353 nBytesLeft -= nSkipSize;
355 if( nBytesLeft > 0 )
356 jumpToNextContinue();
357 OSL_ENSURE( !mbEof, "BiffInputStream::skip - record overread" );
361 // byte strings ---------------------------------------------------------------
363 OString BiffInputStream::readByteString( bool b16BitLen, bool bAllowNulChars )
365 sal_Int32 nStrLen = b16BitLen ? readuInt16() : readuInt8();
366 return readCharArray( nStrLen, bAllowNulChars );
369 OUString BiffInputStream::readByteStringUC( bool b16BitLen, rtl_TextEncoding eTextEnc, bool bAllowNulChars )
371 return OStringToOUString( readByteString( b16BitLen, bAllowNulChars ), eTextEnc );
374 void BiffInputStream::skipByteString( bool b16BitLen )
376 skip( b16BitLen ? readuInt16() : readuInt8() );
379 // Unicode strings ------------------------------------------------------------
381 OUString BiffInputStream::readUniStringChars( sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars )
383 OUStringBuffer aBuffer;
384 aBuffer.ensureCapacity( nChars );
386 /* This function has to react on CONTINUE records to read the repeated
387 flags field, so readUnicodeArray() cannot be used here. */
388 sal_uInt16 nCharsLeft = nChars;
389 while( !mbEof && (nCharsLeft > 0) )
391 sal_uInt16 nPortionCount = 0;
392 if( b16BitChars )
394 nPortionCount = ::std::min< sal_uInt16 >( nCharsLeft, maRecBuffer.getRecLeft() / 2 );
395 OSL_ENSURE( (nPortionCount <= nCharsLeft) || ((maRecBuffer.getRecLeft() & 1) == 0),
396 "BiffInputStream::readUniStringChars - missing a byte" );
398 else
400 nPortionCount = getMaxRawReadSize( nCharsLeft );
403 // read the character array
404 appendUnicodeArray( aBuffer, nPortionCount, b16BitChars, bAllowNulChars );
406 // prepare for next CONTINUE record
407 nCharsLeft = nCharsLeft - nPortionCount;
408 if( nCharsLeft > 0 )
409 jumpToNextStringContinue( b16BitChars );
412 return aBuffer.makeStringAndClear();
415 OUString BiffInputStream::readUniStringBody( sal_uInt16 nChars, bool bAllowNulChars )
417 bool b16BitChars;
418 sal_Int32 nAddSize;
419 readUniStringHeader( b16BitChars, nAddSize );
420 OUString aString = readUniStringChars( nChars, b16BitChars, bAllowNulChars );
421 skip( nAddSize );
422 return aString;
425 OUString BiffInputStream::readUniString( bool bAllowNulChars )
427 return readUniStringBody( readuInt16(), bAllowNulChars );
430 void BiffInputStream::skipUniStringChars( sal_uInt16 nChars, bool b16BitChars )
432 sal_uInt16 nCharsLeft = nChars;
433 while( !mbEof && (nCharsLeft > 0) )
435 sal_uInt16 nPortionCount;
436 if( b16BitChars )
438 nPortionCount = ::std::min< sal_uInt16 >( nCharsLeft, maRecBuffer.getRecLeft() / 2 );
439 OSL_ENSURE( (nPortionCount <= nCharsLeft) || ((maRecBuffer.getRecLeft() & 1) == 0),
440 "BiffInputStream::skipUniStringChars - missing a byte" );
441 skip( 2 * nPortionCount );
443 else
445 nPortionCount = getMaxRawReadSize( nCharsLeft );
446 skip( nPortionCount );
449 // prepare for next CONTINUE record
450 nCharsLeft = nCharsLeft - nPortionCount;
451 if( nCharsLeft > 0 )
452 jumpToNextStringContinue( b16BitChars );
456 void BiffInputStream::skipUniStringBody( sal_uInt16 nChars )
458 bool b16BitChars;
459 sal_Int32 nAddSize;
460 readUniStringHeader( b16BitChars, nAddSize );
461 skipUniStringChars( nChars, b16BitChars );
462 skip( nAddSize );
465 void BiffInputStream::skipUniString()
467 skipUniStringBody( readuInt16() );
470 // private --------------------------------------------------------------------
472 void BiffInputStream::readAtom( void* opMem, sal_uInt8 nSize )
474 // byte swapping is done in calling BinaryInputStream::readValue() template function
475 if( ensureRawReadSize( nSize ) )
476 maRecBuffer.read( opMem, nSize );
479 void BiffInputStream::setupRecord()
481 // initialize class members
482 mnRecHandle = maRecBuffer.getRecHeaderPos();
483 mnRecId = maRecBuffer.getRecId();
484 mnAltContId = BIFF_ID_UNKNOWN;
485 mnCurrRecSize = mnComplRecSize = maRecBuffer.getRecSize();
486 mbHasComplRec = !mbCont;
487 mbEof = !isInRecord();
488 // enable decoder in new record
489 enableDecoder( true );
492 void BiffInputStream::restartRecord( bool bInvalidateRecSize )
494 if( isInRecord() )
496 maRecBuffer.startRecord( getRecHandle() );
497 mnCurrRecSize = maRecBuffer.getRecSize();
498 if( bInvalidateRecSize )
500 mnComplRecSize = mnCurrRecSize;
501 mbHasComplRec = !mbCont;
503 mbEof = false;
507 void BiffInputStream::rewindToRecord( sal_Int64 nRecHandle )
509 if( nRecHandle >= 0 )
511 maRecBuffer.restartAt( nRecHandle );
512 mnRecHandle = -1;
513 mbEof = true; // as long as the record is not started
517 bool BiffInputStream::isContinueId( sal_uInt16 nRecId ) const
519 return (nRecId == BIFF_ID_CONT) || (nRecId == mnAltContId);
522 bool BiffInputStream::jumpToNextContinue()
524 mbEof = mbEof || !mbCont || !isContinueId( maRecBuffer.getNextRecId() ) || !maRecBuffer.startNextRecord();
525 if( !mbEof )
526 mnCurrRecSize += maRecBuffer.getRecSize();
527 return !mbEof;
530 bool BiffInputStream::jumpToNextStringContinue( bool& rb16BitChars )
532 OSL_ENSURE( maRecBuffer.getRecLeft() == 0, "BiffInputStream::jumpToNextStringContinue - unexpected garbage" );
534 if( mbCont && (getRemaining() > 0) )
536 jumpToNextContinue();
538 else if( mnRecId == BIFF_ID_CONT )
540 /* CONTINUE handling is off, but we have started reading in a CONTINUE
541 record -> start next CONTINUE for TXO import. We really start a new
542 record here - no chance to return to string origin. */
543 mbEof = mbEof || (maRecBuffer.getNextRecId() != BIFF_ID_CONT) || !maRecBuffer.startNextRecord();
544 if( !mbEof )
545 setupRecord();
548 // trying to read the flags invalidates stream, if no CONTINUE record has been found
549 sal_uInt8 nFlags;
550 readValue( nFlags );
551 rb16BitChars = getFlag( nFlags, BIFF_STRF_16BIT );
552 return !mbEof;
555 void BiffInputStream::calcRecordLength()
557 sal_Int64 nCurrPos = tell(); // save current position in record
558 while( jumpToNextContinue() ) {} // jumpToNextContinue() adds up mnCurrRecSize
559 mnComplRecSize = mnCurrRecSize;
560 mbHasComplRec = true;
561 seek( nCurrPos ); // restore position, seek() resets old mbValid state
564 bool BiffInputStream::ensureRawReadSize( sal_uInt16 nBytes )
566 if( !mbEof && (nBytes > 0) )
568 while( !mbEof && (maRecBuffer.getRecLeft() == 0) ) jumpToNextContinue();
569 mbEof = mbEof || (nBytes > maRecBuffer.getRecLeft());
570 OSL_ENSURE( !mbEof, "BiffInputStream::ensureRawReadSize - record overread" );
572 return !mbEof;
575 sal_uInt16 BiffInputStream::getMaxRawReadSize( sal_Int32 nBytes ) const
577 return getLimitedValue< sal_uInt16, sal_Int32 >( nBytes, 0, maRecBuffer.getRecLeft() );
580 void BiffInputStream::appendUnicodeArray( OUStringBuffer& orBuffer, sal_uInt16 nChars, bool b16BitChars, bool bAllowNulChars )
582 orBuffer.ensureCapacity( orBuffer.getLength() + nChars );
583 sal_uInt16 nChar;
584 for( sal_uInt16 nCharIdx = 0; !mbEof && (nCharIdx < nChars); ++nCharIdx )
586 if( b16BitChars ) readValue( nChar ); else nChar = readuInt8();
587 orBuffer.append( static_cast< sal_Unicode >( (!bAllowNulChars && (nChar == 0)) ? '?' : nChar ) );
591 void BiffInputStream::readUniStringHeader( bool& orb16BitChars, sal_Int32& ornAddSize )
593 sal_uInt8 nFlags = readuInt8();
594 OSL_ENSURE( !getFlag( nFlags, BIFF_STRF_UNKNOWN ), "BiffInputStream::readUniStringHeader - unknown flags" );
595 orb16BitChars = getFlag( nFlags, BIFF_STRF_16BIT );
596 sal_uInt16 nFontCount = getFlag( nFlags, BIFF_STRF_RICH ) ? readuInt16() : 0;
597 sal_Int32 nPhoneticSize = getFlag( nFlags, BIFF_STRF_PHONETIC ) ? readInt32() : 0;
598 ornAddSize = 4 * nFontCount + ::std::max< sal_Int32 >( 0, nPhoneticSize );
601 // ============================================================================
603 BiffInputStreamPos::BiffInputStreamPos( BiffInputStream& rStrm ) :
604 mrStrm( rStrm ),
605 mnRecHandle( rStrm.getRecHandle() ),
606 mnRecPos( rStrm.tell() )
610 bool BiffInputStreamPos::restorePosition()
612 bool bValidRec = mrStrm.startRecordByHandle( mnRecHandle );
613 if( bValidRec )
614 mrStrm.seek( mnRecPos );
615 return bValidRec && !mrStrm.isEof();
618 // ============================================================================
620 BiffInputStreamPosGuard::BiffInputStreamPosGuard( BiffInputStream& rStrm ) :
621 BiffInputStreamPos( rStrm )
625 BiffInputStreamPosGuard::~BiffInputStreamPosGuard()
627 restorePosition();
630 // ============================================================================
632 } // namespace xls
633 } // namespace oox