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 // MARKER(update_precomp.py): autogen include statement, do not remove
24 #include "precompiled_filter.hxx"
25 
26 #include <filter/msfilter/msvbahelper.hxx>
27 #include <basic/sbx.hxx>
28 #include <basic/sbstar.hxx>
29 #include <basic/basmgr.hxx>
30 #include <basic/sbmod.hxx>
31 #include <basic/sbmeth.hxx>
32 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
33 #include <com/sun/star/document/XDocumentProperties.hpp>
34 #include <com/sun/star/document/XDocumentInfoSupplier.hpp>
35 #include <com/sun/star/lang/XUnoTunnel.hpp>
36 #include <com/sun/star/script/ModuleType.hpp>
37 #include <tools/urlobj.hxx>
38 #include <osl/file.hxx>
39 #include <unotools/pathoptions.hxx>
40 
41 using namespace ::com::sun::star;
42 
43 namespace ooo {
44 namespace vba {
45 
46 const static rtl::OUString sUrlPart0 = rtl::OUString::createFromAscii( "vnd.sun.star.script:");
47 const static rtl::OUString sUrlPart1 = rtl::OUString::createFromAscii( "?language=Basic&location=document");
48 
makeMacroURL(const String & sMacroName)49 String makeMacroURL( const String& sMacroName )
50 {
51 	return sUrlPart0.concat( sMacroName ).concat( sUrlPart1 ) ;
52 }
53 
extractMacroName(const::rtl::OUString & rMacroUrl)54 ::rtl::OUString extractMacroName( const ::rtl::OUString& rMacroUrl )
55 {
56     if( (rMacroUrl.getLength() > sUrlPart0.getLength() + sUrlPart1.getLength()) &&
57         rMacroUrl.match( sUrlPart0 ) &&
58         rMacroUrl.match( sUrlPart1, rMacroUrl.getLength() - sUrlPart1.getLength() ) )
59     {
60         return rMacroUrl.copy( sUrlPart0.getLength(), rMacroUrl.getLength() - sUrlPart0.getLength() - sUrlPart1.getLength() );
61     }
62     return ::rtl::OUString();
63 }
64 
trimMacroName(const::rtl::OUString & rMacroName)65 ::rtl::OUString trimMacroName( const ::rtl::OUString& rMacroName )
66 {
67     // the name may contain whitespaces and may be enclosed in apostrophs
68     ::rtl::OUString aMacroName = rMacroName.trim();
69     sal_Int32 nMacroLen = aMacroName.getLength();
70     if( (nMacroLen >= 2) && (aMacroName[ 0 ] == '\'') && (aMacroName[ nMacroLen - 1 ] == '\'') )
71         aMacroName = aMacroName.copy( 1, nMacroLen - 2 ).trim();
72     return aMacroName;
73 }
74 
findShellForUrl(const rtl::OUString & sMacroURLOrPath)75 SfxObjectShell* findShellForUrl( const rtl::OUString& sMacroURLOrPath )
76 {
77     SfxObjectShell* pFoundShell=NULL;
78     SfxObjectShell* pShell = SfxObjectShell::GetFirst();
79     INetURLObject aObj;
80     aObj.SetURL( sMacroURLOrPath );
81     bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
82     rtl::OUString aURL;
83     if ( bIsURL )
84         aURL = sMacroURLOrPath;
85     else
86     {
87         osl::FileBase::getFileURLFromSystemPath( sMacroURLOrPath, aURL );
88         aObj.SetURL( aURL );
89     }
90     OSL_TRACE("Trying to find shell for url %s", rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr() );
91     while ( pShell )
92     {
93 
94         uno::Reference< frame::XModel > xModel = pShell->GetModel();
95         // are we searching for a template? if so we have to cater for the
96         // fact that in openoffice a document opened from a template is always
97         // a new document :/
98         if ( xModel.is() )
99         {
100             OSL_TRACE("shell 0x%x has model with url %s and we look for %s", pShell
101                 , rtl::OUStringToOString( xModel->getURL(), RTL_TEXTENCODING_UTF8 ).getStr()
102                 , rtl::OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ).getStr()
103             );
104 			::rtl::OUString aName = xModel->getURL() ;
105 			if (0 == aName.getLength())
106 				{
107 
108 					const static rtl::OUString sTitle( RTL_CONSTASCII_USTRINGPARAM("Title" ) );
109 				    uno::Reference< frame::XFrame > xFrame( xModel->getCurrentController()->getFrame(), uno::UNO_QUERY_THROW );
110 					uno::Reference< beans::XPropertySet > xProps( xFrame, uno::UNO_QUERY_THROW );
111 					xProps->getPropertyValue(sTitle) >>= aName;
112 					sal_Int32 pos = 0;
113 					aName = aName.getToken(0,'-',pos);
114 					aName = aName.trim();
115 					if( sMacroURLOrPath.lastIndexOf( aName ) >= 0 )
116                     {
117                         pFoundShell = pShell;
118                         break;
119                     }
120 				}
121 
122             if ( sMacroURLOrPath.endsWithIgnoreAsciiCaseAsciiL( ".dot", 4 ) )
123             {
124                 uno::Reference< document::XDocumentInfoSupplier > xDocInfoSupp( xModel, uno::UNO_QUERY );
125                 if( xDocInfoSupp.is() )
126                 {
127                     uno::Reference< document::XDocumentPropertiesSupplier > xDocPropSupp( xDocInfoSupp->getDocumentInfo(), uno::UNO_QUERY_THROW );
128                     uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
129                     rtl::OUString sCurrName = xDocProps->getTemplateName();
130                     if( sMacroURLOrPath.lastIndexOf( sCurrName ) >= 0 )
131                     {
132                         pFoundShell = pShell;
133                         break;
134                     }
135                 }
136             }
137             else
138             {
139                 // sometimes just the name of the document ( without the path
140                 // is used
141                 bool bDocNameNoPathMatch = false;
142                 if ( aURL.getLength() && aURL.indexOf( '/' ) == -1 )
143                 {
144                     sal_Int32 lastSlashIndex = xModel->getURL().lastIndexOf( '/' );
145                     if ( lastSlashIndex > -1 )
146                     {
147                         bDocNameNoPathMatch = xModel->getURL().copy( lastSlashIndex + 1 ).equals( aURL );
148                         if ( !bDocNameNoPathMatch )
149                         {
150                             rtl::OUString aTmpName = rtl::OUString::createFromAscii("'") + xModel->getURL().copy( lastSlashIndex + 1 ) + rtl::OUString::createFromAscii("'");
151                             bDocNameNoPathMatch = aTmpName.equals( aURL );
152                         }
153                     }
154                 }
155 
156                 if ( aURL.equals( xModel->getURL() ) || bDocNameNoPathMatch )
157                 {
158                     pFoundShell = pShell;
159                     break;
160                 }
161             }
162         }
163         pShell = SfxObjectShell::GetNext( *pShell );
164     }
165     return pFoundShell;
166 }
167 
168 // sMod can be empty ( but we really need the library to search in )
169 // if sMod is empty and a macro is found then sMod is updated
170 // if sMod is empty, only standard modules will be searched (no class, document, form modules)
hasMacro(SfxObjectShell * pShell,const String & sLibrary,String & sMod,const String & sMacro)171 bool hasMacro( SfxObjectShell* pShell, const String& sLibrary, String& sMod, const String& sMacro )
172 {
173     bool bFound = false;
174     if ( sLibrary.Len() && sMacro.Len() )
175     {
176         OSL_TRACE("** Searching for %s.%s in library %s"
177             ,rtl::OUStringToOString( sMod, RTL_TEXTENCODING_UTF8 ).getStr()
178             ,rtl::OUStringToOString( sMacro, RTL_TEXTENCODING_UTF8 ).getStr()
179             ,rtl::OUStringToOString( sLibrary, RTL_TEXTENCODING_UTF8 ).getStr() );
180         BasicManager* pBasicMgr = pShell-> GetBasicManager();
181         if ( pBasicMgr )
182         {
183             StarBASIC* pBasic = pBasicMgr->GetLib( sLibrary );
184             if ( !pBasic )
185             {
186                 sal_uInt16 nId = pBasicMgr->GetLibId( sLibrary );
187                 pBasicMgr->LoadLib( nId );
188                 pBasic = pBasicMgr->GetLib( sLibrary );
189             }
190             if ( pBasic )
191             {
192                 if ( sMod.Len() ) // we wish to find the macro is a specific module
193                 {
194                     SbModule* pModule = pBasic->FindModule( sMod );
195                     if ( pModule )
196                     {
197                         SbxArray* pMethods = pModule->GetMethods();
198                         if ( pMethods )
199                         {
200                             SbMethod* pMethod = static_cast< SbMethod* >( pMethods->Find( sMacro, SbxCLASS_METHOD ) );
201                             if ( pMethod )
202                               bFound = true;
203                         }
204                     }
205                 }
206                 else if( SbMethod* pMethod = dynamic_cast< SbMethod* >( pBasic->Find( sMacro, SbxCLASS_METHOD ) ) )
207                 {
208                     if( SbModule* pModule = pMethod->GetModule() )
209                     {
210                         // when searching for a macro without module name, do not search in class/document/form modules
211                         if( pModule->GetModuleType() == script::ModuleType::NORMAL )
212                         {
213                             sMod = pModule->GetName();
214                             bFound = true;
215                         }
216                     }
217                 }
218             }
219         }
220     }
221     return bFound;
222 }
223 
getDefaultProjectName(SfxObjectShell * pShell)224 ::rtl::OUString getDefaultProjectName( SfxObjectShell* pShell )
225 {
226     ::rtl::OUString aPrjName;
227     if( BasicManager* pBasicMgr = pShell ? pShell->GetBasicManager() : 0 )
228     {
229         aPrjName = pBasicMgr->GetName();
230         if( aPrjName.getLength() == 0 )
231             aPrjName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Standard" ) );
232     }
233     return aPrjName;
234 }
235 
parseMacro(const rtl::OUString & sMacro,String & sContainer,String & sModule,String & sProcedure)236 void parseMacro( const rtl::OUString& sMacro, String& sContainer, String& sModule, String& sProcedure )
237 {
238     sal_Int32 nMacroDot = sMacro.lastIndexOf( '.' );
239 
240     if ( nMacroDot != -1 )
241     {
242         sProcedure = sMacro.copy( nMacroDot + 1 );
243 
244         sal_Int32 nContainerDot = sMacro.lastIndexOf( '.',  nMacroDot - 1 );
245         if ( nContainerDot != -1 )
246         {
247             sModule = sMacro.copy( nContainerDot + 1, nMacroDot - nContainerDot - 1 );
248             sContainer = sMacro.copy( 0, nContainerDot );
249         }
250         else
251             sModule = sMacro.copy( 0, nMacroDot );
252     }
253     else
254        sProcedure = sMacro;
255 }
256 
resolveVBAMacro(SfxObjectShell * pShell,const::rtl::OUString & rLibName,const::rtl::OUString & rModuleName,const::rtl::OUString & rMacroName)257 ::rtl::OUString resolveVBAMacro( SfxObjectShell* pShell, const ::rtl::OUString& rLibName, const ::rtl::OUString& rModuleName, const ::rtl::OUString& rMacroName )
258 {
259     if( pShell )
260     {
261         ::rtl::OUString aLibName = (rLibName.getLength() > 0) ? rLibName : getDefaultProjectName( pShell );
262         String aModuleName = rModuleName;
263         if( hasMacro( pShell, aLibName, aModuleName, rMacroName ) )
264             return ::rtl::OUStringBuffer( aLibName ).append( sal_Unicode( '.' ) ).append( aModuleName ).append( sal_Unicode( '.' ) ).append( rMacroName ).makeStringAndClear();
265     }
266     return ::rtl::OUString();
267 }
268 
resolveVBAMacro(SfxObjectShell * pShell,const rtl::OUString & MacroName,bool bSearchGlobalTemplates)269 MacroResolvedInfo resolveVBAMacro( SfxObjectShell* pShell, const rtl::OUString& MacroName, bool bSearchGlobalTemplates )
270 {
271     if( !pShell )
272         return MacroResolvedInfo();
273 
274     // the name may be enclosed in apostrophs
275     ::rtl::OUString aMacroName = trimMacroName( MacroName );
276 
277     // parse the macro name
278     sal_Int32 nDocSepIndex = aMacroName.indexOf( '!' );
279     if( nDocSepIndex > 0 )
280     {
281         // macro specified by document name
282         // find document shell for document name and call ourselves
283         // recursively
284 
285         // assume for now that the document name is *this* document
286         String sDocUrlOrPath = aMacroName.copy( 0, nDocSepIndex );
287         aMacroName = aMacroName.copy( nDocSepIndex + 1 );
288         OSL_TRACE("doc search, current shell is 0x%x", pShell );
289         SfxObjectShell* pFoundShell = 0;
290         if( bSearchGlobalTemplates )
291         {
292             SvtPathOptions aPathOpt;
293             String aAddinPath = aPathOpt.GetAddinPath();
294             if( rtl::OUString( sDocUrlOrPath ).indexOf( aAddinPath ) == 0 )
295                 pFoundShell = pShell;
296         }
297         if( !pFoundShell )
298             pFoundShell = findShellForUrl( sDocUrlOrPath );
299         OSL_TRACE("doc search, after find, found shell is 0x%x", pFoundShell );
300         return resolveVBAMacro( pFoundShell, aMacroName );
301     }
302 
303     // macro is contained in 'this' document ( or code imported from a template
304     // where that template is a global template or perhaps the template this
305     // document is created from )
306 
307     MacroResolvedInfo aRes( pShell );
308 
309     // macro format = Container.Module.Procedure
310     String sContainer, sModule, sProcedure;
311     parseMacro( aMacroName, sContainer, sModule, sProcedure );
312 
313 #if 0
314     // As long as service VBAProjectNameProvider isn't supported in the model, disable the createInstance call
315     // (the ServiceNotRegisteredException is wrongly caught in ScModelObj::createInstance)
316     uno::Reference< container::XNameContainer > xPrjNameCache;
317     uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY);
318     if ( xSF.is() ) try
319     {
320         xPrjNameCache.set( xSF->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAProjectNameProvider" ) ) ), uno::UNO_QUERY );
321     }
322     catch( uno::Exception& )    // createInstance may throw
323     {
324     }
325 #endif
326 
327     std::vector< rtl::OUString > sSearchList;
328 
329     if ( sContainer.Len() > 0 )
330     {
331 // service VBAProjectNameProvider not implemented
332 #if 0
333         // get the Project associated with the Container
334         if ( xPrjNameCache.is() )
335         {
336             if ( xPrjNameCache->hasByName( sContainer ) )
337             {
338                 rtl::OUString sProject;
339                 xPrjNameCache->getByName( sContainer ) >>= sProject;
340                 sContainer = sProject;
341             }
342         }
343 #endif
344         sSearchList.push_back( sContainer ); // First Lib to search
345     }
346     else
347     {
348         // Ok, if we have no Container specified then we need to search them in order, this document, template this document created from, global templates,
349         // get the name of Project/Library for 'this' document
350         rtl::OUString sThisProject = getDefaultProjectName( pShell );
351         sSearchList.push_back( sThisProject ); // First Lib to search
352 
353 // service VBAProjectNameProvider not implemented
354 #if 0
355         if ( xPrjNameCache.is() )
356         {
357             // is this document created from a template?
358             uno::Reference< document::XDocumentInfoSupplier > xDocInfoSupp( pShell->GetModel(), uno::UNO_QUERY_THROW );
359             uno::Reference< document::XDocumentPropertiesSupplier > xDocPropSupp( xDocInfoSupp->getDocumentInfo(), uno::UNO_QUERY_THROW );
360             uno::Reference< document::XDocumentProperties > xDocProps( xDocPropSupp->getDocumentProperties(), uno::UNO_QUERY_THROW );
361 
362             rtl::OUString sCreatedFrom = xDocProps->getTemplateURL();
363             if ( sCreatedFrom.getLength() )
364             {
365                 INetURLObject aObj;
366                 aObj.SetURL( sCreatedFrom );
367                 bool bIsURL = aObj.GetProtocol() != INET_PROT_NOT_VALID;
368                 rtl::OUString aURL;
369                 if ( bIsURL )
370                     aURL = sCreatedFrom;
371                 else
372                 {
373                     osl::FileBase::getFileURLFromSystemPath( sCreatedFrom, aURL );
374                     aObj.SetURL( aURL );
375                 }
376                 sCreatedFrom =  aObj.GetLastName();
377             }
378 
379             sal_Int32 nIndex =  sCreatedFrom.lastIndexOf( '.' );
380             if ( nIndex != -1 )
381                 sCreatedFrom = sCreatedFrom.copy( 0, nIndex );
382 
383             rtl::OUString sPrj;
384             if ( sCreatedFrom.getLength() && xPrjNameCache->hasByName( sCreatedFrom ) )
385             {
386                 xPrjNameCache->getByName( sCreatedFrom ) >>= sPrj;
387                 // Make sure we don't double up with this project
388                 if ( !sPrj.equals( sThisProject ) )
389                     sSearchList.push_back( sPrj );
390             }
391 
392             // get list of global template Names
393             uno::Sequence< rtl::OUString > sTemplateNames = xPrjNameCache->getElementNames();
394             sal_Int32 nLen = sTemplateNames.getLength();
395             for ( sal_Int32 index = 0; ( bSearchGlobalTemplates && index < nLen ); ++index )
396             {
397 
398                 if ( !sCreatedFrom.equals( sTemplateNames[ index ] ) )
399                 {
400                     if ( xPrjNameCache->hasByName( sTemplateNames[ index ] ) )
401                     {
402                         xPrjNameCache->getByName( sTemplateNames[ index ] ) >>= sPrj;
403                         // Make sure we don't double up with this project
404                         if ( !sPrj.equals( sThisProject ) )
405                             sSearchList.push_back( sPrj );
406                     }
407                 }
408 
409             }
410         }
411 #endif
412     }
413 
414     std::vector< rtl::OUString >::iterator it_end = sSearchList.end();
415     for ( std::vector< rtl::OUString >::iterator it = sSearchList.begin(); !aRes.mbFound && (it != it_end); ++it )
416     {
417         aRes.mbFound = hasMacro( pShell, *it, sModule, sProcedure );
418         if ( aRes.mbFound )
419             sContainer = *it;
420     }
421     aRes.msResolvedMacro = sProcedure.Insert( '.', 0 ).Insert( sModule, 0).Insert( '.', 0 ).Insert( sContainer, 0 );
422 
423     return aRes;
424 }
425 
426 // Treat the args as possible inouts ( conversion at bottom of method )
executeMacro(SfxObjectShell * pShell,const String & sMacroName,uno::Sequence<uno::Any> & aArgs,uno::Any & aRet,const uno::Any &)427 sal_Bool executeMacro( SfxObjectShell* pShell, const String& sMacroName, uno::Sequence< uno::Any >& aArgs, uno::Any& aRet, const uno::Any& /*aCaller*/)
428 {
429     sal_Bool bRes = sal_False;
430     if ( !pShell )
431         return bRes;
432     rtl::OUString sUrl = makeMacroURL( sMacroName );
433 
434     uno::Sequence< sal_Int16 > aOutArgsIndex;
435     uno::Sequence< uno::Any > aOutArgs;
436 
437     try
438     {   ErrCode nErr( ERRCODE_BASIC_INTERNAL_ERROR );
439         if ( pShell )
440         {
441             nErr = pShell->CallXScript( sUrl,
442 				aArgs, aRet, aOutArgsIndex, aOutArgs, ::rtl::OUString(), false );
443             sal_Int32 nLen = aOutArgs.getLength();
444             // convert any out params to seem like they were inouts
445             if ( nLen )
446             {
447                 for ( sal_Int32 index=0; index < nLen; ++index )
448                 {
449                     sal_Int32 nOutIndex = aOutArgsIndex[ index ];
450                     aArgs[ nOutIndex ] = aOutArgs[ index ];
451                 }
452             }
453         }
454         bRes = ( nErr == ERRCODE_NONE );
455     }
456     catch ( uno::Exception& )
457     {
458        bRes = sal_False;
459     }
460     return bRes;
461 }
462 
463 // ============================================================================
464 
VBAMacroResolver_getSupportedServiceNames()465 uno::Sequence< ::rtl::OUString > VBAMacroResolver_getSupportedServiceNames()
466 {
467     uno::Sequence< ::rtl::OUString > aServiceNames( 1 );
468     aServiceNames[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.script.vba.VBAMacroResolver" ) );
469     return aServiceNames;
470 }
471 
VBAMacroResolver_getImplementationName()472 ::rtl::OUString VBAMacroResolver_getImplementationName()
473 {
474     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.vba.VBAMacroResolver" ) );
475 }
476 
VBAMacroResolver_createInstance(const uno::Reference<uno::XComponentContext> &)477 uno::Reference< uno::XInterface > SAL_CALL VBAMacroResolver_createInstance( const uno::Reference< uno::XComponentContext >& ) throw (uno::Exception)
478 {
479     return static_cast< ::cppu::OWeakObject* >( new VBAMacroResolver );
480 }
481 
482 // ============================================================================
483 
VBAMacroResolver()484 VBAMacroResolver::VBAMacroResolver() :
485     mpObjShell( 0 )
486 {
487 }
488 
~VBAMacroResolver()489 VBAMacroResolver::~VBAMacroResolver()
490 {
491 }
492 
493 // com.sun.star.lang.XServiceInfo interface -----------------------------------
494 
getImplementationName()495 ::rtl::OUString SAL_CALL VBAMacroResolver::getImplementationName() throw (uno::RuntimeException)
496 {
497     return VBAMacroResolver_getImplementationName();
498 }
499 
supportsService(const::rtl::OUString & rService)500 sal_Bool SAL_CALL VBAMacroResolver::supportsService( const ::rtl::OUString& rService ) throw (uno::RuntimeException)
501 {
502     uno::Sequence< ::rtl::OUString > aServices = VBAMacroResolver_getSupportedServiceNames();
503     const ::rtl::OUString* pArray = aServices.getConstArray();
504     const ::rtl::OUString* pArrayEnd = pArray + aServices.getLength();
505     return ::std::find( pArray, pArrayEnd, rService ) != pArrayEnd;
506 }
507 
getSupportedServiceNames()508 uno::Sequence< ::rtl::OUString > SAL_CALL VBAMacroResolver::getSupportedServiceNames() throw (uno::RuntimeException)
509 {
510     return VBAMacroResolver_getSupportedServiceNames();
511 }
512 
513 // com.sun.star.lang.XInitialization interface --------------------------------
514 
initialize(const uno::Sequence<uno::Any> & rArgs)515 void SAL_CALL VBAMacroResolver::initialize( const uno::Sequence< uno::Any >& rArgs ) throw (uno::Exception, uno::RuntimeException)
516 {
517     OSL_ENSURE( rArgs.getLength() < 2, "VBAMacroResolver::initialize - missing arguments" );
518     if( rArgs.getLength() < 2 )
519         throw uno::RuntimeException();
520 
521     // first argument: document model
522     mxModel.set( rArgs[ 0 ], uno::UNO_QUERY_THROW );
523     uno::Reference< lang::XUnoTunnel > xUnoTunnel( mxModel, uno::UNO_QUERY_THROW );
524     mpObjShell = reinterpret_cast< SfxObjectShell* >( xUnoTunnel->getSomething( SfxObjectShell::getUnoTunnelId() ) );
525     if( !mpObjShell )
526         throw uno::RuntimeException();
527 
528     // second argument: VBA project name
529     if( !(rArgs[ 1 ] >>= maProjectName) || (maProjectName.getLength() == 0) )
530         throw uno::RuntimeException();
531 }
532 
533 // com.sun.star.script.vba.XVBAMacroResolver interface ------------------------
534 
resolveVBAMacroToScriptURL(const::rtl::OUString & rVBAMacroName)535 ::rtl::OUString SAL_CALL VBAMacroResolver::resolveVBAMacroToScriptURL( const ::rtl::OUString& rVBAMacroName ) throw (lang::IllegalArgumentException, uno::RuntimeException)
536 {
537     if( !mpObjShell )
538         throw uno::RuntimeException();
539 
540     // the name may be enclosed in apostrophs
541     ::rtl::OUString aMacroName = trimMacroName( rVBAMacroName );
542     if( aMacroName.getLength() == 0 )
543         throw lang::IllegalArgumentException();
544 
545     // external references not supported here (syntax is "url!macroname" or "[url]!macroname" or "[url]macroname")
546     if( (aMacroName[ 0 ] == '[') || (aMacroName.indexOf( '!' ) >= 0) )
547         throw lang::IllegalArgumentException();
548 
549     // check if macro name starts with project name, replace with "Standard"
550     // TODO: adjust this when custom VBA project name is supported
551     sal_Int32 nDotPos = aMacroName.indexOf( '.' );
552     if( (nDotPos == 0) || (nDotPos + 1 == aMacroName.getLength()) )
553         throw lang::IllegalArgumentException();
554     if( (nDotPos > 0) && aMacroName.matchIgnoreAsciiCase( maProjectName ) )
555         aMacroName = aMacroName.copy( nDotPos + 1 );
556 
557     // try to find the macro
558     MacroResolvedInfo aInfo = resolveVBAMacro( mpObjShell, aMacroName, false );
559     if( !aInfo.mbFound )
560         throw lang::IllegalArgumentException();
561 
562     // build and return the script URL
563     return makeMacroURL( aInfo.msResolvedMacro );
564 }
565 
resolveScriptURLtoVBAMacro(const::rtl::OUString &)566 ::rtl::OUString SAL_CALL VBAMacroResolver::resolveScriptURLtoVBAMacro( const ::rtl::OUString& /*rScriptURL*/ ) throw (lang::IllegalArgumentException, uno::RuntimeException)
567 {
568     OSL_ENSURE( false, "VBAMacroResolver::resolveScriptURLtoVBAMacro - not implemented" );
569     throw uno::RuntimeException();
570 }
571 
572 // ============================================================================
573 
574 } // namespace vba
575 } // namespace ooo
576