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