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