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