1*ca5ec200SAndrew Rist /**************************************************************
2*ca5ec200SAndrew Rist *
3*ca5ec200SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4*ca5ec200SAndrew Rist * or more contributor license agreements. See the NOTICE file
5*ca5ec200SAndrew Rist * distributed with this work for additional information
6*ca5ec200SAndrew Rist * regarding copyright ownership. The ASF licenses this file
7*ca5ec200SAndrew Rist * to you under the Apache License, Version 2.0 (the
8*ca5ec200SAndrew Rist * "License"); you may not use this file except in compliance
9*ca5ec200SAndrew Rist * with the License. You may obtain a copy of the License at
10*ca5ec200SAndrew Rist *
11*ca5ec200SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*ca5ec200SAndrew Rist *
13*ca5ec200SAndrew Rist * Unless required by applicable law or agreed to in writing,
14*ca5ec200SAndrew Rist * software distributed under the License is distributed on an
15*ca5ec200SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*ca5ec200SAndrew Rist * KIND, either express or implied. See the License for the
17*ca5ec200SAndrew Rist * specific language governing permissions and limitations
18*ca5ec200SAndrew Rist * under the License.
19*ca5ec200SAndrew Rist *
20*ca5ec200SAndrew Rist *************************************************************/
21*ca5ec200SAndrew Rist
22*ca5ec200SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir #include "oox/ole/vbamodule.hxx"
25cdf0e10cSrcweir
26cdf0e10cSrcweir #include <com/sun/star/container/XNameContainer.hpp>
27cdf0e10cSrcweir #include <com/sun/star/script/ModuleInfo.hpp>
28cdf0e10cSrcweir #include <com/sun/star/script/ModuleType.hpp>
29cdf0e10cSrcweir #include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
30cdf0e10cSrcweir #include "oox/helper/binaryinputstream.hxx"
31cdf0e10cSrcweir #include "oox/helper/storagebase.hxx"
32cdf0e10cSrcweir #include "oox/helper/textinputstream.hxx"
33cdf0e10cSrcweir #include "oox/ole/vbahelper.hxx"
34cdf0e10cSrcweir #include "oox/ole/vbainputstream.hxx"
35cdf0e10cSrcweir
36cdf0e10cSrcweir namespace oox {
37cdf0e10cSrcweir namespace ole {
38cdf0e10cSrcweir
39cdf0e10cSrcweir // ============================================================================
40cdf0e10cSrcweir
41cdf0e10cSrcweir using namespace ::com::sun::star::container;
42cdf0e10cSrcweir using namespace ::com::sun::star::frame;
43cdf0e10cSrcweir using namespace ::com::sun::star::lang;
44cdf0e10cSrcweir using namespace ::com::sun::star::script;
45cdf0e10cSrcweir using namespace ::com::sun::star::script::vba;
46cdf0e10cSrcweir using namespace ::com::sun::star::uno;
47cdf0e10cSrcweir
48cdf0e10cSrcweir using ::rtl::OUString;
49cdf0e10cSrcweir using ::rtl::OUStringBuffer;
50cdf0e10cSrcweir
51cdf0e10cSrcweir // ============================================================================
52cdf0e10cSrcweir
VbaModule(const Reference<XComponentContext> & rxContext,const Reference<XModel> & rxDocModel,const OUString & rName,rtl_TextEncoding eTextEnc,bool bExecutable)53cdf0e10cSrcweir VbaModule::VbaModule( const Reference< XComponentContext >& rxContext, const Reference< XModel >& rxDocModel,
54cdf0e10cSrcweir const OUString& rName, rtl_TextEncoding eTextEnc, bool bExecutable ) :
55cdf0e10cSrcweir mxContext( rxContext ),
56cdf0e10cSrcweir mxDocModel( rxDocModel ),
57cdf0e10cSrcweir maName( rName ),
58cdf0e10cSrcweir meTextEnc( eTextEnc ),
59cdf0e10cSrcweir mnType( ModuleType::UNKNOWN ),
60cdf0e10cSrcweir mnOffset( SAL_MAX_UINT32 ),
61cdf0e10cSrcweir mbReadOnly( false ),
62cdf0e10cSrcweir mbPrivate( false ),
63cdf0e10cSrcweir mbExecutable( bExecutable )
64cdf0e10cSrcweir {
65cdf0e10cSrcweir }
66cdf0e10cSrcweir
importDirRecords(BinaryInputStream & rDirStrm)67cdf0e10cSrcweir void VbaModule::importDirRecords( BinaryInputStream& rDirStrm )
68cdf0e10cSrcweir {
69cdf0e10cSrcweir sal_uInt16 nRecId = 0;
70cdf0e10cSrcweir StreamDataSequence aRecData;
71cdf0e10cSrcweir while( VbaHelper::readDirRecord( nRecId, aRecData, rDirStrm ) && (nRecId != VBA_ID_MODULEEND) )
72cdf0e10cSrcweir {
73cdf0e10cSrcweir SequenceInputStream aRecStrm( aRecData );
74cdf0e10cSrcweir sal_Int32 nRecSize = aRecData.getLength();
75cdf0e10cSrcweir switch( nRecId )
76cdf0e10cSrcweir {
77cdf0e10cSrcweir #define OOX_ENSURE_RECORDSIZE( cond ) OSL_ENSURE( cond, "VbaModule::importDirRecords - invalid record size" )
78cdf0e10cSrcweir case VBA_ID_MODULENAME:
79cdf0e10cSrcweir OSL_ENSURE( false, "VbaModule::importDirRecords - unexpected MODULENAME record" );
80cdf0e10cSrcweir maName = aRecStrm.readCharArrayUC( nRecSize, meTextEnc );
81cdf0e10cSrcweir break;
82cdf0e10cSrcweir case VBA_ID_MODULENAMEUNICODE:
83cdf0e10cSrcweir break;
84cdf0e10cSrcweir case VBA_ID_MODULESTREAMNAME:
85cdf0e10cSrcweir maStreamName = aRecStrm.readCharArrayUC( nRecSize, meTextEnc );
86cdf0e10cSrcweir break;
87cdf0e10cSrcweir case VBA_ID_MODULESTREAMNAMEUNICODE:
88cdf0e10cSrcweir break;
89cdf0e10cSrcweir case VBA_ID_MODULEDOCSTRING:
90cdf0e10cSrcweir maDocString = aRecStrm.readCharArrayUC( nRecSize, meTextEnc );
91cdf0e10cSrcweir break;
92cdf0e10cSrcweir case VBA_ID_MODULEDOCSTRINGUNICODE:
93cdf0e10cSrcweir break;
94cdf0e10cSrcweir case VBA_ID_MODULEOFFSET:
95cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 4 );
96cdf0e10cSrcweir aRecStrm >> mnOffset;
97cdf0e10cSrcweir break;
98cdf0e10cSrcweir case VBA_ID_MODULEHELPCONTEXT:
99cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 4 );
100cdf0e10cSrcweir break;
101cdf0e10cSrcweir case VBA_ID_MODULECOOKIE:
102cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 2 );
103cdf0e10cSrcweir break;
104cdf0e10cSrcweir case VBA_ID_MODULETYPEPROCEDURAL:
105cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 0 );
106cdf0e10cSrcweir OSL_ENSURE( mnType == ModuleType::UNKNOWN, "VbaModule::importDirRecords - multiple module type records" );
107cdf0e10cSrcweir mnType = ModuleType::NORMAL;
108cdf0e10cSrcweir break;
109cdf0e10cSrcweir case VBA_ID_MODULETYPEDOCUMENT:
110cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 0 );
111cdf0e10cSrcweir OSL_ENSURE( mnType == ModuleType::UNKNOWN, "VbaModule::importDirRecords - multiple module type records" );
112cdf0e10cSrcweir mnType = ModuleType::DOCUMENT;
113cdf0e10cSrcweir break;
114cdf0e10cSrcweir case VBA_ID_MODULEREADONLY:
115cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 0 );
116cdf0e10cSrcweir mbReadOnly = true;
117cdf0e10cSrcweir break;
118cdf0e10cSrcweir case VBA_ID_MODULEPRIVATE:
119cdf0e10cSrcweir OOX_ENSURE_RECORDSIZE( nRecSize == 0 );
120cdf0e10cSrcweir mbPrivate = true;
121cdf0e10cSrcweir break;
122cdf0e10cSrcweir default:
123cdf0e10cSrcweir OSL_ENSURE( false, "VbaModule::importDirRecords - unknown module record" );
124cdf0e10cSrcweir #undef OOX_ENSURE_RECORDSIZE
125cdf0e10cSrcweir }
126cdf0e10cSrcweir }
127cdf0e10cSrcweir OSL_ENSURE( maName.getLength() > 0, "VbaModule::importDirRecords - missing module name" );
128cdf0e10cSrcweir OSL_ENSURE( maStreamName.getLength() > 0, "VbaModule::importDirRecords - missing module stream name" );
129cdf0e10cSrcweir OSL_ENSURE( mnType != ModuleType::UNKNOWN, "VbaModule::importDirRecords - missing module type" );
130cdf0e10cSrcweir OSL_ENSURE( mnOffset < SAL_MAX_UINT32, "VbaModule::importDirRecords - missing module stream offset" );
131cdf0e10cSrcweir }
132cdf0e10cSrcweir
createAndImportModule(StorageBase & rVbaStrg,const Reference<XNameContainer> & rxBasicLib,const Reference<XNameAccess> & rxDocObjectNA) const133cdf0e10cSrcweir void VbaModule::createAndImportModule( StorageBase& rVbaStrg, const Reference< XNameContainer >& rxBasicLib,
134cdf0e10cSrcweir const Reference< XNameAccess >& rxDocObjectNA ) const
135cdf0e10cSrcweir {
136cdf0e10cSrcweir OUString aVBASourceCode = readSourceCode( rVbaStrg );
137cdf0e10cSrcweir createModule( aVBASourceCode, rxBasicLib, rxDocObjectNA );
138cdf0e10cSrcweir }
139cdf0e10cSrcweir
createEmptyModule(const Reference<XNameContainer> & rxBasicLib,const Reference<XNameAccess> & rxDocObjectNA) const140cdf0e10cSrcweir void VbaModule::createEmptyModule( const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const
141cdf0e10cSrcweir {
142cdf0e10cSrcweir createModule( OUString(), rxBasicLib, rxDocObjectNA );
143cdf0e10cSrcweir }
144cdf0e10cSrcweir
145cdf0e10cSrcweir // private --------------------------------------------------------------------
146cdf0e10cSrcweir
readSourceCode(StorageBase & rVbaStrg) const147cdf0e10cSrcweir OUString VbaModule::readSourceCode( StorageBase& rVbaStrg ) const
148cdf0e10cSrcweir {
149cdf0e10cSrcweir OUStringBuffer aSourceCode;
150cdf0e10cSrcweir if( (maStreamName.getLength() > 0) && (mnOffset != SAL_MAX_UINT32) )
151cdf0e10cSrcweir {
152cdf0e10cSrcweir BinaryXInputStream aInStrm( rVbaStrg.openInputStream( maStreamName ), true );
153cdf0e10cSrcweir OSL_ENSURE( !aInStrm.isEof(), "VbaModule::readSourceCode - cannot open module stream" );
154cdf0e10cSrcweir // skip the 'performance cache' stored before the actual source code
155cdf0e10cSrcweir aInStrm.seek( mnOffset );
156cdf0e10cSrcweir // if stream is still valid, load the source code
157cdf0e10cSrcweir if( !aInStrm.isEof() )
158cdf0e10cSrcweir {
159cdf0e10cSrcweir // decompression starts at current stream position of aInStrm
160cdf0e10cSrcweir VbaInputStream aVbaStrm( aInStrm );
161cdf0e10cSrcweir // load the source code line-by-line, with some more processing
162cdf0e10cSrcweir TextInputStream aVbaTextStrm( mxContext, aVbaStrm, meTextEnc );
163cdf0e10cSrcweir while( !aVbaTextStrm.isEof() )
164cdf0e10cSrcweir {
165cdf0e10cSrcweir OUString aCodeLine = aVbaTextStrm.readLine();
166cdf0e10cSrcweir if( !aCodeLine.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "Attribute " ) ) )
167cdf0e10cSrcweir {
168cdf0e10cSrcweir // normal source code line
169cdf0e10cSrcweir if( !mbExecutable )
170cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem " ) );
171cdf0e10cSrcweir aSourceCode.append( aCodeLine ).append( sal_Unicode( '\n' ) );
172cdf0e10cSrcweir }
173cdf0e10cSrcweir }
174cdf0e10cSrcweir }
175cdf0e10cSrcweir }
176cdf0e10cSrcweir return aSourceCode.makeStringAndClear();
177cdf0e10cSrcweir }
178cdf0e10cSrcweir
createModule(const OUString & rVBASourceCode,const Reference<XNameContainer> & rxBasicLib,const Reference<XNameAccess> & rxDocObjectNA) const179cdf0e10cSrcweir void VbaModule::createModule( const OUString& rVBASourceCode,
180cdf0e10cSrcweir const Reference< XNameContainer >& rxBasicLib, const Reference< XNameAccess >& rxDocObjectNA ) const
181cdf0e10cSrcweir {
182cdf0e10cSrcweir if( maName.getLength() == 0 )
183cdf0e10cSrcweir return;
184cdf0e10cSrcweir
185cdf0e10cSrcweir // prepare the Basic module
186cdf0e10cSrcweir ModuleInfo aModuleInfo;
187cdf0e10cSrcweir aModuleInfo.ModuleType = mnType;
188cdf0e10cSrcweir OUStringBuffer aSourceCode;
189cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Rem Attribute VBA_ModuleType=" ) );
190cdf0e10cSrcweir switch( mnType )
191cdf0e10cSrcweir {
192cdf0e10cSrcweir case ModuleType::NORMAL:
193cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAModule" ) );
194cdf0e10cSrcweir break;
195cdf0e10cSrcweir case ModuleType::CLASS:
196cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAClassModule" ) );
197cdf0e10cSrcweir break;
198cdf0e10cSrcweir case ModuleType::FORM:
199cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAFormModule" ) );
200cdf0e10cSrcweir // hack from old filter, document Basic should know the XModel, but it doesn't
201cdf0e10cSrcweir aModuleInfo.ModuleObject.set( mxDocModel, UNO_QUERY );
202cdf0e10cSrcweir break;
203cdf0e10cSrcweir case ModuleType::DOCUMENT:
204cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBADocumentModule" ) );
205cdf0e10cSrcweir // get the VBA implementation object associated to the document module
206cdf0e10cSrcweir if( rxDocObjectNA.is() ) try
207cdf0e10cSrcweir {
208cdf0e10cSrcweir aModuleInfo.ModuleObject.set( rxDocObjectNA->getByName( maName ), UNO_QUERY );
209cdf0e10cSrcweir }
210cdf0e10cSrcweir catch( Exception& )
211cdf0e10cSrcweir {
212cdf0e10cSrcweir }
213cdf0e10cSrcweir break;
214cdf0e10cSrcweir default:
215cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "VBAUnknown" ) );
216cdf0e10cSrcweir }
217cdf0e10cSrcweir aSourceCode.append( sal_Unicode( '\n' ) );
218cdf0e10cSrcweir if( mbExecutable )
219cdf0e10cSrcweir {
220cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Option VBASupport 1\n" ) );
221cdf0e10cSrcweir if( mnType == ModuleType::CLASS )
222cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Option ClassModule\n" ) );
223cdf0e10cSrcweir }
224cdf0e10cSrcweir else
225cdf0e10cSrcweir {
226cdf0e10cSrcweir // add a subroutine named after the module itself
227cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Sub " ) ).
228cdf0e10cSrcweir append( maName.replace( ' ', '_' ) ).append( sal_Unicode( '\n' ) );
229cdf0e10cSrcweir }
230cdf0e10cSrcweir
231cdf0e10cSrcweir // append passed VBA source code
232cdf0e10cSrcweir aSourceCode.append( rVBASourceCode );
233cdf0e10cSrcweir
234cdf0e10cSrcweir // close the subroutine named after the module
235cdf0e10cSrcweir if( !mbExecutable )
236cdf0e10cSrcweir aSourceCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "End Sub\n" ) );
237cdf0e10cSrcweir
238cdf0e10cSrcweir // insert extended module info
239cdf0e10cSrcweir try
240cdf0e10cSrcweir {
241cdf0e10cSrcweir Reference< XVBAModuleInfo > xVBAModuleInfo( rxBasicLib, UNO_QUERY_THROW );
242cdf0e10cSrcweir xVBAModuleInfo->insertModuleInfo( maName, aModuleInfo );
243cdf0e10cSrcweir }
244cdf0e10cSrcweir catch( Exception& )
245cdf0e10cSrcweir {
246cdf0e10cSrcweir }
247cdf0e10cSrcweir
248cdf0e10cSrcweir // insert the module into the passed Basic library
249cdf0e10cSrcweir try
250cdf0e10cSrcweir {
251cdf0e10cSrcweir rxBasicLib->insertByName( maName, Any( aSourceCode.makeStringAndClear() ) );
252cdf0e10cSrcweir }
253cdf0e10cSrcweir catch( Exception& )
254cdf0e10cSrcweir {
255cdf0e10cSrcweir OSL_ENSURE( false, "VbaModule::createModule - cannot insert module into library" );
256cdf0e10cSrcweir }
257cdf0e10cSrcweir }
258cdf0e10cSrcweir
259cdf0e10cSrcweir // ============================================================================
260cdf0e10cSrcweir
261cdf0e10cSrcweir } // namespace ole
262cdf0e10cSrcweir } // namespace oox
263