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 {
352 OUString aModulePath( makeComponentPath( rLibName, rPath ) );
353 if (! checkAccessPath( &aModulePath ))
354 {
355 throw loader::CannotActivateFactoryException(
356 OUSTR("permission denied to load component library: ") +
357 aModulePath,
358 Reference< XInterface >() );
359 }
360
361 oslModule lib = osl_loadModule(
362 aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL );
363 if (! lib)
364 {
365 throw loader::CannotActivateFactoryException(
366 OUSTR("loading component library failed: ") + aModulePath,
367 Reference< XInterface >() );
368 }
369
370 Reference< XInterface > xRet;
371
372 uno::Environment currentEnv(Environment::getCurrent());
373 uno::Environment env;
374
375 OUString aEnvTypeName;
376
377 OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv, rImplName);
378 if (!aExcMsg.getLength())
379 {
380 OUString aGetFactoryName = OUSTR(COMPONENT_GETFACTORY);
381 oslGenericFunction pSym = osl_getFunctionSymbol( lib, aGetFactoryName.pData );
382 if (pSym != 0)
383 {
384 OString aImplName(
385 OUStringToOString( rImplName, RTL_TEXTENCODING_ASCII_US ) );
386
387 if (!env.is())
388 env = uno::Environment(aEnvTypeName);
389
390 if (env.is() && currentEnv.is())
391 {
392 #if OSL_DEBUG_LEVEL > 1
393 {
394 rtl::OString libName(rtl::OUStringToOString(rLibName, RTL_TEXTENCODING_ASCII_US));
395 rtl::OString implName(rtl::OUStringToOString(rImplName, RTL_TEXTENCODING_ASCII_US));
396 rtl::OString envDcp(rtl::OUStringToOString(env.getTypeName(), RTL_TEXTENCODING_ASCII_US));
397
398 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());
399 }
400 #endif
401
402 Mapping aCurrent2Env( currentEnv, env );
403 Mapping aEnv2Current( env, currentEnv );
404
405 if (aCurrent2Env.is() && aEnv2Current.is())
406 {
407 void * pSMgr = aCurrent2Env.mapInterface(
408 xMgr.get(), ::getCppuType( &xMgr ) );
409 void * pKey = aCurrent2Env.mapInterface(
410 xKey.get(), ::getCppuType( &xKey ) );
411
412 void * pSSF = NULL;
413
414 env.invoke(s_getFactory, pSym, &aImplName, pSMgr, pKey, &pSSF);
415
416 if (pKey)
417 {
418 (env.get()->pExtEnv->releaseInterface)(
419 env.get()->pExtEnv, pKey );
420 }
421 if (pSMgr)
422 {
423 (*env.get()->pExtEnv->releaseInterface)(
424 env.get()->pExtEnv, pSMgr );
425 }
426
427 if (pSSF)
428 {
429 aEnv2Current.mapInterface(
430 reinterpret_cast< void ** >( &xRet ),
431 pSSF, ::getCppuType( &xRet ) );
432 (env.get()->pExtEnv->releaseInterface)(
433 env.get()->pExtEnv, pSSF );
434 }
435 else
436 {
437 aExcMsg = aModulePath;
438 aExcMsg += OUSTR(": cannot get factory of "
439 "demanded implementation: ");
440 aExcMsg += OStringToOUString(
441 aImplName, RTL_TEXTENCODING_ASCII_US );
442 }
443 }
444 else
445 {
446 aExcMsg =
447 OUSTR("cannot get uno mappings: C++ <=> UNO!");
448 }
449 }
450 else
451 {
452 aExcMsg = OUSTR("cannot get uno environments!");
453 }
454 }
455 else
456 {
457 aExcMsg = aModulePath;
458 aExcMsg += OUSTR(": cannot get symbol: ");
459 aExcMsg += aGetFactoryName;
460 }
461 }
462
463 if (! xRet.is())
464 {
465 osl_unloadModule( lib );
466 #if OSL_DEBUG_LEVEL > 1
467 out( "### cannot activate factory: " );
468 out( aExcMsg );
469 out( "\n" );
470 #endif
471 throw loader::CannotActivateFactoryException(
472 aExcMsg,
473 Reference< XInterface >() );
474 }
475
476 rtl_registerModuleForUnloading( lib);
477 return xRet;
478 }
479
480 //==============================================================================
s_writeInfo(va_list * pParam)481 extern "C" { static void s_writeInfo(va_list * pParam)
482 {
483 component_writeInfoFunc pSym = va_arg(*pParam, component_writeInfoFunc);
484 void * pSMgr = va_arg(*pParam, void *);
485 void * pKey = va_arg(*pParam, void *);
486 sal_Bool * pbRet = va_arg(*pParam, sal_Bool *);
487
488 *pbRet = pSym(pSMgr, pKey);
489
490 }}
491
writeSharedLibComponentInfo(OUString const & rLibName,OUString const & rPath,Reference<lang::XMultiServiceFactory> const & xMgr,Reference<registry::XRegistryKey> const & xKey)492 void SAL_CALL writeSharedLibComponentInfo(
493 OUString const & rLibName, OUString const & rPath,
494 Reference< lang::XMultiServiceFactory > const & xMgr,
495 Reference< registry::XRegistryKey > const & xKey )
496 {
497 OUString aModulePath( makeComponentPath( rLibName, rPath ) );
498
499 if (! checkAccessPath( &aModulePath ))
500 {
501 throw registry::CannotRegisterImplementationException(
502 OUSTR("permission denied to load component library: ") +
503 aModulePath,
504 Reference< XInterface >() );
505 }
506
507 oslModule lib = osl_loadModule(
508 aModulePath.pData, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL );
509 if (! lib)
510 {
511 throw registry::CannotRegisterImplementationException(
512 OUSTR("loading component library failed: ") + aModulePath,
513 Reference< XInterface >() );
514 }
515
516 sal_Bool bRet = sal_False;
517
518 uno::Environment currentEnv(Environment::getCurrent());
519 uno::Environment env;
520
521 OUString aEnvTypeName;
522 OUString aExcMsg = getLibEnv(aModulePath, lib, &env, &aEnvTypeName, currentEnv);
523 if (!aExcMsg.getLength())
524 {
525 OUString aWriteInfoName = OUSTR(COMPONENT_WRITEINFO);
526 oslGenericFunction pSym = osl_getFunctionSymbol( lib, aWriteInfoName.pData );
527 if (pSym != 0)
528 {
529 if (!env.is())
530 env = uno::Environment(aEnvTypeName);
531
532 if (env.is() && currentEnv.is())
533 {
534 Mapping aCurrent2Env( currentEnv, env );
535 if (aCurrent2Env.is())
536 {
537 void * pSMgr = aCurrent2Env.mapInterface(
538 xMgr.get(), ::getCppuType( &xMgr ) );
539 void * pKey = aCurrent2Env.mapInterface(
540 xKey.get(), ::getCppuType( &xKey ) );
541 if (pKey)
542 {
543 env.invoke(s_writeInfo, pSym, pSMgr, pKey, &bRet);
544
545
546 (*env.get()->pExtEnv->releaseInterface)(
547 env.get()->pExtEnv, pKey );
548 if (! bRet)
549 {
550 aExcMsg = aModulePath;
551 aExcMsg += OUSTR(": component_writeInfo() "
552 "returned false!");
553 }
554 }
555 else
556 {
557 // key is mandatory
558 aExcMsg = aModulePath;
559 aExcMsg += OUSTR(": registry is mandatory to invoke"
560 " component_writeInfo()!");
561 }
562
563 if (pSMgr)
564 {
565 (*env.get()->pExtEnv->releaseInterface)(
566 env.get()->pExtEnv, pSMgr );
567 }
568 }
569 else
570 {
571 aExcMsg = OUSTR("cannot get uno mapping: C++ <=> UNO!");
572 }
573 }
574 else
575 {
576 aExcMsg = OUSTR("cannot get uno environments!");
577 }
578 }
579 else
580 {
581 aExcMsg = aModulePath;
582 aExcMsg += OUSTR(": cannot get symbol: ");
583 aExcMsg += aWriteInfoName;
584 }
585 }
586
587 //!
588 //! OK: please look at #88219#
589 //!
590 //! ::osl_unloadModule( lib);
591 if (! bRet)
592 {
593 #if OSL_DEBUG_LEVEL > 1
594 out( "### cannot write component info: " );
595 out( aExcMsg );
596 out( "\n" );
597 #endif
598 throw registry::CannotRegisterImplementationException(
599 aExcMsg, Reference< XInterface >() );
600 }
601 }
602
603 }
604