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 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_cppuhelper.hxx" 26 27 #include "osl/diagnose.h" 28 #include "osl/file.hxx" 29 #include "osl/mutex.hxx" 30 #include "osl/module.hxx" 31 #include "rtl/unload.h" 32 #include "rtl/ustrbuf.hxx" 33 #include "uno/environment.h" 34 #include "uno/mapping.hxx" 35 #include "cppuhelper/factory.hxx" 36 #include "cppuhelper/shlib.hxx" 37 38 #include "com/sun/star/beans/XPropertySet.hpp" 39 40 #if OSL_DEBUG_LEVEL > 1 41 #include <stdio.h> 42 #endif 43 #include <vector> 44 45 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) 46 47 48 using namespace ::rtl; 49 using namespace ::osl; 50 using namespace ::com::sun::star; 51 using namespace ::com::sun::star::uno; 52 53 namespace cppu 54 { 55 56 #if OSL_DEBUG_LEVEL > 1 57 //------------------------------------------------------------------------------ 58 static inline void out( const char * p ) SAL_THROW( () ) 59 { 60 printf( p ); 61 } 62 static inline void out( const OUString & r ) throw () 63 { 64 OString s( OUStringToOString( r, RTL_TEXTENCODING_ASCII_US ) ); 65 out( s.getStr() ); 66 } 67 #endif 68 69 //------------------------------------------------------------------------------ 70 static const ::std::vector< OUString > * getAccessDPath() SAL_THROW( () ) 71 { 72 static ::std::vector< OUString > * s_p = 0; 73 static bool s_bInit = false; 74 75 if (! s_bInit) 76 { 77 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); 78 if (! s_bInit) 79 { 80 const char * pEnv = ::getenv( "CPLD_ACCESSPATH" ); 81 if (pEnv) 82 { 83 static ::std::vector< OUString > s_v; 84 85 OString aEnv( pEnv ); 86 sal_Int32 nIndex = 0; 87 do 88 { 89 OUString aStr( OStringToOUString( 90 aEnv.getToken( 0, ';', nIndex ), 91 RTL_TEXTENCODING_ASCII_US ) ); 92 OUString aFileUrl; 93 if (FileBase::getFileURLFromSystemPath(aStr, aFileUrl) 94 != FileBase::E_None) 95 { 96 OSL_ASSERT(false); 97 } 98 s_v.push_back( aFileUrl ); 99 } while( nIndex != -1 ); 100 #if OSL_DEBUG_LEVEL > 1 101 out( "> cpld: acknowledged following access path(s): \"" ); 102 ::std::vector< OUString >::const_iterator iPos( s_v.begin() ); 103 while (iPos != s_v.end()) 104 { 105 out( *iPos ); 106 ++iPos; 107 if (iPos != s_v.end()) 108 out( ";" ); 109 } 110 out( "\"\n" ); 111 #endif 112 s_p = & s_v; 113 } 114 else 115 { 116 // no access path env set 117 #if OSL_DEBUG_LEVEL > 1 118 out( "=> no CPLD_ACCESSPATH set.\n" ); 119 #endif 120 } 121 s_bInit = true; 122 } 123 } 124 125 return s_p; 126 } 127 128 //------------------------------------------------------------------------------ 129 static bool checkAccessPath( OUString * pComp ) throw () 130 { 131 const ::std::vector< OUString > * pPath = getAccessDPath(); 132 133 if (pPath) 134 { 135 sal_Bool bAbsolute = (pComp->compareToAscii( "file://" , 7 ) == 0); 136 for ( ::std::vector< OUString >::const_iterator iPos( pPath->begin() ); 137 iPos != pPath->end(); ++iPos ) 138 { 139 OUString aBaseDir( *iPos ); 140 OUString aAbs; 141 142 if ( bAbsolute ) 143 { 144 aAbs = *pComp; 145 #if OSL_DEBUG_LEVEL > 1 146 out( "> taking path: \"" ); 147 out( aAbs ); 148 #endif 149 } 150 else 151 { 152 if (osl_File_E_None != 153 ::osl_getAbsoluteFileURL( 154 aBaseDir.pData, pComp->pData, &aAbs.pData )) 155 { 156 continue; 157 } 158 #if OSL_DEBUG_LEVEL > 1 159 out( "> found path: \"" ); 160 out( aBaseDir ); 161 out( "\" + \"" ); 162 out( *pComp ); 163 out( "\" => \"" ); 164 out( aAbs ); 165 #endif 166 } 167 168 if (0 == aAbs.indexOf( aBaseDir ) && // still part of it? 169 aBaseDir.getLength() < aAbs.getLength() && 170 (aBaseDir[ aBaseDir.getLength() -1 ] == (sal_Unicode)'/' || 171 // dir boundary 172 aAbs[ aBaseDir.getLength() ] == (sal_Unicode)'/')) 173 { 174 #if OSL_DEBUG_LEVEL > 1 175 out( ": ok.\n" ); 176 #endif 177 // load from absolute path 178 *pComp = aAbs; 179 return true; 180 } 181 #if OSL_DEBUG_LEVEL > 1 182 else 183 { 184 out( "\" ...does not match given path \"" ); 185 out( aBaseDir ); 186 out( "\".\n" ); 187 } 188 #endif 189 } 190 return false; 191 } 192 else 193 { 194 // no access path env set 195 return true; 196 } 197 } 198 199 //------------------------------------------------------------------------------ 200 static inline sal_Int32 endsWith( 201 const OUString & rText, const OUString & rEnd ) SAL_THROW( () ) 202 { 203 if (rText.getLength() >= rEnd.getLength() && 204 rEnd.equalsIgnoreAsciiCase( 205 rText.copy( rText.getLength() - rEnd.getLength() ) )) 206 { 207 return rText.getLength() - rEnd.getLength(); 208 } 209 return -1; 210 } 211 212 //------------------------------------------------------------------------------ 213 static OUString makeComponentPath( 214 const OUString & rLibName, const OUString & rPath ) 215 { 216 #if OSL_DEBUG_LEVEL > 0 217 // No system path allowed here ! 218 { 219 OUString aComp; 220 OSL_ASSERT( FileBase::E_None == 221 FileBase::getSystemPathFromFileURL( rLibName, aComp ) ); 222 OSL_ASSERT( 223 ! rPath.getLength() || 224 FileBase::E_None == 225 FileBase::getSystemPathFromFileURL( rPath, aComp ) ); 226 } 227 #endif 228 229 OUStringBuffer buf( rPath.getLength() + rLibName.getLength() + 12 ); 230 231 if (0 != rPath.getLength()) 232 { 233 buf.append( rPath ); 234 if (rPath[ rPath.getLength() -1 ] != '/') 235 buf.append( (sal_Unicode) '/' ); 236 } 237 sal_Int32 nEnd = endsWith( rLibName, OUSTR(SAL_DLLEXTENSION) ); 238 if (nEnd < 0) // !endsWith 239 { 240 #ifndef OS2 241 //this is always triggered with .uno components 242 #if (OSL_DEBUG_LEVEL >= 2) 243 OSL_ENSURE( 244 !"### library name has no proper extension!", 245 OUStringToOString( rLibName, RTL_TEXTENCODING_ASCII_US ).getStr() ); 246 #endif 247 #endif // OS2 248 249 #if defined SAL_DLLPREFIX 250 nEnd = endsWith( rLibName, OUSTR(".uno") ); 251 if (nEnd < 0) // !endsWith 252 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(SAL_DLLPREFIX) ); 253 #endif 254 buf.append( rLibName ); 255 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(SAL_DLLEXTENSION) ); 256 } 257 else // name is completely pre/postfixed 258 { 259 buf.append( rLibName ); 260 } 261 262 OUString out( buf.makeStringAndClear() ); 263 #if OSL_DEBUG_LEVEL > 1 264 OString str( OUStringToOString( out, RTL_TEXTENCODING_ASCII_US ) ); 265 OSL_TRACE( "component path=%s\n", str.getStr() ); 266 #endif 267 268 return out; 269 } 270 271 //============================================================================== 272 static OUString getLibEnv(OUString const & aModulePath, 273 oslModule lib, 274 uno::Environment * pEnv, 275 OUString * pSourceEnv_name, 276 uno::Environment const & cTargetEnv, 277 OUString const & cImplName = OUString()) 278 { 279 OUString aExcMsg; 280 281 sal_Char const * pEnvTypeName = NULL; 282 283 OUString aGetEnvNameExt = OUSTR(COMPONENT_GETENVEXT); 284 component_getImplementationEnvironmentExtFunc pGetImplEnvExt = 285 (component_getImplementationEnvironmentExtFunc)osl_getFunctionSymbol(lib, aGetEnvNameExt.pData); 286 287 if (pGetImplEnvExt) 288 { 289 OString implName(OUStringToOString(cImplName, RTL_TEXTENCODING_ASCII_US)); 290 pGetImplEnvExt(&pEnvTypeName, (uno_Environment **)pEnv, implName.getStr(), cTargetEnv.get()); 291 } 292 else 293 { 294 OUString aGetEnvName = OUSTR(COMPONENT_GETENV); 295 component_getImplementationEnvironmentFunc pGetImplEnv = 296 (component_getImplementationEnvironmentFunc)osl_getFunctionSymbol( 297 lib, aGetEnvName.pData ); 298 if (pGetImplEnv) 299 pGetImplEnv(&pEnvTypeName, (uno_Environment **)pEnv); 300 301 else 302 { 303 aExcMsg = aModulePath; 304 aExcMsg += OUSTR(": cannot get symbol: "); 305 aExcMsg += aGetEnvName; 306 aExcMsg += OUSTR("- nor: "); 307 } 308 } 309 310 if (!pEnv->is() && pEnvTypeName) 311 { 312 *pSourceEnv_name = OUString::createFromAscii(pEnvTypeName); 313 const char * pUNO_ENV_LOG = ::getenv( "UNO_ENV_LOG" ); 314 if (pUNO_ENV_LOG && rtl_str_getLength(pUNO_ENV_LOG) ) 315 { 316 OString implName(OUStringToOString(cImplName, RTL_TEXTENCODING_ASCII_US)); 317 OString aEnv( pUNO_ENV_LOG ); 318 sal_Int32 nIndex = 0; 319 do 320 { 321 const OString aStr( aEnv.getToken( 0, ';', nIndex ) ); 322 if ( aStr.equals(implName) ) 323 { 324 *pSourceEnv_name += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":log")); 325 break; 326 } 327 } while( nIndex != -1 ); 328 } 329 330 } 331 332 return aExcMsg; 333 } 334 335 extern "C" {static void s_getFactory(va_list * pParam) 336 { 337 component_getFactoryFunc pSym = va_arg(*pParam, component_getFactoryFunc); 338 OString const * pImplName = va_arg(*pParam, OString const *); 339 void * pSMgr = va_arg(*pParam, void *); 340 void * pKey = va_arg(*pParam, void *); 341 void ** ppSSF = va_arg(*pParam, void **); 342 343 *ppSSF = pSym(pImplName->getStr(), pSMgr, pKey); 344 }} 345 346 Reference< XInterface > SAL_CALL loadSharedLibComponentFactory( 347 OUString const & rLibName, OUString const & rPath, 348 OUString const & rImplName, 349 Reference< lang::XMultiServiceFactory > const & xMgr, 350 Reference< registry::XRegistryKey > const & xKey ) 351 SAL_THROW( (loader::CannotActivateFactoryException) ) 352 { 353 OUString aModulePath( makeComponentPath( rLibName, rPath ) ); 354 if (! checkAccessPath( &aModulePath )) 355 { 356 throw loader::CannotActivateFactoryException( 357 OUSTR("permission denied to load component library: ") + 358 aModulePath, 359 Reference< XInterface >() ); 360 } 361 362 oslModule lib = osl_loadModule( 363 aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL ); 364 if (! lib) 365 { 366 throw loader::CannotActivateFactoryException( 367 OUSTR("loading component library failed: ") + aModulePath, 368 Reference< XInterface >() ); 369 } 370 371 Reference< XInterface > xRet; 372 373 uno::Environment currentEnv(Environment::getCurrent()); 374 uno::Environment env; 375 376 OUString aEnvTypeName; 377 378 OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv, rImplName); 379 if (!aExcMsg.getLength()) 380 { 381 OUString aGetFactoryName = OUSTR(COMPONENT_GETFACTORY); 382 oslGenericFunction pSym = osl_getFunctionSymbol( lib, aGetFactoryName.pData ); 383 if (pSym != 0) 384 { 385 OString aImplName( 386 OUStringToOString( rImplName, RTL_TEXTENCODING_ASCII_US ) ); 387 388 if (!env.is()) 389 env = uno::Environment(aEnvTypeName); 390 391 if (env.is() && currentEnv.is()) 392 { 393 #if OSL_DEBUG_LEVEL > 1 394 { 395 rtl::OString libName(rtl::OUStringToOString(rLibName, RTL_TEXTENCODING_ASCII_US)); 396 rtl::OString implName(rtl::OUStringToOString(rImplName, RTL_TEXTENCODING_ASCII_US)); 397 rtl::OString envDcp(rtl::OUStringToOString(env.getTypeName(), RTL_TEXTENCODING_ASCII_US)); 398 399 fprintf(stderr, "loadSharedLibComponentFactory envDcp: %-12.12s implName: %30.30s libName: %-15.15s\n", envDcp.getStr(), implName.getStr() + (implName.getLength() > 30 ? implName.getLength() - 30 : 0), libName.getStr()); 400 } 401 #endif 402 403 Mapping aCurrent2Env( currentEnv, env ); 404 Mapping aEnv2Current( env, currentEnv ); 405 406 if (aCurrent2Env.is() && aEnv2Current.is()) 407 { 408 void * pSMgr = aCurrent2Env.mapInterface( 409 xMgr.get(), ::getCppuType( &xMgr ) ); 410 void * pKey = aCurrent2Env.mapInterface( 411 xKey.get(), ::getCppuType( &xKey ) ); 412 413 void * pSSF = NULL; 414 415 env.invoke(s_getFactory, pSym, &aImplName, pSMgr, pKey, &pSSF); 416 417 if (pKey) 418 { 419 (env.get()->pExtEnv->releaseInterface)( 420 env.get()->pExtEnv, pKey ); 421 } 422 if (pSMgr) 423 { 424 (*env.get()->pExtEnv->releaseInterface)( 425 env.get()->pExtEnv, pSMgr ); 426 } 427 428 if (pSSF) 429 { 430 aEnv2Current.mapInterface( 431 reinterpret_cast< void ** >( &xRet ), 432 pSSF, ::getCppuType( &xRet ) ); 433 (env.get()->pExtEnv->releaseInterface)( 434 env.get()->pExtEnv, pSSF ); 435 } 436 else 437 { 438 aExcMsg = aModulePath; 439 aExcMsg += OUSTR(": cannot get factory of " 440 "demanded implementation: "); 441 aExcMsg += OStringToOUString( 442 aImplName, RTL_TEXTENCODING_ASCII_US ); 443 } 444 } 445 else 446 { 447 aExcMsg = 448 OUSTR("cannot get uno mappings: C++ <=> UNO!"); 449 } 450 } 451 else 452 { 453 aExcMsg = OUSTR("cannot get uno environments!"); 454 } 455 } 456 else 457 { 458 aExcMsg = aModulePath; 459 aExcMsg += OUSTR(": cannot get symbol: "); 460 aExcMsg += aGetFactoryName; 461 } 462 } 463 464 if (! xRet.is()) 465 { 466 osl_unloadModule( lib ); 467 #if OSL_DEBUG_LEVEL > 1 468 out( "### cannot activate factory: " ); 469 out( aExcMsg ); 470 out( "\n" ); 471 #endif 472 throw loader::CannotActivateFactoryException( 473 aExcMsg, 474 Reference< XInterface >() ); 475 } 476 477 rtl_registerModuleForUnloading( lib); 478 return xRet; 479 } 480 481 //============================================================================== 482 extern "C" { static void s_writeInfo(va_list * pParam) 483 { 484 component_writeInfoFunc pSym = va_arg(*pParam, component_writeInfoFunc); 485 void * pSMgr = va_arg(*pParam, void *); 486 void * pKey = va_arg(*pParam, void *); 487 sal_Bool * pbRet = va_arg(*pParam, sal_Bool *); 488 489 *pbRet = pSym(pSMgr, pKey); 490 491 }} 492 493 void SAL_CALL writeSharedLibComponentInfo( 494 OUString const & rLibName, OUString const & rPath, 495 Reference< lang::XMultiServiceFactory > const & xMgr, 496 Reference< registry::XRegistryKey > const & xKey ) 497 SAL_THROW( (registry::CannotRegisterImplementationException) ) 498 { 499 OUString aModulePath( makeComponentPath( rLibName, rPath ) ); 500 501 if (! checkAccessPath( &aModulePath )) 502 { 503 throw registry::CannotRegisterImplementationException( 504 OUSTR("permission denied to load component library: ") + 505 aModulePath, 506 Reference< XInterface >() ); 507 } 508 509 oslModule lib = osl_loadModule( 510 aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL ); 511 if (! lib) 512 { 513 throw registry::CannotRegisterImplementationException( 514 OUSTR("loading component library failed: ") + aModulePath, 515 Reference< XInterface >() ); 516 } 517 518 sal_Bool bRet = sal_False; 519 520 uno::Environment currentEnv(Environment::getCurrent()); 521 uno::Environment env; 522 523 OUString aEnvTypeName; 524 OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv); 525 if (!aExcMsg.getLength()) 526 { 527 OUString aWriteInfoName = OUSTR(COMPONENT_WRITEINFO); 528 oslGenericFunction pSym = osl_getFunctionSymbol( lib, aWriteInfoName.pData ); 529 if (pSym != 0) 530 { 531 if (!env.is()) 532 env = uno::Environment(aEnvTypeName); 533 534 if (env.is() && currentEnv.is()) 535 { 536 Mapping aCurrent2Env( currentEnv, env ); 537 if (aCurrent2Env.is()) 538 { 539 void * pSMgr = aCurrent2Env.mapInterface( 540 xMgr.get(), ::getCppuType( &xMgr ) ); 541 void * pKey = aCurrent2Env.mapInterface( 542 xKey.get(), ::getCppuType( &xKey ) ); 543 if (pKey) 544 { 545 env.invoke(s_writeInfo, pSym, pSMgr, pKey, &bRet); 546 547 548 (*env.get()->pExtEnv->releaseInterface)( 549 env.get()->pExtEnv, pKey ); 550 if (! bRet) 551 { 552 aExcMsg = aModulePath; 553 aExcMsg += OUSTR(": component_writeInfo() " 554 "returned false!"); 555 } 556 } 557 else 558 { 559 // key is mandatory 560 aExcMsg = aModulePath; 561 aExcMsg += OUSTR(": registry is mandatory to invoke" 562 " component_writeInfo()!"); 563 } 564 565 if (pSMgr) 566 { 567 (*env.get()->pExtEnv->releaseInterface)( 568 env.get()->pExtEnv, pSMgr ); 569 } 570 } 571 else 572 { 573 aExcMsg = OUSTR("cannot get uno mapping: C++ <=> UNO!"); 574 } 575 } 576 else 577 { 578 aExcMsg = OUSTR("cannot get uno environments!"); 579 } 580 } 581 else 582 { 583 aExcMsg = aModulePath; 584 aExcMsg += OUSTR(": cannot get symbol: "); 585 aExcMsg += aWriteInfoName; 586 } 587 } 588 589 //! 590 //! OK: please look at #88219# 591 //! 592 //! ::osl_unloadModule( lib); 593 if (! bRet) 594 { 595 #if OSL_DEBUG_LEVEL > 1 596 out( "### cannot write component info: " ); 597 out( aExcMsg ); 598 out( "\n" ); 599 #endif 600 throw registry::CannotRegisterImplementationException( 601 aExcMsg, Reference< XInterface >() ); 602 } 603 } 604 605 } 606