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>
24 #include <string_view>
26 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
27 #include <com/sun/star/registry/CannotRegisterImplementationException.hpp>
28 #include <com/sun/star/registry/XRegistryKey.hpp>
29 #include <cppuhelper/factory.hxx>
30 #include <cppuhelper/shlib.hxx>
31 #include <osl/module.hxx>
32 #include <sal/log.hxx>
33 #include <uno/environment.hxx>
34 #include <uno/mapping.hxx>
36 #include "loadsharedlibcomponentfactory.hxx"
38 #if defined DISABLE_DYNLOADING
39 #include <osl/detail/component-mapping.h>
42 css::uno::Environment
cppuhelper::detail::getEnvironment(
43 OUString
const & name
, OUString
const & implementation
)
46 if (!implementation
.isEmpty()) {
47 static char const * log
= std::getenv("UNO_ENV_LOG");
48 if (log
!= nullptr && *log
!= 0) {
50 for (sal_Int32 i
= 0; i
!= -1;) {
51 OString
imp(imps
.getToken(0, ';', i
));
52 //TODO: this assumes UNO_ENV_LOG only contains ASCII characters:
53 if (implementation
.equalsAsciiL(imp
.getStr(), imp
.getLength()))
61 return css::uno::Environment(n
);
66 #if !defined DISABLE_DYNLOADING
68 css::uno::Environment
getEnvironmentFromModule(
69 osl::Module
const & module
, css::uno::Environment
const & target
,
70 OUString
const & implementation
, OUString
const & prefix
)
72 char const * name
= nullptr;
73 css::uno::Environment env
;
74 OUString
fullPrefix(prefix
);
75 if (!fullPrefix
.isEmpty()) {
78 component_getImplementationEnvironmentExtFunc fp1
79 = reinterpret_cast<component_getImplementationEnvironmentExtFunc
>(
80 module
.getFunctionSymbol(fullPrefix
+ COMPONENT_GETENVEXT
));
83 &name
, reinterpret_cast<uno_Environment
**>(&env
),
84 (OUStringToOString(implementation
, RTL_TEXTENCODING_ASCII_US
)
88 component_getImplementationEnvironmentFunc fp2
89 = reinterpret_cast<component_getImplementationEnvironmentFunc
>(
90 module
.getFunctionSymbol(fullPrefix
+ COMPONENT_GETENV
));
92 (*fp2
)(&name
, reinterpret_cast<uno_Environment
**>(&env
));
94 name
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
; //TODO: fail
97 if (!env
.is() && name
!= nullptr) {
98 env
= cppuhelper::detail::getEnvironment(
99 OUString::createFromAscii(name
), implementation
);
106 extern "C" void getFactory(va_list * args
) {
107 component_getFactoryFunc fn
= va_arg(*args
, component_getFactoryFunc
);
108 OString
const * implementation
= va_arg(*args
, OString
const *);
109 void * smgr
= va_arg(*args
, void *);
110 void ** factory
= va_arg(*args
, void **);
111 *factory
= (*fn
)(implementation
->getStr(), smgr
, nullptr);
114 css::uno::Reference
<css::uno::XInterface
> invokeComponentFactory(
115 css::uno::Environment
const & source
, css::uno::Environment
const & target
,
116 component_getFactoryFunc function
, std::u16string_view uri
,
117 std::u16string_view implementation
,
118 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & serviceManager
)
120 if (!(source
.is() && target
.is())) {
121 throw css::loader::CannotActivateFactoryException(
122 "cannot get environments",
123 css::uno::Reference
<css::uno::XInterface
>());
126 OUStringToOString(implementation
, RTL_TEXTENCODING_ASCII_US
));
127 if (source
.get() == target
.get()) {
128 return css::uno::Reference
<css::uno::XInterface
>(
129 static_cast<css::uno::XInterface
*>(
130 (*function
)(impl
.getStr(), serviceManager
.get(), nullptr)),
133 css::uno::Mapping
mapTo(source
, target
);
134 css::uno::Mapping
mapFrom(target
, source
);
135 if (!(mapTo
.is() && mapFrom
.is())) {
136 throw css::loader::CannotActivateFactoryException(
137 "cannot get mappings",
138 css::uno::Reference
<css::uno::XInterface
>());
140 void * smgr
= mapTo
.mapInterface(
141 serviceManager
.get(),
142 cppu::UnoType
<css::lang::XMultiServiceFactory
>::get());
143 void * factory
= nullptr;
144 target
.invoke(getFactory
, function
, &impl
, smgr
, &factory
);
145 if (smgr
!= nullptr) {
146 (*target
.get()->pExtEnv
->releaseInterface
)(
147 target
.get()->pExtEnv
, smgr
);
149 if (factory
== nullptr) {
150 throw css::loader::CannotActivateFactoryException(
151 (OUString::Concat("calling factory function for \"") + implementation
+ "\" in <"
152 + uri
+ "> returned null"),
153 css::uno::Reference
<css::uno::XInterface
>());
155 css::uno::Reference
<css::uno::XInterface
> res
;
156 mapFrom
.mapInterface(
157 reinterpret_cast<void **>(&res
), factory
,
158 cppu::UnoType
<css::uno::XInterface
>::get());
159 (*target
.get()->pExtEnv
->releaseInterface
)(
160 target
.get()->pExtEnv
, factory
);
164 #if !defined DISABLE_DYNLOADING
166 extern "C" void getInstance(va_list * args
) {
167 cppuhelper::ImplementationConstructorFn
* fn
= va_arg(*args
, cppuhelper::ImplementationConstructorFn
*);
168 void * ctxt
= va_arg(*args
, void *);
170 void * argseq
= va_arg(*args
, void *);
172 void ** instance
= va_arg(*args
, void **);
174 assert(*instance
== nullptr);
175 *instance
= (*fn
)(static_cast<css::uno::XComponentContext
*>(ctxt
),
176 *static_cast<css::uno::Sequence
<css::uno::Any
> const*>(argseq
));
179 cppuhelper::WrapperConstructorFn
mapConstructorFn(
180 css::uno::Environment
const & source
, css::uno::Environment
const & target
,
181 cppuhelper::ImplementationConstructorFn
*const constructorFunction
)
183 if (!(source
.is() && target
.is())) {
184 throw css::loader::CannotActivateFactoryException(
185 "cannot get environments",
186 css::uno::Reference
<css::uno::XInterface
>());
188 if (source
.get() == target
.get()) {
189 return cppuhelper::WrapperConstructorFn(constructorFunction
);
191 // note: it should be valid to capture these mappings because they are
192 // ref-counted, and the returned closure will always be invoked in the
193 // "source" environment
194 css::uno::Mapping
mapTo(source
, target
);
195 css::uno::Mapping
mapFrom(target
, source
);
196 if (!(mapTo
.is() && mapFrom
.is())) {
197 throw css::loader::CannotActivateFactoryException(
198 "cannot get mappings",
199 css::uno::Reference
<css::uno::XInterface
>());
201 return [mapFrom
, mapTo
, target
, constructorFunction
]
202 (css::uno::XComponentContext
*const context
, css::uno::Sequence
<css::uno::Any
> const& args
)
204 void *const ctxt
= mapTo
.mapInterface(
206 cppu::UnoType
<css::uno::XComponentContext
>::get());
207 if (args
.hasElements()) {
208 std::abort(); // TODO map args
210 void * instance
= nullptr;
211 target
.invoke(getInstance
, constructorFunction
, ctxt
, &args
, &instance
);
212 if (ctxt
!= nullptr) {
213 (*target
.get()->pExtEnv
->releaseInterface
)(
214 target
.get()->pExtEnv
, ctxt
);
216 css::uno::XInterface
* res
= nullptr;
217 if (instance
== nullptr) {
220 mapFrom
.mapInterface(
221 reinterpret_cast<void **>(&res
), instance
,
222 cppu::UnoType
<css::uno::XInterface
>::get());
223 (*target
.get()->pExtEnv
->releaseInterface
)(
224 target
.get()->pExtEnv
, instance
);
233 void cppuhelper::detail::loadSharedLibComponentFactory(
234 OUString
const & uri
, OUString
const & environment
,
235 OUString
const & prefix
, OUString
const & implementation
,
236 OUString
const & constructor
,
237 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & serviceManager
,
238 WrapperConstructorFn
* constructorFunction
,
239 css::uno::Reference
<css::uno::XInterface
> * factory
)
241 assert(constructor
.isEmpty() || !environment
.isEmpty());
243 (constructorFunction
== nullptr && constructor
.isEmpty())
244 || !*constructorFunction
);
245 assert(factory
!= nullptr && !factory
->is());
246 #if defined DISABLE_DYNLOADING
247 assert(!environment
.isEmpty());
248 if (constructor
.isEmpty()) {
249 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
250 css::uno::Environment
env(getEnvironment(environment
, implementation
));
251 if (!(curEnv
.is() && env
.is())) {
252 throw css::loader::CannotActivateFactoryException(
253 "cannot get environments",
254 css::uno::Reference
<css::uno::XInterface
>());
256 if (curEnv
.get() != env
.get()) {
259 SAL_INFO("cppuhelper.shlib", "prefix=" << prefix
<< " implementation=" << implementation
<< " uri=" << uri
);
260 lib_to_factory_mapping
const * map
= lo_get_factory_map();
261 component_getFactoryFunc fp
= 0;
262 for (int i
= 0; map
[i
].name
!= 0; ++i
) {
263 if (uri
.equalsAscii(map
[i
].name
)) {
264 fp
= map
[i
].component_getFactory_function
;
269 SAL_WARN("cppuhelper", "unknown factory name \"" << uri
<< "\"");
270 throw css::loader::CannotActivateFactoryException(
271 "unknown factory name \"" + uri
+ "\"",
272 css::uno::Reference
<css::uno::XInterface
>());
274 *factory
= invokeComponentFactory(
275 css::uno::Environment::getCurrent(),
276 getEnvironment(environment
, implementation
), fp
, uri
,
277 implementation
, serviceManager
);
279 SAL_INFO("cppuhelper.shlib", "constructor=" << constructor
);
280 lib_to_constructor_mapping
const * map
= lo_get_constructor_map();
281 for (int i
= 0; map
[i
].name
!= 0; ++i
) {
282 if (constructor
.equalsAscii(map
[i
].name
)) {
284 = reinterpret_cast<ImplementationConstructorFn
*>(
285 map
[i
].constructor_function
);
289 SAL_WARN("cppuhelper", "unknown constructor name \"" << constructor
<< "\"");
290 throw css::loader::CannotActivateFactoryException(
291 "unknown constructor name \"" + constructor
+ "\"",
292 css::uno::Reference
<css::uno::XInterface
>());
295 osl::Module
mod(uri
, SAL_LOADMODULE_LAZY
| SAL_LOADMODULE_GLOBAL
);
297 throw css::loader::CannotActivateFactoryException(
298 "loading component library <" + uri
+ "> failed",
299 css::uno::Reference
<css::uno::XInterface
>());
301 if (constructor
.isEmpty()) {
303 SAL_INFO("cppuhelper.shlib", "prefix=" << prefix
<< " implementation=" << implementation
<< " uri=" << uri
);
304 if (!prefix
.isEmpty()) {
305 sym
= prefix
+ "_" COMPONENT_GETFACTORY
;
307 sym
= COMPONENT_GETFACTORY
;
309 oslGenericFunction fp
= mod
.getFunctionSymbol(sym
);
311 throw css::loader::CannotActivateFactoryException(
312 ("no factory symbol \"" + sym
+ "\" in component library <"
314 css::uno::Reference
<css::uno::XInterface
>());
316 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
317 *factory
= invokeComponentFactory(
319 (environment
.isEmpty()
320 ? getEnvironmentFromModule(mod
, curEnv
, implementation
, prefix
)
321 : getEnvironment(environment
, implementation
)),
322 reinterpret_cast<component_getFactoryFunc
>(fp
), uri
, implementation
,
325 SAL_INFO("cppuhelper.shlib", "constructor=" << constructor
);
326 oslGenericFunction fp
= mod
.getFunctionSymbol(constructor
);
328 throw css::loader::CannotActivateFactoryException(
329 ("no constructor symbol \"" + constructor
330 + "\" in component library <" + uri
+ ">"),
331 css::uno::Reference
<css::uno::XInterface
>());
333 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
334 *constructorFunction
= mapConstructorFn(
336 (environment
.isEmpty()
337 ? getEnvironmentFromModule(mod
, curEnv
, implementation
, prefix
)
338 : getEnvironment(environment
, implementation
)),
339 reinterpret_cast<ImplementationConstructorFn
*>(fp
));
345 css::uno::Reference
<css::uno::XInterface
> cppu::loadSharedLibComponentFactory(
346 OUString
const & uri
, OUString
const & rPath
,
347 OUString
const & rImplName
,
348 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & xMgr
,
349 css::uno::Reference
<css::registry::XRegistryKey
> const & xKey
)
351 assert(rPath
.isEmpty()); (void) rPath
;
352 assert(!xKey
.is()); (void) xKey
;
353 css::uno::Reference
<css::uno::XInterface
> fac
;
354 cppuhelper::detail::loadSharedLibComponentFactory(
355 uri
, "", "", rImplName
, "", xMgr
, nullptr, &fac
);
359 #if !defined DISABLE_DYNLOADING
363 extern "C" void writeInfo(va_list * args
) {
364 component_writeInfoFunc fn
= va_arg(*args
, component_writeInfoFunc
);
365 void * smgr
= va_arg(*args
, void *);
366 void * key
= va_arg(*args
, void *);
367 sal_Bool
* ok
= va_arg(*args
, sal_Bool
*);
368 *ok
= (*fn
)(smgr
, key
);
373 void cppu::writeSharedLibComponentInfo(
374 OUString
const & uri
, OUString
const & rPath
,
375 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & xMgr
,
376 css::uno::Reference
<css::registry::XRegistryKey
> const & xKey
)
378 assert(rPath
.isEmpty()); (void) rPath
;
379 osl::Module
mod(uri
, SAL_LOADMODULE_LAZY
| SAL_LOADMODULE_GLOBAL
);
381 throw css::registry::CannotRegisterImplementationException(
382 "loading component library <" + uri
+ "> failed",
383 css::uno::Reference
<css::uno::XInterface
>());
385 oslGenericFunction fp
= mod
.getFunctionSymbol(COMPONENT_WRITEINFO
);
387 throw css::registry::CannotRegisterImplementationException(
388 ("no symbol \"" COMPONENT_WRITEINFO
"\" in component library <"
390 css::uno::Reference
<css::uno::XInterface
>());
392 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
393 css::uno::Environment
env(getEnvironmentFromModule(mod
, curEnv
, "", ""));
394 if (!(curEnv
.is() && env
.is())) {
395 throw css::registry::CannotRegisterImplementationException(
396 "cannot get environments",
397 css::uno::Reference
<css::uno::XInterface
>());
399 css::uno::Mapping
map(curEnv
, env
);
401 throw css::registry::CannotRegisterImplementationException(
402 "cannot get mapping", css::uno::Reference
<css::uno::XInterface
>());
404 void * smgr
= map
.mapInterface(
405 xMgr
.get(), cppu::UnoType
<css::lang::XMultiServiceFactory
>::get());
406 void * key
= map
.mapInterface(
407 xKey
.get(), cppu::UnoType
<css::registry::XRegistryKey
>::get());
409 env
.invoke(writeInfo
, fp
, smgr
, key
, &ok
);
410 (*env
.get()->pExtEnv
->releaseInterface
)(env
.get()->pExtEnv
, key
);
411 if (smgr
!= nullptr) {
412 (*env
.get()->pExtEnv
->releaseInterface
)(env
.get()->pExtEnv
, smgr
);
415 throw css::registry::CannotRegisterImplementationException(
416 ("calling \"" COMPONENT_WRITEINFO
"\" in component library <" + uri
417 + "> returned false"),
418 css::uno::Reference
<css::uno::XInterface
>());
424 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */