xref: /trunk/main/cppuhelper/source/shlib.cxx (revision cdf0e10c)
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