| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_cppuhelper.hxx" |
| |
| #include "osl/diagnose.h" |
| #include "osl/file.hxx" |
| #include "osl/mutex.hxx" |
| #include "osl/module.hxx" |
| #include "rtl/unload.h" |
| #include "rtl/ustrbuf.hxx" |
| #include "uno/environment.h" |
| #include "uno/mapping.hxx" |
| #include "cppuhelper/factory.hxx" |
| #include "cppuhelper/shlib.hxx" |
| |
| #include "com/sun/star/beans/XPropertySet.hpp" |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| #include <stdio.h> |
| #endif |
| #include <vector> |
| |
| #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) |
| |
| |
| using namespace ::rtl; |
| using namespace ::osl; |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| |
| namespace cppu |
| { |
| |
| #if OSL_DEBUG_LEVEL > 1 |
| //------------------------------------------------------------------------------ |
| static inline void out( const char * p ) SAL_THROW( () ) |
| { |
| printf( p ); |
| } |
| static inline void out( const OUString & r ) throw () |
| { |
| OString s( OUStringToOString( r, RTL_TEXTENCODING_ASCII_US ) ); |
| out( s.getStr() ); |
| } |
| #endif |
| |
| //------------------------------------------------------------------------------ |
| static const ::std::vector< OUString > * getAccessDPath() SAL_THROW( () ) |
| { |
| static ::std::vector< OUString > * s_p = 0; |
| static bool s_bInit = false; |
| |
| if (! s_bInit) |
| { |
| ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); |
| if (! s_bInit) |
| { |
| const char * pEnv = ::getenv( "CPLD_ACCESSPATH" ); |
| if (pEnv) |
| { |
| static ::std::vector< OUString > s_v; |
| |
| OString aEnv( pEnv ); |
| sal_Int32 nIndex = 0; |
| do |
| { |
| OUString aStr( OStringToOUString( |
| aEnv.getToken( 0, ';', nIndex ), |
| RTL_TEXTENCODING_ASCII_US ) ); |
| OUString aFileUrl; |
| if (FileBase::getFileURLFromSystemPath(aStr, aFileUrl) |
| != FileBase::E_None) |
| { |
| OSL_ASSERT(false); |
| } |
| s_v.push_back( aFileUrl ); |
| } while( nIndex != -1 ); |
| #if OSL_DEBUG_LEVEL > 1 |
| out( "> cpld: acknowledged following access path(s): \"" ); |
| ::std::vector< OUString >::const_iterator iPos( s_v.begin() ); |
| while (iPos != s_v.end()) |
| { |
| out( *iPos ); |
| ++iPos; |
| if (iPos != s_v.end()) |
| out( ";" ); |
| } |
| out( "\"\n" ); |
| #endif |
| s_p = & s_v; |
| } |
| else |
| { |
| // no access path env set |
| #if OSL_DEBUG_LEVEL > 1 |
| out( "=> no CPLD_ACCESSPATH set.\n" ); |
| #endif |
| } |
| s_bInit = true; |
| } |
| } |
| |
| return s_p; |
| } |
| |
| //------------------------------------------------------------------------------ |
| static bool checkAccessPath( OUString * pComp ) throw () |
| { |
| const ::std::vector< OUString > * pPath = getAccessDPath(); |
| |
| if (pPath) |
| { |
| sal_Bool bAbsolute = (pComp->compareToAscii( "file://" , 7 ) == 0); |
| for ( ::std::vector< OUString >::const_iterator iPos( pPath->begin() ); |
| iPos != pPath->end(); ++iPos ) |
| { |
| OUString aBaseDir( *iPos ); |
| OUString aAbs; |
| |
| if ( bAbsolute ) |
| { |
| aAbs = *pComp; |
| #if OSL_DEBUG_LEVEL > 1 |
| out( "> taking path: \"" ); |
| out( aAbs ); |
| #endif |
| } |
| else |
| { |
| if (osl_File_E_None != |
| ::osl_getAbsoluteFileURL( |
| aBaseDir.pData, pComp->pData, &aAbs.pData )) |
| { |
| continue; |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| out( "> found path: \"" ); |
| out( aBaseDir ); |
| out( "\" + \"" ); |
| out( *pComp ); |
| out( "\" => \"" ); |
| out( aAbs ); |
| #endif |
| } |
| |
| if (0 == aAbs.indexOf( aBaseDir ) && // still part of it? |
| aBaseDir.getLength() < aAbs.getLength() && |
| (aBaseDir[ aBaseDir.getLength() -1 ] == (sal_Unicode)'/' || |
| // dir boundary |
| aAbs[ aBaseDir.getLength() ] == (sal_Unicode)'/')) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| out( ": ok.\n" ); |
| #endif |
| // load from absolute path |
| *pComp = aAbs; |
| return true; |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| else |
| { |
| out( "\" ...does not match given path \"" ); |
| out( aBaseDir ); |
| out( "\".\n" ); |
| } |
| #endif |
| } |
| return false; |
| } |
| else |
| { |
| // no access path env set |
| return true; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| static inline sal_Int32 endsWith( |
| const OUString & rText, const OUString & rEnd ) SAL_THROW( () ) |
| { |
| if (rText.getLength() >= rEnd.getLength() && |
| rEnd.equalsIgnoreAsciiCase( |
| rText.copy( rText.getLength() - rEnd.getLength() ) )) |
| { |
| return rText.getLength() - rEnd.getLength(); |
| } |
| return -1; |
| } |
| |
| //------------------------------------------------------------------------------ |
| static OUString makeComponentPath( |
| const OUString & rLibName, const OUString & rPath ) |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| // No system path allowed here ! |
| { |
| OUString aComp; |
| OSL_ASSERT( FileBase::E_None == |
| FileBase::getSystemPathFromFileURL( rLibName, aComp ) ); |
| OSL_ASSERT( |
| ! rPath.getLength() || |
| FileBase::E_None == |
| FileBase::getSystemPathFromFileURL( rPath, aComp ) ); |
| } |
| #endif |
| |
| OUStringBuffer buf( rPath.getLength() + rLibName.getLength() + 12 ); |
| |
| if (0 != rPath.getLength()) |
| { |
| buf.append( rPath ); |
| if (rPath[ rPath.getLength() -1 ] != '/') |
| buf.append( (sal_Unicode) '/' ); |
| } |
| sal_Int32 nEnd = endsWith( rLibName, OUSTR(SAL_DLLEXTENSION) ); |
| if (nEnd < 0) // !endsWith |
| { |
| #ifndef OS2 |
| //this is always triggered with .uno components |
| #if (OSL_DEBUG_LEVEL >= 2) |
| OSL_ENSURE( |
| !"### library name has no proper extension!", |
| OUStringToOString( rLibName, RTL_TEXTENCODING_ASCII_US ).getStr() ); |
| #endif |
| #endif // OS2 |
| |
| #if defined SAL_DLLPREFIX |
| nEnd = endsWith( rLibName, OUSTR(".uno") ); |
| if (nEnd < 0) // !endsWith |
| buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(SAL_DLLPREFIX) ); |
| #endif |
| buf.append( rLibName ); |
| buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(SAL_DLLEXTENSION) ); |
| } |
| else // name is completely pre/postfixed |
| { |
| buf.append( rLibName ); |
| } |
| |
| OUString out( buf.makeStringAndClear() ); |
| #if OSL_DEBUG_LEVEL > 1 |
| OString str( OUStringToOString( out, RTL_TEXTENCODING_ASCII_US ) ); |
| OSL_TRACE( "component path=%s\n", str.getStr() ); |
| #endif |
| |
| return out; |
| } |
| |
| //============================================================================== |
| static OUString getLibEnv(OUString const & aModulePath, |
| oslModule lib, |
| uno::Environment * pEnv, |
| OUString * pSourceEnv_name, |
| uno::Environment const & cTargetEnv, |
| OUString const & cImplName = OUString()) |
| { |
| OUString aExcMsg; |
| |
| sal_Char const * pEnvTypeName = NULL; |
| |
| OUString aGetEnvNameExt = OUSTR(COMPONENT_GETENVEXT); |
| component_getImplementationEnvironmentExtFunc pGetImplEnvExt = |
| (component_getImplementationEnvironmentExtFunc)osl_getFunctionSymbol(lib, aGetEnvNameExt.pData); |
| |
| if (pGetImplEnvExt) |
| { |
| OString implName(OUStringToOString(cImplName, RTL_TEXTENCODING_ASCII_US)); |
| pGetImplEnvExt(&pEnvTypeName, (uno_Environment **)pEnv, implName.getStr(), cTargetEnv.get()); |
| } |
| else |
| { |
| OUString aGetEnvName = OUSTR(COMPONENT_GETENV); |
| component_getImplementationEnvironmentFunc pGetImplEnv = |
| (component_getImplementationEnvironmentFunc)osl_getFunctionSymbol( |
| lib, aGetEnvName.pData ); |
| if (pGetImplEnv) |
| pGetImplEnv(&pEnvTypeName, (uno_Environment **)pEnv); |
| |
| else |
| { |
| aExcMsg = aModulePath; |
| aExcMsg += OUSTR(": cannot get symbol: "); |
| aExcMsg += aGetEnvName; |
| aExcMsg += OUSTR("- nor: "); |
| } |
| } |
| |
| if (!pEnv->is() && pEnvTypeName) |
| { |
| *pSourceEnv_name = OUString::createFromAscii(pEnvTypeName); |
| const char * pUNO_ENV_LOG = ::getenv( "UNO_ENV_LOG" ); |
| if (pUNO_ENV_LOG && rtl_str_getLength(pUNO_ENV_LOG) ) |
| { |
| OString implName(OUStringToOString(cImplName, RTL_TEXTENCODING_ASCII_US)); |
| OString aEnv( pUNO_ENV_LOG ); |
| sal_Int32 nIndex = 0; |
| do |
| { |
| const OString aStr( aEnv.getToken( 0, ';', nIndex ) ); |
| if ( aStr.equals(implName) ) |
| { |
| *pSourceEnv_name += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":log")); |
| break; |
| } |
| } while( nIndex != -1 ); |
| } |
| |
| } |
| |
| return aExcMsg; |
| } |
| |
| extern "C" {static void s_getFactory(va_list * pParam) |
| { |
| component_getFactoryFunc pSym = va_arg(*pParam, component_getFactoryFunc); |
| OString const * pImplName = va_arg(*pParam, OString const *); |
| void * pSMgr = va_arg(*pParam, void *); |
| void * pKey = va_arg(*pParam, void *); |
| void ** ppSSF = va_arg(*pParam, void **); |
| |
| *ppSSF = pSym(pImplName->getStr(), pSMgr, pKey); |
| }} |
| |
| Reference< XInterface > SAL_CALL loadSharedLibComponentFactory( |
| OUString const & rLibName, OUString const & rPath, |
| OUString const & rImplName, |
| Reference< lang::XMultiServiceFactory > const & xMgr, |
| Reference< registry::XRegistryKey > const & xKey ) |
| SAL_THROW( (loader::CannotActivateFactoryException) ) |
| { |
| OUString aModulePath( makeComponentPath( rLibName, rPath ) ); |
| if (! checkAccessPath( &aModulePath )) |
| { |
| throw loader::CannotActivateFactoryException( |
| OUSTR("permission denied to load component library: ") + |
| aModulePath, |
| Reference< XInterface >() ); |
| } |
| |
| oslModule lib = osl_loadModule( |
| aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL ); |
| if (! lib) |
| { |
| throw loader::CannotActivateFactoryException( |
| OUSTR("loading component library failed: ") + aModulePath, |
| Reference< XInterface >() ); |
| } |
| |
| Reference< XInterface > xRet; |
| |
| uno::Environment currentEnv(Environment::getCurrent()); |
| uno::Environment env; |
| |
| OUString aEnvTypeName; |
| |
| OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv, rImplName); |
| if (!aExcMsg.getLength()) |
| { |
| OUString aGetFactoryName = OUSTR(COMPONENT_GETFACTORY); |
| oslGenericFunction pSym = osl_getFunctionSymbol( lib, aGetFactoryName.pData ); |
| if (pSym != 0) |
| { |
| OString aImplName( |
| OUStringToOString( rImplName, RTL_TEXTENCODING_ASCII_US ) ); |
| |
| if (!env.is()) |
| env = uno::Environment(aEnvTypeName); |
| |
| if (env.is() && currentEnv.is()) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| { |
| rtl::OString libName(rtl::OUStringToOString(rLibName, RTL_TEXTENCODING_ASCII_US)); |
| rtl::OString implName(rtl::OUStringToOString(rImplName, RTL_TEXTENCODING_ASCII_US)); |
| rtl::OString envDcp(rtl::OUStringToOString(env.getTypeName(), RTL_TEXTENCODING_ASCII_US)); |
| |
| 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()); |
| } |
| #endif |
| |
| Mapping aCurrent2Env( currentEnv, env ); |
| Mapping aEnv2Current( env, currentEnv ); |
| |
| if (aCurrent2Env.is() && aEnv2Current.is()) |
| { |
| void * pSMgr = aCurrent2Env.mapInterface( |
| xMgr.get(), ::getCppuType( &xMgr ) ); |
| void * pKey = aCurrent2Env.mapInterface( |
| xKey.get(), ::getCppuType( &xKey ) ); |
| |
| void * pSSF = NULL; |
| |
| env.invoke(s_getFactory, pSym, &aImplName, pSMgr, pKey, &pSSF); |
| |
| if (pKey) |
| { |
| (env.get()->pExtEnv->releaseInterface)( |
| env.get()->pExtEnv, pKey ); |
| } |
| if (pSMgr) |
| { |
| (*env.get()->pExtEnv->releaseInterface)( |
| env.get()->pExtEnv, pSMgr ); |
| } |
| |
| if (pSSF) |
| { |
| aEnv2Current.mapInterface( |
| reinterpret_cast< void ** >( &xRet ), |
| pSSF, ::getCppuType( &xRet ) ); |
| (env.get()->pExtEnv->releaseInterface)( |
| env.get()->pExtEnv, pSSF ); |
| } |
| else |
| { |
| aExcMsg = aModulePath; |
| aExcMsg += OUSTR(": cannot get factory of " |
| "demanded implementation: "); |
| aExcMsg += OStringToOUString( |
| aImplName, RTL_TEXTENCODING_ASCII_US ); |
| } |
| } |
| else |
| { |
| aExcMsg = |
| OUSTR("cannot get uno mappings: C++ <=> UNO!"); |
| } |
| } |
| else |
| { |
| aExcMsg = OUSTR("cannot get uno environments!"); |
| } |
| } |
| else |
| { |
| aExcMsg = aModulePath; |
| aExcMsg += OUSTR(": cannot get symbol: "); |
| aExcMsg += aGetFactoryName; |
| } |
| } |
| |
| if (! xRet.is()) |
| { |
| osl_unloadModule( lib ); |
| #if OSL_DEBUG_LEVEL > 1 |
| out( "### cannot activate factory: " ); |
| out( aExcMsg ); |
| out( "\n" ); |
| #endif |
| throw loader::CannotActivateFactoryException( |
| aExcMsg, |
| Reference< XInterface >() ); |
| } |
| |
| rtl_registerModuleForUnloading( lib); |
| return xRet; |
| } |
| |
| //============================================================================== |
| extern "C" { static void s_writeInfo(va_list * pParam) |
| { |
| component_writeInfoFunc pSym = va_arg(*pParam, component_writeInfoFunc); |
| void * pSMgr = va_arg(*pParam, void *); |
| void * pKey = va_arg(*pParam, void *); |
| sal_Bool * pbRet = va_arg(*pParam, sal_Bool *); |
| |
| *pbRet = pSym(pSMgr, pKey); |
| |
| }} |
| |
| void SAL_CALL writeSharedLibComponentInfo( |
| OUString const & rLibName, OUString const & rPath, |
| Reference< lang::XMultiServiceFactory > const & xMgr, |
| Reference< registry::XRegistryKey > const & xKey ) |
| SAL_THROW( (registry::CannotRegisterImplementationException) ) |
| { |
| OUString aModulePath( makeComponentPath( rLibName, rPath ) ); |
| |
| if (! checkAccessPath( &aModulePath )) |
| { |
| throw registry::CannotRegisterImplementationException( |
| OUSTR("permission denied to load component library: ") + |
| aModulePath, |
| Reference< XInterface >() ); |
| } |
| |
| oslModule lib = osl_loadModule( |
| aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL ); |
| if (! lib) |
| { |
| throw registry::CannotRegisterImplementationException( |
| OUSTR("loading component library failed: ") + aModulePath, |
| Reference< XInterface >() ); |
| } |
| |
| sal_Bool bRet = sal_False; |
| |
| uno::Environment currentEnv(Environment::getCurrent()); |
| uno::Environment env; |
| |
| OUString aEnvTypeName; |
| OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv); |
| if (!aExcMsg.getLength()) |
| { |
| OUString aWriteInfoName = OUSTR(COMPONENT_WRITEINFO); |
| oslGenericFunction pSym = osl_getFunctionSymbol( lib, aWriteInfoName.pData ); |
| if (pSym != 0) |
| { |
| if (!env.is()) |
| env = uno::Environment(aEnvTypeName); |
| |
| if (env.is() && currentEnv.is()) |
| { |
| Mapping aCurrent2Env( currentEnv, env ); |
| if (aCurrent2Env.is()) |
| { |
| void * pSMgr = aCurrent2Env.mapInterface( |
| xMgr.get(), ::getCppuType( &xMgr ) ); |
| void * pKey = aCurrent2Env.mapInterface( |
| xKey.get(), ::getCppuType( &xKey ) ); |
| if (pKey) |
| { |
| env.invoke(s_writeInfo, pSym, pSMgr, pKey, &bRet); |
| |
| |
| (*env.get()->pExtEnv->releaseInterface)( |
| env.get()->pExtEnv, pKey ); |
| if (! bRet) |
| { |
| aExcMsg = aModulePath; |
| aExcMsg += OUSTR(": component_writeInfo() " |
| "returned false!"); |
| } |
| } |
| else |
| { |
| // key is mandatory |
| aExcMsg = aModulePath; |
| aExcMsg += OUSTR(": registry is mandatory to invoke" |
| " component_writeInfo()!"); |
| } |
| |
| if (pSMgr) |
| { |
| (*env.get()->pExtEnv->releaseInterface)( |
| env.get()->pExtEnv, pSMgr ); |
| } |
| } |
| else |
| { |
| aExcMsg = OUSTR("cannot get uno mapping: C++ <=> UNO!"); |
| } |
| } |
| else |
| { |
| aExcMsg = OUSTR("cannot get uno environments!"); |
| } |
| } |
| else |
| { |
| aExcMsg = aModulePath; |
| aExcMsg += OUSTR(": cannot get symbol: "); |
| aExcMsg += aWriteInfoName; |
| } |
| } |
| |
| //! |
| //! OK: please look at #88219# |
| //! |
| //! ::osl_unloadModule( lib); |
| if (! bRet) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| out( "### cannot write component info: " ); |
| out( aExcMsg ); |
| out( "\n" ); |
| #endif |
| throw registry::CannotRegisterImplementationException( |
| aExcMsg, Reference< XInterface >() ); |
| } |
| } |
| |
| } |