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 10 #include <sal/config.h> 11 12 #include <cassert> 13 #include <cmath> 14 #include <random> 15 16 #include <oox/ole/vbaexport.hxx> 17 18 #include <tools/stream.hxx> 19 20 #include <com/sun/star/beans/XPropertySet.hpp> 21 #include <com/sun/star/script/XLibraryContainer.hpp> 22 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp> 23 #include <com/sun/star/script/vba/XVBACompatibility.hpp> 24 #include <com/sun/star/frame/XModel.hpp> 25 26 #include <ooo/vba/excel/XWorkbook.hpp> 27 28 #include <oox/helper/binaryoutputstream.hxx> 29 #include <oox/helper/propertyset.hxx> 30 #include <oox/token/properties.hxx> 31 32 #include <sot/storage.hxx> 33 34 #include <comphelper/xmltools.hxx> 35 36 #define USE_UTF8_CODEPAGE 0 37 #if USE_UTF8_CODEPAGE 38 #define CODEPAGE_MS 65001 39 #define CODEPAGE RTL_TEXTENCODING_UTF8 40 #else 41 #define CODEPAGE_MS 1252 42 #define CODEPAGE RTL_TEXTENCODING_MS_1252 43 #endif 44 45 #define VBA_EXPORT_DEBUG 0 46 #define VBA_USE_ORIGINAL_WM_STREAM 0 47 #define VBA_USE_ORIGINAL_DIR_STREAM 0 48 #define VBA_USE_ORIGINAL_PROJECT_STREAM 0 49 #define VBA_USE_ORIGINAL_VBA_PROJECT 0 50 51 /* Enable to see VBA Encryption work. For now the input data and length values 52 * for encryption correspond to the case when the VBA macro is not protected. 53 */ 54 #define VBA_ENCRYPTION 1 55 56 namespace { 57 58 void exportString(SvStream& rStrm, const OUString& rString) 59 { 60 OString aStringCorrectCodepage = OUStringToOString(rString, CODEPAGE); 61 rStrm.WriteOString(aStringCorrectCodepage); 62 } 63 64 void exportUTF16String(SvStream& rStrm, const OUString& rString) 65 { 66 sal_Int32 n = rString.getLength(); 67 const sal_Unicode* pString = rString.getStr(); 68 for (sal_Int32 i = 0; i < n; ++i) 69 { 70 sal_Unicode character = pString[i]; 71 rStrm.WriteUnicode(character); 72 } 73 } 74 75 bool isWorkbook(const css::uno::Reference<css::uno::XInterface>& xInterface) 76 { 77 css::uno::Reference<ooo::vba::excel::XWorkbook> xWorkbook(xInterface, css::uno::UNO_QUERY); 78 return xWorkbook.is(); 79 } 80 81 OUString createHexStringFromDigit(sal_uInt8 nDigit) 82 { 83 OUString aString = OUString::number( nDigit, 16 ); 84 if(aString.getLength() == 1) 85 aString = OUString::number(0) + aString; 86 return aString.toAsciiUpperCase(); 87 } 88 89 } 90 91 VBACompressionChunk::VBACompressionChunk(SvStream& rCompressedStream, const sal_uInt8* pData, std::size_t nChunkSize) 92 : mrCompressedStream(rCompressedStream) 93 , mpUncompressedData(pData) 94 , mpCompressedChunkStream(nullptr) 95 , mnChunkSize(nChunkSize) 96 , mnCompressedCurrent(0) 97 , mnCompressedEnd(0) 98 , mnDecompressedCurrent(0) 99 , mnDecompressedEnd(0) 100 { 101 } 102 103 static void setUInt16(sal_uInt8* pBuffer, size_t nPos, sal_uInt16 nVal) 104 { 105 pBuffer[nPos] = nVal & 0xFF; 106 pBuffer[nPos+1] = (nVal & 0xFF00) >> 8; 107 } 108 109 sal_uInt16 VBACompressionChunk::handleHeader(bool bCompressed) 110 { 111 // handle header bytes 112 size_t nSize = mnCompressedCurrent; 113 sal_uInt16 nHeader = 0; 114 PackCompressedChunkSize(nSize, nHeader); 115 PackCompressedChunkFlag(bCompressed, nHeader); 116 PackCompressedChunkSignature(nHeader); 117 118 return nHeader; 119 } 120 121 // section 2.4.1.3.7 122 void VBACompressionChunk::write() 123 { 124 125 mnDecompressedCurrent = 0; 126 mnCompressedCurrent = 2; 127 mnCompressedEnd = 4098; 128 mnDecompressedEnd = std::min<sal_uInt64>(4096, mnChunkSize); 129 130 // if that stream becomes larger than 4096 bytes then 131 // we use the uncompressed stream 132 sal_uInt8 pCompressedChunkStream[4098]; 133 mpCompressedChunkStream = pCompressedChunkStream; 134 135 while (mnDecompressedCurrent < mnDecompressedEnd 136 && mnCompressedCurrent < mnCompressedEnd) 137 { 138 // compress token sequence 139 compressTokenSequence(); 140 } 141 142 if (mnDecompressedCurrent < mnDecompressedEnd) 143 { 144 sal_uInt64 nChunkStart = mrCompressedStream.Tell(); 145 mrCompressedStream.WriteUInt16(0); 146 writeRawChunk(); 147 mrCompressedStream.Seek(nChunkStart); 148 sal_uInt16 nHeader = handleHeader(false); 149 mrCompressedStream.WriteUInt16(nHeader); 150 } 151 else 152 { 153 sal_uInt16 nHeader = handleHeader(true); 154 setUInt16(pCompressedChunkStream, 0, nHeader); 155 // copy the compressed stream to our output stream 156 mrCompressedStream.WriteBytes(pCompressedChunkStream, mnCompressedCurrent); 157 } 158 } 159 160 // section 2.4.1.3.13 161 void VBACompressionChunk::PackCompressedChunkSize(size_t nSize, sal_uInt16& rHeader) 162 { 163 sal_uInt16 nTemp1 = rHeader & 0xF000; 164 sal_uInt16 nTemp2 = nSize - 3; 165 rHeader = nTemp1 | nTemp2; 166 } 167 168 // section 2.4.1.3.16 169 void VBACompressionChunk::PackCompressedChunkFlag(bool bCompressed, sal_uInt16& rHeader) 170 { 171 sal_uInt16 nTemp1 = rHeader & 0x7FFF; 172 sal_uInt16 nTemp2 = static_cast<sal_uInt16>(bCompressed) << 15; 173 rHeader = nTemp1 | nTemp2; 174 } 175 176 // section 2.4.1.3.14 177 void VBACompressionChunk::PackCompressedChunkSignature(sal_uInt16& rHeader) 178 { 179 sal_Int32 nTemp = rHeader & 0x8FFFF; 180 rHeader = nTemp | 0x3000; 181 } 182 183 // section 2.4.1.3.8 184 void VBACompressionChunk::compressTokenSequence() 185 { 186 sal_uInt64 nFlagByteIndex = mnCompressedCurrent; 187 sal_uInt8 nFlagByte = 0; 188 ++mnCompressedCurrent; 189 for (size_t index = 0; index <= 7; ++index) 190 { 191 if (mnDecompressedCurrent < mnDecompressedEnd 192 && mnCompressedCurrent < mnCompressedEnd) 193 { 194 compressToken(index, nFlagByte); 195 } 196 } 197 mpCompressedChunkStream[nFlagByteIndex] = nFlagByte; 198 } 199 200 // section 2.4.1.3.9 201 void VBACompressionChunk::compressToken(size_t index, sal_uInt8& nFlagByte) 202 { 203 size_t nLength = 0; 204 size_t nOffset = 0; 205 match(nLength, nOffset); 206 if (nOffset != 0) 207 { 208 if (mnCompressedCurrent + 1 < mnCompressedEnd) 209 { 210 sal_uInt16 nToken = CopyToken(nLength, nOffset); 211 setUInt16(mpCompressedChunkStream, mnCompressedCurrent, nToken); 212 SetFlagBit(index, true, nFlagByte); 213 mnCompressedCurrent += 2; 214 mnDecompressedCurrent += nLength; 215 } 216 else 217 { 218 mnCompressedCurrent = mnCompressedEnd; 219 } 220 } 221 else 222 { 223 if (mnCompressedCurrent + 1 < mnCompressedEnd) 224 { 225 mpCompressedChunkStream[mnCompressedCurrent] = mpUncompressedData[mnDecompressedCurrent]; 226 ++mnCompressedCurrent; 227 ++mnDecompressedCurrent; 228 } 229 else 230 { 231 mnCompressedCurrent = mnCompressedEnd; 232 } 233 } 234 } 235 236 // section 2.4.1.3.18 237 void VBACompressionChunk::SetFlagBit(size_t index, bool bVal, sal_uInt8& rFlag) 238 { 239 size_t nTemp1 = static_cast<int>(bVal) << index; 240 sal_uInt8 nTemp2 = rFlag & (~nTemp1); 241 rFlag = nTemp2 | nTemp1; 242 } 243 244 // section 2.4.1.3.19.3 245 sal_uInt16 VBACompressionChunk::CopyToken(size_t nLength, size_t nOffset) 246 { 247 sal_uInt16 nLengthMask = 0; 248 sal_uInt16 nOffsetMask = 0; 249 sal_uInt16 nBitCount = 0; 250 sal_uInt16 nMaxLength; 251 CopyTokenHelp(nLengthMask, nOffsetMask, nBitCount, nMaxLength); 252 sal_uInt16 nTemp1 = nOffset -1; 253 sal_uInt16 nTemp2 = 16 - nBitCount; 254 sal_uInt16 nTemp3 = nLength - 3; 255 sal_uInt16 nToken = (nTemp1 << nTemp2) | nTemp3; 256 return nToken; 257 } 258 259 // section 2.4.1.3.19.4 260 void VBACompressionChunk::match(size_t& rLength, size_t& rOffset) 261 { 262 size_t nBestLen = 0; 263 sal_Int32 nCandidate = mnDecompressedCurrent - 1; 264 sal_Int32 nBestCandidate = nCandidate; 265 while (nCandidate >= 0) 266 { 267 sal_Int32 nC = nCandidate; 268 sal_Int32 nD = mnDecompressedCurrent; 269 size_t nLen = 0; 270 while (nD < static_cast<sal_Int32>(mnChunkSize) // TODO: check if this needs to be including a minus -1 271 && mpUncompressedData[nC] == mpUncompressedData[nD]) 272 { 273 ++nLen; 274 ++nC; 275 ++nD; 276 } 277 if (nLen > nBestLen) 278 { 279 nBestLen = nLen; 280 nBestCandidate = nCandidate; 281 } 282 --nCandidate; 283 } 284 285 if (nBestLen >= 3) 286 { 287 sal_uInt16 nMaximumLength = 0; 288 sal_uInt16 nLengthMask, nOffsetMask, nBitCount; 289 CopyTokenHelp(nLengthMask, nOffsetMask, nBitCount, nMaximumLength); 290 rLength = std::min<sal_uInt16>(nMaximumLength, nBestLen); 291 rOffset = mnDecompressedCurrent - nBestCandidate; 292 } 293 else 294 { 295 rLength = 0; 296 rOffset = 0; 297 } 298 } 299 300 // section 2.4.1.3.19.1 301 void VBACompressionChunk::CopyTokenHelp(sal_uInt16& rLengthMask, sal_uInt16& rOffsetMask, 302 sal_uInt16& rBitCount, sal_uInt16& rMaximumLength) 303 { 304 sal_uInt16 nDifference = mnDecompressedCurrent; 305 assert(nDifference <= 4096); 306 assert(nDifference >= 1); 307 if (nDifference >= 2049) 308 rBitCount = 12; 309 else if (nDifference >= 1025) 310 rBitCount = 11; 311 else if (nDifference >= 513) 312 rBitCount = 10; 313 else if (nDifference >= 257) 314 rBitCount = 9; 315 else if (nDifference >= 129) 316 rBitCount = 8; 317 else if (nDifference >= 65) 318 rBitCount = 7; 319 else if (nDifference >= 33) 320 rBitCount = 6; 321 else if (nDifference >= 17) 322 rBitCount = 5; 323 else 324 rBitCount = 4; 325 rLengthMask = 0xffff >> rBitCount; 326 rOffsetMask = ~rLengthMask; 327 rMaximumLength = rLengthMask + 3; 328 } 329 330 // section 2.4.1.3.10 331 void VBACompressionChunk::writeRawChunk() 332 { 333 // we need to use up to 4096 bytes of the original stream 334 // and fill the rest with padding 335 mrCompressedStream.WriteBytes(mpUncompressedData, mnChunkSize); 336 std::size_t nPadding = 4096 - mnChunkSize; 337 for (size_t i = 0; i < nPadding; ++i) 338 { 339 mrCompressedStream.WriteUInt8(0); 340 } 341 } 342 343 VBACompression::VBACompression(SvStream& rCompressedStream, 344 SvMemoryStream& rUncompressedStream): 345 mrCompressedStream(rCompressedStream), 346 mrUncompressedStream(rUncompressedStream) 347 { 348 } 349 350 // section 2.4.1.3.6 351 void VBACompression::write() 352 { 353 // section 2.4.1.1.1 354 mrCompressedStream.WriteUInt8(0x01); // signature byte of a compressed container 355 bool bStreamNotEnded = true; 356 const sal_uInt8* pData = static_cast<const sal_uInt8*>(mrUncompressedStream.GetData()); 357 std::size_t nSize = mrUncompressedStream.GetEndOfData(); 358 std::size_t nRemainingSize = nSize; 359 while(bStreamNotEnded) 360 { 361 std::size_t nChunkSize = std::min<size_t>(nRemainingSize, 4096); 362 VBACompressionChunk aChunk(mrCompressedStream, &pData[nSize - nRemainingSize], nChunkSize); 363 aChunk.write(); 364 365 // update the uncompressed chunk start marker 366 nRemainingSize -= nChunkSize; 367 bStreamNotEnded = nRemainingSize != 0; 368 } 369 } 370 371 // section 2.4.3 372 #if VBA_ENCRYPTION 373 374 VBAEncryption::VBAEncryption(const sal_uInt8* pData, const sal_uInt16 length, SvStream& rEncryptedData, sal_uInt8 nProjKey) 375 :mpData(pData) 376 ,mnLength(length) 377 ,mrEncryptedData(rEncryptedData) 378 ,mnUnencryptedByte1(0) 379 ,mnEncryptedByte1(0) 380 ,mnEncryptedByte2(0) 381 ,mnProjKey(nProjKey) 382 ,mnIgnoredLength(0) 383 ,mnSeed(0x00) 384 ,mnVersionEnc(0) 385 { 386 std::random_device rd; 387 std::mt19937 gen(rd()); 388 std::uniform_int_distribution<> dis(0, 255); 389 mnSeed = dis(gen); 390 } 391 392 void VBAEncryption::writeSeed() 393 { 394 exportString(mrEncryptedData, createHexStringFromDigit(mnSeed)); 395 } 396 397 void VBAEncryption::writeVersionEnc() 398 { 399 static const sal_uInt8 mnVersion = 2; // the encrypted version 400 mnVersionEnc = mnSeed ^ mnVersion; 401 exportString(mrEncryptedData, createHexStringFromDigit(mnVersionEnc)); 402 } 403 404 sal_uInt8 VBAEncryption::calculateProjKey(const OUString& rProjectKey) 405 { 406 sal_uInt8 nProjKey = 0; 407 sal_Int32 n = rProjectKey.getLength(); 408 const sal_Unicode* pString = rProjectKey.getStr(); 409 for (sal_Int32 i = 0; i < n; ++i) 410 { 411 sal_Unicode character = pString[i]; 412 nProjKey += character; 413 } 414 415 return nProjKey; 416 } 417 418 void VBAEncryption::writeProjKeyEnc() 419 { 420 sal_uInt8 nProjKeyEnc = mnSeed ^ mnProjKey; 421 exportString(mrEncryptedData, createHexStringFromDigit(nProjKeyEnc)); 422 mnUnencryptedByte1 = mnProjKey; 423 mnEncryptedByte1 = nProjKeyEnc; // ProjKeyEnc 424 mnEncryptedByte2 = mnVersionEnc; // VersionEnc 425 } 426 427 void VBAEncryption::writeIgnoredEnc() 428 { 429 mnIgnoredLength = (mnSeed & 6) / 2; 430 for(sal_Int32 i = 1; i <= mnIgnoredLength; ++i) 431 { 432 sal_uInt8 nTempValue = 0xBE; // Any value can be assigned here 433 sal_uInt8 nByteEnc = nTempValue ^ (mnEncryptedByte2 + mnUnencryptedByte1); 434 exportString(mrEncryptedData, createHexStringFromDigit(nByteEnc)); 435 mnEncryptedByte2 = mnEncryptedByte1; 436 mnEncryptedByte1 = nByteEnc; 437 mnUnencryptedByte1 = nTempValue; 438 } 439 } 440 441 void VBAEncryption::writeDataLengthEnc() 442 { 443 sal_uInt16 temp = mnLength; 444 for(sal_Int8 i = 0; i < 4; ++i) 445 { 446 sal_uInt8 nByte = temp & 0xFF; 447 sal_uInt8 nByteEnc = nByte ^ (mnEncryptedByte2 + mnUnencryptedByte1); 448 exportString(mrEncryptedData, createHexStringFromDigit(nByteEnc)); 449 mnEncryptedByte2 = mnEncryptedByte1; 450 mnEncryptedByte1 = nByteEnc; 451 mnUnencryptedByte1 = nByte; 452 temp >>= 8; 453 } 454 } 455 456 void VBAEncryption::writeDataEnc() 457 { 458 for(sal_Int16 i = 0; i < mnLength; i++) 459 { 460 sal_uInt8 nByteEnc = mpData[i] ^ (mnEncryptedByte2 + mnUnencryptedByte1); 461 exportString(mrEncryptedData, createHexStringFromDigit(nByteEnc)); 462 mnEncryptedByte2 = mnEncryptedByte1; 463 mnEncryptedByte1 = nByteEnc; 464 mnUnencryptedByte1 = mpData[i]; 465 } 466 } 467 468 void VBAEncryption::write() 469 { 470 writeSeed(); 471 writeVersionEnc(); 472 writeProjKeyEnc(); 473 writeIgnoredEnc(); 474 writeDataLengthEnc(); 475 writeDataEnc(); 476 } 477 478 #endif 479 480 VbaExport::VbaExport(css::uno::Reference<css::frame::XModel> const & xModel): 481 mxModel(xModel) 482 { 483 } 484 485 namespace { 486 487 // section 2.3.4.2.1.1 488 void writePROJECTSYSKIND(SvStream& rStrm) 489 { 490 rStrm.WriteUInt16(0x0001); // id 491 rStrm.WriteUInt32(0x00000004); // size 492 rStrm.WriteUInt32(0x00000001); // SysKind, hard coded to 32-bin windows for now 493 } 494 495 // section 2.3.4.2.1.2 496 void writePROJECTLCID(SvStream& rStrm) 497 { 498 rStrm.WriteUInt16(0x0002); // id 499 rStrm.WriteUInt32(0x00000004); // size 500 rStrm.WriteUInt32(0x00000409); // Lcid 501 } 502 503 // section 2.3.4.2.1.3 504 void writePROJECTLCIDINVOKE(SvStream& rStrm) 505 { 506 rStrm.WriteUInt16(0x0014); // id 507 rStrm.WriteUInt32(0x00000004); // size 508 rStrm.WriteUInt32(0x00000409); // LcidInvoke 509 } 510 511 // section 2.3.4.2.1.4 512 void writePROJECTCODEPAGE(SvStream& rStrm) 513 { 514 rStrm.WriteUInt16(0x0003); // id 515 rStrm.WriteUInt32(0x00000002); // size 516 rStrm.WriteUInt16(CODEPAGE_MS); // CodePage 517 } 518 519 //section 2.3.4.2.1.5 520 void writePROJECTNAME(SvStream& rStrm, const OUString& name) 521 { 522 rStrm.WriteUInt16(0x0004); // id 523 sal_uInt32 sizeOfProjectName = name.getLength(); 524 rStrm.WriteUInt32(sizeOfProjectName); // sizeOfProjectName 525 exportString(rStrm, name); // ProjectName 526 } 527 528 //section 2.3.4.2.1.6 529 void writePROJECTDOCSTRING(SvStream& rStrm) 530 { 531 rStrm.WriteUInt16(0x0005); // id 532 rStrm.WriteUInt32(0x00000000); // sizeOfDocString 533 rStrm.WriteUInt16(0x0040); // Reserved 534 rStrm.WriteUInt32(0x00000000); // sizeOfDocStringUnicode, MUST be even 535 } 536 537 //section 2.3.4.2.1.7 538 void writePROJECTHELPFILEPATH(SvStream& rStrm) 539 { 540 rStrm.WriteUInt16(0x0006); // id 541 rStrm.WriteUInt32(0x00000000); // sizeOfHelpFile1 542 rStrm.WriteUInt16(0x003D); // Reserved 543 rStrm.WriteUInt32(0x00000000); // sizeOfHelpFile2 544 } 545 546 //section 2.3.4.2.1.8 547 void writePROJECTHELPCONTEXT(SvStream& rStrm) 548 { 549 rStrm.WriteUInt16(0x0007); // id 550 rStrm.WriteUInt32(0x00000004); // size 551 rStrm.WriteUInt32(0x00000000); // HelpContext 552 } 553 554 //section 2.3.4.2.1.9 555 void writePROJECTLIBFLAGS(SvStream& rStrm) 556 { 557 rStrm.WriteUInt16(0x0008); // id 558 rStrm.WriteUInt32(0x00000004); // size 559 rStrm.WriteUInt32(0x00000000); // ProjectLibFlags 560 } 561 562 //section 2.3.4.2.1.10 563 void writePROJECTVERSION(SvStream& rStrm) 564 { 565 rStrm.WriteUInt16(0x0009); // id 566 rStrm.WriteUInt32(0x00000004); // Reserved 567 rStrm.WriteUInt32(1467127224); // VersionMajor // TODO: where is this magic number coming from 568 rStrm.WriteUInt16(5); // VersionMinor // TODO: where is this magic number coming from 569 } 570 571 //section 2.3.4.2.1.11 572 void writePROJECTCONSTANTS(SvStream& rStrm) 573 { 574 rStrm.WriteUInt16(0x000C); // id 575 rStrm.WriteUInt32(0x00000000); // sizeOfConstants 576 rStrm.WriteUInt16(0x003C); // Reserved 577 rStrm.WriteUInt32(0x00000000); // sizeOfConstantsUnicode 578 } 579 580 // section 2.3.4.2.1 581 void writePROJECTINFORMATION(SvStream& rStrm, const OUString& projectName) 582 { 583 writePROJECTSYSKIND(rStrm); 584 writePROJECTLCID(rStrm); 585 writePROJECTLCIDINVOKE(rStrm); 586 writePROJECTCODEPAGE(rStrm); 587 writePROJECTNAME(rStrm, projectName); 588 writePROJECTDOCSTRING(rStrm); 589 writePROJECTHELPFILEPATH(rStrm); 590 writePROJECTHELPCONTEXT(rStrm); 591 writePROJECTLIBFLAGS(rStrm); 592 writePROJECTVERSION(rStrm); 593 writePROJECTCONSTANTS(rStrm); 594 } 595 596 // section 2.3.4.2.2.2 597 void writeREFERENCENAME(SvStream& rStrm, const OUString& name) 598 { 599 rStrm.WriteUInt16(0x0016); // id 600 sal_Int32 size = name.getLength(); 601 rStrm.WriteUInt32(size); // sizeOfName 602 exportString(rStrm, name); // name 603 rStrm.WriteUInt16(0x003E); // reserved 604 sal_Int32 unicodesize = size * 2; 605 rStrm.WriteUInt32(unicodesize); // sizeOfNameUnicode 606 exportUTF16String(rStrm, name); // nameUnicode 607 } 608 609 // section 2.3.4.2.2.5 610 void writeREFERENCEREGISTERED(SvStream& rStrm, const OUString& libid) 611 { 612 rStrm.WriteUInt16(0x000D); // id 613 sal_Int32 sizeOfLibid = libid.getLength(); 614 sal_Int32 size = sizeOfLibid + 10; // size of Libid, sizeOfLibid(4 bytes), reserved 1(4 bytes) and reserved 2(2 bytes) 615 rStrm.WriteUInt32(size); // size 616 rStrm.WriteUInt32(sizeOfLibid); // sizeOfLibid 617 exportString(rStrm, libid); // Libid 618 rStrm.WriteUInt32(0x00000000); // reserved 1 619 rStrm.WriteUInt16(0x0000); // reserved 2 620 } 621 622 // section 2.3.4.2.2.1 623 void writeREFERENCE(SvStream& rStrm, const OUString& name, const OUString& libid) 624 { 625 writeREFERENCENAME(rStrm, name); 626 writeREFERENCEREGISTERED(rStrm, libid); 627 } 628 629 // section 2.3.4.2.2 630 void writePROJECTREFERENCES(SvStream& rStrm) 631 { 632 // TODO: find out where these references are coming from 633 writeREFERENCE(rStrm, "stdole", "*\\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\\Windows\\SysWOW64\\stdole2.tlb#OLE Automation"); 634 writeREFERENCE(rStrm, "Office", "*\\G{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}#2.0#0#C:\\Program Files (x86)\\Common Files\\Microsoft Shared\\OFFICE14\\MSO.DLL#Microsoft Office 14.0 Object Library"); 635 } 636 637 // section 2.3.4.2.3.1 638 void writePROJECTCOOKIE(SvStream& rStrm) 639 { 640 rStrm.WriteUInt16(0x0013); // id 641 rStrm.WriteUInt32(0x00000002); // size 642 rStrm.WriteUInt16(0xFFFF); // cookie 643 } 644 645 // section 2.3.4.2.3.2.1 646 void writeMODULENAME(SvStream& rStrm, const OUString& name) 647 { 648 rStrm.WriteUInt16(0x0019); // id 649 sal_Int32 n = name.getLength(); // sizeOfModuleName 650 rStrm.WriteUInt32(n); 651 exportString(rStrm, name); // ModuleName 652 } 653 654 // section 2.3.4.2.3.2.2 655 void writeMODULENAMEUNICODE(SvStream& rStrm, const OUString& name) 656 { 657 rStrm.WriteUInt16(0x0047); // id 658 sal_Int32 n = name.getLength() * 2; // sizeOfModuleNameUnicode // TODO: better calculation for unicode string length 659 rStrm.WriteUInt32(n); 660 exportUTF16String(rStrm, name); // ModuleNameUnicode 661 } 662 663 // section 2.3.4.2.3.2.3 664 void writeMODULESTREAMNAME(SvStream& rStrm, const OUString& streamName) 665 { 666 rStrm.WriteUInt16(0x001A); // id 667 sal_Int32 n = streamName.getLength(); // sizeOfStreamName 668 rStrm.WriteUInt32(n); 669 exportString(rStrm, streamName); // StreamName 670 rStrm.WriteUInt16(0x0032); // reserved 671 rStrm.WriteUInt32(n * 2); // sizeOfStreamNameUnicode // TODO: better calculation for unicode string length 672 exportUTF16String(rStrm, streamName); // StreamNameUnicode 673 } 674 675 // section 2.3.4.2.3.2.4 676 void writeMODULEDOCSTRING(SvStream& rStrm) 677 { 678 rStrm.WriteUInt16(0x001C); // id 679 rStrm.WriteUInt32(0x00000000); // sizeOfDocString 680 rStrm.WriteUInt16(0x0048); // reserved 681 rStrm.WriteUInt32(0x00000000); // sizeOfDocStringUnicode 682 } 683 684 // section 2.3.4.2.3.2.5 685 void writeMODULEOFFSET(SvStream& rStrm) 686 { 687 rStrm.WriteUInt16(0x0031); // id 688 rStrm.WriteUInt32(0x00000004); // sizeOfTextOffset 689 rStrm.WriteUInt32(0x00000000); // TextOffset 690 } 691 692 // section 2.3.4.2.3.2.6 693 void writeMODULEHELPCONTEXT(SvStream& rStrm) 694 { 695 rStrm.WriteUInt16(0x001E); // id 696 rStrm.WriteUInt32(0x00000004); // sizeOfHelpContext 697 rStrm.WriteUInt32(0x00000000); // HelpContext 698 } 699 700 // section 2.3.4.2.3.2.7 701 void writeMODULECOOKIE(SvStream& rStrm) 702 { 703 rStrm.WriteUInt16(0x002C); // id 704 rStrm.WriteUInt32(0x00000002); // sizeOfHelpContext 705 rStrm.WriteUInt16(0xFFFF); // HelpContext 706 } 707 708 // section 2.3.4.2.3.2.8 709 void writeMODULETYPE(SvStream& rStrm, const sal_uInt16 type) 710 { 711 if(type == 1) 712 rStrm.WriteUInt16(0x0021); // id for a procedural module 713 else 714 rStrm.WriteUInt16(0x0022); // id for document, class or design module 715 rStrm.WriteUInt32(0x00000000); // reserved 716 } 717 718 // section 2.3.4.2.3.2 719 void writePROJECTMODULE(SvStream& rStrm, const OUString& name, const sal_uInt16 type) 720 { 721 writeMODULENAME(rStrm, name); 722 writeMODULENAMEUNICODE(rStrm, name); 723 writeMODULESTREAMNAME(rStrm, name); 724 writeMODULEDOCSTRING(rStrm); 725 writeMODULEOFFSET(rStrm); 726 writeMODULEHELPCONTEXT(rStrm); 727 writeMODULECOOKIE(rStrm); 728 writeMODULETYPE(rStrm, type); 729 rStrm.WriteUInt16(0x002B); // terminator 730 rStrm.WriteUInt32(0x00000000); // reserved 731 } 732 733 // section 2.3.4.2.3 734 void writePROJECTMODULES(SvStream& rStrm, const css::uno::Reference<css::container::XNameContainer>& xNameContainer, const std::vector<sal_Int32>& rLibrayMap) 735 { 736 const css::uno::Sequence<OUString> aElementNames = xNameContainer->getElementNames(); 737 sal_Int32 n = aElementNames.getLength(); 738 css::uno::Reference<css::script::vba::XVBAModuleInfo> xModuleInfo(xNameContainer, css::uno::UNO_QUERY); 739 assert(xModuleInfo.is()); 740 741 // TODO: this whole part is document specific 742 rStrm.WriteUInt16(0x000F); // id 743 rStrm.WriteUInt32(0x00000002); // size of Count 744 sal_Int16 count = n; // Number of modules // TODO: this is dependent on the document 745 rStrm.WriteUInt16(count); // Count 746 writePROJECTCOOKIE(rStrm); 747 748 for (sal_Int32 i = 0; i < n; ++i) 749 { 750 const OUString& rModuleName = aElementNames[rLibrayMap[i]]; 751 css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(rModuleName); 752 writePROJECTMODULE(rStrm, rModuleName, aModuleInfo.ModuleType); 753 } 754 } 755 756 // section 2.3.4.2 757 void exportDirStream(SvStream& rStrm, const css::uno::Reference<css::container::XNameContainer>& xNameContainer, const std::vector<sal_Int32>& rLibraryMap, const OUString& projectName) 758 { 759 SvMemoryStream aDirStream(4096, 4096); 760 761 writePROJECTINFORMATION(aDirStream, projectName); 762 writePROJECTREFERENCES(aDirStream); 763 writePROJECTMODULES(aDirStream, xNameContainer, rLibraryMap); 764 aDirStream.WriteUInt16(0x0010); // terminator 765 aDirStream.WriteUInt32(0x00000000); // reserved 766 767 aDirStream.Seek(0); 768 769 #if VBA_EXPORT_DEBUG 770 const OUString aDirFileName("/tmp/vba_dir_out.bin"); 771 SvFileStream aDirStreamDebug(aDirFileName, StreamMode::READWRITE); 772 773 aDirStreamDebug.WriteStream(aDirStream); 774 aDirStream.Seek(0); 775 #endif 776 777 // the stream for the compression 778 SvMemoryStream aMemoryStream(4096, 4096); 779 aMemoryStream.WriteStream(aDirStream); 780 781 VBACompression aCompression(rStrm, aDirStream); 782 aCompression.write(); 783 } 784 785 // section 2.3.4.3 Module Stream 786 void exportModuleStream(SvStream& rStrm, const OUString& rSourceCode, const OUString& aElementName, css::script::ModuleInfo const & rInfo) 787 { 788 SvMemoryStream aModuleStream(4096, 4096); 789 790 exportString(aModuleStream, "Attribute VB_Name = \"" + aElementName + "\"\r\n"); 791 if (rInfo.ModuleType == 4) 792 { 793 if (isWorkbook(rInfo.ModuleObject)) 794 exportString(aModuleStream, "Attribute VB_Base = \"0{00020819-0000-0000-C000-000000000046}\"\r\n"); 795 else 796 exportString(aModuleStream, "Attribute VB_Base = \"0{00020820-0000-0000-C000-000000000046}\"\r\n"); 797 798 exportString(aModuleStream, "Attribute VB_GlobalNameSpace = False\r\n"); 799 exportString(aModuleStream, "Attribute VB_Creatable = False\r\n"); 800 exportString(aModuleStream, "Attribute VB_PredeclaredId = True\r\n"); 801 exportString(aModuleStream, "Attribute VB_Exposed = True\r\n"); 802 exportString(aModuleStream, "Attribute VB_TemplateDerived = False\r\n"); 803 exportString(aModuleStream, "Attribute VB_Customizable = True\r\n"); 804 } 805 OUString aSourceCode = rSourceCode.replaceFirst("Option VBASupport 1\n", ""); 806 const sal_Int32 nPos = aSourceCode.indexOf("Rem Attribute VBA_ModuleType="); 807 const sal_Int32 nEndPos = nPos != -1 ? aSourceCode.indexOf("\n", nPos) : -1; 808 if (nPos != -1 && nEndPos != -1) 809 aSourceCode = aSourceCode.replaceAt(nPos, nEndPos - nPos+1, ""); 810 aSourceCode = aSourceCode.replaceAll("\n", "\r\n"); 811 exportString(aModuleStream, aSourceCode); 812 aModuleStream.Seek(0); 813 814 #if VBA_EXPORT_DEBUG 815 OUString aModuleFileName("/tmp/vba_" + aElementName + "_out.bin"); 816 SvFileStream aModuleStreamDebug(aModuleFileName, StreamMode::READWRITE); 817 aModuleStreamDebug.WriteStream(aModuleStream); 818 aModuleStream.Seek(0); 819 #endif 820 821 // the stream for the compression 822 SvMemoryStream aMemoryStream(4096, 4096); 823 aMemoryStream.WriteStream(aModuleStream); 824 825 VBACompression aCompression(rStrm, aModuleStream); 826 aCompression.write(); 827 } 828 829 // section 2.3.4.1 _VBA_PROJECT Stream 830 void exportVBAProjectStream(SvStream& rStrm) 831 { 832 rStrm.WriteUInt16(0x61CC); // Reserved1 833 rStrm.WriteUInt16(0xFFFF); // Version 834 rStrm.WriteUInt8(0x00); // Reserved2 835 rStrm.WriteUInt16(0x0000); // Undefined 836 } 837 838 // section 2.3.1 PROJECT Stream 839 void exportPROJECTStream(SvStream& rStrm, const css::uno::Reference<css::container::XNameContainer>& xNameContainer, 840 const OUString& projectName, const std::vector<sal_Int32>& rLibraryMap) 841 { 842 const css::uno::Sequence<OUString> aElementNames = xNameContainer->getElementNames(); 843 sal_Int32 n = aElementNames.getLength(); 844 css::uno::Reference<css::script::vba::XVBAModuleInfo> xModuleInfo(xNameContainer, css::uno::UNO_QUERY); 845 assert(xModuleInfo.is()); 846 847 // section 2.3.1.1ProjectProperties 848 849 // section 2.3.1.2 ProjectId 850 exportString(rStrm, "ID=\""); 851 OUString aProjectID 852 = OStringToOUString(comphelper::xml::generateGUIDString(), RTL_TEXTENCODING_UTF8); 853 exportString(rStrm, aProjectID); 854 exportString(rStrm, "\"\r\n"); 855 856 // section 2.3.1.3 ProjectModule 857 for (sal_Int32 i = 0; i < n; ++i) 858 { 859 const OUString& rModuleName = aElementNames[rLibraryMap[i]]; 860 css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(rModuleName); 861 if(aModuleInfo.ModuleType == 1) 862 { 863 exportString(rStrm, "Module=" + rModuleName + "\r\n"); 864 } 865 else if(aModuleInfo.ModuleType == 4) 866 { 867 exportString(rStrm, "Document=" + rModuleName + "/&H00000000\r\n"); 868 } 869 } 870 871 // section 2.3.1.11 ProjectName 872 exportString(rStrm, "Name=\"" + projectName + "\"\r\n"); 873 874 // section 2.3.1.12 ProjectHelpId 875 exportString(rStrm, "HelpContextID=\"0\"\r\n"); 876 877 // section 2.3.1.14 ProjectVersionCompat32 878 exportString(rStrm, "VersionCompatible32=\"393222000\"\r\n"); 879 880 // section 2.3.1.15 ProjectProtectionState 881 #if VBA_ENCRYPTION 882 exportString(rStrm, "CMG=\""); 883 SvMemoryStream aProtectedStream(4096, 4096); 884 aProtectedStream.WriteUInt32(0x00000000); 885 const sal_uInt8* pData = static_cast<const sal_uInt8*>(aProtectedStream.GetData()); 886 sal_uInt8 nProjKey = VBAEncryption::calculateProjKey(aProjectID); 887 VBAEncryption aProtectionState(pData, 4, rStrm, nProjKey); 888 aProtectionState.write(); 889 exportString(rStrm, "\"\r\n"); 890 #else 891 exportString(rStrm, "CMG=\"BEBC9256EEAAA8AEA8AEA8AEA8AE\"\r\n"); 892 #endif 893 894 // section 2.3.1.16 ProjectPassword 895 #if VBA_ENCRYPTION 896 exportString(rStrm, "DPB=\""); 897 aProtectedStream.Seek(0); 898 aProtectedStream.WriteUInt8(0x00); 899 pData = static_cast<const sal_uInt8*>(aProtectedStream.GetData()); 900 VBAEncryption aProjectPassword(pData, 1, rStrm, nProjKey); 901 aProjectPassword.write(); 902 exportString(rStrm, "\"\r\n"); 903 #else 904 exportString(rStrm, "DPB=\"7C7E5014B0D3B1D3B1D3\"\r\n"); 905 #endif 906 907 // section 2.3.1.17 ProjectVisibilityState 908 #if VBA_ENCRYPTION 909 exportString(rStrm, "GC=\""); 910 aProtectedStream.Seek(0); 911 aProtectedStream.WriteUInt8(0xFF); 912 pData = static_cast<const sal_uInt8*>(aProtectedStream.GetData()); 913 VBAEncryption aVisibilityState(pData, 1, rStrm, nProjKey); 914 aVisibilityState.write(); 915 exportString(rStrm, "\"\r\n\r\n"); 916 #else 917 exportString(rStrm, "GC=\"3A3816DAD5DBD5DB2A\"\r\n\r\n"); 918 #endif 919 920 // section 2.3.1.18 HostExtenders 921 exportString(rStrm, "[Host Extender Info]\r\n" 922 "&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000\r\n\r\n" 923 ); 924 925 // section 2.3.1.19 ProjectWorkspace 926 exportString(rStrm, "[Workspace]\r\n"); 927 for (sal_Int32 i = 0; i < n; ++i) 928 { 929 const OUString& rModuleName = aElementNames[rLibraryMap[i]]; 930 css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(rModuleName); 931 if(aModuleInfo.ModuleType == 1) 932 { 933 exportString(rStrm, rModuleName + "=25, 25, 1439, 639, \r\n"); 934 } 935 else 936 { 937 exportString(rStrm, rModuleName + "=0, 0, 0, 0, C\r\n"); 938 } 939 } 940 } 941 942 // section 2.3.3.1 NAMEMAP 943 void writeNAMEMAP(SvStream& rStrm, const css::uno::Sequence<OUString>& rElementNames, 944 const std::vector<sal_Int32>& rLibraryMap) 945 { 946 int n = rElementNames.getLength(); 947 for(sal_Int32 i = 0; i < n; ++i) 948 { 949 const OUString& rModuleName = rElementNames[rLibraryMap[i]]; 950 exportString(rStrm, rModuleName); 951 rStrm.WriteUInt8(0x00); // terminator 952 exportUTF16String(rStrm, rModuleName); 953 rStrm.WriteUInt16(0x0000); // terminator 954 } 955 } 956 957 // section 2.3.3 PROJECTwm Stream 958 void exportPROJECTwmStream(SvStream& rStrm, const css::uno::Sequence<OUString>& rElementNames, 959 const std::vector<sal_Int32>& rLibraryMap) 960 { 961 writeNAMEMAP(rStrm, rElementNames, rLibraryMap); 962 rStrm.WriteUInt16(0x0000); // terminator 963 } 964 965 void getCorrectExportOrder(const css::uno::Reference<css::container::XNameContainer>& xNameContainer, std::vector<sal_Int32>& rLibraryMap) 966 { 967 const css::uno::Sequence<OUString> aElementNames = xNameContainer->getElementNames(); 968 sal_Int32 n = aElementNames.getLength(); 969 css::uno::Reference<css::script::vba::XVBAModuleInfo> xModuleInfo(xNameContainer, css::uno::UNO_QUERY); 970 971 sal_Int32 nCurrentId = 0; 972 // first all the non-document modules 973 for (sal_Int32 i = 0; i < n; ++i) 974 { 975 css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(aElementNames[i]); 976 if (aModuleInfo.ModuleType != 4) 977 { 978 rLibraryMap[nCurrentId] = i; 979 ++nCurrentId; 980 } 981 } 982 983 sal_Int32 nWorkbookIndex = -1; 984 // then possibly the workbook module 985 for (sal_Int32 i = 0; i < n; ++i) 986 { 987 css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(aElementNames[i]); 988 bool bWorkbook = isWorkbook(aModuleInfo.ModuleObject); 989 if (bWorkbook) 990 { 991 nWorkbookIndex = i; 992 rLibraryMap[nCurrentId] = i; 993 ++nCurrentId; 994 } 995 } 996 997 // then the remaining modules 998 for (sal_Int32 i = 0; i < n; ++i) 999 { 1000 if (i == nWorkbookIndex) 1001 continue; 1002 1003 css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(aElementNames[i]); 1004 if (aModuleInfo.ModuleType == 4) 1005 { 1006 rLibraryMap[nCurrentId] = i; 1007 ++nCurrentId; 1008 } 1009 } 1010 } 1011 1012 } 1013 1014 #if VBA_USE_ORIGINAL_WM_STREAM || VBA_USE_ORIGINAL_DIR_STREAM \ 1015 || VBA_USE_ORIGINAL_PROJECT_STREAM || VBA_USE_ORIGINAL_VBA_PROJECT \ 1016 || VBA_USE_ORIGINAL_DIR_STREAM 1017 void addFileStreamToSotStream(const OUString& rPath, SotStorageStream* pStream) 1018 { 1019 SvFileStream aFileStream(rPath, StreamMode::READWRITE); 1020 pStream->WriteStream(aFileStream); 1021 } 1022 #endif 1023 1024 void VbaExport::exportVBA(SotStorage* pRootStorage) 1025 { 1026 css::uno::Reference<css::container::XNameContainer> xNameContainer = getBasicLibrary(); 1027 if (!xNameContainer.is()) { 1028 return; 1029 } 1030 const css::uno::Sequence<OUString> aElementNames = xNameContainer->getElementNames(); 1031 sal_Int32 n = aElementNames.getLength(); // get the number of modules 1032 // export the elements in the order MSO expects them 1033 // we store the index of the 1034 std::vector<sal_Int32> aLibraryMap(n, 0); 1035 getCorrectExportOrder(xNameContainer, aLibraryMap); 1036 1037 // start here with the VBA export 1038 tools::SvRef<SotStorage> xVBAStream = pRootStorage->OpenSotStorage("VBA", StreamMode::READWRITE); 1039 SotStorageStream* pDirStream = xVBAStream->OpenSotStream("dir", StreamMode::READWRITE); 1040 1041 SotStorageStream* pVBAProjectStream = xVBAStream->OpenSotStream("_VBA_PROJECT", StreamMode::READWRITE); 1042 SotStorageStream* pPROJECTStream = pRootStorage->OpenSotStream("PROJECT", StreamMode::READWRITE); 1043 SotStorageStream* pPROJECTwmStream = pRootStorage->OpenSotStream("PROJECTwm", StreamMode::READWRITE); 1044 1045 #if VBA_USE_ORIGINAL_WM_STREAM 1046 OUString aProjectwmPath = "/home/moggi/Documents/testfiles/vba/PROJECTwm"; 1047 addFileStreamToSotStream(aProjectwmPath, pPROJECTwmStream); 1048 #else 1049 exportPROJECTwmStream(*pPROJECTwmStream, aElementNames, aLibraryMap); 1050 #endif 1051 1052 #if VBA_USE_ORIGINAL_DIR_STREAM 1053 OUString aDirPath = "/home/moggi/Documents/testfiles/vba/VBA/dir"; 1054 addFileStreamToSotStream(aDirPath, pDirStream); 1055 #else 1056 exportDirStream(*pDirStream, xNameContainer, aLibraryMap, getProjectName()); 1057 #endif 1058 1059 #if VBA_USE_ORIGINAL_PROJECT_STREAM 1060 OUString aProjectPath = "/home/moggi/Documents/testfiles/vba/PROJECT"; 1061 addFileStreamToSotStream(aProjectPath, pPROJECTStream); 1062 #else 1063 exportPROJECTStream(*pPROJECTStream, xNameContainer, getProjectName(), aLibraryMap); 1064 #endif 1065 1066 #if VBA_USE_ORIGINAL_VBA_PROJECT 1067 OUString a_VBA_ProjectPath = "/home/moggi/Documents/testfiles/vba/VBA/_VBA_PROJECT"; 1068 addFileStreamToSotStream(a_VBA_ProjectPath, pVBAProjectStream); 1069 #else 1070 exportVBAProjectStream(*pVBAProjectStream); 1071 #endif 1072 1073 #if VBA_USE_ORIGINAL_DIR_STREAM 1074 OUString aModule1Path = "/home/moggi/Documents/testfiles/vba/VBA/Module1"; 1075 OUString aSheet1Path = "/home/moggi/Documents/testfiles/vba/VBA/Sheet1"; 1076 OUString aSheet2Path = "/home/moggi/Documents/testfiles/vba/VBA/Sheet2"; 1077 OUString aSheet3Path = "/home/moggi/Documents/testfiles/vba/VBA/Sheet3"; 1078 OUString aWorkbookPath = "/home/moggi/Documents/testfiles/vba/VBA/ThisWorkbook"; 1079 SotStorageStream* pModule1Stream = xVBAStream->OpenSotStream("Module1", StreamMode::READWRITE); 1080 SotStorageStream* pSheet1Stream = xVBAStream->OpenSotStream("Sheet1", StreamMode::READWRITE); 1081 SotStorageStream* pSheet2Stream = xVBAStream->OpenSotStream("Sheet2", StreamMode::READWRITE); 1082 SotStorageStream* pSheet3Stream = xVBAStream->OpenSotStream("Sheet3", StreamMode::READWRITE); 1083 SotStorageStream* pWorkbookStream = xVBAStream->OpenSotStream("ThisWorkbook", StreamMode::READWRITE); 1084 addFileStreamToSotStream(aModule1Path, pModule1Stream); 1085 addFileStreamToSotStream(aSheet1Path, pSheet1Stream); 1086 addFileStreamToSotStream(aSheet2Path, pSheet2Stream); 1087 addFileStreamToSotStream(aSheet3Path, pSheet3Stream); 1088 addFileStreamToSotStream(aWorkbookPath, pWorkbookStream); 1089 1090 pModule1Stream->Commit(); 1091 pSheet1Stream->Commit(); 1092 pSheet2Stream->Commit(); 1093 pSheet3Stream->Commit(); 1094 pWorkbookStream->Commit(); 1095 #else 1096 1097 css::uno::Reference<css::script::vba::XVBAModuleInfo> xModuleInfo(xNameContainer, css::uno::UNO_QUERY); 1098 for (sal_Int32 i = 0; i < n; ++i) 1099 { 1100 const OUString& rModuleName = aElementNames[aLibraryMap[i]]; 1101 SotStorageStream* pModuleStream = xVBAStream->OpenSotStream(rModuleName, StreamMode::READWRITE); 1102 css::uno::Any aCode = xNameContainer->getByName(rModuleName); 1103 css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(rModuleName); 1104 OUString aSourceCode; 1105 aCode >>= aSourceCode; 1106 exportModuleStream(*pModuleStream, aSourceCode, rModuleName, aModuleInfo); 1107 pModuleStream->Commit(); 1108 } 1109 1110 #endif 1111 1112 pVBAProjectStream->Commit(); 1113 1114 pDirStream->Commit(); 1115 xVBAStream->Commit(); 1116 pPROJECTStream->Commit(); 1117 pPROJECTwmStream->Commit(); 1118 pRootStorage->Commit(); 1119 } 1120 1121 css::uno::Reference<css::script::XLibraryContainer> VbaExport::getLibraryContainer() const 1122 { 1123 oox::PropertySet aDocProp(mxModel); 1124 css::uno::Reference<css::script::XLibraryContainer> xLibContainer(aDocProp.getAnyProperty(oox::PROP_BasicLibraries), css::uno::UNO_QUERY); 1125 1126 return xLibContainer; 1127 } 1128 1129 css::uno::Reference<css::container::XNameContainer> VbaExport::getBasicLibrary() const 1130 { 1131 css::uno::Reference<css::container::XNameContainer> xLibrary; 1132 try 1133 { 1134 css::uno::Reference<css::script::XLibraryContainer> xLibContainer = getLibraryContainer(); 1135 OUString aProjectName = getProjectName(); 1136 xLibrary.set( xLibContainer->getByName(aProjectName), css::uno::UNO_QUERY_THROW ); 1137 } 1138 catch(...) 1139 { 1140 } 1141 1142 return xLibrary; 1143 } 1144 1145 bool VbaExport::containsVBAProject() 1146 { 1147 css::uno::Reference<css::script::XLibraryContainer> xLibContainer = getLibraryContainer(); 1148 if (!xLibContainer.is()) 1149 return false; 1150 1151 css::uno::Reference<css::script::vba::XVBACompatibility> xVbaCompatibility (xLibContainer, css::uno::UNO_QUERY); 1152 if (!xVbaCompatibility.is()) 1153 return false; 1154 1155 bool bVBACompatibilty = xVbaCompatibility->getVBACompatibilityMode(); 1156 1157 return bVBACompatibilty; 1158 } 1159 1160 OUString VbaExport::getProjectName() const 1161 { 1162 css::uno::Reference<css::script::vba::XVBACompatibility> xVbaCompatibility(getLibraryContainer(), css::uno::UNO_QUERY); 1163 if (xVbaCompatibility.is()) 1164 return xVbaCompatibility->getProjectName(); 1165 1166 return OUString(); 1167 } 1168 1169 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1170
