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