Coverage Report

Created: 2026-08-14 10:22

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