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 { 352 OUString aModulePath( makeComponentPath( rLibName, rPath ) ); 353 if (! checkAccessPath( &aModulePath )) 354 { 355 throw loader::CannotActivateFactoryException( 356 OUSTR("permission denied to load component library: ") + 357 aModulePath, 358 Reference< XInterface >() ); 359 } 360 361 oslModule lib = osl_loadModule( 362 aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL ); 363 if (! lib) 364 { 365 throw loader::CannotActivateFactoryException( 366 OUSTR("loading component library failed: ") + aModulePath, 367 Reference< XInterface >() ); 368 } 369 370 Reference< XInterface > xRet; 371 372 uno::Environment currentEnv(Environment::getCurrent()); 373 uno::Environment env; 374 375 OUString aEnvTypeName; 376 377 OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv, rImplName); 378 if (!aExcMsg.getLength()) 379 { 380 OUString aGetFactoryName = OUSTR(COMPONENT_GETFACTORY); 381 oslGenericFunction pSym = osl_getFunctionSymbol( lib, aGetFactoryName.pData ); 382 if (pSym != 0) 383 { 384 OString aImplName( 385 OUStringToOString( rImplName, RTL_TEXTENCODING_ASCII_US ) ); 386 387 if (!env.is()) 388 env = uno::Environment(aEnvTypeName); 389 390 if (env.is() && currentEnv.is()) 391 { 392 #if OSL_DEBUG_LEVEL > 1 393 { 394 rtl::OString libName(rtl::OUStringToOString(rLibName, RTL_TEXTENCODING_ASCII_US)); 395 rtl::OString implName(rtl::OUStringToOString(rImplName, RTL_TEXTENCODING_ASCII_US)); 396 rtl::OString envDcp(rtl::OUStringToOString(env.getTypeName(), RTL_TEXTENCODING_ASCII_US)); 397 398 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()); 399 } 400 #endif 401 402 Mapping aCurrent2Env( currentEnv, env ); 403 Mapping aEnv2Current( env, currentEnv ); 404 405 if (aCurrent2Env.is() && aEnv2Current.is()) 406 { 407 void * pSMgr = aCurrent2Env.mapInterface( 408 xMgr.get(), ::getCppuType( &xMgr ) ); 409 void * pKey = aCurrent2Env.mapInterface( 410 xKey.get(), ::getCppuType( &xKey ) ); 411 412 void * pSSF = NULL; 413 414 env.invoke(s_getFactory, pSym, &aImplName, pSMgr, pKey, &pSSF); 415 416 if (pKey) 417 { 418 (env.get()->pExtEnv->releaseInterface)( 419 env.get()->pExtEnv, pKey ); 420 } 421 if (pSMgr) 422 { 423 (*env.get()->pExtEnv->releaseInterface)( 424 env.get()->pExtEnv, pSMgr ); 425 } 426 427 if (pSSF) 428 { 429 aEnv2Current.mapInterface( 430 reinterpret_cast< void ** >( &xRet ), 431 pSSF, ::getCppuType( &xRet ) ); 432 (env.get()->pExtEnv->releaseInterface)( 433 env.get()->pExtEnv, pSSF ); 434 } 435 else 436 { 437 aExcMsg = aModulePath; 438 aExcMsg += OUSTR(": cannot get factory of " 439 "demanded implementation: "); 440 aExcMsg += OStringToOUString( 441 aImplName, RTL_TEXTENCODING_ASCII_US ); 442 } 443 } 444 else 445 { 446 aExcMsg = 447 OUSTR("cannot get uno mappings: C++ <=> UNO!"); 448 } 449 } 450 else 451 { 452 aExcMsg = OUSTR("cannot get uno environments!"); 453 } 454 } 455 else 456 { 457 aExcMsg = aModulePath; 458 aExcMsg += OUSTR(": cannot get symbol: "); 459 aExcMsg += aGetFactoryName; 460 } 461 } 462 463 if (! xRet.is()) 464 { 465 osl_unloadModule( lib ); 466 #if OSL_DEBUG_LEVEL > 1 467 out( "### cannot activate factory: " ); 468 out( aExcMsg ); 469 out( "\n" ); 470 #endif 471 throw loader::CannotActivateFactoryException( 472 aExcMsg, 473 Reference< XInterface >() ); 474 } 475 476 rtl_registerModuleForUnloading( lib); 477 return xRet; 478 } 479 480 //============================================================================== 481 extern "C" { static void s_writeInfo(va_list * pParam) 482 { 483 component_writeInfoFunc pSym = va_arg(*pParam, component_writeInfoFunc); 484 void * pSMgr = va_arg(*pParam, void *); 485 void * pKey = va_arg(*pParam, void *); 486 sal_Bool * pbRet = va_arg(*pParam, sal_Bool *); 487 488 *pbRet = pSym(pSMgr, pKey); 489 490 }} 491 492 void SAL_CALL writeSharedLibComponentInfo( 493 OUString const & rLibName, OUString const & rPath, 494 Reference< lang::XMultiServiceFactory > const & xMgr, 495 Reference< registry::XRegistryKey > const & xKey ) 496 { 497 OUString aModulePath( makeComponentPath( rLibName, rPath ) ); 498 499 if (! checkAccessPath( &aModulePath )) 500 { 501 throw registry::CannotRegisterImplementationException( 502 OUSTR("permission denied to load component library: ") + 503 aModulePath, 504 Reference< XInterface >() ); 505 } 506 507 oslModule lib = osl_loadModule( 508 aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL ); 509 if (! lib) 510 { 511 throw registry::CannotRegisterImplementationException( 512 OUSTR("loading component library failed: ") + aModulePath, 513 Reference< XInterface >() ); 514 } 515 516 sal_Bool bRet = sal_False; 517 518 uno::Environment currentEnv(Environment::getCurrent()); 519 uno::Environment env; 520 521 OUString aEnvTypeName; 522 OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv); 523 if (!aExcMsg.getLength()) 524 { 525 OUString aWriteInfoName = OUSTR(COMPONENT_WRITEINFO); 526 oslGenericFunction pSym = osl_getFunctionSymbol( lib, aWriteInfoName.pData ); 527 if (pSym != 0) 528 { 529 if (!env.is()) 530 env = uno::Environment(aEnvTypeName); 531 532 if (env.is() && currentEnv.is()) 533 { 534 Mapping aCurrent2Env( currentEnv, env ); 535 if (aCurrent2Env.is()) 536 { 537 void * pSMgr = aCurrent2Env.mapInterface( 538 xMgr.get(), ::getCppuType( &xMgr ) ); 539 void * pKey = aCurrent2Env.mapInterface( 540 xKey.get(), ::getCppuType( &xKey ) ); 541 if (pKey) 542 { 543 env.invoke(s_writeInfo, pSym, pSMgr, pKey, &bRet); 544 545 546 (*env.get()->pExtEnv->releaseInterface)( 547 env.get()->pExtEnv, pKey ); 548 if (! bRet) 549 { 550 aExcMsg = aModulePath; 551 aExcMsg += OUSTR(": component_writeInfo() " 552 "returned false!"); 553 } 554 } 555 else 556 { 557 // key is mandatory 558 aExcMsg = aModulePath; 559 aExcMsg += OUSTR(": registry is mandatory to invoke" 560 " component_writeInfo()!"); 561 } 562 563 if (pSMgr) 564 { 565 (*env.get()->pExtEnv->releaseInterface)( 566 env.get()->pExtEnv, pSMgr ); 567 } 568 } 569 else 570 { 571 aExcMsg = OUSTR("cannot get uno mapping: C++ <=> UNO!"); 572 } 573 } 574 else 575 { 576 aExcMsg = OUSTR("cannot get uno environments!"); 577 } 578 } 579 else 580 { 581 aExcMsg = aModulePath; 582 aExcMsg += OUSTR(": cannot get symbol: "); 583 aExcMsg += aWriteInfoName; 584 } 585 } 586 587 //! 588 //! OK: please look at #88219# 589 //! 590 //! ::osl_unloadModule( lib); 591 if (! bRet) 592 { 593 #if OSL_DEBUG_LEVEL > 1 594 out( "### cannot write component info: " ); 595 out( aExcMsg ); 596 out( "\n" ); 597 #endif 598 throw registry::CannotRegisterImplementationException( 599 aExcMsg, Reference< XInterface >() ); 600 } 601 } 602 603 } 604