1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include "basprov.hxx" 21 #include "basscript.hxx" 22 #include "baslibnode.hxx" 23 #include <com/sun/star/frame/XModel.hpp> 24 #include <com/sun/star/script/browse/BrowseNodeTypes.hpp> 25 #include <com/sun/star/script/provider/ScriptFrameworkErrorException.hpp> 26 #include <com/sun/star/script/provider/ScriptFrameworkErrorType.hpp> 27 #include <com/sun/star/document/XEmbeddedScripts.hpp> 28 #include <com/sun/star/uri/UriReferenceFactory.hpp> 29 30 #include <cppuhelper/implementationentry.hxx> 31 #include <cppuhelper/supportsservice.hxx> 32 #include <rtl/uri.hxx> 33 #include <sal/log.hxx> 34 #include <osl/process.h> 35 #include <osl/file.hxx> 36 #include <osl/mutex.hxx> 37 #include <vcl/svapp.hxx> 38 #include <basic/sbx.hxx> 39 #include <basic/basmgr.hxx> 40 #include <basic/basicmanagerrepository.hxx> 41 #include <basic/sbstar.hxx> 42 #include <basic/sbmod.hxx> 43 #include <basic/sbmeth.hxx> 44 #include <sfx2/app.hxx> 45 #include <sfx2/objsh.hxx> 46 47 #include <com/sun/star/util/theMacroExpander.hpp> 48 #include <com/sun/star/script/XLibraryContainer2.hpp> 49 #include <com/sun/star/uri/XUriReference.hpp> 50 #include <com/sun/star/uri/XUriReferenceFactory.hpp> 51 #include <com/sun/star/uri/XVndSunStarScriptUrl.hpp> 52 53 #include <util/MiscUtils.hxx> 54 55 56 using namespace ::com::sun::star; 57 using namespace ::com::sun::star::lang; 58 using namespace ::com::sun::star::uno; 59 using namespace ::com::sun::star::script; 60 using namespace ::com::sun::star::document; 61 using namespace ::sf_misc; 62 63 64 namespace basprov 65 { 66 67 68 // component operations 69 70 71 static OUString getImplementationName_BasicProviderImpl() 72 { 73 return OUString( "com.sun.star.comp.scripting.ScriptProviderForBasic" ); 74 } 75 76 77 static Sequence< OUString > getSupportedServiceNames_BasicProviderImpl() 78 { 79 static Sequence< OUString > s_Names{ 80 "com.sun.star.script.provider.ScriptProviderForBasic", 81 "com.sun.star.script.provider.LanguageScriptProvider", 82 "com.sun.star.script.provider.ScriptProvider", 83 "com.sun.star.script.browse.BrowseNode"}; 84 85 return s_Names; 86 } 87 88 89 // BasicProviderImpl 90 91 92 BasicProviderImpl::BasicProviderImpl( const Reference< XComponentContext >& xContext ) 93 :m_pAppBasicManager( nullptr ) 94 ,m_pDocBasicManager( nullptr ) 95 ,m_xContext( xContext ) 96 ,m_bIsAppScriptCtx( true ) 97 ,m_bIsUserCtx(true) 98 { 99 } 100 101 102 BasicProviderImpl::~BasicProviderImpl() 103 { 104 } 105 106 107 bool BasicProviderImpl::isLibraryShared( const Reference< script::XLibraryContainer >& rxLibContainer, const OUString& rLibName ) 108 { 109 bool bIsShared = false; 110 111 Reference< script::XLibraryContainer2 > xLibContainer( rxLibContainer, UNO_QUERY ); 112 if ( xLibContainer.is() && xLibContainer->hasByName( rLibName ) && xLibContainer->isLibraryLink( rLibName ) ) 113 { 114 OUString aFileURL; 115 if ( m_xContext.is() ) 116 { 117 Reference< uri::XUriReferenceFactory > xUriFac( uri::UriReferenceFactory::create( m_xContext ) ); 118 119 OUString aLinkURL( xLibContainer->getLibraryLinkURL( rLibName ) ); 120 Reference< uri::XUriReference > xUriRef( xUriFac->parse( aLinkURL ), UNO_QUERY ); 121 122 if ( xUriRef.is() ) 123 { 124 OUString aScheme = xUriRef->getScheme(); 125 if ( aScheme.equalsIgnoreAsciiCase("file") ) 126 { 127 aFileURL = aLinkURL; 128 } 129 else if ( aScheme.equalsIgnoreAsciiCase("vnd.sun.star.pkg") ) 130 { 131 OUString aAuthority = xUriRef->getAuthority(); 132 if ( aAuthority.matchIgnoreAsciiCase( "vnd.sun.star.expand:" ) ) 133 { 134 OUString aDecodedURL( aAuthority.copy( sizeof ( "vnd.sun.star.expand:" ) - 1 ) ); 135 aDecodedURL = ::rtl::Uri::decode( aDecodedURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); 136 Reference<util::XMacroExpander> xMacroExpander = 137 util::theMacroExpander::get(m_xContext); 138 aFileURL = xMacroExpander->expandMacros( aDecodedURL ); 139 } 140 } 141 } 142 } 143 144 if ( !aFileURL.isEmpty() ) 145 { 146 osl::DirectoryItem aFileItem; 147 osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL ); 148 OSL_VERIFY( osl::DirectoryItem::get( aFileURL, aFileItem ) == osl::FileBase::E_None ); 149 OSL_VERIFY( aFileItem.getFileStatus( aFileStatus ) == osl::FileBase::E_None ); 150 OUString aCanonicalFileURL( aFileStatus.getFileURL() ); 151 152 if( aCanonicalFileURL.indexOf( "share/basic" ) != -1 153 || aCanonicalFileURL.indexOf( "share/uno_packages" ) != -1 ) 154 bIsShared = true; 155 } 156 } 157 158 return bIsShared; 159 } 160 161 // SfxListener 162 void BasicProviderImpl::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) 163 { 164 if (auto pManager = dynamic_cast<const BasicManager*>(&rBC)) 165 if (pManager == m_pAppBasicManager && rHint.GetId() == SfxHintId::Dying) 166 { 167 EndListening(*m_pAppBasicManager); 168 m_pAppBasicManager = nullptr; 169 } 170 } 171 172 // XServiceInfo 173 OUString BasicProviderImpl::getImplementationName( ) 174 { 175 return getImplementationName_BasicProviderImpl(); 176 } 177 178 sal_Bool BasicProviderImpl::supportsService( const OUString& rServiceName ) 179 { 180 return cppu::supportsService(this, rServiceName); 181 } 182 183 Sequence< OUString > BasicProviderImpl::getSupportedServiceNames( ) 184 { 185 return getSupportedServiceNames_BasicProviderImpl(); 186 } 187 188 189 // XInitialization 190 191 192 void BasicProviderImpl::initialize( const Sequence< Any >& aArguments ) 193 { 194 // TODO 195 196 SolarMutexGuard aGuard; 197 198 if ( aArguments.getLength() != 1 ) 199 { 200 throw IllegalArgumentException( 201 "BasicProviderImpl::initialize: incorrect argument count.", 202 *this, 203 1 204 ); 205 } 206 207 Reference< frame::XModel > xModel; 208 209 m_xInvocationContext.set( aArguments[0], UNO_QUERY ); 210 if ( m_xInvocationContext.is() ) 211 { 212 xModel.set( m_xInvocationContext->getScriptContainer(), UNO_QUERY ); 213 if ( !xModel.is() ) 214 { 215 throw IllegalArgumentException( 216 "BasicProviderImpl::initialize: unable to determine the document model from the script invocation context.", 217 *this, 218 1 219 ); 220 } 221 } 222 else 223 { 224 if ( !( aArguments[0] >>= m_sScriptingContext ) ) 225 { 226 throw IllegalArgumentException( 227 "BasicProviderImpl::initialize: incorrect argument type " + aArguments[0].getValueTypeName(), 228 *this, 229 1 230 ); 231 } 232 233 OUString sDoc = "vnd.sun.star.tdoc"; 234 if ( m_sScriptingContext.startsWith( sDoc ) ) 235 { 236 xModel = MiscUtils::tDocUrlToModel( m_sScriptingContext ); 237 // TODO: use ScriptingContantsPool for SCRIPTING_DOC_REF 238 } 239 } 240 241 if ( xModel.is() ) 242 { 243 Reference< XEmbeddedScripts > xDocumentScripts( xModel, UNO_QUERY ); 244 if ( xDocumentScripts.is() ) 245 { 246 m_pDocBasicManager = ::basic::BasicManagerRepository::getDocumentBasicManager( xModel ); 247 m_xLibContainerDoc.set( xDocumentScripts->getBasicLibraries(), UNO_QUERY ); 248 OSL_ENSURE( m_pDocBasicManager && m_xLibContainerDoc.is(), 249 "BasicProviderImpl::initialize: invalid BasicManager, or invalid script container!" ); 250 } 251 m_bIsAppScriptCtx = false; 252 } 253 else 254 { 255 // Provider has been created with application context for user 256 // or share 257 if ( m_sScriptingContext != "user" ) 258 { 259 m_bIsUserCtx = false; 260 } 261 else 262 { 263 /* 264 throw RuntimeException( 265 "BasicProviderImpl::initialize: no scripting context!" ); 266 */ 267 } 268 } 269 270 // TODO 271 if ( !m_pAppBasicManager ) 272 { 273 m_pAppBasicManager = SfxApplication::GetBasicManager(); 274 if (m_pAppBasicManager) 275 StartListening(*m_pAppBasicManager); 276 } 277 278 if ( !m_xLibContainerApp.is() ) 279 m_xLibContainerApp.set( SfxGetpApp()->GetBasicContainer(), UNO_QUERY ); 280 } 281 282 283 // XScriptProvider 284 285 286 Reference < provider::XScript > BasicProviderImpl::getScript( const OUString& scriptURI ) 287 { 288 // TODO 289 290 SolarMutexGuard aGuard; 291 292 Reference< provider::XScript > xScript; 293 Reference< uri::XUriReferenceFactory > xFac ( uri::UriReferenceFactory::create( m_xContext ) ); 294 295 Reference< uri::XUriReference > uriRef( 296 xFac->parse( scriptURI ), UNO_QUERY ); 297 298 Reference < uri::XVndSunStarScriptUrl > sfUri( uriRef, UNO_QUERY ); 299 300 if ( !uriRef.is() || !sfUri.is() ) 301 { 302 throw provider::ScriptFrameworkErrorException( 303 "BasicProviderImpl::getScript: failed to parse URI: " + scriptURI, 304 Reference< XInterface >(), 305 scriptURI, "Basic", 306 provider::ScriptFrameworkErrorType::MALFORMED_URL ); 307 } 308 309 310 OUString aDescription = sfUri->getName(); 311 OUString aLocation = sfUri->getParameter( "location" ); 312 313 sal_Int32 nIndex = 0; 314 // In some strange circumstances the Library name can have an 315 // apparently illegal '.' in it ( in imported VBA ) 316 317 BasicManager* pBasicMgr = nullptr; 318 if ( aLocation == "document" ) 319 { 320 pBasicMgr = m_pDocBasicManager; 321 } 322 else if ( aLocation == "application" ) 323 { 324 pBasicMgr = m_pAppBasicManager; 325 } 326 OUString sProjectName; 327 if ( pBasicMgr ) 328 sProjectName = pBasicMgr->GetName(); 329 330 OUString aLibrary; 331 if ( !sProjectName.isEmpty() && aDescription.match( sProjectName ) ) 332 { 333 SAL_WARN("scripting", "LibraryName " << sProjectName << " is part of the url " << aDescription ); 334 aLibrary = sProjectName; 335 nIndex = sProjectName.getLength() + 1; 336 } 337 else 338 aLibrary = aDescription.getToken( 0, '.', nIndex ); 339 OUString aModule; 340 if ( nIndex != -1 ) 341 aModule = aDescription.getToken( 0, '.', nIndex ); 342 OUString aMethod; 343 if ( nIndex != -1 ) 344 aMethod = aDescription.getToken( 0, '.', nIndex ); 345 346 if ( !aLibrary.isEmpty() && !aModule.isEmpty() && !aMethod.isEmpty() && !aLocation.isEmpty() ) 347 { 348 349 if ( pBasicMgr ) 350 { 351 StarBASIC* pBasic = pBasicMgr->GetLib( aLibrary ); 352 if ( !pBasic ) 353 { 354 sal_uInt16 nId = pBasicMgr->GetLibId( aLibrary ); 355 if ( nId != LIB_NOTFOUND ) 356 { 357 pBasicMgr->LoadLib( nId ); 358 pBasic = pBasicMgr->GetLib( aLibrary ); 359 } 360 } 361 if ( pBasic ) 362 { 363 SbModule* pModule = pBasic->FindModule( aModule ); 364 if ( pModule ) 365 { 366 SbMethod* pMethod = pModule->FindMethod( aMethod, SbxClassType::Method ); 367 if ( pMethod && !pMethod->IsHidden() ) 368 { 369 if ( m_pDocBasicManager == pBasicMgr ) 370 xScript = new BasicScriptImpl( aDescription, pMethod, *m_pDocBasicManager, m_xInvocationContext ); 371 else 372 xScript = new BasicScriptImpl( aDescription, pMethod ); 373 } 374 } 375 } 376 } 377 } 378 379 if ( !xScript.is() ) 380 { 381 throw provider::ScriptFrameworkErrorException( 382 "The following Basic script could not be found:\n" 383 "library: '" + aLibrary + "'\n" 384 "module: '" + aModule + "'\n" 385 "method: '" + aMethod + "'\n" 386 "location: '" + aLocation + "'\n", 387 Reference< XInterface >(), 388 scriptURI, "Basic", 389 provider::ScriptFrameworkErrorType::NO_SUCH_SCRIPT ); 390 } 391 392 return xScript; 393 } 394 395 396 // XBrowseNode 397 398 399 OUString BasicProviderImpl::getName( ) 400 { 401 return OUString("Basic"); 402 } 403 404 405 Sequence< Reference< browse::XBrowseNode > > BasicProviderImpl::getChildNodes( ) 406 { 407 SolarMutexGuard aGuard; 408 409 Reference< script::XLibraryContainer > xLibContainer; 410 BasicManager* pBasicManager = nullptr; 411 412 if ( m_bIsAppScriptCtx ) 413 { 414 xLibContainer = m_xLibContainerApp; 415 pBasicManager = m_pAppBasicManager; 416 } 417 else 418 { 419 xLibContainer = m_xLibContainerDoc; 420 pBasicManager = m_pDocBasicManager; 421 } 422 423 Sequence< Reference< browse::XBrowseNode > > aChildNodes; 424 425 if ( pBasicManager && xLibContainer.is() ) 426 { 427 Sequence< OUString > aLibNames = xLibContainer->getElementNames(); 428 sal_Int32 nLibCount = aLibNames.getLength(); 429 const OUString* pLibNames = aLibNames.getConstArray(); 430 aChildNodes.realloc( nLibCount ); 431 Reference< browse::XBrowseNode >* pChildNodes = aChildNodes.getArray(); 432 sal_Int32 childrenFound = 0; 433 434 for ( sal_Int32 i = 0 ; i < nLibCount ; ++i ) 435 { 436 bool bCreate = false; 437 if ( m_bIsAppScriptCtx ) 438 { 439 const bool bShared = isLibraryShared( xLibContainer, pLibNames[i] ); 440 if (m_bIsUserCtx != bShared) 441 bCreate = true; 442 } 443 else 444 { 445 bCreate = true; 446 } 447 if ( bCreate ) 448 { 449 pChildNodes[childrenFound++] = static_cast< browse::XBrowseNode* >( new BasicLibraryNodeImpl( 450 m_xContext, m_sScriptingContext, pBasicManager, xLibContainer, pLibNames[i], m_bIsAppScriptCtx ) ); 451 } 452 } 453 454 if ( childrenFound != nLibCount ) 455 aChildNodes.realloc( childrenFound ); 456 } 457 458 return aChildNodes; 459 } 460 461 462 sal_Bool BasicProviderImpl::hasChildNodes( ) 463 { 464 SolarMutexGuard aGuard; 465 466 bool bReturn = false; 467 Reference< script::XLibraryContainer > xLibContainer; 468 if ( m_bIsAppScriptCtx ) 469 { 470 xLibContainer = m_xLibContainerApp; 471 } 472 else 473 { 474 xLibContainer = m_xLibContainerDoc; 475 } 476 if ( xLibContainer.is() ) 477 bReturn = xLibContainer->hasElements(); 478 479 return bReturn; 480 } 481 482 483 sal_Int16 BasicProviderImpl::getType( ) 484 { 485 return browse::BrowseNodeTypes::CONTAINER; 486 } 487 488 489 // component operations 490 491 492 static Reference< XInterface > create_BasicProviderImpl( 493 Reference< XComponentContext > const & xContext ) 494 { 495 return static_cast< lang::XTypeProvider * >( new BasicProviderImpl( xContext ) ); 496 } 497 498 499 static struct ::cppu::ImplementationEntry const s_component_entries [] = 500 { 501 { 502 create_BasicProviderImpl, getImplementationName_BasicProviderImpl, 503 getSupportedServiceNames_BasicProviderImpl, ::cppu::createSingleComponentFactory, 504 nullptr, 0 505 }, 506 { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } 507 }; 508 509 510 } // namespace basprov 511 512 513 // component exports 514 515 516 extern "C" 517 { 518 SAL_DLLPUBLIC_EXPORT void * basprov_component_getFactory( 519 const sal_Char * pImplName, void * pServiceManager, 520 void * pRegistryKey ) 521 { 522 return ::cppu::component_getFactoryHelper( 523 pImplName, pServiceManager, pRegistryKey, ::basprov::s_component_entries ); 524 } 525 } 526 527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 528
