1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
25 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
26 #include <com/sun/star/registry/CannotRegisterImplementationException.hpp>
27 #include <cppuhelper/factory.hxx>
28 #include <cppuhelper/shlib.hxx>
29 #include <osl/module.hxx>
30 #include <sal/log.hxx>
31 #include <uno/environment.hxx>
32 #include <uno/mapping.hxx>
34 #include "loadsharedlibcomponentfactory.hxx"
36 #if defined DISABLE_DYNLOADING
37 #include <osl/detail/component-mapping.h>
40 css::uno::Environment
cppuhelper::detail::getEnvironment(
41 rtl::OUString
const & name
, rtl::OUString
const & implementation
)
43 rtl::OUString
n(name
);
44 if (!implementation
.isEmpty()) {
45 static char const * log
= std::getenv("UNO_ENV_LOG");
46 if (log
!= nullptr && *log
!= 0) {
47 rtl::OString
imps(log
);
48 for (sal_Int32 i
= 0; i
!= -1;) {
49 rtl::OString
imp(imps
.getToken(0, ';', i
));
50 //TODO: this assumes UNO_ENV_LOG only contains ASCII characters:
51 if (implementation
.equalsAsciiL(imp
.getStr(), imp
.getLength()))
59 return css::uno::Environment(n
);
64 #if !defined DISABLE_DYNLOADING
66 css::uno::Environment
getEnvironmentFromModule(
67 osl::Module
const & module
, css::uno::Environment
const & target
,
68 rtl::OUString
const & implementation
, rtl::OUString
const & prefix
)
70 char const * name
= nullptr;
71 css::uno::Environment env
;
72 rtl::OUString
fullPrefix(prefix
);
73 if (!fullPrefix
.isEmpty()) {
76 component_getImplementationEnvironmentExtFunc fp1
77 = reinterpret_cast<component_getImplementationEnvironmentExtFunc
>(
78 module
.getFunctionSymbol(fullPrefix
+ COMPONENT_GETENVEXT
));
81 &name
, reinterpret_cast<uno_Environment
**>(&env
),
82 (rtl::OUStringToOString(implementation
, RTL_TEXTENCODING_ASCII_US
)
86 component_getImplementationEnvironmentFunc fp2
87 = reinterpret_cast<component_getImplementationEnvironmentFunc
>(
88 module
.getFunctionSymbol(fullPrefix
+ COMPONENT_GETENV
));
90 (*fp2
)(&name
, reinterpret_cast<uno_Environment
**>(&env
));
92 name
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
; //TODO: fail
95 if (!env
.is() && name
!= nullptr) {
96 env
= cppuhelper::detail::getEnvironment(
97 rtl::OUString::createFromAscii(name
), implementation
);
104 extern "C" void getFactory(va_list * args
) {
105 component_getFactoryFunc fn
= va_arg(*args
, component_getFactoryFunc
);
106 rtl::OString
const * implementation
= va_arg(*args
, rtl::OString
const *);
107 void * smgr
= va_arg(*args
, void *);
108 void ** factory
= va_arg(*args
, void **);
109 *factory
= (*fn
)(implementation
->getStr(), smgr
, nullptr);
112 css::uno::Reference
<css::uno::XInterface
> invokeComponentFactory(
113 css::uno::Environment
const & source
, css::uno::Environment
const & target
,
114 component_getFactoryFunc function
, rtl::OUString
const & uri
,
115 rtl::OUString
const & implementation
,
116 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & serviceManager
)
118 if (!(source
.is() && target
.is())) {
119 throw css::loader::CannotActivateFactoryException(
120 "cannot get environments",
121 css::uno::Reference
<css::uno::XInterface
>());
124 rtl::OUStringToOString(implementation
, RTL_TEXTENCODING_ASCII_US
));
125 if (source
.get() == target
.get()) {
126 return css::uno::Reference
<css::uno::XInterface
>(
127 static_cast<css::uno::XInterface
*>(
128 (*function
)(impl
.getStr(), serviceManager
.get(), nullptr)),
131 css::uno::Mapping
mapTo(source
, target
);
132 css::uno::Mapping
mapFrom(target
, source
);
133 if (!(mapTo
.is() && mapFrom
.is())) {
134 throw css::loader::CannotActivateFactoryException(
135 "cannot get mappings",
136 css::uno::Reference
<css::uno::XInterface
>());
138 void * smgr
= mapTo
.mapInterface(
139 serviceManager
.get(),
140 cppu::UnoType
<css::lang::XMultiServiceFactory
>::get());
141 void * factory
= nullptr;
142 target
.invoke(getFactory
, function
, &impl
, smgr
, &factory
);
143 if (smgr
!= nullptr) {
144 (*target
.get()->pExtEnv
->releaseInterface
)(
145 target
.get()->pExtEnv
, smgr
);
147 if (factory
== nullptr) {
148 throw css::loader::CannotActivateFactoryException(
149 ("calling factory function for \"" + implementation
+ "\" in <"
150 + uri
+ "> returned null"),
151 css::uno::Reference
<css::uno::XInterface
>());
153 css::uno::Reference
<css::uno::XInterface
> res
;
154 mapFrom
.mapInterface(
155 reinterpret_cast<void **>(&res
), factory
,
156 cppu::UnoType
<css::uno::XInterface
>::get());
157 (*target
.get()->pExtEnv
->releaseInterface
)(
158 target
.get()->pExtEnv
, factory
);
162 #if !defined DISABLE_DYNLOADING
164 extern "C" void getInstance(va_list * args
) {
165 cppuhelper::ImplementationConstructorFn
* fn
= va_arg(*args
, cppuhelper::ImplementationConstructorFn
*);
166 void * ctxt
= va_arg(*args
, void *);
168 void * argseq
= va_arg(*args
, void *);
170 void ** instance
= va_arg(*args
, void **);
172 assert(*instance
== nullptr);
173 *instance
= (*fn
)(static_cast<css::uno::XComponentContext
*>(ctxt
),
174 *static_cast<css::uno::Sequence
<css::uno::Any
> const*>(argseq
));
177 cppuhelper::WrapperConstructorFn
mapConstructorFn(
178 css::uno::Environment
const & source
, css::uno::Environment
const & target
,
179 cppuhelper::ImplementationConstructorFn
*const constructorFunction
)
181 if (!(source
.is() && target
.is())) {
182 throw css::loader::CannotActivateFactoryException(
183 "cannot get environments",
184 css::uno::Reference
<css::uno::XInterface
>());
186 if (source
.get() == target
.get()) {
187 return cppuhelper::WrapperConstructorFn(constructorFunction
);
189 // note: it should be valid to capture these mappings because they are
190 // ref-counted, and the returned closure will always be invoked in the
191 // "source" environment
192 css::uno::Mapping
mapTo(source
, target
);
193 css::uno::Mapping
mapFrom(target
, source
);
194 if (!(mapTo
.is() && mapFrom
.is())) {
195 throw css::loader::CannotActivateFactoryException(
196 "cannot get mappings",
197 css::uno::Reference
<css::uno::XInterface
>());
199 return [mapFrom
, mapTo
, target
, constructorFunction
]
200 (css::uno::XComponentContext
*const context
, css::uno::Sequence
<css::uno::Any
> const& args
)
202 void *const ctxt
= mapTo
.mapInterface(
204 cppu::UnoType
<css::uno::XComponentContext
>::get());
205 if (args
.getLength() > 0) {
206 std::abort(); // TODO map args
208 void * instance
= nullptr;
209 target
.invoke(getInstance
, constructorFunction
, ctxt
, &args
, &instance
);
210 if (ctxt
!= nullptr) {
211 (*target
.get()->pExtEnv
->releaseInterface
)(
212 target
.get()->pExtEnv
, ctxt
);
214 css::uno::XInterface
* res
= nullptr;
215 if (instance
== nullptr) {
218 mapFrom
.mapInterface(
219 reinterpret_cast<void **>(&res
), instance
,
220 cppu::UnoType
<css::uno::XInterface
>::get());
221 (*target
.get()->pExtEnv
->releaseInterface
)(
222 target
.get()->pExtEnv
, instance
);
231 void cppuhelper::detail::loadSharedLibComponentFactory(
232 rtl::OUString
const & uri
, rtl::OUString
const & environment
,
233 rtl::OUString
const & prefix
, rtl::OUString
const & implementation
,
234 rtl::OUString
const & constructor
,
235 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & serviceManager
,
236 WrapperConstructorFn
* constructorFunction
,
237 css::uno::Reference
<css::uno::XInterface
> * factory
)
239 assert(constructor
.isEmpty() || !environment
.isEmpty());
241 (constructorFunction
== nullptr && constructor
.isEmpty())
242 || !*constructorFunction
);
243 assert(factory
!= nullptr && !factory
->is());
244 #if defined DISABLE_DYNLOADING
245 assert(!environment
.isEmpty());
246 if (constructor
.isEmpty()) {
247 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
248 css::uno::Environment
env(getEnvironment(environment
, implementation
));
249 if (!(curEnv
.is() && env
.is())) {
250 throw css::loader::CannotActivateFactoryException(
251 "cannot get environments",
252 css::uno::Reference
<css::uno::XInterface
>());
254 if (curEnv
.get() != env
.get()) {
257 rtl::OUString
name(prefix
== "direct" ? implementation
: uri
);
258 SAL_INFO("cppuhelper.shlib", "prefix=" << prefix
<< " implementation=" << implementation
<< " uri=" << uri
);
259 lib_to_factory_mapping
const * map
= lo_get_factory_map();
260 component_getFactoryFunc fp
= 0;
261 for (int i
= 0; map
[i
].name
!= 0; ++i
) {
262 if (name
.equalsAscii(map
[i
].name
)) {
263 fp
= map
[i
].component_getFactory_function
;
268 SAL_WARN("cppuhelper", "unknown factory name \"" << name
<< "\"");
269 throw css::loader::CannotActivateFactoryException(
270 "unknown factory name \"" + name
+ "\"",
271 css::uno::Reference
<css::uno::XInterface
>());
273 *factory
= invokeComponentFactory(
274 css::uno::Environment::getCurrent(),
275 getEnvironment(environment
, implementation
), fp
, uri
,
276 implementation
, serviceManager
);
278 SAL_INFO("cppuhelper.shlib", "constructor=" << constructor
);
279 lib_to_constructor_mapping
const * map
= lo_get_constructor_map();
280 for (int i
= 0; map
[i
].name
!= 0; ++i
) {
281 if (constructor
.equalsAscii(map
[i
].name
)) {
283 = reinterpret_cast<ImplementationConstructorFn
*>(
284 map
[i
].constructor_function
);
288 SAL_WARN("cppuhelper", "unknown constructor name \"" << constructor
<< "\"");
289 throw css::loader::CannotActivateFactoryException(
290 "unknown constructor name \"" + constructor
+ "\"",
291 css::uno::Reference
<css::uno::XInterface
>());
294 osl::Module
mod(uri
, SAL_LOADMODULE_LAZY
| SAL_LOADMODULE_GLOBAL
);
296 throw css::loader::CannotActivateFactoryException(
297 "loading component library <" + uri
+ "> failed",
298 css::uno::Reference
<css::uno::XInterface
>());
300 if (constructor
.isEmpty()) {
302 SAL_INFO("cppuhelper.shlib", "prefix=" << prefix
<< " implementation=" << implementation
<< " uri=" << uri
);
303 if (prefix
== "direct") {
304 sym
= implementation
.replace('.', '_') + "_" COMPONENT_GETFACTORY
;
305 } else if (!prefix
.isEmpty()) {
306 sym
= prefix
+ "_" COMPONENT_GETFACTORY
;
308 sym
= COMPONENT_GETFACTORY
;
310 oslGenericFunction fp
= mod
.getFunctionSymbol(sym
);
312 throw css::loader::CannotActivateFactoryException(
313 ("no factory symbol \"" + sym
+ "\" in component library <"
315 css::uno::Reference
<css::uno::XInterface
>());
317 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
318 *factory
= invokeComponentFactory(
320 (environment
.isEmpty()
321 ? getEnvironmentFromModule(mod
, curEnv
, implementation
, prefix
)
322 : getEnvironment(environment
, implementation
)),
323 reinterpret_cast<component_getFactoryFunc
>(fp
), uri
, implementation
,
326 SAL_INFO("cppuhelper.shlib", "constructor=" << constructor
);
327 oslGenericFunction fp
= mod
.getFunctionSymbol(constructor
);
329 throw css::loader::CannotActivateFactoryException(
330 ("no constructor symbol \"" + constructor
331 + "\" in component library <" + uri
+ ">"),
332 css::uno::Reference
<css::uno::XInterface
>());
334 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
335 *constructorFunction
= mapConstructorFn(
337 (environment
.isEmpty()
338 ? getEnvironmentFromModule(mod
, curEnv
, implementation
, prefix
)
339 : getEnvironment(environment
, implementation
)),
340 reinterpret_cast<ImplementationConstructorFn
*>(fp
));
346 css::uno::Reference
<css::uno::XInterface
> cppu::loadSharedLibComponentFactory(
347 rtl::OUString
const & uri
, rtl::OUString
const & rPath
,
348 rtl::OUString
const & rImplName
,
349 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & xMgr
,
350 css::uno::Reference
<css::registry::XRegistryKey
> const & xKey
)
352 assert(rPath
.isEmpty()); (void) rPath
;
353 assert(!xKey
.is()); (void) xKey
;
354 css::uno::Reference
<css::uno::XInterface
> fac
;
355 cppuhelper::detail::loadSharedLibComponentFactory(
356 uri
, "", "", rImplName
, "", xMgr
, nullptr, &fac
);
360 #if !defined DISABLE_DYNLOADING
364 extern "C" void writeInfo(va_list * args
) {
365 component_writeInfoFunc fn
= va_arg(*args
, component_writeInfoFunc
);
366 void * smgr
= va_arg(*args
, void *);
367 void * key
= va_arg(*args
, void *);
368 sal_Bool
* ok
= va_arg(*args
, sal_Bool
*);
369 *ok
= (*fn
)(smgr
, key
);
374 void cppu::writeSharedLibComponentInfo(
375 rtl::OUString
const & uri
, rtl::OUString
const & rPath
,
376 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & xMgr
,
377 css::uno::Reference
<css::registry::XRegistryKey
> const & xKey
)
379 assert(rPath
.isEmpty()); (void) rPath
;
380 osl::Module
mod(uri
, SAL_LOADMODULE_LAZY
| SAL_LOADMODULE_GLOBAL
);
382 throw css::registry::CannotRegisterImplementationException(
383 "loading component library <" + uri
+ "> failed",
384 css::uno::Reference
<css::uno::XInterface
>());
386 oslGenericFunction fp
= mod
.getFunctionSymbol(COMPONENT_WRITEINFO
);
388 throw css::registry::CannotRegisterImplementationException(
389 ("no symbol \"" COMPONENT_WRITEINFO
"\" in component library <"
391 css::uno::Reference
<css::uno::XInterface
>());
393 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
394 css::uno::Environment
env(getEnvironmentFromModule(mod
, curEnv
, "", ""));
395 if (!(curEnv
.is() && env
.is())) {
396 throw css::registry::CannotRegisterImplementationException(
397 "cannot get environments",
398 css::uno::Reference
<css::uno::XInterface
>());
400 css::uno::Mapping
map(curEnv
, env
);
402 throw css::registry::CannotRegisterImplementationException(
403 "cannot get mapping", css::uno::Reference
<css::uno::XInterface
>());
405 void * smgr
= map
.mapInterface(
406 xMgr
.get(), cppu::UnoType
<css::lang::XMultiServiceFactory
>::get());
407 void * key
= map
.mapInterface(
408 xKey
.get(), cppu::UnoType
<css::registry::XRegistryKey
>::get());
410 env
.invoke(writeInfo
, fp
, smgr
, key
, &ok
);
411 (*env
.get()->pExtEnv
->releaseInterface
)(env
.get()->pExtEnv
, key
);
412 if (smgr
!= nullptr) {
413 (*env
.get()->pExtEnv
->releaseInterface
)(env
.get()->pExtEnv
, smgr
);
416 throw css::registry::CannotRegisterImplementationException(
417 ("calling \"" COMPONENT_WRITEINFO
"\" in component library <" + uri
418 + "> returned false"),
419 css::uno::Reference
<css::uno::XInterface
>());
425 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */