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