xref: /AOO41X/main/oox/source/ole/vbaproject.cxx (revision ca5ec2004b000a7d9aaa8381be8ac2853e3b1dc7)
1*ca5ec200SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
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
10cdf0e10cSrcweir  *
11*ca5ec200SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
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.
19cdf0e10cSrcweir  *
20*ca5ec200SAndrew Rist  *************************************************************/
21*ca5ec200SAndrew Rist 
22*ca5ec200SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #include "oox/ole/vbaproject.hxx"
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #include <com/sun/star/document/XStorageBasedDocument.hpp>
27cdf0e10cSrcweir #include <com/sun/star/embed/ElementModes.hpp>
28cdf0e10cSrcweir #include <com/sun/star/embed/XTransactedObject.hpp>
29cdf0e10cSrcweir #include <com/sun/star/frame/XModel.hpp>
30cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31cdf0e10cSrcweir #include <com/sun/star/script/ModuleType.hpp>
32cdf0e10cSrcweir #include <com/sun/star/script/XLibraryContainer.hpp>
33cdf0e10cSrcweir #include <com/sun/star/script/vba/XVBACompatibility.hpp>
34cdf0e10cSrcweir #include <com/sun/star/script/vba/XVBAMacroResolver.hpp>
35cdf0e10cSrcweir #include <com/sun/star/uno/XComponentContext.hpp>
36cdf0e10cSrcweir #include <comphelper/configurationhelper.hxx>
37cdf0e10cSrcweir #include <comphelper/string.hxx>
38cdf0e10cSrcweir #include <rtl/tencinfo.h>
39cdf0e10cSrcweir #include <rtl/ustrbuf.h>
40cdf0e10cSrcweir #include "oox/helper/binaryinputstream.hxx"
41cdf0e10cSrcweir #include "oox/helper/containerhelper.hxx"
42cdf0e10cSrcweir #include "oox/helper/propertyset.hxx"
43cdf0e10cSrcweir #include "oox/helper/textinputstream.hxx"
44cdf0e10cSrcweir #include "oox/ole/olestorage.hxx"
45cdf0e10cSrcweir #include "oox/ole/vbacontrol.hxx"
46cdf0e10cSrcweir #include "oox/ole/vbahelper.hxx"
47cdf0e10cSrcweir #include "oox/ole/vbainputstream.hxx"
48cdf0e10cSrcweir #include "oox/ole/vbamodule.hxx"
49cdf0e10cSrcweir 
50cdf0e10cSrcweir namespace oox {
51cdf0e10cSrcweir namespace ole {
52cdf0e10cSrcweir 
53cdf0e10cSrcweir // ============================================================================
54cdf0e10cSrcweir 
55cdf0e10cSrcweir using namespace ::com::sun::star::container;
56cdf0e10cSrcweir using namespace ::com::sun::star::document;
57cdf0e10cSrcweir using namespace ::com::sun::star::embed;
58cdf0e10cSrcweir using namespace ::com::sun::star::frame;
59cdf0e10cSrcweir using namespace ::com::sun::star::io;
60cdf0e10cSrcweir using namespace ::com::sun::star::lang;
61cdf0e10cSrcweir using namespace ::com::sun::star::script;
62cdf0e10cSrcweir using namespace ::com::sun::star::script::vba;
63cdf0e10cSrcweir using namespace ::com::sun::star::uno;
64cdf0e10cSrcweir 
65cdf0e10cSrcweir using ::comphelper::ConfigurationHelper;
66cdf0e10cSrcweir using ::rtl::OUString;
67cdf0e10cSrcweir using ::rtl::OUStringBuffer;
68cdf0e10cSrcweir 
69cdf0e10cSrcweir // ============================================================================
70cdf0e10cSrcweir 
71cdf0e10cSrcweir namespace {
72cdf0e10cSrcweir 
lclReadConfigItem(const Reference<XInterface> & rxConfigAccess,const OUString & rItemName)73cdf0e10cSrcweir bool lclReadConfigItem( const Reference< XInterface >& rxConfigAccess, const OUString& rItemName )
74cdf0e10cSrcweir {
75cdf0e10cSrcweir     // some applications do not support all configuration items, assume 'false' in this case
76cdf0e10cSrcweir     try
77cdf0e10cSrcweir     {
78cdf0e10cSrcweir         Any aItem = ConfigurationHelper::readRelativeKey( rxConfigAccess, CREATE_OUSTRING( "Filter/Import/VBA" ), rItemName );
79cdf0e10cSrcweir         return aItem.has< bool >() && aItem.get< bool >();
80cdf0e10cSrcweir     }
81cdf0e10cSrcweir     catch( Exception& )
82cdf0e10cSrcweir     {
83cdf0e10cSrcweir     }
84cdf0e10cSrcweir     return false;
85cdf0e10cSrcweir }
86cdf0e10cSrcweir 
87cdf0e10cSrcweir } // namespace
88cdf0e10cSrcweir 
89cdf0e10cSrcweir // ----------------------------------------------------------------------------
90cdf0e10cSrcweir 
VbaFilterConfig(const Reference<XComponentContext> & rxContext,const OUString & rConfigCompName)91cdf0e10cSrcweir VbaFilterConfig::VbaFilterConfig( const Reference< XComponentContext >& rxContext, const OUString& rConfigCompName )
92cdf0e10cSrcweir {
93cdf0e10cSrcweir     OSL_ENSURE( rxContext.is(), "VbaFilterConfig::VbaFilterConfig - missing component context" );
94cdf0e10cSrcweir     if( rxContext.is() ) try
95cdf0e10cSrcweir     {
96cdf0e10cSrcweir         OSL_ENSURE( rConfigCompName.getLength() > 0, "VbaFilterConfig::VbaFilterConfig - invalid configuration component name" );
97cdf0e10cSrcweir         OUString aConfigPackage = CREATE_OUSTRING( "org.openoffice.Office." ) + rConfigCompName;
98cdf0e10cSrcweir         Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW );
99cdf0e10cSrcweir         mxConfigAccess = ConfigurationHelper::openConfig( xFactory, aConfigPackage, ConfigurationHelper::E_READONLY );
100cdf0e10cSrcweir     }
101cdf0e10cSrcweir     catch( Exception& )
102cdf0e10cSrcweir     {
103cdf0e10cSrcweir     }
104cdf0e10cSrcweir     OSL_ENSURE( mxConfigAccess.is(), "VbaFilterConfig::VbaFilterConfig - cannot open configuration" );
105cdf0e10cSrcweir }
106cdf0e10cSrcweir 
~VbaFilterConfig()107cdf0e10cSrcweir VbaFilterConfig::~VbaFilterConfig()
108cdf0e10cSrcweir {
109cdf0e10cSrcweir }
110cdf0e10cSrcweir 
isImportVba() const111cdf0e10cSrcweir bool VbaFilterConfig::isImportVba() const
112cdf0e10cSrcweir {
113cdf0e10cSrcweir     return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Load" ) );
114cdf0e10cSrcweir }
115cdf0e10cSrcweir 
isImportVbaExecutable() const116cdf0e10cSrcweir bool VbaFilterConfig::isImportVbaExecutable() const
117cdf0e10cSrcweir {
118cdf0e10cSrcweir     return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Executable" ) );
119cdf0e10cSrcweir }
120cdf0e10cSrcweir 
isExportVba() const121cdf0e10cSrcweir bool VbaFilterConfig::isExportVba() const
122cdf0e10cSrcweir {
123cdf0e10cSrcweir     return lclReadConfigItem( mxConfigAccess, CREATE_OUSTRING( "Save" ) );
124cdf0e10cSrcweir }
125cdf0e10cSrcweir 
126cdf0e10cSrcweir // ============================================================================
127cdf0e10cSrcweir 
VbaMacroAttacherBase(const OUString & rMacroName)128cdf0e10cSrcweir VbaMacroAttacherBase::VbaMacroAttacherBase( const OUString& rMacroName ) :
129cdf0e10cSrcweir     maMacroName( rMacroName )
130cdf0e10cSrcweir {
131cdf0e10cSrcweir     OSL_ENSURE( maMacroName.getLength() > 0, "VbaMacroAttacherBase::VbaMacroAttacherBase - empty macro name" );
132cdf0e10cSrcweir }
133cdf0e10cSrcweir 
~VbaMacroAttacherBase()134cdf0e10cSrcweir VbaMacroAttacherBase::~VbaMacroAttacherBase()
135cdf0e10cSrcweir {
136cdf0e10cSrcweir }
137cdf0e10cSrcweir 
resolveAndAttachMacro(const Reference<XVBAMacroResolver> & rxResolver)138cdf0e10cSrcweir void VbaMacroAttacherBase::resolveAndAttachMacro( const Reference< XVBAMacroResolver >& rxResolver )
139cdf0e10cSrcweir {
140cdf0e10cSrcweir     try
141cdf0e10cSrcweir     {
142cdf0e10cSrcweir         attachMacro( rxResolver->resolveVBAMacroToScriptURL( maMacroName ) );
143cdf0e10cSrcweir     }
144cdf0e10cSrcweir     catch( Exception& )
145cdf0e10cSrcweir     {
146cdf0e10cSrcweir     }
147cdf0e10cSrcweir }
148cdf0e10cSrcweir 
149cdf0e10cSrcweir // ============================================================================
150cdf0e10cSrcweir 
VbaProject(const Reference<XComponentContext> & rxContext,const Reference<XModel> & rxDocModel,const OUString & rConfigCompName)151cdf0e10cSrcweir VbaProject::VbaProject( const Reference< XComponentContext >& rxContext,
152cdf0e10cSrcweir         const Reference< XModel >& rxDocModel, const OUString& rConfigCompName ) :
153cdf0e10cSrcweir     VbaFilterConfig( rxContext, rConfigCompName ),
154cdf0e10cSrcweir     mxContext( rxContext ),
155cdf0e10cSrcweir     mxDocModel( rxDocModel ),
156cdf0e10cSrcweir     maPrjName( CREATE_OUSTRING( "Standard" ) )
157cdf0e10cSrcweir {
158cdf0e10cSrcweir     OSL_ENSURE( mxContext.is(), "VbaProject::VbaProject - missing component context" );
159cdf0e10cSrcweir     OSL_ENSURE( mxDocModel.is(), "VbaProject::VbaProject - missing document model" );
160cdf0e10cSrcweir     mxBasicLib = openLibrary( PROP_BasicLibraries, false );
161cdf0e10cSrcweir     mxDialogLib = openLibrary( PROP_DialogLibraries, false );
162cdf0e10cSrcweir }
163cdf0e10cSrcweir 
~VbaProject()164cdf0e10cSrcweir VbaProject::~VbaProject()
165cdf0e10cSrcweir {
166cdf0e10cSrcweir }
167cdf0e10cSrcweir 
importVbaProject(StorageBase & rVbaPrjStrg,const GraphicHelper & rGraphicHelper,bool bDefaultColorBgr)168cdf0e10cSrcweir void VbaProject::importVbaProject( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr )
169cdf0e10cSrcweir {
170cdf0e10cSrcweir     if( rVbaPrjStrg.isStorage() )
171cdf0e10cSrcweir     {
172cdf0e10cSrcweir         // load the code modules and forms
173cdf0e10cSrcweir         if( isImportVba() )
174cdf0e10cSrcweir             importVba( rVbaPrjStrg, rGraphicHelper, bDefaultColorBgr );
175cdf0e10cSrcweir         // copy entire storage into model
176cdf0e10cSrcweir         if( isExportVba() )
177cdf0e10cSrcweir             copyStorage( rVbaPrjStrg );
178cdf0e10cSrcweir     }
179cdf0e10cSrcweir }
180cdf0e10cSrcweir 
registerMacroAttacher(const VbaMacroAttacherRef & rxAttacher)181cdf0e10cSrcweir void VbaProject::registerMacroAttacher( const VbaMacroAttacherRef& rxAttacher )
182cdf0e10cSrcweir {
183cdf0e10cSrcweir     OSL_ENSURE( rxAttacher.get(), "VbaProject::registerMacroAttacher - unexpected empty reference" );
184cdf0e10cSrcweir     maMacroAttachers.push_back( rxAttacher );
185cdf0e10cSrcweir }
186cdf0e10cSrcweir 
hasModules() const187cdf0e10cSrcweir bool VbaProject::hasModules() const
188cdf0e10cSrcweir {
189cdf0e10cSrcweir     return mxBasicLib.is() && mxBasicLib->hasElements();
190cdf0e10cSrcweir }
191cdf0e10cSrcweir 
hasModule(const OUString & rModuleName) const192cdf0e10cSrcweir bool VbaProject::hasModule( const OUString& rModuleName ) const
193cdf0e10cSrcweir {
194cdf0e10cSrcweir     return mxBasicLib.is() && mxBasicLib->hasByName( rModuleName );
195cdf0e10cSrcweir }
196cdf0e10cSrcweir 
hasDialogs() const197cdf0e10cSrcweir bool VbaProject::hasDialogs() const
198cdf0e10cSrcweir {
199cdf0e10cSrcweir     return mxDialogLib.is() && mxDialogLib->hasElements();
200cdf0e10cSrcweir }
201cdf0e10cSrcweir 
hasDialog(const OUString & rDialogName) const202cdf0e10cSrcweir bool VbaProject::hasDialog( const OUString& rDialogName ) const
203cdf0e10cSrcweir {
204cdf0e10cSrcweir     return mxDialogLib.is() && mxDialogLib->hasByName( rDialogName );
205cdf0e10cSrcweir }
206cdf0e10cSrcweir 
207cdf0e10cSrcweir // protected ------------------------------------------------------------------
208cdf0e10cSrcweir 
addDummyModule(const OUString & rName,sal_Int32 nType)209cdf0e10cSrcweir void VbaProject::addDummyModule( const OUString& rName, sal_Int32 nType )
210cdf0e10cSrcweir {
211cdf0e10cSrcweir     OSL_ENSURE( rName.getLength() > 0, "VbaProject::addDummyModule - missing module name" );
212cdf0e10cSrcweir     maDummyModules[ rName ] = nType;
213cdf0e10cSrcweir }
214cdf0e10cSrcweir 
prepareImport()215cdf0e10cSrcweir void VbaProject::prepareImport()
216cdf0e10cSrcweir {
217cdf0e10cSrcweir }
218cdf0e10cSrcweir 
finalizeImport()219cdf0e10cSrcweir void VbaProject::finalizeImport()
220cdf0e10cSrcweir {
221cdf0e10cSrcweir }
222cdf0e10cSrcweir 
223cdf0e10cSrcweir // private --------------------------------------------------------------------
224cdf0e10cSrcweir 
getLibraryContainer(sal_Int32 nPropId)225cdf0e10cSrcweir Reference< XLibraryContainer > VbaProject::getLibraryContainer( sal_Int32 nPropId )
226cdf0e10cSrcweir {
227cdf0e10cSrcweir     PropertySet aDocProp( mxDocModel );
228cdf0e10cSrcweir     Reference< XLibraryContainer > xLibContainer( aDocProp.getAnyProperty( nPropId ), UNO_QUERY );
229cdf0e10cSrcweir     return xLibContainer;
230cdf0e10cSrcweir }
231cdf0e10cSrcweir 
openLibrary(sal_Int32 nPropId,bool bCreateMissing)232cdf0e10cSrcweir Reference< XNameContainer > VbaProject::openLibrary( sal_Int32 nPropId, bool bCreateMissing )
233cdf0e10cSrcweir {
234cdf0e10cSrcweir     Reference< XNameContainer > xLibrary;
235cdf0e10cSrcweir     try
236cdf0e10cSrcweir     {
237cdf0e10cSrcweir         Reference< XLibraryContainer > xLibContainer( getLibraryContainer( nPropId ), UNO_SET_THROW );
238cdf0e10cSrcweir         if( bCreateMissing && !xLibContainer->hasByName( CREATE_OUSTRING( "Standard" ) /*maPrjName*/ ) )
239cdf0e10cSrcweir             xLibContainer->createLibrary( CREATE_OUSTRING( "Standard" ) /*maPrjName*/ );
240cdf0e10cSrcweir         xLibrary.set( xLibContainer->getByName( CREATE_OUSTRING( "Standard" ) /*maPrjName*/ ), UNO_QUERY_THROW );
241cdf0e10cSrcweir     }
242cdf0e10cSrcweir     catch( Exception& )
243cdf0e10cSrcweir     {
244cdf0e10cSrcweir     }
245cdf0e10cSrcweir     OSL_ENSURE( !bCreateMissing || xLibrary.is(), "VbaProject::openLibrary - cannot create library" );
246cdf0e10cSrcweir     return xLibrary;
247cdf0e10cSrcweir }
248cdf0e10cSrcweir 
createBasicLibrary()249cdf0e10cSrcweir Reference< XNameContainer > VbaProject::createBasicLibrary()
250cdf0e10cSrcweir {
251cdf0e10cSrcweir     if( !mxBasicLib.is() )
252cdf0e10cSrcweir         mxBasicLib = openLibrary( PROP_BasicLibraries, true );
253cdf0e10cSrcweir     return mxBasicLib;
254cdf0e10cSrcweir }
255cdf0e10cSrcweir 
createDialogLibrary()256cdf0e10cSrcweir Reference< XNameContainer > VbaProject::createDialogLibrary()
257cdf0e10cSrcweir {
258cdf0e10cSrcweir     if( !mxDialogLib.is() )
259cdf0e10cSrcweir         mxDialogLib = openLibrary( PROP_DialogLibraries, true );
260cdf0e10cSrcweir     return mxDialogLib;
261cdf0e10cSrcweir }
262cdf0e10cSrcweir 
importVba(StorageBase & rVbaPrjStrg,const GraphicHelper & rGraphicHelper,bool bDefaultColorBgr)263cdf0e10cSrcweir void VbaProject::importVba( StorageBase& rVbaPrjStrg, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr )
264cdf0e10cSrcweir {
265cdf0e10cSrcweir     StorageRef xVbaStrg = rVbaPrjStrg.openSubStorage( CREATE_OUSTRING( "VBA" ), false );
266cdf0e10cSrcweir     OSL_ENSURE( xVbaStrg.get(), "VbaProject::importVba - cannot open 'VBA' substorage" );
267cdf0e10cSrcweir     if( !xVbaStrg )
268cdf0e10cSrcweir         return;
269cdf0e10cSrcweir 
270cdf0e10cSrcweir     /*  Read the 'VBA/dir' stream which contains general settings of the VBA
271cdf0e10cSrcweir         project such as the text encoding used throughout several streams, and
272cdf0e10cSrcweir         a list of all code modules.
273cdf0e10cSrcweir      */
274cdf0e10cSrcweir     BinaryXInputStream aInStrm( xVbaStrg->openInputStream( CREATE_OUSTRING( "dir" ) ), true );
275cdf0e10cSrcweir     // VbaInputStream implements decompression
276cdf0e10cSrcweir     VbaInputStream aDirStrm( aInStrm );
277cdf0e10cSrcweir     OSL_ENSURE( !aDirStrm.isEof(), "VbaProject::importVba - cannot open 'dir' stream" );
278cdf0e10cSrcweir     if( aDirStrm.isEof() )
279cdf0e10cSrcweir         return;
280cdf0e10cSrcweir 
281cdf0e10cSrcweir     // virtual call, derived classes may do some preparations
282cdf0e10cSrcweir     prepareImport();
283cdf0e10cSrcweir 
284cdf0e10cSrcweir     // read all records of the directory
285cdf0e10cSrcweir     rtl_TextEncoding eTextEnc = RTL_TEXTENCODING_MS_1252;
286cdf0e10cSrcweir     sal_uInt16 nModuleCount = 0;
287cdf0e10cSrcweir     bool bExecutable = isImportVbaExecutable();
288cdf0e10cSrcweir 
289cdf0e10cSrcweir     typedef RefMap< OUString, VbaModule > VbaModuleMap;
290cdf0e10cSrcweir     VbaModuleMap aModules, aModulesByStrm;
291cdf0e10cSrcweir 
292cdf0e10cSrcweir     sal_uInt16 nRecId = 0;
293cdf0e10cSrcweir     StreamDataSequence aRecData;
294cdf0e10cSrcweir     while( VbaHelper::readDirRecord( nRecId, aRecData, aDirStrm ) && (nRecId != VBA_ID_PROJECTEND) )
295cdf0e10cSrcweir     {
296cdf0e10cSrcweir         // create record stream object from imported record data
297cdf0e10cSrcweir         SequenceInputStream aRecStrm( aRecData );
298cdf0e10cSrcweir         sal_Int32 nRecSize = aRecData.getLength();
299cdf0e10cSrcweir         switch( nRecId )
300cdf0e10cSrcweir         {
301cdf0e10cSrcweir #define OOX_ENSURE_RECORDSIZE( cond ) OSL_ENSURE( cond, "VbaProject::importVba - invalid record size" )
302cdf0e10cSrcweir             case VBA_ID_PROJECTCODEPAGE:
303cdf0e10cSrcweir             {
304cdf0e10cSrcweir                 OOX_ENSURE_RECORDSIZE( nRecSize == 2 );
305cdf0e10cSrcweir                 OSL_ENSURE( aModules.empty(), "VbaProject::importVba - unexpected PROJECTCODEPAGE record" );
306cdf0e10cSrcweir                 rtl_TextEncoding eNewTextEnc = rtl_getTextEncodingFromWindowsCodePage( aRecStrm.readuInt16() );
307cdf0e10cSrcweir                 OSL_ENSURE( eNewTextEnc != RTL_TEXTENCODING_DONTKNOW, "VbaProject::importVba - unknown text encoding" );
308cdf0e10cSrcweir                 if( eNewTextEnc != RTL_TEXTENCODING_DONTKNOW )
309cdf0e10cSrcweir                     eTextEnc = eNewTextEnc;
310cdf0e10cSrcweir             }
311cdf0e10cSrcweir             break;
312cdf0e10cSrcweir             case VBA_ID_PROJECTNAME:
313cdf0e10cSrcweir             {
314cdf0e10cSrcweir                 OUString aPrjName = aRecStrm.readCharArrayUC( nRecSize, eTextEnc );
315cdf0e10cSrcweir                 OSL_ENSURE( aPrjName.getLength() > 0, "VbaProject::importVba - invalid project name" );
316cdf0e10cSrcweir                 if( aPrjName.getLength() > 0 )
317cdf0e10cSrcweir                     maPrjName = aPrjName;
318cdf0e10cSrcweir             }
319cdf0e10cSrcweir             break;
320cdf0e10cSrcweir             case VBA_ID_PROJECTMODULES:
321cdf0e10cSrcweir                 OOX_ENSURE_RECORDSIZE( nRecSize == 2 );
322cdf0e10cSrcweir                 OSL_ENSURE( aModules.empty(), "VbaProject::importVba - unexpected PROJECTMODULES record" );
323cdf0e10cSrcweir                 aRecStrm >> nModuleCount;
324cdf0e10cSrcweir             break;
325cdf0e10cSrcweir             case VBA_ID_MODULENAME:
326cdf0e10cSrcweir             {
327cdf0e10cSrcweir                 OUString aName = aRecStrm.readCharArrayUC( nRecSize, eTextEnc );
328cdf0e10cSrcweir                 OSL_ENSURE( aName.getLength() > 0, "VbaProject::importVba - invalid module name" );
329cdf0e10cSrcweir                 OSL_ENSURE( !aModules.has( aName ), "VbaProject::importVba - multiple modules with the same name" );
330cdf0e10cSrcweir                 VbaModuleMap::mapped_type& rxModule = aModules[ aName ];
331cdf0e10cSrcweir                 rxModule.reset( new VbaModule( mxContext, mxDocModel, aName, eTextEnc, bExecutable ) );
332cdf0e10cSrcweir                 // read all remaining records until the MODULEEND record
333cdf0e10cSrcweir                 rxModule->importDirRecords( aDirStrm );
334cdf0e10cSrcweir                 OSL_ENSURE( !aModulesByStrm.has( rxModule->getStreamName() ), "VbaProject::importVba - multiple modules with the same stream name" );
335cdf0e10cSrcweir                 aModulesByStrm[ rxModule->getStreamName() ] = rxModule;
336cdf0e10cSrcweir             }
337cdf0e10cSrcweir             break;
338cdf0e10cSrcweir #undef OOX_ENSURE_RECORDSIZE
339cdf0e10cSrcweir         }
340cdf0e10cSrcweir     }
341cdf0e10cSrcweir     OSL_ENSURE( nModuleCount == aModules.size(), "VbaProject::importVba - invalid module count" );
342cdf0e10cSrcweir 
343cdf0e10cSrcweir     /*  The directory does not contain the real type of the modules, it
344cdf0e10cSrcweir         distinguishes only between 'procedural' and 'document' (the latter
345cdf0e10cSrcweir         includes class and form modules). Now, the exact type of all modules
346cdf0e10cSrcweir         will be read from the 'PROJECT' stream. It consists of text lines in
347cdf0e10cSrcweir         'key=value' format which list the code modules by type.
348cdf0e10cSrcweir 
349cdf0e10cSrcweir         -   The line 'document=<modulename>/&HXXXXXXXX' declares document
350cdf0e10cSrcweir             modules. These are attached to the Word document (usually called
351cdf0e10cSrcweir             'ThisDocument'), the Excel workbook (usually called
352cdf0e10cSrcweir             'ThisWorkbook'), or single Excel worksheets or chartsheets (usually
353cdf0e10cSrcweir             called 'SheetX' or 'ChartX', X being a decimal number). Of course,
354cdf0e10cSrcweir             users may rename all these modules. The slash character separates
355cdf0e10cSrcweir             an automation server version number (hexadecimal 'XXXXXXXX') from
356cdf0e10cSrcweir             the module name.
357cdf0e10cSrcweir         -   The line 'Module=<modulename>' declares common procedural code
358cdf0e10cSrcweir             modules.
359cdf0e10cSrcweir         -   The line 'Class=<modulename>' declares a class module.
360cdf0e10cSrcweir         -   The line 'BaseClass=<modulename>' declares a code module attached
361cdf0e10cSrcweir             to a user form with the same name.
362cdf0e10cSrcweir      */
363cdf0e10cSrcweir     BinaryXInputStream aPrjStrm( rVbaPrjStrg.openInputStream( CREATE_OUSTRING( "PROJECT" ) ), true );
364cdf0e10cSrcweir     OSL_ENSURE( !aPrjStrm.isEof(), "VbaProject::importVba - cannot open 'PROJECT' stream" );
365cdf0e10cSrcweir     // do not exit if this stream does not exist, but proceed to load the modules below
366cdf0e10cSrcweir     if( !aPrjStrm.isEof() )
367cdf0e10cSrcweir     {
368cdf0e10cSrcweir         TextInputStream aPrjTextStrm( mxContext, aPrjStrm, eTextEnc );
369cdf0e10cSrcweir         OUString aKey, aValue;
370cdf0e10cSrcweir         bool bExitLoop = false;
371cdf0e10cSrcweir         while( !bExitLoop && !aPrjTextStrm.isEof() )
372cdf0e10cSrcweir         {
373cdf0e10cSrcweir             // read a text line from the stream
374cdf0e10cSrcweir             OUString aLine = aPrjTextStrm.readLine().trim();
375cdf0e10cSrcweir             sal_Int32 nLineLen = aLine.getLength();
376cdf0e10cSrcweir             // exit if a subsection starts (section name is given in brackets)
377cdf0e10cSrcweir             bExitLoop = (nLineLen >= 2) && (aLine[ 0 ] == '[') && (aLine[ nLineLen - 1 ] == ']');
378cdf0e10cSrcweir             if( !bExitLoop && VbaHelper::extractKeyValue( aKey, aValue, aLine ) )
379cdf0e10cSrcweir             {
380cdf0e10cSrcweir                 sal_Int32 nType = ModuleType::UNKNOWN;
381cdf0e10cSrcweir                 if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Document" ) ) )
382cdf0e10cSrcweir                 {
383cdf0e10cSrcweir                     nType = ModuleType::DOCUMENT;
384cdf0e10cSrcweir                     // strip automation server version from module names
385cdf0e10cSrcweir                     sal_Int32 nSlashPos = aValue.indexOf( '/' );
386cdf0e10cSrcweir                     if( nSlashPos >= 0 )
387cdf0e10cSrcweir                         aValue = aValue.copy( 0, nSlashPos );
388cdf0e10cSrcweir                 }
389cdf0e10cSrcweir                 else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Module" ) ) )
390cdf0e10cSrcweir                     nType = ModuleType::NORMAL;
391cdf0e10cSrcweir                 else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Class" ) ) )
392cdf0e10cSrcweir                     nType = ModuleType::CLASS;
393cdf0e10cSrcweir                 else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "BaseClass" ) ) )
394cdf0e10cSrcweir                     nType = ModuleType::FORM;
395cdf0e10cSrcweir 
396cdf0e10cSrcweir                 if( (nType != ModuleType::UNKNOWN) && (aValue.getLength() > 0) )
397cdf0e10cSrcweir                 {
398cdf0e10cSrcweir                     OSL_ENSURE( aModules.has( aValue ), "VbaProject::importVba - module not found" );
399cdf0e10cSrcweir                     if( VbaModule* pModule = aModules.get( aValue ).get() )
400cdf0e10cSrcweir                         pModule->setType( nType );
401cdf0e10cSrcweir                 }
402cdf0e10cSrcweir             }
403cdf0e10cSrcweir         }
404cdf0e10cSrcweir     }
405cdf0e10cSrcweir 
406cdf0e10cSrcweir     // create empty dummy modules
407cdf0e10cSrcweir     VbaModuleMap aDummyModules;
408cdf0e10cSrcweir     for( DummyModuleMap::iterator aIt = maDummyModules.begin(), aEnd = maDummyModules.end(); aIt != aEnd; ++aIt )
409cdf0e10cSrcweir     {
410cdf0e10cSrcweir         OSL_ENSURE( !aModules.has( aIt->first ) && !aDummyModules.has( aIt->first ), "VbaProject::importVba - multiple modules with the same name" );
411cdf0e10cSrcweir         VbaModuleMap::mapped_type& rxModule = aDummyModules[ aIt->first ];
412cdf0e10cSrcweir         rxModule.reset( new VbaModule( mxContext, mxDocModel, aIt->first, eTextEnc, bExecutable ) );
413cdf0e10cSrcweir         rxModule->setType( aIt->second );
414cdf0e10cSrcweir     }
415cdf0e10cSrcweir 
416cdf0e10cSrcweir     /*  Now it is time to load the source code. All modules will be inserted
417cdf0e10cSrcweir         into the Basic library of the document specified by the 'maPrjName'
418cdf0e10cSrcweir         member. Do not create the Basic library, if there are no modules
419cdf0e10cSrcweir         specified. */
420cdf0e10cSrcweir     if( !aModules.empty() || !aDummyModules.empty() ) try
421cdf0e10cSrcweir     {
422cdf0e10cSrcweir         // get the model factory and the basic library
423cdf0e10cSrcweir         Reference< XMultiServiceFactory > xModelFactory( mxDocModel, UNO_QUERY_THROW );
424cdf0e10cSrcweir         Reference< XNameContainer > xBasicLib( createBasicLibrary(), UNO_SET_THROW );
425cdf0e10cSrcweir 
426cdf0e10cSrcweir         /*  Set library container to VBA compatibility mode. This will create
427cdf0e10cSrcweir             the VBA Globals object and store it in the Basic manager of the
428cdf0e10cSrcweir             document. */
429cdf0e10cSrcweir         try
430cdf0e10cSrcweir         {
431cdf0e10cSrcweir             Reference< XVBACompatibility >( getLibraryContainer( PROP_BasicLibraries ), UNO_QUERY_THROW )->setVBACompatibilityMode( sal_True );
432cdf0e10cSrcweir         }
433cdf0e10cSrcweir         catch( Exception& )
434cdf0e10cSrcweir         {
435cdf0e10cSrcweir         }
436cdf0e10cSrcweir 
437cdf0e10cSrcweir         // try to get access to document objects related to code modules
438cdf0e10cSrcweir         Reference< XNameAccess > xDocObjectNA;
439cdf0e10cSrcweir         try
440cdf0e10cSrcweir         {
441cdf0e10cSrcweir             xDocObjectNA.set( xModelFactory->createInstance( CREATE_OUSTRING( "ooo.vba.VBAObjectModuleObjectProvider" ) ), UNO_QUERY );
442cdf0e10cSrcweir         }
443cdf0e10cSrcweir         catch( Exception& )
444cdf0e10cSrcweir         {
445cdf0e10cSrcweir             // not all documents support this
446cdf0e10cSrcweir         }
447cdf0e10cSrcweir 
448cdf0e10cSrcweir         if( xBasicLib.is() )
449cdf0e10cSrcweir         {
450cdf0e10cSrcweir             // call Basic source code import for each module, boost::[c]ref enforces pass-by-ref
451cdf0e10cSrcweir             aModules.forEachMem( &VbaModule::createAndImportModule,
452cdf0e10cSrcweir                 ::boost::ref( *xVbaStrg ), ::boost::cref( xBasicLib ),
453cdf0e10cSrcweir                 ::boost::cref( xDocObjectNA ) );
454cdf0e10cSrcweir 
455cdf0e10cSrcweir             // create empty dummy modules
456cdf0e10cSrcweir             aDummyModules.forEachMem( &VbaModule::createEmptyModule,
457cdf0e10cSrcweir                 ::boost::cref( xBasicLib ), ::boost::cref( xDocObjectNA ) );
458cdf0e10cSrcweir         }
459cdf0e10cSrcweir     }
460cdf0e10cSrcweir     catch( Exception& )
461cdf0e10cSrcweir     {
462cdf0e10cSrcweir     }
463cdf0e10cSrcweir 
464cdf0e10cSrcweir     /*  Load the forms. The file format specification requires that a module
465cdf0e10cSrcweir         must exist for every form. We are a bit more tolerant and scan the
466cdf0e10cSrcweir         project storage for all form substorages. This may 'repair' broken VBA
467cdf0e10cSrcweir         storages that misses to mention a module for an existing form. */
468cdf0e10cSrcweir     ::std::vector< OUString > aElements;
469cdf0e10cSrcweir     rVbaPrjStrg.getElementNames( aElements );
470cdf0e10cSrcweir     for( ::std::vector< OUString >::iterator aIt = aElements.begin(), aEnd = aElements.end(); aIt != aEnd; ++aIt )
471cdf0e10cSrcweir     {
472cdf0e10cSrcweir         // try to open the element as storage
473cdf0e10cSrcweir         if( !aIt->equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "VBA" ) ) )
474cdf0e10cSrcweir         {
475cdf0e10cSrcweir             StorageRef xSubStrg = rVbaPrjStrg.openSubStorage( *aIt, false );
476cdf0e10cSrcweir             if( xSubStrg.get() ) try
477cdf0e10cSrcweir             {
478cdf0e10cSrcweir                 // resolve module name from storage name (which equals the module stream name)
479cdf0e10cSrcweir                 VbaModule* pModule = aModulesByStrm.get( *aIt ).get();
480cdf0e10cSrcweir                 OSL_ENSURE( pModule && (pModule->getType() == ModuleType::FORM),
481cdf0e10cSrcweir                     "VbaProject::importVba - form substorage without form module" );
482cdf0e10cSrcweir                 OUString aModuleName;
483cdf0e10cSrcweir                 if( pModule )
484cdf0e10cSrcweir                     aModuleName = pModule->getName();
485cdf0e10cSrcweir 
486cdf0e10cSrcweir                 // create and import the form
487cdf0e10cSrcweir                 Reference< XNameContainer > xDialogLib( createDialogLibrary(), UNO_SET_THROW );
488cdf0e10cSrcweir                 VbaUserForm aForm( mxContext, mxDocModel, rGraphicHelper, bDefaultColorBgr );
489cdf0e10cSrcweir                 aForm.importForm( xDialogLib, *xSubStrg, aModuleName, eTextEnc );
490cdf0e10cSrcweir             }
491cdf0e10cSrcweir             catch( Exception& )
492cdf0e10cSrcweir             {
493cdf0e10cSrcweir             }
494cdf0e10cSrcweir         }
495cdf0e10cSrcweir     }
496cdf0e10cSrcweir 
497cdf0e10cSrcweir     // attach macros to registered objects
498cdf0e10cSrcweir     attachMacros();
499cdf0e10cSrcweir     // virtual call, derived classes may do some more processing
500cdf0e10cSrcweir     finalizeImport();
501cdf0e10cSrcweir }
502cdf0e10cSrcweir 
attachMacros()503cdf0e10cSrcweir void VbaProject::attachMacros()
504cdf0e10cSrcweir {
505cdf0e10cSrcweir     if( !maMacroAttachers.empty() && mxContext.is() ) try
506cdf0e10cSrcweir     {
507cdf0e10cSrcweir         Reference< XMultiComponentFactory > xFactory( mxContext->getServiceManager(), UNO_SET_THROW );
508cdf0e10cSrcweir         Sequence< Any > aArgs( 2 );
509cdf0e10cSrcweir         aArgs[ 0 ] <<= mxDocModel;
510cdf0e10cSrcweir         aArgs[ 1 ] <<= maPrjName;
511cdf0e10cSrcweir         Reference< XVBAMacroResolver > xResolver( xFactory->createInstanceWithArgumentsAndContext(
512cdf0e10cSrcweir             CREATE_OUSTRING( "com.sun.star.script.vba.VBAMacroResolver" ), aArgs, mxContext ), UNO_QUERY_THROW );
513cdf0e10cSrcweir         maMacroAttachers.forEachMem( &VbaMacroAttacherBase::resolveAndAttachMacro, ::boost::cref( xResolver ) );
514cdf0e10cSrcweir     }
515cdf0e10cSrcweir     catch( Exception& )
516cdf0e10cSrcweir     {
517cdf0e10cSrcweir     }
518cdf0e10cSrcweir }
519cdf0e10cSrcweir 
copyStorage(StorageBase & rVbaPrjStrg)520cdf0e10cSrcweir void VbaProject::copyStorage( StorageBase& rVbaPrjStrg )
521cdf0e10cSrcweir {
522cdf0e10cSrcweir     if( mxContext.is() ) try
523cdf0e10cSrcweir     {
524cdf0e10cSrcweir         Reference< XStorageBasedDocument > xStorageBasedDoc( mxDocModel, UNO_QUERY_THROW );
525cdf0e10cSrcweir         Reference< XStorage > xDocStorage( xStorageBasedDoc->getDocumentStorage(), UNO_QUERY_THROW );
526cdf0e10cSrcweir         {
527cdf0e10cSrcweir             const sal_Int32 nOpenMode = ElementModes::SEEKABLE | ElementModes::WRITE | ElementModes::TRUNCATE;
528cdf0e10cSrcweir             Reference< XStream > xDocStream( xDocStorage->openStreamElement( CREATE_OUSTRING( "_MS_VBA_Macros" ), nOpenMode ), UNO_SET_THROW );
529cdf0e10cSrcweir             OleStorage aDestStorage( mxContext, xDocStream, false );
530cdf0e10cSrcweir             rVbaPrjStrg.copyStorageToStorage( aDestStorage );
531cdf0e10cSrcweir             aDestStorage.commit();
532cdf0e10cSrcweir         }
533cdf0e10cSrcweir         Reference< XTransactedObject >( xDocStorage, UNO_QUERY_THROW )->commit();
534cdf0e10cSrcweir     }
535cdf0e10cSrcweir     catch( Exception& )
536cdf0e10cSrcweir     {
537cdf0e10cSrcweir     }
538cdf0e10cSrcweir }
539cdf0e10cSrcweir 
540cdf0e10cSrcweir // ============================================================================
541cdf0e10cSrcweir 
542cdf0e10cSrcweir } // namespace ole
543cdf0e10cSrcweir } // namespace oox
544