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 <stdarg.h> 21 #include <stdio.h> 22 #include <string.h> 23 #include <utility> 24 25 #include <filter/msfilter/util.hxx> 26 #include <rtl/ustring.hxx> 27 #include <rtl/ustrbuf.hxx> 28 #include <rtl/random.h> 29 #include <sax/fshelper.hxx> 30 #include <unotools/streamwrap.hxx> 31 #include <sot/storage.hxx> 32 #include <tools/urlobj.hxx> 33 #include <vcl/svapp.hxx> 34 #include <vcl/settings.hxx> 35 36 #include <docuno.hxx> 37 #include <xestream.hxx> 38 #include <xladdress.hxx> 39 #include <xlstring.hxx> 40 #include <xltools.hxx> 41 #include <xeroot.hxx> 42 #include <xcl97rec.hxx> 43 #include <rangelst.hxx> 44 #include <compiler.hxx> 45 #include <formulacell.hxx> 46 #include <tokenarray.hxx> 47 #include <tokenstringcontext.hxx> 48 #include <refreshtimerprotector.hxx> 49 #include <globstr.hrc> 50 #include <scresid.hxx> 51 #include <root.hxx> 52 53 #include <docsh.hxx> 54 #include <viewdata.hxx> 55 #include <excdoc.hxx> 56 57 #include <oox/token/tokens.hxx> 58 #include <oox/token/relationship.hxx> 59 #include <oox/export/utils.hxx> 60 #include <formula/grammar.hxx> 61 #include <oox/ole/vbaexport.hxx> 62 #include <excelvbaproject.hxx> 63 64 #include <com/sun/star/task/XStatusIndicator.hpp> 65 #include <memory> 66 #include <comphelper/storagehelper.hxx> 67 68 #define DEBUG_XL_ENCRYPTION 0 69 70 using ::com::sun::star::uno::XInterface; 71 using ::std::vector; 72 73 using namespace com::sun::star; 74 using namespace ::com::sun::star::beans; 75 using namespace ::com::sun::star::io; 76 using namespace ::com::sun::star::lang; 77 using namespace ::com::sun::star::sheet; 78 using namespace ::com::sun::star::uno; 79 using namespace ::formula; 80 using namespace ::oox; 81 82 XclExpStream::XclExpStream( SvStream& rOutStrm, const XclExpRoot& rRoot, sal_uInt16 nMaxRecSize ) : 83 mrStrm( rOutStrm ), 84 mrRoot( rRoot ), 85 mbUseEncrypter( false ), 86 mnMaxRecSize( nMaxRecSize ), 87 mnCurrMaxSize( 0 ), 88 mnMaxSliceSize( 0 ), 89 mnHeaderSize( 0 ), 90 mnCurrSize( 0 ), 91 mnSliceSize( 0 ), 92 mnPredictSize( 0 ), 93 mnLastSizePos( 0 ), 94 mbInRec( false ) 95 { 96 if( mnMaxRecSize == 0 ) 97 mnMaxRecSize = (mrRoot.GetBiff() <= EXC_BIFF5) ? EXC_MAXRECSIZE_BIFF5 : EXC_MAXRECSIZE_BIFF8; 98 mnMaxContSize = mnMaxRecSize; 99 } 100 101 XclExpStream::~XclExpStream() 102 { 103 mrStrm.Flush(); 104 } 105 106 void XclExpStream::StartRecord( sal_uInt16 nRecId, std::size_t nRecSize ) 107 { 108 OSL_ENSURE( !mbInRec, "XclExpStream::StartRecord - another record still open" ); 109 DisableEncryption(); 110 mnMaxContSize = mnCurrMaxSize = mnMaxRecSize; 111 mnPredictSize = nRecSize; 112 mbInRec = true; 113 InitRecord( nRecId ); 114 SetSliceSize( 0 ); 115 EnableEncryption(); 116 } 117 118 void XclExpStream::EndRecord() 119 { 120 OSL_ENSURE( mbInRec, "XclExpStream::EndRecord - no record open" ); 121 DisableEncryption(); 122 UpdateRecSize(); 123 mrStrm.Seek( STREAM_SEEK_TO_END ); 124 mbInRec = false; 125 } 126 127 void XclExpStream::SetSliceSize( sal_uInt16 nSize ) 128 { 129 mnMaxSliceSize = nSize; 130 mnSliceSize = 0; 131 } 132 133 XclExpStream& XclExpStream::operator<<( sal_Int8 nValue ) 134 { 135 PrepareWrite( 1 ); 136 if (mbUseEncrypter && HasValidEncrypter()) 137 mxEncrypter->Encrypt(mrStrm, nValue); 138 else 139 mrStrm.WriteSChar( nValue ); 140 return *this; 141 } 142 143 XclExpStream& XclExpStream::operator<<( sal_uInt8 nValue ) 144 { 145 PrepareWrite( 1 ); 146 if (mbUseEncrypter && HasValidEncrypter()) 147 mxEncrypter->Encrypt(mrStrm, nValue); 148 else 149 mrStrm.WriteUChar( nValue ); 150 return *this; 151 } 152 153 XclExpStream& XclExpStream::operator<<( sal_Int16 nValue ) 154 { 155 PrepareWrite( 2 ); 156 if (mbUseEncrypter && HasValidEncrypter()) 157 mxEncrypter->Encrypt(mrStrm, nValue); 158 else 159 mrStrm.WriteInt16( nValue ); 160 return *this; 161 } 162 163 XclExpStream& XclExpStream::operator<<( sal_uInt16 nValue ) 164 { 165 PrepareWrite( 2 ); 166 if (mbUseEncrypter && HasValidEncrypter()) 167 mxEncrypter->Encrypt(mrStrm, nValue); 168 else 169 mrStrm.WriteUInt16( nValue ); 170 return *this; 171 } 172 173 XclExpStream& XclExpStream::operator<<( sal_Int32 nValue ) 174 { 175 PrepareWrite( 4 ); 176 if (mbUseEncrypter && HasValidEncrypter()) 177 mxEncrypter->Encrypt(mrStrm, nValue); 178 else 179 mrStrm.WriteInt32( nValue ); 180 return *this; 181 } 182 183 XclExpStream& XclExpStream::operator<<( sal_uInt32 nValue ) 184 { 185 PrepareWrite( 4 ); 186 if (mbUseEncrypter && HasValidEncrypter()) 187 mxEncrypter->Encrypt(mrStrm, nValue); 188 else 189 mrStrm.WriteUInt32( nValue ); 190 return *this; 191 } 192 193 XclExpStream& XclExpStream::operator<<( float fValue ) 194 { 195 PrepareWrite( 4 ); 196 if (mbUseEncrypter && HasValidEncrypter()) 197 mxEncrypter->Encrypt(mrStrm, fValue); 198 else 199 mrStrm.WriteFloat( fValue ); 200 return *this; 201 } 202 203 XclExpStream& XclExpStream::operator<<( double fValue ) 204 { 205 PrepareWrite( 8 ); 206 if (mbUseEncrypter && HasValidEncrypter()) 207 mxEncrypter->Encrypt(mrStrm, fValue); 208 else 209 mrStrm.WriteDouble( fValue ); 210 return *this; 211 } 212 213 std::size_t XclExpStream::Write( const void* pData, std::size_t nBytes ) 214 { 215 std::size_t nRet = 0; 216 if( pData && (nBytes > 0) ) 217 { 218 if( mbInRec ) 219 { 220 const sal_uInt8* pBuffer = static_cast< const sal_uInt8* >( pData ); 221 std::size_t nBytesLeft = nBytes; 222 bool bValid = true; 223 224 while( bValid && (nBytesLeft > 0) ) 225 { 226 std::size_t nWriteLen = ::std::min< std::size_t >( PrepareWrite(), nBytesLeft ); 227 std::size_t nWriteRet = nWriteLen; 228 if (mbUseEncrypter && HasValidEncrypter()) 229 { 230 OSL_ENSURE(nWriteLen > 0, "XclExpStream::Write: write length is 0!"); 231 vector<sal_uInt8> aBytes(nWriteLen); 232 memcpy(aBytes.data(), pBuffer, nWriteLen); 233 mxEncrypter->EncryptBytes(mrStrm, aBytes); 234 // TODO: How do I check if all the bytes have been successfully written ? 235 } 236 else 237 { 238 nWriteRet = mrStrm.WriteBytes(pBuffer, nWriteLen); 239 bValid = (nWriteLen == nWriteRet); 240 OSL_ENSURE( bValid, "XclExpStream::Write - stream write error" ); 241 } 242 pBuffer += nWriteRet; 243 nRet += nWriteRet; 244 nBytesLeft -= nWriteRet; 245 UpdateSizeVars( nWriteRet ); 246 } 247 } 248 else 249 nRet = mrStrm.WriteBytes(pData, nBytes); 250 } 251 return nRet; 252 } 253 254 void XclExpStream::WriteZeroBytes( std::size_t nBytes ) 255 { 256 if( mbInRec ) 257 { 258 std::size_t nBytesLeft = nBytes; 259 while( nBytesLeft > 0 ) 260 { 261 std::size_t nWriteLen = ::std::min< std::size_t >( PrepareWrite(), nBytesLeft ); 262 WriteRawZeroBytes( nWriteLen ); 263 nBytesLeft -= nWriteLen; 264 UpdateSizeVars( nWriteLen ); 265 } 266 } 267 else 268 WriteRawZeroBytes( nBytes ); 269 } 270 271 void XclExpStream::WriteZeroBytesToRecord( std::size_t nBytes ) 272 { 273 if (!mbInRec) 274 // not in record. 275 return; 276 277 for (std::size_t i = 0; i < nBytes; ++i) 278 *this << sal_uInt8(0)/*nZero*/; 279 } 280 281 void XclExpStream::CopyFromStream(SvStream& rInStrm, sal_uInt64 const nBytes) 282 { 283 sal_uInt64 const nRemaining(rInStrm.remainingSize()); 284 sal_uInt64 nBytesLeft = ::std::min(nBytes, nRemaining); 285 if( nBytesLeft > 0 ) 286 { 287 const std::size_t nMaxBuffer = 4096; 288 std::unique_ptr<sal_uInt8[]> pBuffer( 289 new sal_uInt8[ ::std::min<std::size_t>(nBytesLeft, nMaxBuffer) ]); 290 bool bValid = true; 291 292 while( bValid && (nBytesLeft > 0) ) 293 { 294 std::size_t nWriteLen = ::std::min<std::size_t>(nBytesLeft, nMaxBuffer); 295 rInStrm.ReadBytes(pBuffer.get(), nWriteLen); 296 std::size_t nWriteRet = Write( pBuffer.get(), nWriteLen ); 297 bValid = (nWriteLen == nWriteRet); 298 nBytesLeft -= nWriteRet; 299 } 300 } 301 } 302 303 void XclExpStream::WriteUnicodeBuffer( const ScfUInt16Vec& rBuffer, sal_uInt8 nFlags ) 304 { 305 SetSliceSize( 0 ); 306 nFlags &= EXC_STRF_16BIT; // repeat only 16bit flag 307 sal_uInt16 nCharLen = nFlags ? 2 : 1; 308 309 for( const auto& rItem : rBuffer ) 310 { 311 if( mbInRec && (mnCurrSize + nCharLen > mnCurrMaxSize) ) 312 { 313 StartContinue(); 314 operator<<( nFlags ); 315 } 316 if( nCharLen == 2 ) 317 operator<<( rItem ); 318 else 319 operator<<( static_cast< sal_uInt8 >( rItem ) ); 320 } 321 } 322 323 // Xcl has an obscure sense of whether starting a new record or not, 324 // and crashes if it encounters the string header at the very end of a record. 325 // Thus we add 1 to give some room, seems like they do it that way but with another count (10?) 326 void XclExpStream::WriteByteString( const OString& rString ) 327 { 328 SetSliceSize( 0 ); 329 std::size_t nLen = ::std::min< std::size_t >( rString.getLength(), 0x00FF ); 330 nLen = ::std::min< std::size_t >( nLen, 0xFF ); 331 332 sal_uInt16 nLeft = PrepareWrite(); 333 if( mbInRec && (nLeft <= 1) ) 334 StartContinue(); 335 336 operator<<( static_cast< sal_uInt8 >( nLen ) ); 337 Write( rString.getStr(), nLen ); 338 } 339 340 void XclExpStream::WriteCharBuffer( const ScfUInt8Vec& rBuffer ) 341 { 342 SetSliceSize( 0 ); 343 Write( rBuffer.data(), rBuffer.size() ); 344 } 345 346 void XclExpStream::SetEncrypter( XclExpEncrypterRef const & xEncrypter ) 347 { 348 mxEncrypter = xEncrypter; 349 } 350 351 bool XclExpStream::HasValidEncrypter() const 352 { 353 return mxEncrypter && mxEncrypter->IsValid(); 354 } 355 356 void XclExpStream::EnableEncryption( bool bEnable ) 357 { 358 mbUseEncrypter = bEnable && HasValidEncrypter(); 359 } 360 361 void XclExpStream::DisableEncryption() 362 { 363 EnableEncryption(false); 364 } 365 366 void XclExpStream::SetSvStreamPos(sal_uInt64 const nPos) 367 { 368 OSL_ENSURE( !mbInRec, "XclExpStream::SetSvStreamPos - not allowed inside of a record" ); 369 mbInRec ? 0 : mrStrm.Seek( nPos ); 370 } 371 372 // private -------------------------------------------------------------------- 373 374 void XclExpStream::InitRecord( sal_uInt16 nRecId ) 375 { 376 mrStrm.Seek( STREAM_SEEK_TO_END ); 377 mrStrm.WriteUInt16( nRecId ); 378 379 mnLastSizePos = mrStrm.Tell(); 380 mnHeaderSize = static_cast< sal_uInt16 >( ::std::min< std::size_t >( mnPredictSize, mnCurrMaxSize ) ); 381 mrStrm.WriteUInt16( mnHeaderSize ); 382 mnCurrSize = mnSliceSize = 0; 383 } 384 385 void XclExpStream::UpdateRecSize() 386 { 387 if( mnCurrSize != mnHeaderSize ) 388 { 389 mrStrm.Seek( mnLastSizePos ); 390 mrStrm.WriteUInt16( mnCurrSize ); 391 } 392 } 393 394 void XclExpStream::UpdateSizeVars( std::size_t nSize ) 395 { 396 OSL_ENSURE( mnCurrSize + nSize <= mnCurrMaxSize, "XclExpStream::UpdateSizeVars - record overwritten" ); 397 mnCurrSize = mnCurrSize + static_cast< sal_uInt16 >( nSize ); 398 399 if( mnMaxSliceSize > 0 ) 400 { 401 OSL_ENSURE( mnSliceSize + nSize <= mnMaxSliceSize, "XclExpStream::UpdateSizeVars - slice overwritten" ); 402 mnSliceSize = mnSliceSize + static_cast< sal_uInt16 >( nSize ); 403 if( mnSliceSize >= mnMaxSliceSize ) 404 mnSliceSize = 0; 405 } 406 } 407 408 void XclExpStream::StartContinue() 409 { 410 UpdateRecSize(); 411 mnCurrMaxSize = mnMaxContSize; 412 mnPredictSize -= mnCurrSize; 413 InitRecord( EXC_ID_CONT ); 414 } 415 416 void XclExpStream::PrepareWrite( sal_uInt16 nSize ) 417 { 418 if( mbInRec ) 419 { 420 if( (mnCurrSize + nSize > mnCurrMaxSize) || 421 ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) ) 422 StartContinue(); 423 UpdateSizeVars( nSize ); 424 } 425 } 426 427 sal_uInt16 XclExpStream::PrepareWrite() 428 { 429 sal_uInt16 nRet = 0; 430 if( mbInRec ) 431 { 432 if( (mnCurrSize >= mnCurrMaxSize) || 433 ((mnMaxSliceSize > 0) && (mnSliceSize == 0) && (mnCurrSize + mnMaxSliceSize > mnCurrMaxSize)) ) 434 StartContinue(); 435 UpdateSizeVars( 0 ); 436 437 nRet = (mnMaxSliceSize > 0) ? (mnMaxSliceSize - mnSliceSize) : (mnCurrMaxSize - mnCurrSize); 438 } 439 return nRet; 440 } 441 442 void XclExpStream::WriteRawZeroBytes( std::size_t nBytes ) 443 { 444 const sal_uInt32 nData = 0; 445 std::size_t nBytesLeft = nBytes; 446 while( nBytesLeft >= sizeof( nData ) ) 447 { 448 mrStrm.WriteUInt32( nData ); 449 nBytesLeft -= sizeof( nData ); 450 } 451 if( nBytesLeft ) 452 mrStrm.WriteBytes(&nData, nBytesLeft); 453 } 454 455 XclExpBiff8Encrypter::XclExpBiff8Encrypter( const XclExpRoot& rRoot ) : 456 mnOldPos(STREAM_SEEK_TO_END), 457 mbValid(false) 458 { 459 Sequence< NamedValue > aEncryptionData = rRoot.GetEncryptionData(); 460 if( !aEncryptionData.hasElements() ) 461 // Empty password. Get the default biff8 password. 462 aEncryptionData = XclExpRoot::GenerateDefaultEncryptionData(); 463 Init( aEncryptionData ); 464 } 465 466 XclExpBiff8Encrypter::~XclExpBiff8Encrypter() 467 { 468 } 469 470 void XclExpBiff8Encrypter::GetSaltDigest( sal_uInt8 pnSaltDigest[16] ) const 471 { 472 if ( sizeof( mpnSaltDigest ) == 16 ) 473 memcpy( pnSaltDigest, mpnSaltDigest, 16 ); 474 } 475 476 void XclExpBiff8Encrypter::GetSalt( sal_uInt8 pnSalt[16] ) const 477 { 478 if ( sizeof( mpnSalt ) == 16 ) 479 memcpy( pnSalt, mpnSalt, 16 ); 480 } 481 482 void XclExpBiff8Encrypter::GetDocId( sal_uInt8 pnDocId[16] ) const 483 { 484 if ( sizeof( mpnDocId ) == 16 ) 485 memcpy( pnDocId, mpnDocId, 16 ); 486 } 487 488 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt8 nData ) 489 { 490 vector<sal_uInt8> aByte(1); 491 aByte[0] = nData; 492 EncryptBytes(rStrm, aByte); 493 } 494 495 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt16 nData ) 496 { 497 ::std::vector<sal_uInt8> pnBytes(2); 498 pnBytes[0] = nData & 0xFF; 499 pnBytes[1] = (nData >> 8) & 0xFF; 500 EncryptBytes(rStrm, pnBytes); 501 } 502 503 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_uInt32 nData ) 504 { 505 ::std::vector<sal_uInt8> pnBytes(4); 506 pnBytes[0] = nData & 0xFF; 507 pnBytes[1] = (nData >> 8) & 0xFF; 508 pnBytes[2] = (nData >> 16) & 0xFF; 509 pnBytes[3] = (nData >> 24) & 0xFF; 510 EncryptBytes(rStrm, pnBytes); 511 } 512 513 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, float fValue ) 514 { 515 ::std::vector<sal_uInt8> pnBytes(4); 516 memcpy(pnBytes.data(), &fValue, 4); 517 EncryptBytes(rStrm, pnBytes); 518 } 519 520 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, double fValue ) 521 { 522 ::std::vector<sal_uInt8> pnBytes(8); 523 memcpy(pnBytes.data(), &fValue, 8); 524 EncryptBytes(rStrm, pnBytes); 525 } 526 527 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int8 nData ) 528 { 529 Encrypt(rStrm, static_cast<sal_uInt8>(nData)); 530 } 531 532 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int16 nData ) 533 { 534 Encrypt(rStrm, static_cast<sal_uInt16>(nData)); 535 } 536 537 void XclExpBiff8Encrypter::Encrypt( SvStream& rStrm, sal_Int32 nData ) 538 { 539 Encrypt(rStrm, static_cast<sal_uInt32>(nData)); 540 } 541 542 void XclExpBiff8Encrypter::Init( const Sequence< NamedValue >& rEncryptionData ) 543 { 544 mbValid = false; 545 546 if( maCodec.InitCodec( rEncryptionData ) ) 547 { 548 maCodec.GetDocId( mpnDocId ); 549 550 // generate the salt here 551 rtlRandomPool aRandomPool = rtl_random_createPool (); 552 rtl_random_getBytes( aRandomPool, mpnSalt, 16 ); 553 rtl_random_destroyPool( aRandomPool ); 554 555 memset( mpnSaltDigest, 0, sizeof( mpnSaltDigest ) ); 556 557 // generate salt hash. 558 ::msfilter::MSCodec_Std97 aCodec; 559 aCodec.InitCodec( rEncryptionData ); 560 aCodec.CreateSaltDigest( mpnSalt, mpnSaltDigest ); 561 562 // verify to make sure it's in good shape. 563 mbValid = maCodec.VerifyKey( mpnSalt, mpnSaltDigest ); 564 } 565 } 566 567 sal_uInt32 XclExpBiff8Encrypter::GetBlockPos( std::size_t nStrmPos ) 568 { 569 return static_cast< sal_uInt32 >( nStrmPos / EXC_ENCR_BLOCKSIZE ); 570 } 571 572 sal_uInt16 XclExpBiff8Encrypter::GetOffsetInBlock( std::size_t nStrmPos ) 573 { 574 return static_cast< sal_uInt16 >( nStrmPos % EXC_ENCR_BLOCKSIZE ); 575 } 576 577 void XclExpBiff8Encrypter::EncryptBytes( SvStream& rStrm, vector<sal_uInt8>& aBytes ) 578 { 579 sal_uInt64 nStrmPos = rStrm.Tell(); 580 sal_uInt16 nBlockOffset = GetOffsetInBlock(nStrmPos); 581 sal_uInt32 nBlockPos = GetBlockPos(nStrmPos); 582 583 #if DEBUG_XL_ENCRYPTION 584 fprintf(stdout, "XclExpBiff8Encrypter::EncryptBytes: stream pos = %ld offset in block = %d block pos = %ld\n", 585 nStrmPos, nBlockOffset, nBlockPos); 586 #endif 587 588 sal_uInt16 nSize = static_cast< sal_uInt16 >( aBytes.size() ); 589 if (nSize == 0) 590 return; 591 592 #if DEBUG_XL_ENCRYPTION 593 fprintf(stdout, "RAW: "); 594 for (sal_uInt16 i = 0; i < nSize; ++i) 595 fprintf(stdout, "%2.2X ", aBytes[i]); 596 fprintf(stdout, "\n"); 597 #endif 598 599 if (mnOldPos != nStrmPos) 600 { 601 sal_uInt16 nOldOffset = GetOffsetInBlock(mnOldPos); 602 sal_uInt32 nOldBlockPos = GetBlockPos(mnOldPos); 603 604 if ( (nBlockPos != nOldBlockPos) || (nBlockOffset < nOldOffset) ) 605 { 606 maCodec.InitCipher(nBlockPos); 607 nOldOffset = 0; 608 } 609 610 if (nBlockOffset > nOldOffset) 611 maCodec.Skip(nBlockOffset - nOldOffset); 612 } 613 614 sal_uInt16 nBytesLeft = nSize; 615 sal_uInt16 nPos = 0; 616 while (nBytesLeft > 0) 617 { 618 sal_uInt16 nBlockLeft = EXC_ENCR_BLOCKSIZE - nBlockOffset; 619 sal_uInt16 nEncBytes = ::std::min(nBlockLeft, nBytesLeft); 620 621 bool bRet = maCodec.Encode(&aBytes[nPos], nEncBytes, &aBytes[nPos], nEncBytes); 622 OSL_ENSURE(bRet, "XclExpBiff8Encrypter::EncryptBytes: encryption failed!!"); 623 624 std::size_t nRet = rStrm.WriteBytes(&aBytes[nPos], nEncBytes); 625 OSL_ENSURE(nRet == nEncBytes, "XclExpBiff8Encrypter::EncryptBytes: fail to write to stream!!"); 626 627 nStrmPos = rStrm.Tell(); 628 nBlockOffset = GetOffsetInBlock(nStrmPos); 629 nBlockPos = GetBlockPos(nStrmPos); 630 if (nBlockOffset == 0) 631 maCodec.InitCipher(nBlockPos); 632 633 nBytesLeft -= nEncBytes; 634 nPos += nEncBytes; 635 } 636 mnOldPos = nStrmPos; 637 } 638 639 static const char* lcl_GetErrorString( FormulaError nScErrCode ) 640 { 641 sal_uInt8 nXclErrCode = XclTools::GetXclErrorCode( nScErrCode ); 642 switch( nXclErrCode ) 643 { 644 case EXC_ERR_NULL: return "#NULL!"; 645 case EXC_ERR_DIV0: return "#DIV/0!"; 646 case EXC_ERR_VALUE: return "#VALUE!"; 647 case EXC_ERR_REF: return "#REF!"; 648 case EXC_ERR_NAME: return "#NAME?"; 649 case EXC_ERR_NUM: return "#NUM!"; 650 case EXC_ERR_NA: 651 default: return "#N/A"; 652 } 653 } 654 655 void XclXmlUtils::GetFormulaTypeAndValue( ScFormulaCell& rCell, const char*& rsType, OUString& rsValue ) 656 { 657 sc::FormulaResultValue aResValue = rCell.GetResult(); 658 659 switch (aResValue.meType) 660 { 661 case sc::FormulaResultValue::Error: 662 rsType = "e"; 663 rsValue = ToOUString(lcl_GetErrorString(aResValue.mnError)); 664 break; 665 case sc::FormulaResultValue::Value: 666 rsType = "n"; 667 rsValue = OUString::number(aResValue.mfValue); 668 break; 669 case sc::FormulaResultValue::String: 670 rsType = "str"; 671 rsValue = rCell.GetString().getString(); 672 break; 673 case sc::FormulaResultValue::Invalid: 674 default: 675 // TODO : double-check this to see if this is correct. 676 rsType = "inlineStr"; 677 rsValue = rCell.GetString().getString(); 678 } 679 } 680 681 OUString XclXmlUtils::GetStreamName( const char* sStreamDir, const char* sStream, sal_Int32 nId ) 682 { 683 OUStringBuffer sBuf; 684 if( sStreamDir ) 685 sBuf.appendAscii( sStreamDir ); 686 sBuf.appendAscii( sStream ); 687 if( nId ) 688 sBuf.append( nId ); 689 if( strstr(sStream, "vml") ) 690 sBuf.append( ".vml" ); 691 else 692 sBuf.append( ".xml" ); 693 return sBuf.makeStringAndClear(); 694 } 695 696 OString XclXmlUtils::ToOString( const Color& rColor ) 697 { 698 char buf[9]; 699 sprintf( buf, "%.2X%.2X%.2X%.2X", 0xFF-rColor.GetTransparency(), rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue() ); 700 buf[8] = '\0'; 701 return buf; 702 } 703 704 OStringBuffer& XclXmlUtils::ToOString( OStringBuffer& s, const ScAddress& rAddress ) 705 { 706 rAddress.Format(s, ScRefFlags::VALID, nullptr, ScAddress::Details( FormulaGrammar::CONV_XL_A1)); 707 return s; 708 } 709 710 OString XclXmlUtils::ToOString( const ScfUInt16Vec& rBuffer ) 711 { 712 if(rBuffer.empty()) 713 return OString(); 714 715 const sal_uInt16* pBuffer = rBuffer.data(); 716 return OString( 717 reinterpret_cast<sal_Unicode const *>(pBuffer), rBuffer.size(), 718 RTL_TEXTENCODING_UTF8); 719 } 720 721 OString XclXmlUtils::ToOString( const ScRange& rRange, bool bFullAddressNotation ) 722 { 723 OUString sRange(rRange.Format( ScRefFlags::VALID, nullptr, 724 ScAddress::Details( FormulaGrammar::CONV_XL_A1 ), 725 bFullAddressNotation ) ); 726 return sRange.toUtf8(); 727 } 728 729 OString XclXmlUtils::ToOString( const ScRangeList& rRangeList ) 730 { 731 OUString s; 732 rRangeList.Format(s, ScRefFlags::VALID, nullptr, FormulaGrammar::CONV_XL_OOX, ' '); 733 return s.toUtf8(); 734 } 735 736 static ScAddress lcl_ToAddress( const XclAddress& rAddress ) 737 { 738 ScAddress aAddress; 739 740 // For some reason, ScRange::Format() returns omits row numbers if 741 // the row is >= MAXROW or the column is >= MAXCOL, and Excel doesn't 742 // like "A:IV" (i.e. no row numbers). Prevent this. 743 // KOHEI: Find out if the above comment is still true. 744 aAddress.SetRow( std::min<sal_Int32>( rAddress.mnRow, MAXROW ) ); 745 aAddress.SetCol( static_cast<sal_Int16>(std::min<sal_Int32>( rAddress.mnCol, MAXCOL )) ); 746 747 return aAddress; 748 } 749 750 OStringBuffer& XclXmlUtils::ToOString( OStringBuffer& s, const XclAddress& rAddress ) 751 { 752 return ToOString( s, lcl_ToAddress( rAddress )); 753 } 754 755 OString XclXmlUtils::ToOString( const XclExpString& s ) 756 { 757 OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" ); 758 return ToOString( s.GetUnicodeBuffer() ); 759 } 760 761 static ScRange lcl_ToRange( const XclRange& rRange ) 762 { 763 ScRange aRange; 764 765 aRange.aStart = lcl_ToAddress( rRange.maFirst ); 766 aRange.aEnd = lcl_ToAddress( rRange.maLast ); 767 768 return aRange; 769 } 770 771 OString XclXmlUtils::ToOString( const XclRangeList& rRanges ) 772 { 773 ScRangeList aRanges; 774 for( const auto& rRange : rRanges ) 775 { 776 aRanges.push_back( lcl_ToRange( rRange ) ); 777 } 778 return ToOString( aRanges ); 779 } 780 781 OUString XclXmlUtils::ToOUString( const char* s ) 782 { 783 return OUString( s, static_cast<sal_Int32>(strlen( s )), RTL_TEXTENCODING_ASCII_US ); 784 } 785 786 OUString XclXmlUtils::ToOUString( const ScfUInt16Vec& rBuf, sal_Int32 nStart, sal_Int32 nLength ) 787 { 788 if( nLength == -1 || ( nLength > (static_cast<sal_Int32>(rBuf.size()) - nStart) ) ) 789 nLength = (rBuf.size() - nStart); 790 791 return nLength > 0 792 ? OUString( 793 reinterpret_cast<sal_Unicode const *>(&rBuf[nStart]), nLength) 794 : OUString(); 795 } 796 797 OUString XclXmlUtils::ToOUString( 798 sc::CompileFormulaContext& rCtx, const ScAddress& rAddress, const ScTokenArray* pTokenArray ) 799 { 800 ScCompiler aCompiler( rCtx, rAddress, const_cast<ScTokenArray&>(*pTokenArray)); 801 802 /* TODO: isn't this the same as passed in rCtx and thus superfluous? */ 803 aCompiler.SetGrammar(FormulaGrammar::GRAM_OOXML); 804 805 OUStringBuffer aBuffer( pTokenArray->GetLen() * 5 ); 806 aCompiler.CreateStringFromTokenArray( aBuffer ); 807 return aBuffer.makeStringAndClear(); 808 } 809 810 OUString XclXmlUtils::ToOUString( const XclExpString& s ) 811 { 812 OSL_ENSURE( !s.IsRich(), "XclXmlUtils::ToOString(XclExpString): rich text string found!" ); 813 return ToOUString( s.GetUnicodeBuffer() ); 814 } 815 816 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int32 nValue ) 817 { 818 pStream->startElement(nElement); 819 pStream->write( nValue ); 820 pStream->endElement( nElement ); 821 822 return pStream; 823 } 824 825 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, sal_Int64 nValue ) 826 { 827 pStream->startElement(nElement); 828 pStream->write( nValue ); 829 pStream->endElement( nElement ); 830 831 return pStream; 832 } 833 834 sax_fastparser::FSHelperPtr XclXmlUtils::WriteElement( sax_fastparser::FSHelperPtr pStream, sal_Int32 nElement, const char* sValue ) 835 { 836 pStream->startElement(nElement); 837 pStream->write( sValue ); 838 pStream->endElement( nElement ); 839 840 return pStream; 841 } 842 843 static void lcl_WriteValue( const sax_fastparser::FSHelperPtr& rStream, sal_Int32 nElement, const char* pValue ) 844 { 845 if( !pValue ) 846 return; 847 rStream->singleElement(nElement, XML_val, pValue); 848 } 849 850 static const char* lcl_GetUnderlineStyle( FontLineStyle eUnderline, bool& bHaveUnderline ) 851 { 852 bHaveUnderline = true; 853 switch( eUnderline ) 854 { 855 // OOXTODO: doubleAccounting, singleAccounting 856 // OOXTODO: what should be done with the other FontLineStyle values? 857 case LINESTYLE_SINGLE: return "single"; 858 case LINESTYLE_DOUBLE: return "double"; 859 case LINESTYLE_NONE: 860 default: bHaveUnderline = false; return "none"; 861 } 862 } 863 864 static const char* lcl_ToVerticalAlignmentRun( SvxEscapement eEscapement, bool& bHaveAlignment ) 865 { 866 bHaveAlignment = true; 867 switch( eEscapement ) 868 { 869 case SvxEscapement::Superscript: return "superscript"; 870 case SvxEscapement::Subscript: return "subscript"; 871 case SvxEscapement::Off: 872 default: bHaveAlignment = false; return "baseline"; 873 } 874 } 875 876 sax_fastparser::FSHelperPtr XclXmlUtils::WriteFontData( sax_fastparser::FSHelperPtr pStream, const XclFontData& rFontData, sal_Int32 nFontId ) 877 { 878 bool bHaveUnderline, bHaveVertAlign; 879 const char* pUnderline = lcl_GetUnderlineStyle( rFontData.GetScUnderline(), bHaveUnderline ); 880 const char* pVertAlign = lcl_ToVerticalAlignmentRun( rFontData.GetScEscapement(), bHaveVertAlign ); 881 882 lcl_WriteValue( pStream, XML_b, rFontData.mnWeight > 400 ? ToPsz( true ) : nullptr ); 883 lcl_WriteValue( pStream, XML_i, rFontData.mbItalic ? ToPsz( true ) : nullptr ); 884 lcl_WriteValue( pStream, XML_strike, rFontData.mbStrikeout ? ToPsz( true ) : nullptr ); 885 // OOXTODO: lcl_WriteValue( rStream, XML_condense, ); // mac compatibility setting 886 // OOXTODO: lcl_WriteValue( rStream, XML_extend, ); // compatibility setting 887 lcl_WriteValue( pStream, XML_outline, rFontData.mbOutline ? ToPsz( true ) : nullptr ); 888 lcl_WriteValue( pStream, XML_shadow, rFontData.mbShadow ? ToPsz( true ) : nullptr ); 889 lcl_WriteValue( pStream, XML_u, bHaveUnderline ? pUnderline : nullptr ); 890 lcl_WriteValue( pStream, XML_vertAlign, bHaveVertAlign ? pVertAlign : nullptr ); 891 lcl_WriteValue( pStream, XML_sz, OString::number( rFontData.mnHeight / 20.0 ).getStr() ); // Twips->Pt 892 if( rFontData.maColor != Color( 0xFF, 0xFF, 0xFF, 0xFF ) ) 893 pStream->singleElement( XML_color, 894 // OOXTODO: XML_auto, bool 895 // OOXTODO: XML_indexed, uint 896 XML_rgb, XclXmlUtils::ToOString(rFontData.maColor) 897 // OOXTODO: XML_theme, index into <clrScheme/> 898 // OOXTODO: XML_tint, double 899 ); 900 lcl_WriteValue( pStream, nFontId, rFontData.maName.toUtf8().getStr() ); 901 lcl_WriteValue( pStream, XML_family, OString::number( rFontData.mnFamily ).getStr() ); 902 lcl_WriteValue( pStream, XML_charset, rFontData.mnCharSet != 0 ? OString::number( rFontData.mnCharSet ).getStr() : nullptr ); 903 904 return pStream; 905 } 906 907 XclExpXmlStream::XclExpXmlStream( const uno::Reference< XComponentContext >& rCC, bool bExportVBA, bool bExportTemplate ) 908 : XmlFilterBase( rCC ), 909 mpRoot( nullptr ), 910 mbExportVBA(bExportVBA), 911 mbExportTemplate(bExportTemplate) 912 { 913 } 914 915 XclExpXmlStream::~XclExpXmlStream() 916 { 917 assert(maStreams.empty() && "Forgotten PopStream()?"); 918 } 919 920 sax_fastparser::FSHelperPtr& XclExpXmlStream::GetCurrentStream() 921 { 922 OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::GetCurrentStream - no current stream" ); 923 return maStreams.top(); 924 } 925 926 void XclExpXmlStream::PushStream( sax_fastparser::FSHelperPtr const & aStream ) 927 { 928 maStreams.push( aStream ); 929 } 930 931 void XclExpXmlStream::PopStream() 932 { 933 OSL_ENSURE( !maStreams.empty(), "XclExpXmlStream::PopStream - stack is empty!" ); 934 maStreams.pop(); 935 } 936 937 sax_fastparser::FSHelperPtr XclExpXmlStream::GetStreamForPath( const OUString& sPath ) 938 { 939 if( maOpenedStreamMap.find( sPath ) == maOpenedStreamMap.end() ) 940 return sax_fastparser::FSHelperPtr(); 941 return maOpenedStreamMap[ sPath ].second; 942 } 943 944 void XclExpXmlStream::WriteAttribute(sal_Int32 nAttr, const OUString& sVal) 945 { 946 GetCurrentStream()->write(" ")->writeId(nAttr)->write("=\"")->writeEscaped(sVal)->write("\""); 947 } 948 949 sax_fastparser::FSHelperPtr XclExpXmlStream::CreateOutputStream ( 950 const OUString& sFullStream, 951 const OUString& sRelativeStream, 952 const uno::Reference< XOutputStream >& xParentRelation, 953 const char* sContentType, 954 const char* sRelationshipType, 955 OUString* pRelationshipId ) 956 { 957 OUString sRelationshipId; 958 if (xParentRelation.is()) 959 sRelationshipId = addRelation( xParentRelation, OUString::createFromAscii( sRelationshipType), sRelativeStream ); 960 else 961 sRelationshipId = addRelation( OUString::createFromAscii( sRelationshipType ), sRelativeStream ); 962 963 if( pRelationshipId ) 964 *pRelationshipId = sRelationshipId; 965 966 sax_fastparser::FSHelperPtr p = openFragmentStreamWithSerializer( sFullStream, OUString::createFromAscii( sContentType ) ); 967 968 maOpenedStreamMap[ sFullStream ] = std::make_pair( sRelationshipId, p ); 969 970 return p; 971 } 972 973 bool XclExpXmlStream::importDocument() throw() 974 { 975 return false; 976 } 977 978 oox::vml::Drawing* XclExpXmlStream::getVmlDrawing() 979 { 980 return nullptr; 981 } 982 983 const oox::drawingml::Theme* XclExpXmlStream::getCurrentTheme() const 984 { 985 return nullptr; 986 } 987 988 oox::drawingml::table::TableStyleListPtr XclExpXmlStream::getTableStyles() 989 { 990 return oox::drawingml::table::TableStyleListPtr(); 991 } 992 993 oox::drawingml::chart::ChartConverter* XclExpXmlStream::getChartConverter() 994 { 995 // DO NOT CALL 996 return nullptr; 997 } 998 999 ScDocShell* XclExpXmlStream::getDocShell() 1000 { 1001 uno::Reference< XInterface > xModel( getModel(), UNO_QUERY ); 1002 1003 ScModelObj *pObj = dynamic_cast < ScModelObj* >( xModel.get() ); 1004 1005 if ( pObj ) 1006 return static_cast < ScDocShell* >( pObj->GetEmbeddedObject() ); 1007 1008 return nullptr; 1009 } 1010 1011 bool XclExpXmlStream::exportDocument() 1012 { 1013 ScDocShell* pShell = getDocShell(); 1014 ScDocument& rDoc = pShell->GetDocument(); 1015 ScRefreshTimerProtector aProt(rDoc.GetRefreshTimerControlAddress()); 1016 1017 uno::Reference<task::XStatusIndicator> xStatusIndicator = getStatusIndicator(); 1018 1019 if (xStatusIndicator.is()) 1020 xStatusIndicator->start(ScResId(STR_SAVE_DOC), 100); 1021 1022 // NOTE: Don't use SotStorage or SvStream any more, and never call 1023 // SfxMedium::GetOutStream() anywhere in the xlsx export filter code! 1024 // Instead, write via XOutputStream instance. 1025 tools::SvRef<SotStorage> rStorage = static_cast<SotStorage*>(nullptr); 1026 XclExpObjList::ResetCounters(); 1027 1028 XclExpRootData aData( 1029 EXC_BIFF8, *pShell->GetMedium (), rStorage, rDoc, 1030 msfilter::util::getBestTextEncodingFromLocale( 1031 Application::GetSettings().GetLanguageTag().getLocale())); 1032 aData.meOutput = EXC_OUTPUT_XML_2007; 1033 aData.maXclMaxPos.Set( EXC_MAXCOL_XML_2007, EXC_MAXROW_XML_2007, EXC_MAXTAB_XML_2007 ); 1034 aData.maMaxPos.SetCol( ::std::min( aData.maScMaxPos.Col(), aData.maXclMaxPos.Col() ) ); 1035 aData.maMaxPos.SetRow( ::std::min( aData.maScMaxPos.Row(), aData.maXclMaxPos.Row() ) ); 1036 aData.maMaxPos.SetTab( ::std::min( aData.maScMaxPos.Tab(), aData.maXclMaxPos.Tab() ) ); 1037 aData.mpCompileFormulaCxt.reset( new sc::CompileFormulaContext(&rDoc) ); 1038 // set target path to get correct relative links to target document, not source 1039 INetURLObject aPath(getFileUrl()); 1040 aData.maBasePath = aPath.GetPath() + "\\"; 1041 aData.maBasePath = "file:///" + aData.maBasePath.replace('\\', '/'); 1042 1043 XclExpRoot aRoot( aData ); 1044 1045 mpRoot = &aRoot; 1046 aRoot.GetOldRoot().pER = &aRoot; 1047 aRoot.GetOldRoot().eDateiTyp = Biff8; 1048 // Get the viewsettings before processing 1049 if( ScDocShell::GetViewData() ) 1050 ScDocShell::GetViewData()->WriteExtOptions( mpRoot->GetExtDocOptions() ); 1051 1052 OUString const workbook = "xl/workbook.xml"; 1053 const char* pWorkbookContentType = nullptr; 1054 if (mbExportVBA) 1055 { 1056 if (mbExportTemplate) 1057 { 1058 pWorkbookContentType = "application/vnd.ms-excel.template.macroEnabled.main+xml"; 1059 } 1060 else 1061 { 1062 pWorkbookContentType = "application/vnd.ms-excel.sheet.macroEnabled.main+xml"; 1063 } 1064 } 1065 else 1066 { 1067 if (mbExportTemplate) 1068 { 1069 pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"; 1070 } 1071 else 1072 { 1073 pWorkbookContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"; 1074 } 1075 } 1076 1077 PushStream( CreateOutputStream( workbook, workbook, 1078 uno::Reference <XOutputStream>(), 1079 pWorkbookContentType, 1080 OUStringToOString(oox::getRelationship(Relationship::OFFICEDOCUMENT), RTL_TEXTENCODING_UTF8).getStr() ) ); 1081 1082 if (mbExportVBA) 1083 { 1084 VbaExport aExport(getModel()); 1085 if (aExport.containsVBAProject()) 1086 { 1087 SvMemoryStream aVbaStream(4096, 4096); 1088 tools::SvRef<SotStorage> pVBAStorage(new SotStorage(aVbaStream)); 1089 aExport.exportVBA( pVBAStorage.get() ); 1090 aVbaStream.Seek(0); 1091 css::uno::Reference<css::io::XInputStream> xVBAStream( 1092 new utl::OInputStreamWrapper(aVbaStream)); 1093 css::uno::Reference<css::io::XOutputStream> xVBAOutput = 1094 openFragmentStream("xl/vbaProject.bin", "application/vnd.ms-office.vbaProject"); 1095 comphelper::OStorageHelper::CopyInputToOutput(xVBAStream, xVBAOutput); 1096 1097 addRelation(GetCurrentStream()->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), "vbaProject.bin"); 1098 } 1099 } 1100 1101 // destruct at the end of the block 1102 { 1103 ExcDocument aDocRoot( aRoot ); 1104 if (xStatusIndicator.is()) 1105 xStatusIndicator->setValue(10); 1106 aDocRoot.ReadDoc(); 1107 if (xStatusIndicator.is()) 1108 xStatusIndicator->setValue(40); 1109 aDocRoot.WriteXml( *this ); 1110 } 1111 1112 PopStream(); 1113 // Free all FSHelperPtr, to flush data before committing storage 1114 maOpenedStreamMap.clear(); 1115 1116 commitStorage(); 1117 1118 if (xStatusIndicator.is()) 1119 xStatusIndicator->end(); 1120 mpRoot = nullptr; 1121 return true; 1122 } 1123 1124 ::oox::ole::VbaProject* XclExpXmlStream::implCreateVbaProject() const 1125 { 1126 return new ::oox::xls::ExcelVbaProject( getComponentContext(), uno::Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) ); 1127 } 1128 1129 OUString XclExpXmlStream::getImplementationName() 1130 { 1131 return "TODO"; 1132 } 1133 1134 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1135
