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