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