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