xref: /trunk/main/oox/source/ole/vbamodule.cxx (revision ca5ec200)
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