merge the formfield patch from ooo-build
[ooovba.git] / svx / source / msfilter / msvbasic.cxx
blob7163037edb3382377c7ceb2bc99954616da59ef1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: msvbasic.cxx,v $
10 * $Revision: 1.22 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
36 #include <string.h> // memset(), ...
37 #ifndef UNX
38 #include <io.h> // access()
39 #endif
40 #include <osl/endian.h>
41 #include <rtl/tencinfo.h> //rtl_getTextEncodingFromWindowsCodePage
42 #include "msvbasic.hxx"
43 #include <fstream>
44 #include <memory>
45 #include <rtl/ustrbuf.hxx>
46 #include <boost/shared_ptr.hpp>
47 #include <boost/scoped_array.hpp>
48 #include <boost/shared_array.hpp>
49 #include <svtools/filterutils.hxx>
51 using namespace ::com::sun::star::script;
53 namespace MSLZSS {
55 static unsigned int getShift( sal_uInt32 nPos )
57 if (nPos <= 0x80) {
58 if (nPos <= 0x20)
59 return (nPos <= 0x10) ? 12 : 11;
60 else
61 return (nPos <= 0x40) ? 10 : 9;
62 } else {
63 if (nPos <= 0x200)
64 return (nPos <= 0x100) ? 8 : 7;
65 else if (nPos <= 0x800)
66 return (nPos <= 0x400) ? 6 : 5;
67 else
68 return 4;
72 SvMemoryStream *decompressAsStream( SvStream *pStream, sal_uInt32 nOffset, sal_uInt32 *pCompressedLength = NULL, sal_uInt32 *pLength = NULL )
74 SvMemoryStream *pResult;
75 const sal_Int32 nWINDOWLEN = 4096;
76 pResult = new SvMemoryStream();
78 sal_uInt8 nLeadbyte;
79 unsigned int nPos = 0;
80 int nLen, nDistance, nShift, nClean=1;
81 sal_uInt8 aHistory[ nWINDOWLEN ];
83 pStream->Seek( nOffset + 3 );
85 while( pStream->Read( &nLeadbyte, 1 ) )
87 for(int nMask=0x01; nMask < 0x100; nMask = nMask<<1)
89 // we see if the leadbyte has flagged this location as a dataunit
90 // which is actually a token which must be looked up in the history
91 if( nLeadbyte & nMask )
93 sal_uInt16 nToken;
95 *pStream >> nToken;
97 if (nClean == 0)
98 nClean=1;
100 //For some reason the division of the token into the length
101 //field of the data to be inserted, and the distance back into
102 //the history differs depending on how full the history is
103 nShift = getShift( nPos % nWINDOWLEN );
105 nLen = (nToken & ((1<<nShift) - 1)) + 3;
106 nDistance = nToken >> nShift;
108 //read the len of data from the history, wrapping around the
109 //nWINDOWLEN boundary if necessary data read from the history
110 //is also copied into the recent part of the history as well.
111 for (int i = 0; i < nLen; i++)
113 unsigned char c;
114 c = aHistory[(nPos-nDistance-1) % nWINDOWLEN];
115 aHistory[nPos % nWINDOWLEN] = c;
116 nPos++;
119 else
121 // special boundary case code, not guarantueed to be correct
122 // seems to work though, there is something wrong with the
123 // compression scheme (or maybe a feature) where when the data
124 // ends on a nWINDOWLEN boundary and the excess bytes in the 8
125 // dataunit list are discarded, and not interpreted as tokens
126 // or normal data.
127 if ((nPos != 0) && ((nPos % nWINDOWLEN) == 0) && (nClean))
129 pStream->SeekRel(2);
130 nClean=0;
131 pResult->Write( aHistory, nWINDOWLEN );
132 break;
134 //This is the normal case for when the data unit is not a
135 //token to be looked up, but instead some normal data which
136 //can be output, and placed in the history.
137 if (pStream->Read(&aHistory[nPos % nWINDOWLEN],1))
138 nPos++;
140 if (nClean == 0)
141 nClean=1;
145 if (nPos % nWINDOWLEN)
146 pResult->Write( aHistory, nPos % nWINDOWLEN );
147 pResult->Flush();
149 if( pCompressedLength )
150 *pCompressedLength = nPos;
152 if( pLength )
153 *pLength = pResult->Tell();
155 pResult->Seek( 0 );
157 return pResult;
160 } //MSZSS
162 // also _VBA_PROJECT_VDPI can be used to create a usable
163 // ( and much smaller ) "_VBA_PROJECT" stream
165 // _VBA_PROJECT Stream Version Dependant Project Information
166 // _VBA_PROJECT Stream Version Dependant Project Information
168 class _VBA_PROJECT_VDPI
170 public:
171 sal_Int16 Reserved1;
172 sal_Int16 Version;
173 sal_Int8 Reserved2;
174 sal_Int16 Reserved3;
175 boost::scoped_array< sal_uInt8 > PerformanceCache;
176 sal_Int32 PerformanceCacheSize;
177 _VBA_PROJECT_VDPI(): Reserved1( 0x61CC), Version( 0xFFFF ), Reserved2(0x0), Reserved3(0x0), PerformanceCacheSize(0) {}
178 ~_VBA_PROJECT_VDPI()
180 PerformanceCacheSize = 0;
182 void read(){}
183 void write( SvStream* pStream )
185 *pStream << Reserved1 << Version << Reserved2 << Reserved3;
186 if ( PerformanceCacheSize )
188 PerformanceCache.reset( new sal_uInt8[ PerformanceCacheSize ] );
189 pStream->Read( PerformanceCache.get(), PerformanceCacheSize );
194 class ProjectSysKindRecord
196 public:
197 sal_Int16 Id;
198 sal_Int32 Size;
199 sal_Int32 SysKind;
200 ProjectSysKindRecord(): Id(0x1), Size(0x4), SysKind( 0x1 ) {}
201 void read( SvStream* pStream )
203 *pStream >> Id >> Size >> SysKind;
207 class ProjectLcidRecord
209 public:
210 sal_Int16 Id;
211 sal_Int32 Size;
212 sal_Int32 Lcid;
214 ProjectLcidRecord() : Id( 0x2 ), Size( 0x4 ), Lcid( 0x409 ) {}
215 void read( SvStream* pStream )
217 OSL_TRACE("ProjectLcidRecord [0x%x]", pStream->Tell() );
218 *pStream >> Id >> Size >> Lcid;
222 class ProjectLcidInvokeRecord
224 sal_Int16 Id;
225 sal_Int32 Size;
226 sal_Int32 LcidInvoke;
227 public:
228 ProjectLcidInvokeRecord() : Id( 0x14 ), Size( 0x4 ), LcidInvoke( 0x409 ) {}
229 void read( SvStream* pStream )
231 OSL_TRACE("ProjectLcidInvokeRecord [0x%x]", pStream->Tell() );
232 *pStream >> Id >> Size >> LcidInvoke;
236 class ProjectCodePageRecord
238 sal_Int16 Id;
239 sal_Int32 Size;
240 sal_Int16 CodePage;
241 public:
242 // #FIXME get a better default for the CodePage
243 ProjectCodePageRecord() : Id( 0x03 ), Size( 0x2 ), CodePage( 0x0 ) {}
244 void read( SvStream* pStream )
246 OSL_TRACE("ProjectCodePageRecord [0x%x]", pStream->Tell() );
247 *pStream >> Id >> Size >> CodePage;
250 class ProjectNameRecord
252 public:
253 sal_Int16 Id;
254 sal_Int32 SizeOfProjectName;
255 rtl::OUString ProjectName;
256 ProjectNameRecord() : Id( 0x04 ), SizeOfProjectName( 0x0 ){}
257 ~ProjectNameRecord()
260 void read( SvStream* pStream )
262 OSL_TRACE("ProjectNameRecord [0x%x]", pStream->Tell() );
263 *pStream >> Id >> SizeOfProjectName;
265 if ( SizeOfProjectName )
267 boost::scoped_array< sal_uInt8 > pProjectName( new sal_uInt8[ SizeOfProjectName ] );
268 OSL_TRACE("ProjectNameRecord about to read name from [0x%x], size %d", pStream->Tell(), SizeOfProjectName );
269 pStream->Read( pProjectName.get(), SizeOfProjectName );
270 ProjectName = svt::BinFilterUtils::CreateOUStringFromStringArray( reinterpret_cast< const char* >( pProjectName.get() ), SizeOfProjectName );
275 class ProjectDocStringRecord
277 public:
278 sal_Int16 Id;
279 sal_Int32 SizeOfDocString;
280 sal_Int16 Reserved;
281 sal_Int32 SizeOfDocStringUnicode;
282 rtl::OUString DocString;
283 rtl::OUString DocStringUnicode;
285 ProjectDocStringRecord() : Id( 0x5 ), SizeOfDocString( 0x0 ), Reserved( 0x0 ), SizeOfDocStringUnicode( 0 ){}
287 ~ProjectDocStringRecord()
290 void read( SvStream* pStream )
292 OSL_TRACE("ProjectDocStringRecord [0x%x]", pStream->Tell() );
293 *pStream >> Id >> SizeOfDocString;
296 boost::scoped_array< sal_uInt8 > pDocString( new sal_uInt8[ SizeOfDocString ] );
297 pStream->Read( pDocString.get(), SizeOfDocString );
299 DocString = svt::BinFilterUtils::CreateOUStringFromStringArray( reinterpret_cast< const char* >( pDocString.get() ), SizeOfDocString );
301 *pStream >> Reserved >> SizeOfDocStringUnicode;
303 boost::scoped_array< sal_uInt8 > pDocStringUnicode( new sal_uInt8[ SizeOfDocStringUnicode ] );
305 pStream->Read( pDocStringUnicode.get(), SizeOfDocStringUnicode );
306 DocStringUnicode = svt::BinFilterUtils::CreateOUStringFromUniStringArray( reinterpret_cast< const char* >( pDocStringUnicode.get() ), SizeOfDocString );
312 class ProjectHelpFilePath
314 public:
315 sal_Int16 Id;
316 sal_Int32 SizeOfHelpFile1;
317 boost::scoped_array< sal_uInt8 > HelpFile1;
318 sal_Int16 Reserved;
319 sal_Int32 SizeOfHelpFile2;
320 boost::scoped_array< sal_uInt8 > HelpFile2;
322 ProjectHelpFilePath() : Id( 0x06 ), SizeOfHelpFile1(0), Reserved(0x0), SizeOfHelpFile2(0) {}
323 ~ProjectHelpFilePath()
327 void read( SvStream* pStream )
329 OSL_TRACE("ProjectHelpFilePath [0x%x]", pStream->Tell() );
330 *pStream >> Id >> SizeOfHelpFile1;
332 HelpFile1.reset( new sal_uInt8[ SizeOfHelpFile1 ] );
333 pStream->Read( HelpFile1.get(), SizeOfHelpFile1 );
335 *pStream >> Reserved >> SizeOfHelpFile2;
337 HelpFile2.reset( new sal_uInt8[ SizeOfHelpFile2 ] );
338 pStream->Read( HelpFile2.get(), SizeOfHelpFile2 );
343 class ProjectHelpContextRecord
345 public:
346 sal_Int16 Id;
347 sal_Int32 Size;
348 sal_Int32 HelpContext;
350 ProjectHelpContextRecord() : Id( 0x7 ), Size( 0x4 ), HelpContext( 0 ) {}
351 void read( SvStream* pStream )
354 OSL_TRACE("ProjectHelpContextRecord [0x%x]", pStream->Tell() );
355 *pStream >> Id >> Size >> HelpContext;
360 class ProjectLibFlagsRecord
362 sal_Int16 Id;
363 sal_Int32 Size;
364 sal_Int32 ProjectLibFlags;
366 public:
367 ProjectLibFlagsRecord() : Id( 0x8 ), Size( 0x4 ), ProjectLibFlags( 0x0 ) {}
368 void read( SvStream* pStream )
370 OSL_TRACE("ProjectLibFlagsRecord [0x%x]", pStream->Tell() );
371 *pStream >> Id >> Size >> ProjectLibFlags;
375 class ProjectVersionRecord
377 public:
378 sal_Int16 Id;
379 sal_Int32 Reserved;
380 sal_Int32 VersionMajor;
381 sal_Int16 VersionMinor;
382 ProjectVersionRecord() : Id( 0x9 ), Reserved( 0x4 ), VersionMajor( 0x1 ), VersionMinor( 0 ) {}
383 void read( SvStream* pStream )
385 OSL_TRACE("ProjectVersionRecord [0x%x]", pStream->Tell() );
386 *pStream >> Id >> Reserved >> VersionMajor >> VersionMinor;
390 class ProjectConstantsRecord
392 sal_Int16 Id;
393 sal_Int32 SizeOfConstants;
394 boost::scoped_array< sal_uInt8 > Constants;
395 sal_Int16 Reserved;
396 sal_Int32 SizeOfConstantsUnicode;
397 boost::scoped_array< sal_uInt8 > ConstantsUnicode;
398 public:
399 ProjectConstantsRecord() : Id( 0xC ), SizeOfConstants( 0 ), Constants( 0 ), Reserved( 0x3C ), SizeOfConstantsUnicode( 0 ), ConstantsUnicode(0) {}
401 ~ProjectConstantsRecord()
405 void read( SvStream* pStream )
407 OSL_TRACE("ProjectConstantsRecord [0x%x]", pStream->Tell() );
408 *pStream >> Id >> SizeOfConstants;
409 Constants.reset( new sal_uInt8[ SizeOfConstants ] );
411 pStream->Read( Constants.get(), SizeOfConstants );
413 *pStream >> Reserved;
415 *pStream >> SizeOfConstantsUnicode;
417 ConstantsUnicode.reset( new sal_uInt8[ SizeOfConstantsUnicode ] );
418 pStream->Read( ConstantsUnicode.get(), SizeOfConstantsUnicode );
423 class ReferenceNameRecord
425 public:
426 sal_Int16 Id;
427 sal_Int32 SizeOfName;
428 rtl::OUString Name;
429 sal_Int16 Reserved;
430 sal_Int32 SizeOfNameUnicode;
431 rtl::OUString NameUnicode;
433 ReferenceNameRecord() : Id( 0x16 ), SizeOfName( 0 ), Reserved( 0x3E ), SizeOfNameUnicode( 0 ){}
434 ~ReferenceNameRecord()
438 void read( SvStream* pStream )
440 OSL_TRACE("NameRecord [0x%x]", pStream->Tell() );
441 *pStream >> Id >> SizeOfName;
443 boost::scoped_array< sal_uInt8 > pName( new sal_uInt8[ SizeOfName ] );
445 pStream->Read( pName.get(), SizeOfName );
446 Name = svt::BinFilterUtils::CreateOUStringFromStringArray( reinterpret_cast< const char* >( pName.get() ), SizeOfName );
448 *pStream >> Reserved >> SizeOfNameUnicode;
450 boost::scoped_array< sal_uInt8 > pNameUnicode( new sal_uInt8[ SizeOfNameUnicode ] );
451 pStream->Read( pNameUnicode.get(), SizeOfNameUnicode );
452 NameUnicode = svt::BinFilterUtils::CreateOUStringFromUniStringArray( reinterpret_cast< const char* >( pNameUnicode.get() ), SizeOfName );
457 // Baseclass for ReferenceControlRecord, ReferenceRegisteredRecord, ReferenceProjectRecord
458 class DirDumper;
460 class BaseReferenceRecord
462 public:
463 virtual ~BaseReferenceRecord(){}
464 virtual bool read( SvStream* pStream ) = 0;
465 virtual void import( VBA_Impl& ){}
469 class ReferenceProjectRecord : public BaseReferenceRecord
471 public:
472 sal_uInt16 Id;
473 sal_uInt32 Size;
474 sal_uInt32 SizeOfLibidAbsolute;
475 sal_uInt32 SizeOfLibidRelative;
476 sal_uInt32 MajorVersion;
477 sal_uInt16 MinorVersion;
478 rtl::OUString AbsoluteLibid;
479 rtl::OUString RelativeLibid;
481 virtual bool read( SvStream* pStream );
482 virtual void import( VBA_Impl& rDir );
483 ReferenceProjectRecord();
484 ~ReferenceProjectRecord();
487 ReferenceProjectRecord::ReferenceProjectRecord() : Id( 0x000E ), Size( 0 ), SizeOfLibidAbsolute( 0 ), SizeOfLibidRelative( 0 ), MajorVersion( 0 ), MinorVersion( 0 )
491 ReferenceProjectRecord::~ReferenceProjectRecord()
495 bool ReferenceProjectRecord::read( SvStream* pStream )
497 OSL_TRACE("ReferenceProjectRecord [0x%x]", pStream->Tell() );
498 *pStream >> Id >> Size >> SizeOfLibidAbsolute;
500 boost::scoped_array< sal_uInt8 > pLibidAbsolute( new sal_uInt8[ SizeOfLibidAbsolute ] );
501 OSL_TRACE("ReferenceProjectRecord about to read LibidAbsolute at [0x%x]", pStream->Tell() );
502 pStream->Read( pLibidAbsolute.get(), SizeOfLibidAbsolute );
504 *pStream >> SizeOfLibidRelative;
506 boost::scoped_array< sal_uInt8 > pLibidRelative( new sal_uInt8[ SizeOfLibidRelative ] );
507 OSL_TRACE("ReferenceProjectRecord about to read LibidRelative at [0x%x]", pStream->Tell() );
508 pStream->Read( pLibidRelative.get(), SizeOfLibidRelative );
510 *pStream >> MajorVersion >> MinorVersion;
512 // array size is ORed with SVX_MSOCX_COMPRESSED to force processing of ascii bytes ( and not
513 // 16 bit unicode )
514 // the offset of 3 is needed to skip the ProjectReference "*\" and project kind ( 0x4[1-4] ) info.
516 AbsoluteLibid = svt::BinFilterUtils::CreateOUStringFromStringArray( reinterpret_cast< const char* >( pLibidAbsolute.get() + 3 ), (SizeOfLibidAbsolute - 3 ) );
517 RelativeLibid = svt::BinFilterUtils::CreateOUStringFromStringArray( reinterpret_cast< const char* >( pLibidRelative.get() + 3 ), ( SizeOfLibidRelative -3 ) );
519 OSL_TRACE("ReferenceProjectRecord - absolute path %s", rtl::OUStringToOString( AbsoluteLibid, RTL_TEXTENCODING_UTF8 ).getStr() );
520 OSL_TRACE("ReferenceProjectRecord - relative path %s", rtl::OUStringToOString( RelativeLibid, RTL_TEXTENCODING_UTF8 ).getStr() );
521 return true;
524 void ReferenceProjectRecord::import( VBA_Impl& rDir )
526 rDir.AddProjectReference( AbsoluteLibid );
529 class ReferenceRegisteredRecord : public BaseReferenceRecord
531 public:
532 sal_uInt16 Id;
533 sal_uInt32 Size;
534 sal_uInt32 SizeOfLibid;
535 boost::scoped_array< sal_uInt8> pLibid;
536 sal_Int32 Reserved1;
537 sal_Int16 Reserved2;
539 ReferenceRegisteredRecord();
540 ~ReferenceRegisteredRecord();
541 bool read( SvStream* pStream );
544 ReferenceRegisteredRecord::ReferenceRegisteredRecord() : Id( 0x000D ), Size( 0 ), SizeOfLibid( 0 ), Reserved1( 0 ), Reserved2( 0 )
548 ReferenceRegisteredRecord::~ReferenceRegisteredRecord()
552 bool
553 ReferenceRegisteredRecord::read( SvStream* pStream )
555 OSL_TRACE("ReferenceRegisteredRecord [0x%x]", pStream->Tell() );
556 *pStream >> Id >> Size >> SizeOfLibid;
557 if ( SizeOfLibid )
559 pLibid.reset( new sal_uInt8[ SizeOfLibid] );
560 pStream->Read( pLibid.get(), SizeOfLibid );
562 *pStream >> Reserved1 >> Reserved2;
563 return true;
566 class ReferenceOriginalRecord
568 public:
569 sal_uInt16 Id;
570 sal_uInt32 SizeOfLibOriginal;
571 boost::scoped_array< sal_uInt8 > pLibidOriginal;
574 ReferenceOriginalRecord() : Id( 0x033 ), SizeOfLibOriginal( 0 )
578 ~ReferenceOriginalRecord()
582 void read( SvStream* pStream )
584 *pStream >> Id >> SizeOfLibOriginal;
585 if ( SizeOfLibOriginal )
587 pLibidOriginal.reset( new sal_uInt8[ SizeOfLibOriginal ] );
588 pStream->Read( pLibidOriginal.get(), SizeOfLibOriginal );
594 class ReferenceControlRecord : public BaseReferenceRecord
596 public:
597 std::auto_ptr< ReferenceOriginalRecord > OriginalRecord;
598 sal_Int16 Id;
599 sal_uInt32 SizeTwiddled;
600 sal_uInt32 SizeOfLibidTwiddled;
601 boost::shared_array< sal_uInt8 > LibidTwiddled;
602 sal_uInt32 Reserved1;
603 sal_uInt16 Reserved2;
604 std::auto_ptr< ReferenceNameRecord > NameRecordExtended;// Optional
605 sal_uInt16 Reserved3;
606 sal_uInt32 SizeExtended;
607 sal_uInt32 SizeOfLibidExtended;
608 boost::shared_array< sal_uInt8 > LibidExtended;
609 sal_uInt32 Reserved4;
610 sal_uInt16 Reserved5;
611 sal_uInt8 OriginalTypeLib[ 16 ];
612 sal_uInt32 Cookie;
614 ReferenceControlRecord() : Id( 0x2F ), SizeTwiddled( 0 ), SizeOfLibidTwiddled( 0 ), Reserved1( 0 ), Reserved2( 0 ), Reserved3( 0x30 ), SizeExtended( 0 ), SizeOfLibidExtended( 0 ), Reserved4( 0 ), Reserved5( 0 ), Cookie( 0 )
616 for( int i = 0; i < 16; ++i )
617 OriginalTypeLib[ i ] = 0;
620 ~ReferenceControlRecord()
624 bool read( SvStream* pStream )
626 OSL_TRACE("ReferenceControlRecord [0x%x]", pStream->Tell() );
627 long nPos = pStream->Tell();
629 *pStream >> Id;
630 pStream->Seek( nPos ); // point before the peeked Id
631 if ( Id == 0x33 ) // we have an OriginalRecord
633 OriginalRecord.reset( new ReferenceOriginalRecord() );
634 OriginalRecord->read( pStream );
636 *pStream >> Id >> SizeTwiddled >> SizeOfLibidTwiddled;
638 if ( SizeOfLibidTwiddled )
640 LibidTwiddled.reset( new sal_uInt8[ SizeOfLibidTwiddled ] );
641 pStream->Read( LibidTwiddled.get(), SizeOfLibidTwiddled );
644 *pStream >> Reserved1 >> Reserved2;
646 nPos = pStream->Tell();
647 // peek at the id for optional NameRecord
648 sal_Int16 nTmpId;
649 *pStream >> nTmpId;
650 if ( nTmpId == 0x30 )
652 Reserved3 = 0x30;
654 else
656 pStream->Seek( nPos );
657 NameRecordExtended.reset( new ReferenceNameRecord() );
658 NameRecordExtended->read( pStream );
659 *pStream >> Reserved3;
661 *pStream >> SizeExtended >> SizeOfLibidExtended;
663 if ( SizeExtended )
665 LibidExtended.reset( new sal_uInt8[ SizeOfLibidExtended ] );
666 pStream->Read( LibidExtended.get(), SizeOfLibidExtended );
669 *pStream >> Reserved4;
670 *pStream >> Reserved5;
672 pStream->Read( OriginalTypeLib, sizeof( OriginalTypeLib ) );
673 *pStream >> Cookie;
674 return true;
679 class ReferenceRecord : public BaseReferenceRecord
681 public:
682 // NameRecord is Optional
683 std::auto_ptr< ReferenceNameRecord > NameRecord;
684 std::auto_ptr< BaseReferenceRecord > aReferenceRecord;
686 ReferenceRecord(){}
687 ~ReferenceRecord()
691 // false return would mean failed to read Record e.g. end of array encountered
692 // Note: this read routine will make sure the stream is pointing to where it was the
693 // method was called )
695 bool read( SvStream* pStream )
697 OSL_TRACE("ReferenceRecord [0x%x]", pStream->Tell() );
698 bool bRead = true;
699 long nStart = pStream->Tell();
700 long nPos = nStart;
701 // Peek at the ID
702 sal_Int16 Id;
703 *pStream >> Id;
704 pStream->Seek( nPos ); // place back before Id
705 if ( Id == 0x16 ) // Optional NameRecord
707 NameRecord.reset( new ReferenceNameRecord() );
708 NameRecord->read( pStream );
710 else if ( Id == 0x0f )
712 pStream->Seek( nStart );
713 bRead = false;
714 return bRead; // start of module, terminate read
717 nPos = pStream->Tell(); // mark position, peek at next Id
718 *pStream >> Id;
719 pStream->Seek( nPos ); // place back before Id
721 switch( Id )
723 case 0x0D:
724 aReferenceRecord.reset( new ReferenceRegisteredRecord() );
725 break;
726 case 0x0E:
727 aReferenceRecord.reset( new ReferenceProjectRecord() );
728 break;
729 case 0x2F:
730 case 0x33:
731 aReferenceRecord.reset( new ReferenceControlRecord() );
732 break;
733 default:
734 bRead = false;
735 OSL_TRACE("Big fat error, unknown ID 0x%x", Id);
736 break;
738 if ( bRead )
739 aReferenceRecord->read( pStream );
740 return bRead;
743 void import( VBA_Impl& rVBA )
745 if ( aReferenceRecord.get() )
746 aReferenceRecord->import( rVBA );
751 class DirDumper
753 public:
754 ProjectSysKindRecord mSysKindRec;
755 ProjectLcidRecord mLcidRec;
756 ProjectLcidInvokeRecord mLcidInvokeRec;
757 ProjectCodePageRecord mCodePageRec;
758 ProjectNameRecord mProjectNameRec;
759 ProjectDocStringRecord mDocStringRec;
760 ProjectHelpFilePath mHelpFileRec;
761 ProjectHelpContextRecord mHelpContextRec;
762 ProjectLibFlagsRecord mLibFlagsRec;
763 ProjectVersionRecord mVersionRec;
764 ProjectConstantsRecord mConstantsRecord;
765 std::vector< ReferenceRecord* > ReferenceArray;
767 DirDumper() {}
768 ~DirDumper()
770 for ( std::vector< ReferenceRecord* >::iterator it = ReferenceArray.begin(); it != ReferenceArray.end(); ++it )
771 delete *it;
775 void read( SvStream* pStream )
777 sal_Int32 nPos = pStream->Tell();
778 #ifdef DEBUG
779 std::ofstream aDump("dir.dump");
780 while ( !pStream->IsEof() )
782 sal_Int8 aByte;
783 *pStream >> aByte;
784 aDump << aByte;
786 aDump.flush();
787 #endif
788 pStream->Seek( nPos );
789 readProjectInformation( pStream );
790 readProjectReferenceInformation( pStream );
793 void readProjectReferenceInformation( SvStream* pStream )
795 bool bKeepReading = true;
796 while( bKeepReading )
798 ReferenceRecord* pRef = new ReferenceRecord();
799 bKeepReading = pRef->read( pStream );
800 if ( bKeepReading )
801 ReferenceArray.push_back( pRef );
805 void readProjectInformation( SvStream* pStream )
807 mSysKindRec.read( pStream );
808 mLcidRec.read( pStream );
809 mLcidInvokeRec.read( pStream );
810 mCodePageRec.read( pStream );
811 mProjectNameRec.read( pStream );
812 mDocStringRec.read( pStream );
813 mHelpFileRec.read( pStream );
814 mHelpContextRec.read( pStream );
815 mLibFlagsRec.read( pStream );
816 mVersionRec.read( pStream );
817 sal_Int32 nPos = pStream->Tell();
818 sal_uInt16 nTmp;
819 *pStream >> nTmp;
820 if ( nTmp == 0x0C )
822 pStream->Seek( nPos );
823 mConstantsRecord.read( pStream );
825 OSL_TRACE("After Information pos is 0x%x", pStream->Tell() );
828 void import( VBA_Impl& rVBA )
830 // get project references
831 for ( std::vector< ReferenceRecord* >::iterator it = ReferenceArray.begin(); it != ReferenceArray.end(); ++it )
832 (*it)->import( rVBA );
833 rVBA.SetProjectName( mProjectNameRec.ProjectName );
840 A few urls which may in the future be of some use
841 http://www.virusbtn.com/vb2000/Programme/papers/bontchev.pdf
844 /* class VBA_Impl:
845 * The VBA class provides a set of methods to handle Visual Basic For
846 * Applications streams, the constructor is given the root ole2 stream
847 * of the document, Open reads the VBA project file and figures out
848 * the number of VBA streams, and the offset of the data within them.
849 * Decompress decompresses a particular numbered stream, NoStreams returns
850 * this number, and StreamName can give you the streams name. Decompress
851 * will call Output when it has a 4096 byte collection of data to output,
852 * and also with the final remainder of data if there is still some left
853 * at the end of compression. Output is virtual to allow custom handling
854 * of each chunk of decompressed data. So inherit from this to do something
855 * useful with the data.
857 * cmc
858 * */
859 const int MINVBASTRING = 6;
861 VBA_Impl::VBA_Impl(SvStorage &rIn, bool bCmmntd)
862 : aVBAStrings(0),
863 sComment(RTL_CONSTASCII_USTRINGPARAM("Rem ")),
864 xStor(&rIn), pOffsets(0), nOffsets(0), meCharSet(RTL_TEXTENCODING_MS_1252),
865 bCommented(bCmmntd), mbMac(false), nLines(0)
869 VBA_Impl::~VBA_Impl()
871 delete [] pOffsets;
872 for (ULONG i=0;i<aVBAStrings.GetSize();++i)
873 delete aVBAStrings.Get(i);
876 sal_uInt8 VBA_Impl::ReadPString(SvStorageStreamRef &xVBAProject,
877 bool bIsUnicode)
879 sal_uInt16 nIdLen, nOut16;
880 sal_uInt8 nType = 0, nOut8;
881 String sReference;
883 *xVBAProject >> nIdLen;
885 if (nIdLen < MINVBASTRING) //Error recovery
886 xVBAProject->SeekRel(-2); //undo 2 byte len
887 else
889 for(sal_uInt16 i=0; i < nIdLen / (bIsUnicode ? 2 : 1); i++)
891 if (bIsUnicode)
892 *xVBAProject >> nOut16;
893 else
895 *xVBAProject >> nOut8;
896 nOut16 = nOut8;
898 sReference += nOut16;
899 if (i==2)
901 if ((nOut16 == 'G') || (nOut16 == 'H') || (nOut16 == 'C') ||
902 nOut16 == 'D')
904 nType = static_cast<sal_uInt8>(nOut16);
906 if (nType == 0)
908 //Error recovery, 2byte len + 3 characters of used type
909 xVBAProject->SeekRel(-(2 + 3 * (bIsUnicode ? 2 : 1)));
910 break;
914 maReferences.push_back(sReference);
916 return nType;
919 void VBA_Impl::Output( int nLen, const sal_uInt8*pData )
922 Each StarBasic module is tragically limited to the maximum len of a
923 string and WordBasic is not, so each overlarge module must be split
925 String sTemp((const sal_Char *)pData, (xub_StrLen)nLen,
926 meCharSet);
927 int nTmp = sTemp.GetTokenCount('\x0D');
928 int nIndex = aVBAStrings.GetSize()-1;
929 if (aVBAStrings.Get(nIndex)->Len() +
930 nLen + ((nLines+nTmp) * sComment.Len()) >= STRING_MAXLEN)
932 //DBG_ASSERT(0,"New Module String\n");
933 //we are too large for our boots, break out into another
934 //string
935 nLines=0;
936 nIndex++;
937 aVBAStrings.SetSize(nIndex+1);
938 aVBAStrings.Put(nIndex,new String);
940 *(aVBAStrings.Get(nIndex)) += sTemp;
941 nLines+=nTmp;
945 int VBA_Impl::ReadVBAProject(const SvStorageRef &rxVBAStorage)
947 SvStorageStreamRef xVBAProject;
948 xVBAProject = rxVBAStorage->OpenSotStream(
949 String( RTL_CONSTASCII_USTRINGPARAM( "_VBA_PROJECT" ) ),
950 STREAM_STD_READ | STREAM_NOCREATE );
951 // read Dir stream
952 SvStorageStreamRef xDir = rxVBAStorage->OpenSotStream(
953 String( RTL_CONSTASCII_USTRINGPARAM( "dir" ) ),
954 STREAM_STD_READ | STREAM_NOCREATE );
955 // disable read and import of Dir stream bits, e.g. project references and
956 // project name for 3.1 ( a bit unstable yet )
957 #if 1
958 // decompress the stream
959 std::auto_ptr< SvMemoryStream > xCmpDir;
960 xCmpDir.reset( MSLZSS::decompressAsStream( xDir, 0 ) );
961 // try to parse the dir stream
962 DirDumper dDump;
963 dDump.read( xCmpDir.get() );
964 dDump.import( *this );
965 #endif
966 if( !xVBAProject.Is() || SVSTREAM_OK != xVBAProject->GetError() )
968 DBG_WARNING("Not able to find vba project, cannot find macros");
969 return 0;
972 static const sal_uInt8 aKnownId[] = {0xCC, 0x61};
973 sal_uInt8 aId[2];
974 xVBAProject->Read( aId, sizeof(aId) );
975 if (memcmp( aId, aKnownId, sizeof(aId)))
977 DBG_WARNING("unrecognized VBA macro project type");
978 return 0;
981 static const sal_uInt8 aOffice2003LE_2[] =
983 0x79, 0x00, 0x00, 0x01, 0x00, 0xFF
986 static const sal_uInt8 aOffice2003LE[] =
988 0x76, 0x00, 0x00, 0x01, 0x00, 0xFF
991 static const sal_uInt8 aOfficeXPLE[] =
993 0x73, 0x00, 0x00, 0x01, 0x00, 0xFF
996 static const sal_uInt8 aOfficeXPBE[] =
998 0x63, 0x00, 0x00, 0x0E, 0x00, 0xFF
1001 static const sal_uInt8 aOffice2000LE[] =
1003 0x6D, 0x00, 0x00, 0x01, 0x00, 0xFF
1005 static const sal_uInt8 aOffice98BE[] =
1007 0x60, 0x00, 0x00, 0x0E, 0x00, 0xFF
1009 static const sal_uInt8 aOffice97LE[] =
1011 0x5E, 0x00, 0x00, 0x01, 0x00, 0xFF
1013 sal_uInt8 aProduct[6];
1014 xVBAProject->Read( aProduct, sizeof(aProduct) );
1016 bool bIsUnicode;
1017 if (!(memcmp(aProduct, aOffice2003LE, sizeof(aProduct))) ||
1018 !(memcmp(aProduct, aOffice2003LE_2, sizeof(aProduct))) )
1020 xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
1021 bIsUnicode = true;
1023 else if (!(memcmp(aProduct, aOfficeXPLE, sizeof(aProduct))))
1025 xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
1026 bIsUnicode = true;
1028 else if (!(memcmp(aProduct, aOfficeXPBE, sizeof(aProduct))))
1030 xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
1031 mbMac = true;
1032 bIsUnicode = false;
1034 else if (!(memcmp(aProduct, aOffice2000LE, sizeof(aProduct))))
1036 xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
1037 bIsUnicode = true;
1039 else if (!(memcmp(aProduct, aOffice98BE, sizeof(aProduct))))
1041 xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
1042 mbMac = true;
1043 bIsUnicode = false;
1045 else if (!(memcmp(aProduct, aOffice97LE, sizeof(aProduct))))
1047 xVBAProject->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
1048 bIsUnicode = true;
1050 else
1052 switch (aProduct[3])
1054 case 0x1:
1055 xVBAProject->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN);
1056 bIsUnicode = true;
1057 DBG_ASSERT(!this, "unrecognized VBA macro version, report to cmc. Guessing at unicode little endian");
1058 break;
1059 case 0xe:
1060 xVBAProject->SetNumberFormatInt(NUMBERFORMAT_INT_BIGENDIAN);
1061 mbMac = true;
1062 bIsUnicode = false;
1063 DBG_ASSERT(!this, "unrecognized VBA macro version, report to cmc. Guessing at 8bit big endian");
1064 break;
1065 default:
1066 DBG_ASSERT(!this, "totally unrecognized VBA macro version, report to cmc");
1067 return 0;
1071 sal_uInt32 nLidA; //Language identifiers
1072 sal_uInt32 nLidB;
1073 sal_uInt16 nCharSet;
1074 sal_uInt16 nLenA;
1075 sal_uInt32 nUnknownB;
1076 sal_uInt32 nUnknownC;
1077 sal_uInt16 nLenB;
1078 sal_uInt16 nLenC;
1079 sal_uInt16 nLenD;
1081 *xVBAProject >> nLidA >> nLidB >> nCharSet >> nLenA >> nUnknownB;
1082 *xVBAProject >> nUnknownC >> nLenB >> nLenC >> nLenD;
1084 meCharSet = rtl_getTextEncodingFromWindowsCodePage(nCharSet);
1086 DBG_ASSERT(meCharSet != RTL_TEXTENCODING_DONTKNOW,
1087 "don't know what vba charset to use");
1088 if (meCharSet == RTL_TEXTENCODING_DONTKNOW)
1089 meCharSet = RTL_TEXTENCODING_MS_1252;
1091 if (nLenD != 0x02)
1093 DBG_WARNING("Warning VBA number is different, please report");
1094 return 0;
1098 A sequence of string that are prepended with a len and then begin with G
1099 or H, there are also those that begin with C or D. If a string begins with
1100 C or D, it is really two strings, one right after the other. Each string
1101 then has a 12 bytes suffix
1103 Recognizing the end of the sequence is done by finding a str len of < 6
1104 which does not appear to be the beginning of an object id. Admittedly this
1105 isn't a great test, but nothing in the header appears to count the number
1106 of strings, and nothing else seems to match. So it'll have to do, its
1107 protected by a number of secondry tests to prove its a valid string, and
1108 everything gives up if this isn't proven.
1110 bool bPredictsTrailingTwenty = false;
1111 while (1)
1113 sal_uInt8 nType = ReadPString(xVBAProject,bIsUnicode);
1114 //Type C and D seem to come as pairs, so skip the following one
1115 if (nType == 'C' || nType == 'D')
1117 nType = ReadPString(xVBAProject,bIsUnicode);
1118 DBG_ASSERT( nType == 'C' || nType == 'D',
1119 "VBA: This must be a 'C' or 'D' string!" );
1120 if (nType != 'C' && nType != 'D')
1121 return 0;
1123 if (!nType)
1124 break;
1125 xVBAProject->SeekRel(10);
1126 sal_uInt16 nPredictsTrailingTwenty;
1127 *xVBAProject >> nPredictsTrailingTwenty;
1128 if (nPredictsTrailingTwenty)
1129 bPredictsTrailingTwenty = true;
1130 if (bPredictsTrailingTwenty)
1132 sal_uInt16 nTestIsNotString;
1133 *xVBAProject >> nTestIsNotString;
1134 if (nTestIsNotString < MINVBASTRING)
1136 DBG_ASSERT(nTestIsNotString <= 1,
1137 "Haven't seen a len like this in VBA, report to CMC");
1138 xVBAProject->SeekRel(18);
1139 bPredictsTrailingTwenty = false;
1141 else
1142 xVBAProject->SeekRel(-2);
1146 sal_Int16 nInt16s;
1147 *xVBAProject >> nInt16s;
1148 DBG_ASSERT( nInt16s >= 0, "VBA: Bad no of records in VBA Project, panic!" );
1149 if (!nInt16s)
1150 return 0;
1152 xVBAProject->SeekRel(2*nInt16s);
1154 sal_Int16 nInt32s;
1155 *xVBAProject >> nInt32s;
1156 DBG_ASSERT( nInt32s >= 0, "VBA: Bad no of records in VBA Project, panic!" );
1157 if (!nInt32s)
1158 return 0;
1159 xVBAProject->SeekRel(4*nInt32s);
1161 xVBAProject->SeekRel(2);
1162 for(int k=0;k<3;k++)
1164 sal_uInt16 nLen;
1165 *xVBAProject >> nLen;
1166 if (nLen != 0xFFFF)
1167 xVBAProject->SeekRel(nLen);
1169 xVBAProject->SeekRel(100); //Seems fixed len
1171 *xVBAProject >> nOffsets;
1172 DBG_ASSERT( nOffsets != 0xFFFF, "VBA: Bad nOffsets, panic!!" );
1173 if ((nOffsets == 0xFFFF) || (nOffsets == 0))
1174 return 0;
1175 pOffsets = new VBAOffset_Impl[ nOffsets ];
1177 int i, j;
1178 for( i=0; i < nOffsets; i++)
1180 sal_uInt16 nLen;
1181 *xVBAProject >> nLen;
1183 if (bIsUnicode)
1185 sal_Unicode* pBuf = pOffsets[i].sName.AllocBuffer( nLen / 2 );
1186 xVBAProject->Read( (sal_Char*)pBuf, nLen );
1188 #ifdef OSL_BIGENDIAN
1189 for( j = 0; j < nLen / 2; ++j, ++pBuf )
1190 *pBuf = SWAPSHORT( *pBuf );
1191 #endif // ifdef OSL_BIGENDIAN
1193 else
1195 ByteString aByteStr;
1196 sal_Char* pByteData = aByteStr.AllocBuffer( nLen );
1197 sal_Size nWasRead = xVBAProject->Read( pByteData, nLen );
1198 if( nWasRead != nLen )
1199 aByteStr.ReleaseBufferAccess();
1200 pOffsets[i].sName += String( aByteStr, meCharSet);
1203 *xVBAProject >> nLen;
1204 xVBAProject->SeekRel( nLen );
1206 //begin section, another problem area
1207 *xVBAProject >> nLen;
1208 if ( nLen == 0xFFFF)
1210 xVBAProject->SeekRel(2);
1211 *xVBAProject >> nLen;
1212 xVBAProject->SeekRel( nLen );
1214 else
1215 xVBAProject->SeekRel( nLen+2 );
1217 *xVBAProject >> nLen;
1218 DBG_ASSERT( nLen == 0xFFFF, "VBA: Bad field in VBA Project, panic!!" );
1219 if ( nLen != 0xFFFF)
1220 return 0;
1222 xVBAProject->SeekRel(6);
1223 sal_uInt16 nOctects;
1224 *xVBAProject >> nOctects;
1225 for(j=0;j<nOctects;j++)
1226 xVBAProject->SeekRel(8);
1228 xVBAProject->SeekRel(5);
1229 //end section
1231 *xVBAProject >> pOffsets[i].nOffset;
1232 xVBAProject->SeekRel(2);
1235 return nOffsets;
1239 /* #117718# For a given Module name return its type,
1240 * Form, Class, Document, Normal or Unknown
1244 ModType VBA_Impl::GetModuleType( const UniString& rModuleName )
1246 ModuleTypeHash::iterator iter = mhModHash.find( rModuleName );
1247 ModuleTypeHash::iterator iterEnd = mhModHash.end();
1248 if ( iter != iterEnd )
1250 return iter->second;
1252 return ModuleType::Unknown;
1255 bool VBA_Impl::Open( const String &rToplevel, const String &rSublevel )
1257 /* beginning test for vba stuff */
1258 bool bRet = false;
1259 SvStorageRef xMacros= xStor->OpenSotStorage( rToplevel,
1260 STREAM_READWRITE | STREAM_NOCREATE |
1261 STREAM_SHARE_DENYALL );
1262 if( !xMacros.Is() || SVSTREAM_OK != xMacros->GetError() )
1264 DBG_WARNING("No Macros Storage");
1265 OSL_TRACE("No Macros Storage");
1267 else
1269 xVBA = xMacros->OpenSotStorage( rSublevel,
1270 STREAM_READWRITE | STREAM_NOCREATE |
1271 STREAM_SHARE_DENYALL );
1272 if( !xVBA.Is() || SVSTREAM_OK != xVBA->GetError() )
1274 DBG_WARNING("No Visual Basic in Storage");
1275 OSL_TRACE("No Visual Basic in Storage");
1277 else
1279 if (ReadVBAProject(xVBA))
1280 bRet = true;
1282 /* #117718#
1283 * Information regarding the type of module is contained in the
1284 * "PROJECT" stream, this stream consists of a number of ascii lines
1285 * entries are of the form Key=Value, the ones that we are interested
1286 * in have the keys; Class, BaseClass & Module indicating the module
1287 * ( value ) is either a Class Module, Form Module or a plain VB Module. */
1288 SvStorageStreamRef xProject = xMacros->OpenSotStream(
1289 String( RTL_CONSTASCII_USTRINGPARAM( "PROJECT" ) ) );
1291 SvStorageStream* pStp = xProject;
1292 UniString tmp;
1293 static const String sThisDoc( RTL_CONSTASCII_USTRINGPARAM( "ThisDocument" ) );
1294 static const String sModule( RTL_CONSTASCII_USTRINGPARAM( "Module" ) );
1295 static const String sClass( RTL_CONSTASCII_USTRINGPARAM( "Class" ) );
1296 static const String sBaseClass( RTL_CONSTASCII_USTRINGPARAM( "BaseClass" ) );
1297 static const String sDocument( RTL_CONSTASCII_USTRINGPARAM( "Document" ) );
1298 mhModHash[ sThisDoc ] = ModuleType::Class;
1299 while ( pStp->ReadByteStringLine( tmp, meCharSet ) )
1301 xub_StrLen index = tmp.Search( '=' );
1302 if ( index != STRING_NOTFOUND )
1304 String key = tmp.Copy( 0, index );
1305 String value = tmp.Copy( index + 1 );
1306 if ( key == sClass )
1308 mhModHash[ value ] = ModuleType::Class;
1309 OSL_TRACE("Module %s is of type Class",
1310 ::rtl::OUStringToOString( value ,
1311 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
1313 else if ( key == sBaseClass )
1315 mhModHash[ value ] = ModuleType::Form;
1316 OSL_TRACE("Module %s is of type Form",
1317 ::rtl::OUStringToOString( value ,
1318 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
1320 else if ( key == sDocument )
1322 /* #i37965# DR 2004-12-03: add "Document", used i.e.
1323 in Excel for macros attached to sheet or document. */
1325 // value is of form <name>/&H<identifier>, strip the identifier
1326 value.Erase( value.Search( '/' ) );
1328 mhModHash[ value ] = ModuleType::Document;
1329 OSL_TRACE("Module %s is of type Document VBA",
1330 ::rtl::OUStringToOString( value ,
1331 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
1333 else if ( key == sModule )
1335 mhModHash[ value ] = ModuleType::Normal;
1336 OSL_TRACE("Module %s is of type Normal VBA",
1337 ::rtl::OUStringToOString( value ,
1338 RTL_TEXTENCODING_ASCII_US ).pData->buffer );
1343 /* end test for vba stuff */
1344 return bRet;
1347 const StringArray &VBA_Impl::Decompress(sal_uInt16 nIndex, int *pOverflow)
1349 DBG_ASSERT( nIndex < nOffsets, "Index out of range" );
1350 SvStorageStreamRef xVBAStream;
1351 aVBAStrings.SetSize(1);
1352 aVBAStrings.Put(0,new String);
1354 xVBAStream = xVBA->OpenSotStream( pOffsets[nIndex].sName,
1355 STREAM_STD_READ | STREAM_NOCREATE );
1356 if (pOverflow)
1357 *pOverflow=0;
1359 if( !xVBAStream.Is() || SVSTREAM_OK != xVBAStream->GetError() )
1361 DBG_WARNING("Not able to open vb module ");
1363 else
1365 xVBAStream->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
1366 DecompressVBA( nIndex, xVBAStream );
1368 * if len was too big for a single string set that variable ?
1369 * if ((len > XX) && (pOverflow))
1370 *pOverflow=1;
1372 if (bCommented)
1374 String sTempStringa;
1375 if (mbMac)
1376 sTempStringa = String( RTL_CONSTASCII_USTRINGPARAM( "\x0D" ) );
1377 else
1378 sTempStringa = String( RTL_CONSTASCII_USTRINGPARAM( "\x0D\x0A" ) );
1379 String sTempStringb(sTempStringa);
1380 sTempStringb+=sComment;
1381 for(ULONG i=0;i<aVBAStrings.GetSize();i++)
1383 aVBAStrings.Get(i)->SearchAndReplaceAll(
1384 sTempStringa,sTempStringb);
1385 aVBAStrings.Get(i)->Insert(sComment,0);
1389 return aVBAStrings;
1393 int VBA_Impl::DecompressVBA( int nIndex, SvStorageStreamRef &xVBAStream )
1395 sal_uInt8 nLeadbyte;
1396 sal_uInt16 nToken;
1397 unsigned int nPos = 0;
1398 int nLen, nDistance, nShift, nClean=1;
1400 xVBAStream->Seek( pOffsets[ nIndex ].nOffset + 3 );
1402 while(xVBAStream->Read(&nLeadbyte,1))
1404 for(int nPosition=0x01;nPosition < 0x100;nPosition=nPosition<<1)
1406 //we see if the leadbyte has flagged this location as a dataunit
1407 //which is actually a token which must be looked up in the history
1408 if (nLeadbyte & nPosition)
1410 *xVBAStream >> nToken;
1412 if (nClean == 0)
1413 nClean=1;
1415 //For some reason the division of the token into the length
1416 //field of the data to be inserted, and the distance back into
1417 //the history differs depending on how full the history is
1418 int nPos2 = nPos % nWINDOWLEN;
1419 if (nPos2 <= 0x10)
1420 nShift = 12;
1421 else if (nPos2 <= 0x20)
1422 nShift = 11;
1423 else if (nPos2 <= 0x40)
1424 nShift = 10;
1425 else if (nPos2 <= 0x80)
1426 nShift = 9;
1427 else if (nPos2 <= 0x100)
1428 nShift = 8;
1429 else if (nPos2 <= 0x200)
1430 nShift = 7;
1431 else if (nPos2 <= 0x400)
1432 nShift = 6;
1433 else if (nPos2 <= 0x800)
1434 nShift = 5;
1435 else
1436 nShift = 4;
1438 int i;
1439 nLen=0;
1440 for(i=0;i<nShift;i++)
1441 nLen |= nToken & (1<<i);
1443 nLen += 3;
1445 nDistance = nToken >> nShift;
1447 //read the len of data from the history, wrapping around the
1448 //nWINDOWLEN boundary if necessary data read from the history
1449 //is also copied into the recent part of the history as well.
1450 for (i = 0; i < nLen; i++)
1452 unsigned char c;
1453 c = aHistory[(nPos-nDistance-1) % nWINDOWLEN];
1454 aHistory[nPos % nWINDOWLEN] = c;
1455 nPos++;
1458 else
1460 // special boundary case code, not guarantueed to be correct
1461 // seems to work though, there is something wrong with the
1462 // compression scheme (or maybe a feature) where when the data
1463 // ends on a nWINDOWLEN boundary and the excess bytes in the 8
1464 // dataunit list are discarded, and not interpreted as tokens
1465 // or normal data.
1466 if ((nPos != 0) && ((nPos % nWINDOWLEN) == 0) && (nClean))
1468 xVBAStream->SeekRel(2);
1469 nClean=0;
1470 Output(nWINDOWLEN, aHistory);
1471 break;
1473 //This is the normal case for when the data unit is not a
1474 //token to be looked up, but instead some normal data which
1475 //can be output, and placed in the history.
1476 if (xVBAStream->Read(&aHistory[nPos % nWINDOWLEN],1))
1477 nPos++;
1479 if (nClean == 0)
1480 nClean=1;
1484 if (nPos % nWINDOWLEN)
1485 Output(nPos % nWINDOWLEN,aHistory);
1486 return(nPos);
1489 /* vi:set tabstop=4 shiftwidth=4 expandtab: */