1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: shlib.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_cppuhelper.hxx"
34 #include "osl/diagnose.h"
35 #include "osl/file.hxx"
36 #include "osl/mutex.hxx"
37 #include "osl/module.hxx"
38 #include "rtl/unload.h"
39 #include "rtl/ustrbuf.hxx"
40 #include "uno/environment.h"
41 #include "uno/mapping.hxx"
42 #include "cppuhelper/factory.hxx"
43 #include "cppuhelper/shlib.hxx"
44 #include "cppuhelper/bootstrap.hxx"
45 #include <com/sun/star/lang/IllegalArgumentException.hpp>
47 #include "com/sun/star/beans/XPropertySet.hpp"
49 #if OSL_DEBUG_LEVEL > 1
54 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
57 using namespace ::rtl
;
58 using namespace ::osl
;
59 using namespace ::com::sun::star
;
60 using namespace ::com::sun::star::uno
;
65 #if OSL_DEBUG_LEVEL > 1
66 //------------------------------------------------------------------------------
67 static inline void out( const char * p
) SAL_THROW( () )
71 static inline void out( const OUString
& r
) throw ()
73 OString
s( OUStringToOString( r
, RTL_TEXTENCODING_ASCII_US
) );
78 //------------------------------------------------------------------------------
79 static const ::std::vector
< OUString
> * getAccessDPath() SAL_THROW( () )
81 static ::std::vector
< OUString
> * s_p
= 0;
82 static bool s_bInit
= false;
86 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
89 const char * pEnv
= ::getenv( "CPLD_ACCESSPATH" );
92 static ::std::vector
< OUString
> s_v
;
98 OUString
aStr( OStringToOUString(
99 aEnv
.getToken( 0, ';', nIndex
),
100 RTL_TEXTENCODING_ASCII_US
) );
102 if (FileBase::getFileURLFromSystemPath(aStr
, aFileUrl
)
107 s_v
.push_back( aFileUrl
);
108 } while( nIndex
!= -1 );
109 #if OSL_DEBUG_LEVEL > 1
110 out( "> cpld: acknowledged following access path(s): \"" );
111 ::std::vector
< OUString
>::const_iterator
iPos( s_v
.begin() );
112 while (iPos
!= s_v
.end())
116 if (iPos
!= s_v
.end())
125 // no access path env set
126 #if OSL_DEBUG_LEVEL > 1
127 out( "=> no CPLD_ACCESSPATH set.\n" );
137 //------------------------------------------------------------------------------
138 static bool checkAccessPath( OUString
* pComp
) throw ()
140 const ::std::vector
< OUString
> * pPath
= getAccessDPath();
144 sal_Bool bAbsolute
= (pComp
->compareToAscii( "file://" , 7 ) == 0);
145 for ( ::std::vector
< OUString
>::const_iterator
iPos( pPath
->begin() );
146 iPos
!= pPath
->end(); ++iPos
)
148 OUString
aBaseDir( *iPos
);
154 #if OSL_DEBUG_LEVEL > 1
155 out( "> taking path: \"" );
161 if (osl_File_E_None
!=
162 ::osl_getAbsoluteFileURL(
163 aBaseDir
.pData
, pComp
->pData
, &aAbs
.pData
))
167 #if OSL_DEBUG_LEVEL > 1
168 out( "> found path: \"" );
177 if (0 == aAbs
.indexOf( aBaseDir
) && // still part of it?
178 aBaseDir
.getLength() < aAbs
.getLength() &&
179 (aBaseDir
[ aBaseDir
.getLength() -1 ] == (sal_Unicode
)'/' ||
181 aAbs
[ aBaseDir
.getLength() ] == (sal_Unicode
)'/'))
183 #if OSL_DEBUG_LEVEL > 1
186 // load from absolute path
190 #if OSL_DEBUG_LEVEL > 1
193 out( "\" ...does not match given path \"" );
203 // no access path env set
208 //------------------------------------------------------------------------------
209 static inline sal_Int32
endsWith(
210 const OUString
& rText
, const OUString
& rEnd
) SAL_THROW( () )
212 if (rText
.getLength() >= rEnd
.getLength() &&
213 rEnd
.equalsIgnoreAsciiCase(
214 rText
.copy( rText
.getLength() - rEnd
.getLength() ) ))
216 return rText
.getLength() - rEnd
.getLength();
221 //------------------------------------------------------------------------------
222 static OUString
makeComponentPath(
223 const OUString
& rLibName
, const OUString
& rPath
)
225 #if OSL_DEBUG_LEVEL > 0
226 // No system path allowed here !
229 OSL_ASSERT( FileBase::E_None
==
230 FileBase::getSystemPathFromFileURL( rLibName
, aComp
) );
232 ! rPath
.getLength() ||
234 FileBase::getSystemPathFromFileURL( rPath
, aComp
) );
238 OUStringBuffer
buf( rPath
.getLength() + rLibName
.getLength() + 12 );
240 if (0 != rPath
.getLength())
243 if (rPath
[ rPath
.getLength() -1 ] != '/')
244 buf
.append( (sal_Unicode
) '/' );
246 sal_Int32 nEnd
= endsWith( rLibName
, OUSTR(SAL_DLLEXTENSION
) );
247 if (nEnd
< 0) // !endsWith
250 //this is always triggered with .uno components
251 #if (OSL_DEBUG_LEVEL >= 2)
253 !"### library name has no proper extension!",
254 OUStringToOString( rLibName
, RTL_TEXTENCODING_ASCII_US
).getStr() );
258 #if defined SAL_DLLPREFIX
259 nEnd
= endsWith( rLibName
, OUSTR(".uno") );
260 if (nEnd
< 0) // !endsWith
261 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(SAL_DLLPREFIX
) );
263 buf
.append( rLibName
);
264 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(SAL_DLLEXTENSION
) );
266 else // name is completely pre/postfixed
268 buf
.append( rLibName
);
271 OUString
out( buf
.makeStringAndClear() );
272 #if OSL_DEBUG_LEVEL > 1
273 OString
str( OUStringToOString( out
, RTL_TEXTENCODING_ASCII_US
) );
274 OSL_TRACE( "component path=%s\n", str
.getStr() );
282 // This is a temporary hack until we can add this per
283 // shlib annotation to services.rdb.
286 lcl_isWellKnownInternal(const OString
&rLibName
)
288 // These are loaded at startup ...
289 static const char *pLookup
[] = {
292 "deploymentli.uno.so",
296 "introspection.uno.so",
301 "libfilterconfig1.so",
303 "liblocaledata_en.so",
304 "liblocaledata_es.so",
305 "liblocaledata_euro.so",
306 "liblocaledata_others.so",
316 "regtypeprov.uno.so",
319 "shlibloader.uno.so",
324 "stocservices.uno.so",
327 "typeconverter.uno.so",
333 // Perhaps do some cunning binary search ?
334 for (int i
= 0; pLookup
[i
] != NULL
; i
++) {
335 bool match
= rLibName
.indexOf (pLookup
[i
]) > 0;
336 // fprintf (stderr, "Match '%s' vs. '%s' : %d\n",
337 // (const sal_Char *)rLibName, pLookup[i], match);
346 OUString
const & get_this_libpath();
348 // Amusing hack to get 40% win on linking / startup speedup:
349 // Rational: we load all of OO.o's exception symbols in a single, global
350 // shlib once first of all (RTLD_GLOBAL). This allows us to load all
351 // subsequent components RTLD_LOCAL, their vague linkage symbols will
352 // resolve in the global scope.
354 lcl_isInternalLibrary(OUString
const & rLibName
, OUString
const & rPath
)
356 if (getenv ("OOO_DISABLE_INTERNAL"))
359 // fprintf (stderr, "Lib path '%s' ",
360 // (const sal_Char *)rtl::OUStringToOString(rPath, RTL_TEXTENCODING_ASCII_US));
361 // fprintf (stderr, "name '%s' - test:\n",
362 // (const sal_Char *)rtl::OUStringToOString(rLibName, RTL_TEXTENCODING_ASCII_US));
364 bool bIsInternal
= false;
366 // Is this an internal library ?
367 if (rPath
.getLength() > 0 && rPath
!= get_this_libpath())
369 // fprintf (stderr, "Lib path '%s' - not internal!\n",
370 // (const sal_Char *)rtl::OUStringToOString(rPath, RTL_TEXTENCODING_ASCII_US));
374 sal_Int32 nUpd
= SUPD
;
375 OUString aIntSuffix
= OUSTR("li.so");
376 if (rLibName
.indexOf (aIntSuffix
) > 0)
380 bIsInternal
= lcl_isWellKnownInternal(
381 OUStringToOString(rLibName
, RTL_TEXTENCODING_UTF8
));
383 // If internal - load the exception type library RTLD_GLOBAL first
384 static bool bHaveLoadedExcepts
= false;
385 if (bIsInternal
&& !bHaveLoadedExcepts
)
387 rtl::OUString aExceptTmpl
= rtl::OUString::createFromAscii("vnd.sun.star.expand:$OOO_BASE_DIR/program/libexlink") + aIntSuffix
;
388 rtl::OUString aExceptName
;
391 aExceptName
= cppu::bootstrap_expandUri( aExceptTmpl
);
393 catch ( ::com::sun::star::lang::IllegalArgumentException
& e
) {}
394 oslModule nExceptLib
= osl_loadModule(aExceptName
.pData
,
395 SAL_LOADMODULE_LAZY
| SAL_LOADMODULE_GLOBAL
);
396 if (nExceptLib
!= NULL
) {
397 bHaveLoadedExcepts
= true;
398 // fprintf (stderr, "Loaded'%s'\n",
399 // (const sal_Char *)rtl::OUStringToOString(aExceptName, RTL_TEXTENCODING_ASCII_US));
402 // fprintf (stderr, "Failed to load'%s'\n",
403 // (const sal_Char *)rtl::OUStringToOString(aExceptName, RTL_TEXTENCODING_ASCII_US));
407 // fprintf (stderr, "Lib name '%s' %d %d\n",
408 // (const sal_Char *)rtl::OUStringToOString(rLibName, RTL_TEXTENCODING_ASCII_US),
409 // bIsInternal, bHaveLoadedExcepts);
415 //==============================================================================
416 static OUString
getLibEnv(OUString
const & aModulePath
,
418 uno::Environment
* pEnv
,
419 OUString
* pSourceEnv_name
,
420 uno::Environment
const & cTargetEnv
,
421 OUString
const & cImplName
= OUString())
425 sal_Char
const * pEnvTypeName
= NULL
;
427 OUString aGetEnvNameExt
= OUSTR(COMPONENT_GETENVEXT
);
428 component_getImplementationEnvironmentExtFunc pGetImplEnvExt
=
429 (component_getImplementationEnvironmentExtFunc
)osl_getFunctionSymbol(lib
, aGetEnvNameExt
.pData
);
433 OString
implName(OUStringToOString(cImplName
, RTL_TEXTENCODING_ASCII_US
));
434 pGetImplEnvExt(&pEnvTypeName
, (uno_Environment
**)pEnv
, implName
.getStr(), cTargetEnv
.get());
438 OUString aGetEnvName
= OUSTR(COMPONENT_GETENV
);
439 component_getImplementationEnvironmentFunc pGetImplEnv
=
440 (component_getImplementationEnvironmentFunc
)osl_getFunctionSymbol(
441 lib
, aGetEnvName
.pData
);
443 pGetImplEnv(&pEnvTypeName
, (uno_Environment
**)pEnv
);
447 aExcMsg
= aModulePath
;
448 aExcMsg
+= OUSTR(": cannot get symbol: ");
449 aExcMsg
+= aGetEnvName
;
450 aExcMsg
+= OUSTR("- nor: ");
454 if (!pEnv
->is() && pEnvTypeName
)
456 *pSourceEnv_name
= OUString::createFromAscii(pEnvTypeName
);
457 const char * pUNO_ENV_LOG
= ::getenv( "UNO_ENV_LOG" );
458 if (pUNO_ENV_LOG
&& rtl_str_getLength(pUNO_ENV_LOG
) )
460 OString
implName(OUStringToOString(cImplName
, RTL_TEXTENCODING_ASCII_US
));
461 OString
aEnv( pUNO_ENV_LOG
);
462 sal_Int32 nIndex
= 0;
465 const OString
aStr( aEnv
.getToken( 0, ';', nIndex
) );
466 if ( aStr
.equals(implName
) )
468 *pSourceEnv_name
+= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":log"));
471 } while( nIndex
!= -1 );
479 extern "C" {static void s_getFactory(va_list * pParam
)
481 component_getFactoryFunc pSym
= va_arg(*pParam
, component_getFactoryFunc
);
482 OString
const * pImplName
= va_arg(*pParam
, OString
const *);
483 void * pSMgr
= va_arg(*pParam
, void *);
484 void * pKey
= va_arg(*pParam
, void *);
485 void ** ppSSF
= va_arg(*pParam
, void **);
487 *ppSSF
= pSym(pImplName
->getStr(), pSMgr
, pKey
);
490 Reference
< XInterface
> SAL_CALL
loadSharedLibComponentFactory(
491 OUString
const & rLibName
, OUString
const & rPath
,
492 OUString
const & rImplName
,
493 Reference
< lang::XMultiServiceFactory
> const & xMgr
,
494 Reference
< registry::XRegistryKey
> const & xKey
)
495 SAL_THROW( (loader::CannotActivateFactoryException
) )
497 OUString
aModulePath( makeComponentPath( rLibName
, rPath
) );
498 if (! checkAccessPath( &aModulePath
))
500 throw loader::CannotActivateFactoryException(
501 OUSTR("permission denied to load component library: ") +
503 Reference
< XInterface
>() );
506 sal_Int32 nFlags
= SAL_LOADMODULE_LAZY
;
508 if (!lcl_isInternalLibrary (rLibName
, rPath
))
509 nFlags
|= SAL_LOADMODULE_GLOBAL
;
510 // else - faster local only binding
512 nFlags
|= SAL_LOADMODULE_GLOBAL
;
515 oslModule lib
= osl_loadModule(aModulePath
.pData
, nFlags
);
518 throw loader::CannotActivateFactoryException(
519 OUSTR("loading component library failed: ") + aModulePath
,
520 Reference
< XInterface
>() );
523 Reference
< XInterface
> xRet
;
525 uno::Environment
currentEnv(Environment::getCurrent());
526 uno::Environment env
;
528 OUString aEnvTypeName
;
530 OUString aExcMsg
= getLibEnv(aModulePath
, lib
, &env
, &aEnvTypeName
, currentEnv
, rImplName
);
531 if (!aExcMsg
.getLength())
533 OUString aGetFactoryName
= OUSTR(COMPONENT_GETFACTORY
);
534 oslGenericFunction pSym
= osl_getFunctionSymbol( lib
, aGetFactoryName
.pData
);
538 OUStringToOString( rImplName
, RTL_TEXTENCODING_ASCII_US
) );
541 env
= uno::Environment(aEnvTypeName
);
543 if (env
.is() && currentEnv
.is())
545 #if OSL_DEBUG_LEVEL > 1
547 rtl::OString
libName(rtl::OUStringToOString(rLibName
, RTL_TEXTENCODING_ASCII_US
));
548 rtl::OString
implName(rtl::OUStringToOString(rImplName
, RTL_TEXTENCODING_ASCII_US
));
549 rtl::OString
envDcp(rtl::OUStringToOString(env
.getTypeName(), RTL_TEXTENCODING_ASCII_US
));
551 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());
555 Mapping
aCurrent2Env( currentEnv
, env
);
556 Mapping
aEnv2Current( env
, currentEnv
);
558 if (aCurrent2Env
.is() && aEnv2Current
.is())
560 void * pSMgr
= aCurrent2Env
.mapInterface(
561 xMgr
.get(), ::getCppuType( &xMgr
) );
562 void * pKey
= aCurrent2Env
.mapInterface(
563 xKey
.get(), ::getCppuType( &xKey
) );
567 env
.invoke(s_getFactory
, pSym
, &aImplName
, pSMgr
, pKey
, &pSSF
);
571 (env
.get()->pExtEnv
->releaseInterface
)(
572 env
.get()->pExtEnv
, pKey
);
576 (*env
.get()->pExtEnv
->releaseInterface
)(
577 env
.get()->pExtEnv
, pSMgr
);
582 aEnv2Current
.mapInterface(
583 reinterpret_cast< void ** >( &xRet
),
584 pSSF
, ::getCppuType( &xRet
) );
585 (env
.get()->pExtEnv
->releaseInterface
)(
586 env
.get()->pExtEnv
, pSSF
);
590 aExcMsg
= aModulePath
;
591 aExcMsg
+= OUSTR(": cannot get factory of "
592 "demanded implementation: ");
593 aExcMsg
+= OStringToOUString(
594 aImplName
, RTL_TEXTENCODING_ASCII_US
);
600 OUSTR("cannot get uno mappings: C++ <=> UNO!");
605 aExcMsg
= OUSTR("cannot get uno environments!");
610 aExcMsg
= aModulePath
;
611 aExcMsg
+= OUSTR(": cannot get symbol: ");
612 aExcMsg
+= aGetFactoryName
;
618 osl_unloadModule( lib
);
619 #if OSL_DEBUG_LEVEL > 1
620 out( "### cannot activate factory: " );
624 throw loader::CannotActivateFactoryException(
626 Reference
< XInterface
>() );
629 rtl_registerModuleForUnloading( lib
);
633 //==============================================================================
634 extern "C" { static void s_writeInfo(va_list * pParam
)
636 component_writeInfoFunc pSym
= va_arg(*pParam
, component_writeInfoFunc
);
637 void * pSMgr
= va_arg(*pParam
, void *);
638 void * pKey
= va_arg(*pParam
, void *);
639 sal_Bool
* pbRet
= va_arg(*pParam
, sal_Bool
*);
641 *pbRet
= pSym(pSMgr
, pKey
);
645 void SAL_CALL
writeSharedLibComponentInfo(
646 OUString
const & rLibName
, OUString
const & rPath
,
647 Reference
< lang::XMultiServiceFactory
> const & xMgr
,
648 Reference
< registry::XRegistryKey
> const & xKey
)
649 SAL_THROW( (registry::CannotRegisterImplementationException
) )
651 OUString
aModulePath( makeComponentPath( rLibName
, rPath
) );
653 if (! checkAccessPath( &aModulePath
))
655 throw registry::CannotRegisterImplementationException(
656 OUSTR("permission denied to load component library: ") +
658 Reference
< XInterface
>() );
661 oslModule lib
= osl_loadModule(
662 aModulePath
.pData
, SAL_LOADMODULE_LAZY
| SAL_LOADMODULE_GLOBAL
);
665 throw registry::CannotRegisterImplementationException(
666 OUSTR("loading component library failed: ") + aModulePath
,
667 Reference
< XInterface
>() );
670 sal_Bool bRet
= sal_False
;
672 uno::Environment
currentEnv(Environment::getCurrent());
673 uno::Environment env
;
675 OUString aEnvTypeName
;
676 OUString aExcMsg
= getLibEnv(aModulePath
, lib
, &env
, &aEnvTypeName
, currentEnv
);
677 if (!aExcMsg
.getLength())
679 OUString aWriteInfoName
= OUSTR(COMPONENT_WRITEINFO
);
680 oslGenericFunction pSym
= osl_getFunctionSymbol( lib
, aWriteInfoName
.pData
);
684 env
= uno::Environment(aEnvTypeName
);
686 if (env
.is() && currentEnv
.is())
688 Mapping
aCurrent2Env( currentEnv
, env
);
689 if (aCurrent2Env
.is())
691 void * pSMgr
= aCurrent2Env
.mapInterface(
692 xMgr
.get(), ::getCppuType( &xMgr
) );
693 void * pKey
= aCurrent2Env
.mapInterface(
694 xKey
.get(), ::getCppuType( &xKey
) );
697 env
.invoke(s_writeInfo
, pSym
, pSMgr
, pKey
, &bRet
);
700 (*env
.get()->pExtEnv
->releaseInterface
)(
701 env
.get()->pExtEnv
, pKey
);
704 aExcMsg
= aModulePath
;
705 aExcMsg
+= OUSTR(": component_writeInfo() "
712 aExcMsg
= aModulePath
;
713 aExcMsg
+= OUSTR(": registry is mandatory to invoke"
714 " component_writeInfo()!");
719 (*env
.get()->pExtEnv
->releaseInterface
)(
720 env
.get()->pExtEnv
, pSMgr
);
725 aExcMsg
= OUSTR("cannot get uno mapping: C++ <=> UNO!");
730 aExcMsg
= OUSTR("cannot get uno environments!");
735 aExcMsg
= aModulePath
;
736 aExcMsg
+= OUSTR(": cannot get symbol: ");
737 aExcMsg
+= aWriteInfoName
;
742 //! OK: please look at #88219#
744 //! ::osl_unloadModule( lib);
747 #if OSL_DEBUG_LEVEL > 1
748 out( "### cannot write component info: " );
752 throw registry::CannotRegisterImplementationException(
753 aExcMsg
, Reference
< XInterface
>() );