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