1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
23 #include <rtl/ustrbuf.hxx>
24 #include <osl/diagnose.h>
31 BiffInputRecordBuffer::BiffInputRecordBuffer( BinaryInputStream
& rInStrm
) :
38 mnRecId( BIFF_ID_UNKNOWN
),
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
)
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 );
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());
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());
87 mnHeaderPos
= mnBodyPos
= -1;
89 mnRecId
= BIFF_ID_UNKNOWN
;
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();
112 void BiffInputRecordBuffer::read( void* opData
, sal_uInt16 nBytes
)
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
);
136 mrInStrm
.readMemory( &maOriginalData
.front(), static_cast< sal_Int32
>( mnRecSize
) );
137 mnBufferBodyPos
= mnBodyPos
;
142 void BiffInputRecordBuffer::updateDecoded()
144 if( mxDecoder
.get() && mxDecoder
->isValid() )
146 maDecodedData
.resize( mnRecSize
);
148 mxDecoder
->decode( &maDecodedData
.front(), &maOriginalData
.front(), mnBodyPos
, mnRecSize
);
154 BiffInputStream::BiffInputStream( BinaryInputStream
& rInStream
, bool bContLookup
) :
155 BinaryStreamBase( true ),
156 maRecBuffer( rInStream
),
158 mnRecId( BIFF_ID_UNKNOWN
),
159 mnAltContId( BIFF_ID_UNKNOWN
),
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
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
;
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
231 // BinaryStreamBase interface (seeking) ---------------------------------------
233 sal_Int64
BiffInputStream::size() const
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
)
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
)
267 orData
.realloc( ::std::max
< sal_Int32
>( nBytes
, 0 ) );
269 nRet
= readMemory( orData
.getArray(), nBytes
, nAtomSize
);
274 sal_Int32
BiffInputStream::readMemory( void* opMem
, sal_Int32 nBytes
, size_t nAtomSize
)
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
288 maRecBuffer
.read( pnBuffer
, nReadSize
);
290 pnBuffer
+= nReadSize
;
291 nBytesLeft
-= nReadSize
;
294 jumpToNextContinue();
295 OSL_ENSURE( !mbEof
, "BiffInputStream::readMemory - record overread" );
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
310 maRecBuffer
.skip( nSkipSize
);
311 nBytesLeft
-= nSkipSize
;
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
;
356 jumpToNextStringContinue( b16BitChars
);
359 return aBuffer
.makeStringAndClear();
362 OUString
BiffInputStream::readUniStringBody( sal_uInt16 nChars
, bool bAllowNulChars
)
366 readUniStringHeader( b16BitChars
, nAddSize
);
367 OUString aString
= readUniStringChars( nChars
, b16BitChars
, bAllowNulChars
);
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
)
396 maRecBuffer
.startRecord( getRecHandle() );
397 mnCurrRecSize
= maRecBuffer
.getRecSize();
398 if( bInvalidateRecSize
)
400 mnComplRecSize
= mnCurrRecSize
;
401 mbHasComplRec
= !mbCont
;
407 void BiffInputStream::rewindToRecord( sal_Int64 nRecHandle
)
409 if( nRecHandle
>= 0 )
411 maRecBuffer
.restartAt( nRecHandle
);
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();
426 mnCurrRecSize
+= maRecBuffer
.getRecSize();
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();
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
);
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
;
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
) :
488 mnRecHandle( rStrm
.getRecHandle() ),
489 mnRecPos( rStrm
.tell() )
493 bool BiffInputStreamPos::restorePosition()
495 bool bValidRec
= mrStrm
.startRecordByHandle( mnRecHandle
);
497 mrStrm
.seek( mnRecPos
);
498 return bValidRec
&& !mrStrm
.isEof();
501 BiffInputStreamPosGuard::BiffInputStreamPosGuard( BiffInputStream
& rStrm
) :
502 BiffInputStreamPos( rStrm
)
506 BiffInputStreamPosGuard::~BiffInputStreamPosGuard()
514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */