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