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