Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/oox/source/ole/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 40 kB image not shown  

Quelle  vbaexport.cxx   Sprache: C

 
/* -*- 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 <utility>
#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> xModel):
    mxModel(std::move(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, std::u16string_view name, const rtl_TextEncoding eTextEncoding)
{
    rStrm.WriteUInt16(0x0004); // id
    size_t sizeOfProjectName = name.size();
    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, std::u16string_view 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, std::u16string_view libid,
                              const rtl_TextEncoding eTextEncoding)
{
    rStrm.WriteUInt16(0x000D); // id
    size_t sizeOfLibid = libid.size();
    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, std::u16string_view 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, u"stdole"_ustr, u"*\\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\\Windows\\SysWOW64\\stdole2.tlb#OLE Automation", eTextEncoding);
    writeREFERENCE(rStrm, u"Office"_ustr, u"*\\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, std::u16string_view name, const rtl_TextEncoding eTextEncoding)
{
    rStrm.WriteUInt16(0x0019); // id
    sal_Int32 n = name.size(); // 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 constexpr 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, Concat2View("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, Concat2View("Module=" + rModuleName + "\r\n"),
                         eTextEncoding);
        }
        else if(aModuleInfo.ModuleType == 4)
        {
            exportString(rStrm,
                         Concat2View("Document=" + rModuleName + "/&H00000000\r\n"),
                         eTextEncoding);
        }
    }

    // section 2.3.1.11 ProjectName
    exportString(rStrm, Concat2View("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, Concat2View(rModuleName + "=25, 25, 1439, 639, \r\n"),
                         eTextEncoding);
        }
        else
        {
            exportString(rStrm, Concat2View(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>&&nbsp;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
    rtl::Reference<SotStorage> xVBAStream = pRootStorage->OpenSotStorage(u"VBA"_ustr, StreamMode::READWRITE);
    rtl::Reference<SotStorageStream> pDirStream = xVBAStream->OpenSotStream(u"dir"_ustr, StreamMode::READWRITE);

    rtl::Reference<SotStorageStream> pVBAProjectStream = xVBAStream->OpenSotStream(u"_VBA_PROJECT"_ustr, StreamMode::READWRITE);
    rtl::Reference<SotStorageStream> pPROJECTStream = pRootStorage->OpenSotStream(u"PROJECT"_ustr, StreamMode::READWRITE);
    rtl::Reference<SotStorageStream> pPROJECTwmStream = pRootStorage->OpenSotStream(u"PROJECTwm"_ustr, 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]];
        rtl::Reference<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(u"VBATextEncoding"_ustr) >>= aTextEncoding;
        }
        catch (const css::uno::Exception&)
        {
        }

    return aTextEncoding;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=91 H=92 G=91

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.