summaryrefslogtreecommitdiffstats
path: root/oox/source/ole/vbaexport.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/ole/vbaexport.cxx')
-rw-r--r--oox/source/ole/vbaexport.cxx1193
1 files changed, 1193 insertions, 0 deletions
diff --git a/oox/source/ole/vbaexport.cxx b/oox/source/ole/vbaexport.cxx
new file mode 100644
index 000000000..01eaff558
--- /dev/null
+++ b/oox/source/ole/vbaexport.cxx
@@ -0,0 +1,1193 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <cassert>
+#include <random>
+#include <string_view>
+
+#include <oox/ole/vbaexport.hxx>
+
+#include <tools/stream.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/script/XLibraryContainer.hpp>
+#include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <ooo/vba/excel/XWorkbook.hpp>
+
+#include <oox/helper/propertyset.hxx>
+#include <oox/token/properties.hxx>
+
+#include <sot/storage.hxx>
+
+#include <comphelper/xmltools.hxx>
+#include <rtl/tencinfo.h>
+#include <osl/thread.h>
+
+#define VBA_EXPORT_DEBUG 0
+#define VBA_USE_ORIGINAL_WM_STREAM 0
+#define VBA_USE_ORIGINAL_DIR_STREAM 0
+#define VBA_USE_ORIGINAL_PROJECT_STREAM 0
+#define VBA_USE_ORIGINAL_VBA_PROJECT 0
+
+/* Enable to see VBA Encryption work. For now the input data and length values
+ * for encryption correspond to the case when the VBA macro is not protected.
+ */
+#define VBA_ENCRYPTION 1
+
+namespace {
+
+void exportString(SvStream& rStrm, std::u16string_view rString,
+ const rtl_TextEncoding eTextEncoding)
+{
+ OString aStringCorrectCodepage = OUStringToOString(rString, eTextEncoding);
+ rStrm.WriteOString(aStringCorrectCodepage);
+}
+
+void exportUTF16String(SvStream& rStrm, const OUString& rString)
+{
+ sal_Int32 n = rString.getLength();
+ const sal_Unicode* pString = rString.getStr();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ sal_Unicode character = pString[i];
+ rStrm.WriteUnicode(character);
+ }
+}
+
+bool isWorkbook(const css::uno::Reference<css::uno::XInterface>& xInterface)
+{
+ css::uno::Reference<ooo::vba::excel::XWorkbook> xWorkbook(xInterface, css::uno::UNO_QUERY);
+ return xWorkbook.is();
+}
+
+OUString createHexStringFromDigit(sal_uInt8 nDigit)
+{
+ OUString aString = OUString::number( nDigit, 16 );
+ if(aString.getLength() == 1)
+ aString = OUString::number(0) + aString;
+ return aString.toAsciiUpperCase();
+}
+
+}
+
+VBACompressionChunk::VBACompressionChunk(SvStream& rCompressedStream, const sal_uInt8* pData, std::size_t nChunkSize)
+ : mrCompressedStream(rCompressedStream)
+ , mpUncompressedData(pData)
+ , mpCompressedChunkStream(nullptr)
+ , mnChunkSize(nChunkSize)
+ , mnCompressedCurrent(0)
+ , mnCompressedEnd(0)
+ , mnDecompressedCurrent(0)
+ , mnDecompressedEnd(0)
+{
+}
+
+static void setUInt16(sal_uInt8* pBuffer, size_t nPos, sal_uInt16 nVal)
+{
+ pBuffer[nPos] = nVal & 0xFF;
+ pBuffer[nPos+1] = (nVal & 0xFF00) >> 8;
+}
+
+sal_uInt16 VBACompressionChunk::handleHeader(bool bCompressed)
+{
+ // handle header bytes
+ size_t nSize = mnCompressedCurrent;
+ sal_uInt16 nHeader = 0;
+ PackCompressedChunkSize(nSize, nHeader);
+ PackCompressedChunkFlag(bCompressed, nHeader);
+ PackCompressedChunkSignature(nHeader);
+
+ return nHeader;
+}
+
+// section 2.4.1.3.7
+void VBACompressionChunk::write()
+{
+
+ mnDecompressedCurrent = 0;
+ mnCompressedCurrent = 2;
+ mnCompressedEnd = 4098;
+ mnDecompressedEnd = std::min<sal_uInt64>(4096, mnChunkSize);
+
+ // if that stream becomes larger than 4096 bytes then
+ // we use the uncompressed stream
+ sal_uInt8 pCompressedChunkStream[4098];
+ mpCompressedChunkStream = pCompressedChunkStream;
+
+ while (mnDecompressedCurrent < mnDecompressedEnd
+ && mnCompressedCurrent < mnCompressedEnd)
+ {
+ // compress token sequence
+ compressTokenSequence();
+ }
+
+ if (mnDecompressedCurrent < mnDecompressedEnd)
+ {
+ sal_uInt64 nChunkStart = mrCompressedStream.Tell();
+ mrCompressedStream.WriteUInt16(0);
+ writeRawChunk();
+ mrCompressedStream.Seek(nChunkStart);
+ sal_uInt16 nHeader = handleHeader(false);
+ mrCompressedStream.WriteUInt16(nHeader);
+ }
+ else
+ {
+ sal_uInt16 nHeader = handleHeader(true);
+ setUInt16(pCompressedChunkStream, 0, nHeader);
+ // copy the compressed stream to our output stream
+ mrCompressedStream.WriteBytes(pCompressedChunkStream, mnCompressedCurrent);
+ }
+}
+
+// section 2.4.1.3.13
+void VBACompressionChunk::PackCompressedChunkSize(size_t nSize, sal_uInt16& rHeader)
+{
+ sal_uInt16 nTemp1 = rHeader & 0xF000;
+ sal_uInt16 nTemp2 = nSize - 3;
+ rHeader = nTemp1 | nTemp2;
+}
+
+// section 2.4.1.3.16
+void VBACompressionChunk::PackCompressedChunkFlag(bool bCompressed, sal_uInt16& rHeader)
+{
+ sal_uInt16 nTemp1 = rHeader & 0x7FFF;
+ sal_uInt16 nTemp2 = static_cast<sal_uInt16>(bCompressed) << 15;
+ rHeader = nTemp1 | nTemp2;
+}
+
+// section 2.4.1.3.14
+void VBACompressionChunk::PackCompressedChunkSignature(sal_uInt16& rHeader)
+{
+ sal_Int32 nTemp = rHeader & 0x8FFFF;
+ rHeader = nTemp | 0x3000;
+}
+
+// section 2.4.1.3.8
+void VBACompressionChunk::compressTokenSequence()
+{
+ sal_uInt64 nFlagByteIndex = mnCompressedCurrent;
+ sal_uInt8 nFlagByte = 0;
+ ++mnCompressedCurrent;
+ for (size_t index = 0; index <= 7; ++index)
+ {
+ if (mnDecompressedCurrent < mnDecompressedEnd
+ && mnCompressedCurrent < mnCompressedEnd)
+ {
+ compressToken(index, nFlagByte);
+ }
+ }
+ mpCompressedChunkStream[nFlagByteIndex] = nFlagByte;
+}
+
+// section 2.4.1.3.9
+void VBACompressionChunk::compressToken(size_t index, sal_uInt8& nFlagByte)
+{
+ size_t nLength = 0;
+ size_t nOffset = 0;
+ match(nLength, nOffset);
+ if (nOffset != 0)
+ {
+ if (mnCompressedCurrent + 1 < mnCompressedEnd)
+ {
+ sal_uInt16 nToken = CopyToken(nLength, nOffset);
+ setUInt16(mpCompressedChunkStream, mnCompressedCurrent, nToken);
+ SetFlagBit(index, true, nFlagByte);
+ mnCompressedCurrent += 2;
+ mnDecompressedCurrent += nLength;
+ }
+ else
+ {
+ mnCompressedCurrent = mnCompressedEnd;
+ }
+ }
+ else
+ {
+ if (mnCompressedCurrent + 1 < mnCompressedEnd)
+ {
+ mpCompressedChunkStream[mnCompressedCurrent] = mpUncompressedData[mnDecompressedCurrent];
+ ++mnCompressedCurrent;
+ ++mnDecompressedCurrent;
+ }
+ else
+ {
+ mnCompressedCurrent = mnCompressedEnd;
+ }
+ }
+}
+
+// section 2.4.1.3.18
+void VBACompressionChunk::SetFlagBit(size_t index, bool bVal, sal_uInt8& rFlag)
+{
+ size_t nTemp1 = static_cast<int>(bVal) << index;
+ sal_uInt8 nTemp2 = rFlag & (~nTemp1);
+ rFlag = nTemp2 | nTemp1;
+}
+
+// section 2.4.1.3.19.3
+sal_uInt16 VBACompressionChunk::CopyToken(size_t nLength, size_t nOffset)
+{
+ sal_uInt16 nLengthMask = 0;
+ sal_uInt16 nOffsetMask = 0;
+ sal_uInt16 nBitCount = 0;
+ sal_uInt16 nMaxLength;
+ CopyTokenHelp(nLengthMask, nOffsetMask, nBitCount, nMaxLength);
+ sal_uInt16 nTemp1 = nOffset -1;
+ sal_uInt16 nTemp2 = 16 - nBitCount;
+ sal_uInt16 nTemp3 = nLength - 3;
+ sal_uInt16 nToken = (nTemp1 << nTemp2) | nTemp3;
+ return nToken;
+}
+
+// section 2.4.1.3.19.4
+void VBACompressionChunk::match(size_t& rLength, size_t& rOffset)
+{
+ size_t nBestLen = 0;
+ sal_Int32 nCandidate = mnDecompressedCurrent - 1;
+ sal_Int32 nBestCandidate = nCandidate;
+ while (nCandidate >= 0)
+ {
+ sal_Int32 nC = nCandidate;
+ sal_Int32 nD = mnDecompressedCurrent;
+ size_t nLen = 0;
+ while (nD < static_cast<sal_Int32>(mnChunkSize) // TODO: check if this needs to be including a minus -1
+ && mpUncompressedData[nC] == mpUncompressedData[nD])
+ {
+ ++nLen;
+ ++nC;
+ ++nD;
+ }
+ if (nLen > nBestLen)
+ {
+ nBestLen = nLen;
+ nBestCandidate = nCandidate;
+ }
+ --nCandidate;
+ }
+
+ if (nBestLen >= 3)
+ {
+ sal_uInt16 nMaximumLength = 0;
+ sal_uInt16 nLengthMask, nOffsetMask, nBitCount;
+ CopyTokenHelp(nLengthMask, nOffsetMask, nBitCount, nMaximumLength);
+ rLength = std::min<sal_uInt16>(nMaximumLength, nBestLen);
+ rOffset = mnDecompressedCurrent - nBestCandidate;
+ }
+ else
+ {
+ rLength = 0;
+ rOffset = 0;
+ }
+}
+
+// section 2.4.1.3.19.1
+void VBACompressionChunk::CopyTokenHelp(sal_uInt16& rLengthMask, sal_uInt16& rOffsetMask,
+ sal_uInt16& rBitCount, sal_uInt16& rMaximumLength)
+{
+ sal_uInt16 nDifference = mnDecompressedCurrent;
+ assert(nDifference <= 4096);
+ assert(nDifference >= 1);
+ if (nDifference >= 2049)
+ rBitCount = 12;
+ else if (nDifference >= 1025)
+ rBitCount = 11;
+ else if (nDifference >= 513)
+ rBitCount = 10;
+ else if (nDifference >= 257)
+ rBitCount = 9;
+ else if (nDifference >= 129)
+ rBitCount = 8;
+ else if (nDifference >= 65)
+ rBitCount = 7;
+ else if (nDifference >= 33)
+ rBitCount = 6;
+ else if (nDifference >= 17)
+ rBitCount = 5;
+ else
+ rBitCount = 4;
+ rLengthMask = 0xffff >> rBitCount;
+ rOffsetMask = ~rLengthMask;
+ rMaximumLength = rLengthMask + 3;
+}
+
+// section 2.4.1.3.10
+void VBACompressionChunk::writeRawChunk()
+{
+ // we need to use up to 4096 bytes of the original stream
+ // and fill the rest with padding
+ mrCompressedStream.WriteBytes(mpUncompressedData, mnChunkSize);
+ std::size_t nPadding = 4096 - mnChunkSize;
+ for (size_t i = 0; i < nPadding; ++i)
+ {
+ mrCompressedStream.WriteUInt8(0);
+ }
+}
+
+VBACompression::VBACompression(SvStream& rCompressedStream,
+ SvMemoryStream& rUncompressedStream):
+ mrCompressedStream(rCompressedStream),
+ mrUncompressedStream(rUncompressedStream)
+{
+}
+
+// section 2.4.1.3.6
+void VBACompression::write()
+{
+ // section 2.4.1.1.1
+ mrCompressedStream.WriteUInt8(0x01); // signature byte of a compressed container
+ bool bStreamNotEnded = true;
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>(mrUncompressedStream.GetData());
+ std::size_t nSize = mrUncompressedStream.GetEndOfData();
+ std::size_t nRemainingSize = nSize;
+ while(bStreamNotEnded)
+ {
+ std::size_t nChunkSize = std::min<size_t>(nRemainingSize, 4096);
+ VBACompressionChunk aChunk(mrCompressedStream, &pData[nSize - nRemainingSize], nChunkSize);
+ aChunk.write();
+
+ // update the uncompressed chunk start marker
+ nRemainingSize -= nChunkSize;
+ bStreamNotEnded = nRemainingSize != 0;
+ }
+}
+
+// section 2.4.3
+#if VBA_ENCRYPTION
+
+VBAEncryption::VBAEncryption(const sal_uInt8* pData, const sal_uInt16 length,
+ SvStream& rEncryptedData, sal_uInt8 nProjKey,
+ const rtl_TextEncoding eTextEncoding)
+ :mpData(pData)
+ ,mnLength(length)
+ ,mrEncryptedData(rEncryptedData)
+ ,mnUnencryptedByte1(0)
+ ,mnEncryptedByte1(0)
+ ,mnEncryptedByte2(0)
+ ,mnProjKey(nProjKey)
+ ,mnIgnoredLength(0)
+ ,mnSeed(0x00)
+ ,mnVersionEnc(0)
+ ,meTextEncoding(eTextEncoding)
+{
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<> dis(0, 255);
+ mnSeed = dis(gen);
+}
+
+void VBAEncryption::writeSeed()
+{
+ exportString(mrEncryptedData, createHexStringFromDigit(mnSeed), meTextEncoding);
+}
+
+void VBAEncryption::writeVersionEnc()
+{
+ static const sal_uInt8 mnVersion = 2; // the encrypted version
+ mnVersionEnc = mnSeed ^ mnVersion;
+ exportString(mrEncryptedData, createHexStringFromDigit(mnVersionEnc), meTextEncoding);
+}
+
+sal_uInt8 VBAEncryption::calculateProjKey(const OUString& rProjectKey)
+{
+ sal_uInt8 nProjKey = 0;
+ sal_Int32 n = rProjectKey.getLength();
+ const sal_Unicode* pString = rProjectKey.getStr();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ sal_Unicode character = pString[i];
+ nProjKey += character;
+ }
+
+ return nProjKey;
+}
+
+void VBAEncryption::writeProjKeyEnc()
+{
+ sal_uInt8 nProjKeyEnc = mnSeed ^ mnProjKey;
+ exportString(mrEncryptedData, createHexStringFromDigit(nProjKeyEnc), meTextEncoding);
+ mnUnencryptedByte1 = mnProjKey;
+ mnEncryptedByte1 = nProjKeyEnc; // ProjKeyEnc
+ mnEncryptedByte2 = mnVersionEnc; // VersionEnc
+}
+
+void VBAEncryption::writeIgnoredEnc()
+{
+ mnIgnoredLength = (mnSeed & 6) / 2;
+ for(sal_Int32 i = 1; i <= mnIgnoredLength; ++i)
+ {
+ sal_uInt8 nTempValue = 0xBE; // Any value can be assigned here
+ sal_uInt8 nByteEnc = nTempValue ^ (mnEncryptedByte2 + mnUnencryptedByte1);
+ exportString(mrEncryptedData, createHexStringFromDigit(nByteEnc), meTextEncoding);
+ mnEncryptedByte2 = mnEncryptedByte1;
+ mnEncryptedByte1 = nByteEnc;
+ mnUnencryptedByte1 = nTempValue;
+ }
+}
+
+void VBAEncryption::writeDataLengthEnc()
+{
+ sal_uInt16 temp = mnLength;
+ for(sal_Int8 i = 0; i < 4; ++i)
+ {
+ sal_uInt8 nByte = temp & 0xFF;
+ sal_uInt8 nByteEnc = nByte ^ (mnEncryptedByte2 + mnUnencryptedByte1);
+ exportString(mrEncryptedData, createHexStringFromDigit(nByteEnc), meTextEncoding);
+ mnEncryptedByte2 = mnEncryptedByte1;
+ mnEncryptedByte1 = nByteEnc;
+ mnUnencryptedByte1 = nByte;
+ temp >>= 8;
+ }
+}
+
+void VBAEncryption::writeDataEnc()
+{
+ for(sal_Int16 i = 0; i < mnLength; i++)
+ {
+ sal_uInt8 nByteEnc = mpData[i] ^ (mnEncryptedByte2 + mnUnencryptedByte1);
+ exportString(mrEncryptedData, createHexStringFromDigit(nByteEnc), meTextEncoding);
+ mnEncryptedByte2 = mnEncryptedByte1;
+ mnEncryptedByte1 = nByteEnc;
+ mnUnencryptedByte1 = mpData[i];
+ }
+}
+
+void VBAEncryption::write()
+{
+ writeSeed();
+ writeVersionEnc();
+ writeProjKeyEnc();
+ writeIgnoredEnc();
+ writeDataLengthEnc();
+ writeDataEnc();
+}
+
+#endif
+
+VbaExport::VbaExport(css::uno::Reference<css::frame::XModel> const & xModel):
+ mxModel(xModel)
+{
+}
+
+namespace {
+
+// section 2.3.4.2.1.1
+void writePROJECTSYSKIND(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0001); // id
+ rStrm.WriteUInt32(0x00000004); // size
+ rStrm.WriteUInt32(0x00000001); // SysKind, hard coded to 32-bin windows for now
+}
+
+// section 2.3.4.2.1.2
+void writePROJECTLCID(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0002); // id
+ rStrm.WriteUInt32(0x00000004); // size
+ rStrm.WriteUInt32(0x00000409); // Lcid
+}
+
+// section 2.3.4.2.1.3
+void writePROJECTLCIDINVOKE(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0014); // id
+ rStrm.WriteUInt32(0x00000004); // size
+ rStrm.WriteUInt32(0x00000409); // LcidInvoke
+}
+
+// section 2.3.4.2.1.4
+void writePROJECTCODEPAGE(SvStream& rStrm, const rtl_TextEncoding eTextEncoding)
+{
+ rStrm.WriteUInt16(0x0003); // id
+ rStrm.WriteUInt32(0x00000002); // size
+ rStrm.WriteUInt16(rtl_getWindowsCodePageFromTextEncoding(eTextEncoding)); // CodePage
+}
+
+//section 2.3.4.2.1.5
+void writePROJECTNAME(SvStream& rStrm, const OUString& name, const rtl_TextEncoding eTextEncoding)
+{
+ rStrm.WriteUInt16(0x0004); // id
+ sal_uInt32 sizeOfProjectName = name.getLength();
+ rStrm.WriteUInt32(sizeOfProjectName); // sizeOfProjectName
+ exportString(rStrm, name, eTextEncoding); // ProjectName
+}
+
+//section 2.3.4.2.1.6
+void writePROJECTDOCSTRING(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0005); // id
+ rStrm.WriteUInt32(0x00000000); // sizeOfDocString
+ rStrm.WriteUInt16(0x0040); // Reserved
+ rStrm.WriteUInt32(0x00000000); // sizeOfDocStringUnicode, MUST be even
+}
+
+//section 2.3.4.2.1.7
+void writePROJECTHELPFILEPATH(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0006); // id
+ rStrm.WriteUInt32(0x00000000); // sizeOfHelpFile1
+ rStrm.WriteUInt16(0x003D); // Reserved
+ rStrm.WriteUInt32(0x00000000); // sizeOfHelpFile2
+}
+
+//section 2.3.4.2.1.8
+void writePROJECTHELPCONTEXT(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0007); // id
+ rStrm.WriteUInt32(0x00000004); // size
+ rStrm.WriteUInt32(0x00000000); // HelpContext
+}
+
+//section 2.3.4.2.1.9
+void writePROJECTLIBFLAGS(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0008); // id
+ rStrm.WriteUInt32(0x00000004); // size
+ rStrm.WriteUInt32(0x00000000); // ProjectLibFlags
+}
+
+//section 2.3.4.2.1.10
+void writePROJECTVERSION(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0009); // id
+ rStrm.WriteUInt32(0x00000004); // Reserved
+ rStrm.WriteUInt32(1467127224); // VersionMajor // TODO: where is this magic number coming from
+ rStrm.WriteUInt16(5); // VersionMinor // TODO: where is this magic number coming from
+}
+
+//section 2.3.4.2.1.11
+void writePROJECTCONSTANTS(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x000C); // id
+ rStrm.WriteUInt32(0x00000000); // sizeOfConstants
+ rStrm.WriteUInt16(0x003C); // Reserved
+ rStrm.WriteUInt32(0x00000000); // sizeOfConstantsUnicode
+}
+
+// section 2.3.4.2.1
+void writePROJECTINFORMATION(SvStream& rStrm, const OUString& projectName,
+ const rtl_TextEncoding eTextEncoding)
+{
+ writePROJECTSYSKIND(rStrm);
+ writePROJECTLCID(rStrm);
+ writePROJECTLCIDINVOKE(rStrm);
+ writePROJECTCODEPAGE(rStrm, eTextEncoding);
+ writePROJECTNAME(rStrm, projectName, eTextEncoding);
+ writePROJECTDOCSTRING(rStrm);
+ writePROJECTHELPFILEPATH(rStrm);
+ writePROJECTHELPCONTEXT(rStrm);
+ writePROJECTLIBFLAGS(rStrm);
+ writePROJECTVERSION(rStrm);
+ writePROJECTCONSTANTS(rStrm);
+}
+
+// section 2.3.4.2.2.2
+void writeREFERENCENAME(SvStream& rStrm, const OUString& name, const rtl_TextEncoding eTextEncoding)
+{
+ rStrm.WriteUInt16(0x0016); // id
+ sal_Int32 size = name.getLength();
+ rStrm.WriteUInt32(size); // sizeOfName
+ exportString(rStrm, name, eTextEncoding); // name
+ rStrm.WriteUInt16(0x003E); // reserved
+ sal_Int32 unicodesize = size * 2;
+ rStrm.WriteUInt32(unicodesize); // sizeOfNameUnicode
+ exportUTF16String(rStrm, name); // nameUnicode
+}
+
+// section 2.3.4.2.2.5
+void writeREFERENCEREGISTERED(SvStream& rStrm, const OUString& libid,
+ const rtl_TextEncoding eTextEncoding)
+{
+ rStrm.WriteUInt16(0x000D); // id
+ sal_Int32 sizeOfLibid = libid.getLength();
+ sal_Int32 size = sizeOfLibid + 10; // size of Libid, sizeOfLibid(4 bytes), reserved 1(4 bytes) and reserved 2(2 bytes)
+ rStrm.WriteUInt32(size); // size
+ rStrm.WriteUInt32(sizeOfLibid); // sizeOfLibid
+ exportString(rStrm, libid, eTextEncoding); // Libid
+ rStrm.WriteUInt32(0x00000000); // reserved 1
+ rStrm.WriteUInt16(0x0000); // reserved 2
+}
+
+// section 2.3.4.2.2.1
+void writeREFERENCE(SvStream& rStrm, const OUString& name, const OUString& libid,
+ const rtl_TextEncoding eTextEncoding)
+{
+ writeREFERENCENAME(rStrm, name, eTextEncoding);
+ writeREFERENCEREGISTERED(rStrm, libid, eTextEncoding);
+}
+
+// section 2.3.4.2.2
+void writePROJECTREFERENCES(SvStream& rStrm, const rtl_TextEncoding eTextEncoding)
+{
+ // TODO: find out where these references are coming from
+ writeREFERENCE(rStrm, "stdole", "*\\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\\Windows\\SysWOW64\\stdole2.tlb#OLE Automation", eTextEncoding);
+ 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", eTextEncoding);
+}
+
+// section 2.3.4.2.3.1
+void writePROJECTCOOKIE(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0013); // id
+ rStrm.WriteUInt32(0x00000002); // size
+ rStrm.WriteUInt16(0xFFFF); // cookie
+}
+
+// section 2.3.4.2.3.2.1
+void writeMODULENAME(SvStream& rStrm, const OUString& name, const rtl_TextEncoding eTextEncoding)
+{
+ rStrm.WriteUInt16(0x0019); // id
+ sal_Int32 n = name.getLength(); // sizeOfModuleName
+ rStrm.WriteUInt32(n);
+ exportString(rStrm, name, eTextEncoding); // ModuleName
+}
+
+// section 2.3.4.2.3.2.2
+void writeMODULENAMEUNICODE(SvStream& rStrm, const OUString& name)
+{
+ rStrm.WriteUInt16(0x0047); // id
+ sal_Int32 n = name.getLength() * 2; // sizeOfModuleNameUnicode // TODO: better calculation for unicode string length
+ rStrm.WriteUInt32(n);
+ exportUTF16String(rStrm, name); // ModuleNameUnicode
+}
+
+// section 2.3.4.2.3.2.3
+void writeMODULESTREAMNAME(SvStream& rStrm, const OUString& streamName,
+ const rtl_TextEncoding eTextEncoding)
+{
+ rStrm.WriteUInt16(0x001A); // id
+ sal_Int32 n = streamName.getLength(); // sizeOfStreamName
+ rStrm.WriteUInt32(n);
+ exportString(rStrm, streamName, eTextEncoding); // StreamName
+ rStrm.WriteUInt16(0x0032); // reserved
+ rStrm.WriteUInt32(n * 2); // sizeOfStreamNameUnicode // TODO: better calculation for unicode string length
+ exportUTF16String(rStrm, streamName); // StreamNameUnicode
+}
+
+// section 2.3.4.2.3.2.4
+void writeMODULEDOCSTRING(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x001C); // id
+ rStrm.WriteUInt32(0x00000000); // sizeOfDocString
+ rStrm.WriteUInt16(0x0048); // reserved
+ rStrm.WriteUInt32(0x00000000); // sizeOfDocStringUnicode
+}
+
+// section 2.3.4.2.3.2.5
+void writeMODULEOFFSET(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x0031); // id
+ rStrm.WriteUInt32(0x00000004); // sizeOfTextOffset
+ rStrm.WriteUInt32(0x00000000); // TextOffset
+}
+
+// section 2.3.4.2.3.2.6
+void writeMODULEHELPCONTEXT(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x001E); // id
+ rStrm.WriteUInt32(0x00000004); // sizeOfHelpContext
+ rStrm.WriteUInt32(0x00000000); // HelpContext
+}
+
+// section 2.3.4.2.3.2.7
+void writeMODULECOOKIE(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x002C); // id
+ rStrm.WriteUInt32(0x00000002); // sizeOfHelpContext
+ rStrm.WriteUInt16(0xFFFF); // HelpContext
+}
+
+// section 2.3.4.2.3.2.8
+void writeMODULETYPE(SvStream& rStrm, const sal_uInt16 type)
+{
+ if(type == 1)
+ rStrm.WriteUInt16(0x0021); // id for a procedural module
+ else
+ rStrm.WriteUInt16(0x0022); // id for document, class or design module
+ rStrm.WriteUInt32(0x00000000); // reserved
+}
+
+// section 2.3.4.2.3.2
+void writePROJECTMODULE(SvStream& rStrm, const OUString& name, const sal_uInt16 type,
+ const rtl_TextEncoding eTextEncoding)
+{
+ writeMODULENAME(rStrm, name, eTextEncoding);
+ writeMODULENAMEUNICODE(rStrm, name);
+ writeMODULESTREAMNAME(rStrm, name, eTextEncoding);
+ writeMODULEDOCSTRING(rStrm);
+ writeMODULEOFFSET(rStrm);
+ writeMODULEHELPCONTEXT(rStrm);
+ writeMODULECOOKIE(rStrm);
+ writeMODULETYPE(rStrm, type);
+ rStrm.WriteUInt16(0x002B); // terminator
+ rStrm.WriteUInt32(0x00000000); // reserved
+}
+
+// section 2.3.4.2.3
+void writePROJECTMODULES(SvStream& rStrm,
+ const css::uno::Reference<css::container::XNameContainer>& xNameContainer,
+ const std::vector<sal_Int32>& rLibraryMap,
+ const rtl_TextEncoding eTextEncoding)
+{
+ const css::uno::Sequence<OUString> aElementNames = xNameContainer->getElementNames();
+ sal_Int32 n = aElementNames.getLength();
+ css::uno::Reference<css::script::vba::XVBAModuleInfo> xModuleInfo(xNameContainer, css::uno::UNO_QUERY);
+ assert(xModuleInfo.is());
+
+ // TODO: this whole part is document specific
+ rStrm.WriteUInt16(0x000F); // id
+ rStrm.WriteUInt32(0x00000002); // size of Count
+ sal_Int16 count = n; // Number of modules // TODO: this is dependent on the document
+ rStrm.WriteUInt16(count); // Count
+ writePROJECTCOOKIE(rStrm);
+
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const OUString& rModuleName = aElementNames[rLibraryMap[i]];
+ css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(rModuleName);
+ writePROJECTMODULE(rStrm, rModuleName, aModuleInfo.ModuleType, eTextEncoding);
+ }
+}
+
+// section 2.3.4.2
+void exportDirStream(SvStream& rStrm,
+ const css::uno::Reference<css::container::XNameContainer>& xNameContainer,
+ const std::vector<sal_Int32>& rLibraryMap, const OUString& projectName,
+ const rtl_TextEncoding eTextEncoding)
+{
+ SvMemoryStream aDirStream(4096, 4096);
+
+ writePROJECTINFORMATION(aDirStream, projectName, eTextEncoding);
+ writePROJECTREFERENCES(aDirStream, eTextEncoding);
+ writePROJECTMODULES(aDirStream, xNameContainer, rLibraryMap, eTextEncoding);
+ aDirStream.WriteUInt16(0x0010); // terminator
+ aDirStream.WriteUInt32(0x00000000); // reserved
+
+#if VBA_EXPORT_DEBUG
+ static const OUStringLiteral aDirFileName(u"/tmp/vba_dir_out.bin");
+ SvFileStream aDirStreamDebug(aDirFileName, StreamMode::READWRITE);
+ aDirStream.Seek(0);
+ aDirStreamDebug.WriteStream(aDirStream);
+#endif
+
+ VBACompression aCompression(rStrm, aDirStream);
+ aCompression.write();
+}
+
+// section 2.3.4.3 Module Stream
+void exportModuleStream(SvStream& rStrm, const OUString& rSourceCode, const OUString& aElementName,
+ css::script::ModuleInfo const& rInfo, const rtl_TextEncoding eTextEncoding)
+{
+ SvMemoryStream aModuleStream(4096, 4096);
+
+ exportString(aModuleStream, OUStringConcatenation("Attribute VB_Name = \"" + aElementName + "\"\r\n"), eTextEncoding);
+ if (rInfo.ModuleType == 4)
+ {
+ if (isWorkbook(rInfo.ModuleObject))
+ exportString(aModuleStream, u"Attribute VB_Base = \"0{00020819-0000-0000-C000-000000000046}\"\r\n", eTextEncoding);
+ else
+ exportString(aModuleStream, u"Attribute VB_Base = \"0{00020820-0000-0000-C000-000000000046}\"\r\n", eTextEncoding);
+
+ exportString(aModuleStream, u"Attribute VB_GlobalNameSpace = False\r\n", eTextEncoding);
+ exportString(aModuleStream, u"Attribute VB_Creatable = False\r\n", eTextEncoding);
+ exportString(aModuleStream, u"Attribute VB_PredeclaredId = True\r\n", eTextEncoding);
+ exportString(aModuleStream, u"Attribute VB_Exposed = True\r\n", eTextEncoding);
+ exportString(aModuleStream, u"Attribute VB_TemplateDerived = False\r\n", eTextEncoding);
+ exportString(aModuleStream, u"Attribute VB_Customizable = True\r\n", eTextEncoding);
+ }
+ OUString aSourceCode = rSourceCode.replaceFirst("Option VBASupport 1\n", "");
+ const sal_Int32 nPos = aSourceCode.indexOf("Rem Attribute VBA_ModuleType=");
+ const sal_Int32 nEndPos = nPos != -1 ? aSourceCode.indexOf("\n", nPos) : -1;
+ if (nPos != -1 && nEndPos != -1)
+ aSourceCode = aSourceCode.replaceAt(nPos, nEndPos - nPos+1, u"");
+ aSourceCode = aSourceCode.replaceAll("\n", "\r\n");
+ exportString(aModuleStream, aSourceCode, eTextEncoding);
+
+#if VBA_EXPORT_DEBUG
+ OUString aModuleFileName("/tmp/vba_" + aElementName + "_out.bin");
+ SvFileStream aModuleStreamDebug(aModuleFileName, StreamMode::READWRITE);
+ aModuleStream.Seek(0);
+ aModuleStreamDebug.WriteStream(aModuleStream);
+#endif
+
+ VBACompression aCompression(rStrm, aModuleStream);
+ aCompression.write();
+}
+
+// section 2.3.4.1 _VBA_PROJECT Stream
+void exportVBAProjectStream(SvStream& rStrm)
+{
+ rStrm.WriteUInt16(0x61CC); // Reserved1
+ rStrm.WriteUInt16(0xFFFF); // Version
+ rStrm.WriteUInt8(0x00); // Reserved2
+ rStrm.WriteUInt16(0x0000); // Undefined
+}
+
+// section 2.3.1 PROJECT Stream
+void exportPROJECTStream(SvStream& rStrm,
+ const css::uno::Reference<css::container::XNameContainer>& xNameContainer,
+ const OUString& projectName, const std::vector<sal_Int32>& rLibraryMap,
+ const rtl_TextEncoding eTextEncoding)
+{
+ const css::uno::Sequence<OUString> aElementNames = xNameContainer->getElementNames();
+ sal_Int32 n = aElementNames.getLength();
+ css::uno::Reference<css::script::vba::XVBAModuleInfo> xModuleInfo(xNameContainer, css::uno::UNO_QUERY);
+ assert(xModuleInfo.is());
+
+ // section 2.3.1.1ProjectProperties
+
+ // section 2.3.1.2 ProjectId
+ exportString(rStrm, u"ID=\"", eTextEncoding);
+ OUString aProjectID
+ = OStringToOUString(comphelper::xml::generateGUIDString(), RTL_TEXTENCODING_UTF8);
+ exportString(rStrm, aProjectID, eTextEncoding);
+ exportString(rStrm, u"\"\r\n", eTextEncoding);
+
+ // section 2.3.1.3 ProjectModule
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const OUString& rModuleName = aElementNames[rLibraryMap[i]];
+ css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(rModuleName);
+ if(aModuleInfo.ModuleType == 1)
+ {
+ exportString(rStrm, OUStringConcatenation("Module=" + rModuleName + "\r\n"),
+ eTextEncoding);
+ }
+ else if(aModuleInfo.ModuleType == 4)
+ {
+ exportString(rStrm,
+ OUStringConcatenation("Document=" + rModuleName + "/&H00000000\r\n"),
+ eTextEncoding);
+ }
+ }
+
+ // section 2.3.1.11 ProjectName
+ exportString(rStrm, OUStringConcatenation("Name=\"" + projectName + "\"\r\n"), eTextEncoding);
+
+ // section 2.3.1.12 ProjectHelpId
+ exportString(rStrm, u"HelpContextID=\"0\"\r\n", eTextEncoding);
+
+ // section 2.3.1.14 ProjectVersionCompat32
+ exportString(rStrm, u"VersionCompatible32=\"393222000\"\r\n", eTextEncoding);
+
+ // section 2.3.1.15 ProjectProtectionState
+#if VBA_ENCRYPTION
+ exportString(rStrm, u"CMG=\"", eTextEncoding);
+ SvMemoryStream aProtectedStream(4096, 4096);
+ aProtectedStream.WriteUInt32(0x00000000);
+ const sal_uInt8* pData = static_cast<const sal_uInt8*>(aProtectedStream.GetData());
+ sal_uInt8 nProjKey = VBAEncryption::calculateProjKey(aProjectID);
+ VBAEncryption aProtectionState(pData, 4, rStrm, nProjKey, eTextEncoding);
+ aProtectionState.write();
+ exportString(rStrm, u"\"\r\n", eTextEncoding);
+#else
+ exportString(rStrm, "CMG=\"BEBC9256EEAAA8AEA8AEA8AEA8AE\"\r\n", eTextEncoding);
+#endif
+
+ // section 2.3.1.16 ProjectPassword
+#if VBA_ENCRYPTION
+ exportString(rStrm, u"DPB=\"", eTextEncoding);
+ aProtectedStream.Seek(0);
+ aProtectedStream.WriteUInt8(0x00);
+ pData = static_cast<const sal_uInt8*>(aProtectedStream.GetData());
+ VBAEncryption aProjectPassword(pData, 1, rStrm, nProjKey, eTextEncoding);
+ aProjectPassword.write();
+ exportString(rStrm, u"\"\r\n", eTextEncoding);
+#else
+ exportString(rStrm, "DPB=\"7C7E5014B0D3B1D3B1D3\"\r\n", eTextEncoding);
+#endif
+
+ // section 2.3.1.17 ProjectVisibilityState
+#if VBA_ENCRYPTION
+ exportString(rStrm, u"GC=\"", eTextEncoding);
+ aProtectedStream.Seek(0);
+ aProtectedStream.WriteUInt8(0xFF);
+ pData = static_cast<const sal_uInt8*>(aProtectedStream.GetData());
+ VBAEncryption aVisibilityState(pData, 1, rStrm, nProjKey, eTextEncoding);
+ aVisibilityState.write();
+ exportString(rStrm, u"\"\r\n\r\n", eTextEncoding);
+#else
+ exportString(rStrm, "GC=\"3A3816DAD5DBD5DB2A\"\r\n\r\n", eTextEncoding);
+#endif
+
+ // section 2.3.1.18 HostExtenders
+ exportString(rStrm,
+ u"[Host Extender Info]\r\n"
+ "&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000\r\n\r\n",
+ eTextEncoding);
+
+ // section 2.3.1.19 ProjectWorkspace
+ exportString(rStrm, u"[Workspace]\r\n", eTextEncoding);
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const OUString& rModuleName = aElementNames[rLibraryMap[i]];
+ css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(rModuleName);
+ if(aModuleInfo.ModuleType == 1)
+ {
+ exportString(rStrm, OUStringConcatenation(rModuleName + "=25, 25, 1439, 639, \r\n"),
+ eTextEncoding);
+ }
+ else
+ {
+ exportString(rStrm, OUStringConcatenation(rModuleName + "=0, 0, 0, 0, C\r\n"),
+ eTextEncoding);
+ }
+ }
+}
+
+// section 2.3.3.1 NAMEMAP
+void writeNAMEMAP(SvStream& rStrm, const css::uno::Sequence<OUString>& rElementNames,
+ const std::vector<sal_Int32>& rLibraryMap, const rtl_TextEncoding eTextEncoding)
+{
+ int n = rElementNames.getLength();
+ for(sal_Int32 i = 0; i < n; ++i)
+ {
+ const OUString& rModuleName = rElementNames[rLibraryMap[i]];
+ exportString(rStrm, rModuleName, eTextEncoding);
+ rStrm.WriteUInt8(0x00); // terminator
+ exportUTF16String(rStrm, rModuleName);
+ rStrm.WriteUInt16(0x0000); // terminator
+ }
+}
+
+// section 2.3.3 PROJECTwm Stream
+void exportPROJECTwmStream(SvStream& rStrm, const css::uno::Sequence<OUString>& rElementNames,
+ const std::vector<sal_Int32>& rLibraryMap, const rtl_TextEncoding eTextEncoding)
+{
+ writeNAMEMAP(rStrm, rElementNames, rLibraryMap, eTextEncoding);
+ rStrm.WriteUInt16(0x0000); // terminator
+}
+
+void getCorrectExportOrder(const css::uno::Reference<css::container::XNameContainer>& xNameContainer, std::vector<sal_Int32>& rLibraryMap)
+{
+ const css::uno::Sequence<OUString> aElementNames = xNameContainer->getElementNames();
+ sal_Int32 n = aElementNames.getLength();
+ css::uno::Reference<css::script::vba::XVBAModuleInfo> xModuleInfo(xNameContainer, css::uno::UNO_QUERY);
+
+ sal_Int32 nCurrentId = 0;
+ // first all the non-document modules
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(aElementNames[i]);
+ if (aModuleInfo.ModuleType != 4)
+ {
+ rLibraryMap[nCurrentId] = i;
+ ++nCurrentId;
+ }
+ }
+
+ sal_Int32 nWorkbookIndex = -1;
+ // then possibly the workbook module
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(aElementNames[i]);
+ bool bWorkbook = isWorkbook(aModuleInfo.ModuleObject);
+ if (bWorkbook)
+ {
+ nWorkbookIndex = i;
+ rLibraryMap[nCurrentId] = i;
+ ++nCurrentId;
+ }
+ }
+
+ // then the remaining modules
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ if (i == nWorkbookIndex)
+ continue;
+
+ css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(aElementNames[i]);
+ if (aModuleInfo.ModuleType == 4)
+ {
+ rLibraryMap[nCurrentId] = i;
+ ++nCurrentId;
+ }
+ }
+}
+
+}
+
+#if VBA_USE_ORIGINAL_WM_STREAM || VBA_USE_ORIGINAL_DIR_STREAM \
+ || VBA_USE_ORIGINAL_PROJECT_STREAM || VBA_USE_ORIGINAL_VBA_PROJECT \
+ || VBA_USE_ORIGINAL_DIR_STREAM
+void addFileStreamToSotStream(const OUString& rPath, SotStorageStream& rStream)
+{
+ SvFileStream aFileStream(rPath, StreamMode::READWRITE);
+ rStream.WriteStream(aFileStream);
+}
+#endif
+
+void VbaExport::exportVBA(SotStorage* pRootStorage)
+{
+ css::uno::Reference<css::container::XNameContainer> xNameContainer = getBasicLibrary();
+ if (!xNameContainer.is()) {
+ return;
+ }
+ const css::uno::Sequence<OUString> aElementNames = xNameContainer->getElementNames();
+ sal_Int32 n = aElementNames.getLength(); // get the number of modules
+ // export the elements in the order MSO expects them
+ // we store the index of the
+ std::vector<sal_Int32> aLibraryMap(n, 0);
+ getCorrectExportOrder(xNameContainer, aLibraryMap);
+
+ // start here with the VBA export
+ tools::SvRef<SotStorage> xVBAStream = pRootStorage->OpenSotStorage("VBA", StreamMode::READWRITE);
+ tools::SvRef<SotStorageStream> pDirStream = xVBAStream->OpenSotStream("dir", StreamMode::READWRITE);
+
+ tools::SvRef<SotStorageStream> pVBAProjectStream = xVBAStream->OpenSotStream("_VBA_PROJECT", StreamMode::READWRITE);
+ tools::SvRef<SotStorageStream> pPROJECTStream = pRootStorage->OpenSotStream("PROJECT", StreamMode::READWRITE);
+ tools::SvRef<SotStorageStream> pPROJECTwmStream = pRootStorage->OpenSotStream("PROJECTwm", StreamMode::READWRITE);
+
+ const rtl_TextEncoding eTextEncoding = getVBATextEncoding();
+
+#if VBA_USE_ORIGINAL_WM_STREAM
+ OUString aProjectwmPath = "/home/moggi/Documents/testfiles/vba/PROJECTwm";
+ addFileStreamToSotStream(aProjectwmPath, *pPROJECTwmStream);
+#else
+ exportPROJECTwmStream(*pPROJECTwmStream, aElementNames, aLibraryMap, eTextEncoding);
+#endif
+
+#if VBA_USE_ORIGINAL_DIR_STREAM
+ OUString aDirPath = "/home/moggi/Documents/testfiles/vba/VBA/dir";
+ addFileStreamToSotStream(aDirPath, *pDirStream);
+#else
+ exportDirStream(*pDirStream, xNameContainer, aLibraryMap, getProjectName(), eTextEncoding);
+#endif
+
+#if VBA_USE_ORIGINAL_PROJECT_STREAM
+ OUString aProjectPath = "/home/moggi/Documents/testfiles/vba/PROJECT";
+ addFileStreamToSotStream(aProjectPath, *pPROJECTStream);
+#else
+ exportPROJECTStream(*pPROJECTStream, xNameContainer, getProjectName(), aLibraryMap,
+ eTextEncoding);
+#endif
+
+#if VBA_USE_ORIGINAL_VBA_PROJECT
+ OUString a_VBA_ProjectPath = "/home/moggi/Documents/testfiles/vba/VBA/_VBA_PROJECT";
+ addFileStreamToSotStream(a_VBA_ProjectPath, *pVBAProjectStream);
+#else
+ exportVBAProjectStream(*pVBAProjectStream);
+#endif
+
+#if VBA_USE_ORIGINAL_DIR_STREAM
+ OUString aModule1Path = "/home/moggi/Documents/testfiles/vba/VBA/Module1";
+ OUString aSheet1Path = "/home/moggi/Documents/testfiles/vba/VBA/Sheet1";
+ OUString aSheet2Path = "/home/moggi/Documents/testfiles/vba/VBA/Sheet2";
+ OUString aSheet3Path = "/home/moggi/Documents/testfiles/vba/VBA/Sheet3";
+ OUString aWorkbookPath = "/home/moggi/Documents/testfiles/vba/VBA/ThisWorkbook";
+ tools::SvRef<SotStorageStream> pModule1Stream = xVBAStream->OpenSotStream("Module1", StreamMode::READWRITE);
+ tools::SvRef<SotStorageStream> pSheet1Stream = xVBAStream->OpenSotStream("Sheet1", StreamMode::READWRITE);
+ tools::SvRef<SotStorageStream> pSheet2Stream = xVBAStream->OpenSotStream("Sheet2", StreamMode::READWRITE);
+ tools::SvRef<SotStorageStream> pSheet3Stream = xVBAStream->OpenSotStream("Sheet3", StreamMode::READWRITE);
+ tools::SvRef<SotStorageStream> pWorkbookStream = xVBAStream->OpenSotStream("ThisWorkbook", StreamMode::READWRITE);
+ addFileStreamToSotStream(aModule1Path, *pModule1Stream);
+ addFileStreamToSotStream(aSheet1Path, *pSheet1Stream);
+ addFileStreamToSotStream(aSheet2Path, *pSheet2Stream);
+ addFileStreamToSotStream(aSheet3Path, *pSheet3Stream);
+ addFileStreamToSotStream(aWorkbookPath, *pWorkbookStream);
+
+ pModule1Stream->Commit();
+ pSheet1Stream->Commit();
+ pSheet2Stream->Commit();
+ pSheet3Stream->Commit();
+ pWorkbookStream->Commit();
+#else
+
+ css::uno::Reference<css::script::vba::XVBAModuleInfo> xModuleInfo(xNameContainer, css::uno::UNO_QUERY);
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const OUString& rModuleName = aElementNames[aLibraryMap[i]];
+ tools::SvRef<SotStorageStream> pModuleStream = xVBAStream->OpenSotStream(rModuleName, StreamMode::READWRITE);
+ css::uno::Any aCode = xNameContainer->getByName(rModuleName);
+ css::script::ModuleInfo aModuleInfo = xModuleInfo->getModuleInfo(rModuleName);
+ OUString aSourceCode;
+ aCode >>= aSourceCode;
+ exportModuleStream(*pModuleStream, aSourceCode, rModuleName, aModuleInfo, eTextEncoding);
+ pModuleStream->Commit();
+ }
+
+#endif
+
+ pVBAProjectStream->Commit();
+
+ pDirStream->Commit();
+ xVBAStream->Commit();
+ pPROJECTStream->Commit();
+ pPROJECTwmStream->Commit();
+ pRootStorage->Commit();
+}
+
+css::uno::Reference<css::script::XLibraryContainer> VbaExport::getLibraryContainer() const
+{
+ oox::PropertySet aDocProp(mxModel);
+ css::uno::Reference<css::script::XLibraryContainer> xLibContainer(aDocProp.getAnyProperty(oox::PROP_BasicLibraries), css::uno::UNO_QUERY);
+
+ return xLibContainer;
+}
+
+css::uno::Reference<css::container::XNameContainer> VbaExport::getBasicLibrary() const
+{
+ css::uno::Reference<css::container::XNameContainer> xLibrary;
+ try
+ {
+ css::uno::Reference<css::script::XLibraryContainer> xLibContainer = getLibraryContainer();
+ OUString aProjectName = getProjectName();
+ xLibrary.set( xLibContainer->getByName(aProjectName), css::uno::UNO_QUERY_THROW );
+ }
+ catch(...)
+ {
+ }
+
+ return xLibrary;
+}
+
+bool VbaExport::containsVBAProject()
+{
+ css::uno::Reference<css::script::XLibraryContainer> xLibContainer = getLibraryContainer();
+ if (!xLibContainer.is())
+ return false;
+
+ css::uno::Reference<css::script::vba::XVBACompatibility> xVbaCompatibility (xLibContainer, css::uno::UNO_QUERY);
+ if (!xVbaCompatibility.is())
+ return false;
+
+ bool bVBACompatibility = xVbaCompatibility->getVBACompatibilityMode();
+
+ return bVBACompatibility;
+}
+
+OUString VbaExport::getProjectName() const
+{
+ css::uno::Reference<css::script::vba::XVBACompatibility> xVbaCompatibility(getLibraryContainer(), css::uno::UNO_QUERY);
+ if (xVbaCompatibility.is())
+ return xVbaCompatibility->getProjectName();
+
+ return OUString();
+}
+
+rtl_TextEncoding VbaExport::getVBATextEncoding() const
+{
+ rtl_TextEncoding aTextEncoding = osl_getThreadTextEncoding();
+ css::uno::Reference<css::beans::XPropertySet> xProps(getLibraryContainer(),
+ css::uno::UNO_QUERY);
+ if (xProps.is())
+ try
+ {
+ xProps->getPropertyValue("VBATextEncoding") >>= aTextEncoding;
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+
+ return aTextEncoding;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */