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