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