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>
28 #include <Foundation/Foundation.h>
32 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
33 #include <com/sun/star/registry/CannotRegisterImplementationException.hpp>
34 #include <com/sun/star/registry/XRegistryKey.hpp>
35 #include <cppuhelper/factory.hxx>
36 #include <cppuhelper/shlib.hxx>
37 #include <o3tl/string_view.hxx>
38 #include <osl/module.hxx>
39 #include <sal/log.hxx>
40 #include <uno/environment.hxx>
41 #include <uno/mapping.hxx>
43 #include "loadsharedlibcomponentfactory.hxx"
45 #if defined DISABLE_DYNLOADING
46 #include <osl/detail/component-mapping.h>
49 css::uno::Environment
cppuhelper::detail::getEnvironment(
50 OUString
const & name
, std::u16string_view implementation
)
53 if (!implementation
.empty()) {
54 static char const * log
= std::getenv("UNO_ENV_LOG");
55 if (log
!= nullptr && *log
!= 0) {
57 for (sal_Int32 i
= 0; i
!= -1;) {
58 std::string_view
imp(o3tl::getToken(imps
, 0, ';', i
));
59 //TODO: this assumes UNO_ENV_LOG only contains ASCII characters:
60 if (o3tl::equalsAscii(implementation
, imp
))
68 return css::uno::Environment(n
);
73 #if !defined DISABLE_DYNLOADING
75 css::uno::Environment
getEnvironmentFromModule(
76 osl::Module
const & module
, css::uno::Environment
const & target
,
77 std::u16string_view implementation
, OUString
const & prefix
)
79 char const * name
= nullptr;
80 css::uno::Environment env
;
81 OUString
fullPrefix(prefix
);
82 if (!fullPrefix
.isEmpty()) {
85 component_getImplementationEnvironmentExtFunc fp1
86 = reinterpret_cast<component_getImplementationEnvironmentExtFunc
>(
87 module
.getFunctionSymbol(fullPrefix
+ COMPONENT_GETENVEXT
));
90 &name
, reinterpret_cast<uno_Environment
**>(&env
),
91 (OUStringToOString(implementation
, RTL_TEXTENCODING_ASCII_US
)
95 component_getImplementationEnvironmentFunc fp2
96 = reinterpret_cast<component_getImplementationEnvironmentFunc
>(
97 module
.getFunctionSymbol(fullPrefix
+ COMPONENT_GETENV
));
99 (*fp2
)(&name
, reinterpret_cast<uno_Environment
**>(&env
));
101 name
= CPPU_CURRENT_LANGUAGE_BINDING_NAME
; //TODO: fail
104 if (!env
.is() && name
!= nullptr) {
105 env
= cppuhelper::detail::getEnvironment(
106 OUString::createFromAscii(name
), implementation
);
113 extern "C" void getFactory(va_list * args
) {
114 component_getFactoryFunc fn
= va_arg(*args
, component_getFactoryFunc
);
115 OString
const * implementation
= va_arg(*args
, OString
const *);
116 void * smgr
= va_arg(*args
, void *);
117 void ** factory
= va_arg(*args
, void **);
118 *factory
= (*fn
)(implementation
->getStr(), smgr
, nullptr);
121 css::uno::Reference
<css::uno::XInterface
> invokeComponentFactory(
122 css::uno::Environment
const & source
, css::uno::Environment
const & target
,
123 component_getFactoryFunc function
, std::u16string_view uri
,
124 std::u16string_view implementation
,
125 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & serviceManager
)
127 if (!(source
.is() && target
.is())) {
128 throw css::loader::CannotActivateFactoryException(
129 u
"cannot get environments"_ustr
,
130 css::uno::Reference
<css::uno::XInterface
>());
133 OUStringToOString(implementation
, RTL_TEXTENCODING_ASCII_US
));
134 if (source
.get() == target
.get()) {
135 return css::uno::Reference
<css::uno::XInterface
>(
136 static_cast<css::uno::XInterface
*>(
137 (*function
)(impl
.getStr(), serviceManager
.get(), nullptr)),
140 css::uno::Mapping
mapTo(source
, target
);
141 css::uno::Mapping
mapFrom(target
, source
);
142 if (!(mapTo
.is() && mapFrom
.is())) {
143 throw css::loader::CannotActivateFactoryException(
144 u
"cannot get mappings"_ustr
,
145 css::uno::Reference
<css::uno::XInterface
>());
147 void * smgr
= mapTo
.mapInterface(
148 serviceManager
.get(),
149 cppu::UnoType
<css::lang::XMultiServiceFactory
>::get());
150 void * factory
= nullptr;
151 target
.invoke(getFactory
, function
, &impl
, smgr
, &factory
);
152 if (smgr
!= nullptr) {
153 (*target
.get()->pExtEnv
->releaseInterface
)(
154 target
.get()->pExtEnv
, smgr
);
156 if (factory
== nullptr) {
157 throw css::loader::CannotActivateFactoryException(
158 (OUString::Concat("calling factory function for \"") + implementation
+ "\" in <"
159 + uri
+ "> returned null"),
160 css::uno::Reference
<css::uno::XInterface
>());
162 css::uno::Reference
<css::uno::XInterface
> res
;
163 mapFrom
.mapInterface(
164 reinterpret_cast<void **>(&res
), factory
,
165 cppu::UnoType
<css::uno::XInterface
>::get());
166 (*target
.get()->pExtEnv
->releaseInterface
)(
167 target
.get()->pExtEnv
, factory
);
171 #if !defined DISABLE_DYNLOADING
173 extern "C" void getInstance(va_list * args
) {
174 cppuhelper::ImplementationConstructorFn
* fn
= va_arg(*args
, cppuhelper::ImplementationConstructorFn
*);
175 void * ctxt
= va_arg(*args
, void *);
177 void * argseq
= va_arg(*args
, void *);
179 void ** instance
= va_arg(*args
, void **);
181 assert(*instance
== nullptr);
182 *instance
= (*fn
)(static_cast<css::uno::XComponentContext
*>(ctxt
),
183 *static_cast<css::uno::Sequence
<css::uno::Any
> const*>(argseq
));
186 cppuhelper::WrapperConstructorFn
mapConstructorFn(
187 css::uno::Environment
const & source
, css::uno::Environment
const & target
,
188 cppuhelper::ImplementationConstructorFn
*const constructorFunction
)
190 if (!(source
.is() && target
.is())) {
191 throw css::loader::CannotActivateFactoryException(
192 u
"cannot get environments"_ustr
,
193 css::uno::Reference
<css::uno::XInterface
>());
195 if (source
.get() == target
.get()) {
196 return cppuhelper::WrapperConstructorFn(constructorFunction
);
198 // note: it should be valid to capture these mappings because they are
199 // ref-counted, and the returned closure will always be invoked in the
200 // "source" environment
201 css::uno::Mapping
mapTo(source
, target
);
202 css::uno::Mapping
mapFrom(target
, source
);
203 if (!(mapTo
.is() && mapFrom
.is())) {
204 throw css::loader::CannotActivateFactoryException(
205 u
"cannot get mappings"_ustr
,
206 css::uno::Reference
<css::uno::XInterface
>());
208 return [mapFrom
, mapTo
, target
, constructorFunction
]
209 (css::uno::XComponentContext
*const context
, css::uno::Sequence
<css::uno::Any
> const& args
)
211 void *const ctxt
= mapTo
.mapInterface(
213 cppu::UnoType
<css::uno::XComponentContext
>::get());
214 if (args
.hasElements()) {
215 std::abort(); // TODO map args
217 void * instance
= nullptr;
218 target
.invoke(getInstance
, constructorFunction
, ctxt
, &args
, &instance
);
219 if (ctxt
!= nullptr) {
220 (*target
.get()->pExtEnv
->releaseInterface
)(
221 target
.get()->pExtEnv
, ctxt
);
223 css::uno::XInterface
* res
= nullptr;
224 if (instance
== nullptr) {
227 mapFrom
.mapInterface(
228 reinterpret_cast<void **>(&res
), instance
,
229 cppu::UnoType
<css::uno::XInterface
>::get());
230 (*target
.get()->pExtEnv
->releaseInterface
)(
231 target
.get()->pExtEnv
, instance
);
240 void cppuhelper::detail::loadSharedLibComponentFactory(
241 OUString
const & uri
, OUString
const & environment
,
242 OUString
const & prefix
, OUString
const & implementation
,
243 OUString
const & constructor
,
244 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & serviceManager
,
245 WrapperConstructorFn
* constructorFunction
,
246 css::uno::Reference
<css::uno::XInterface
> * factory
)
248 assert(constructor
.isEmpty() || !environment
.isEmpty());
250 (constructorFunction
== nullptr && constructor
.isEmpty())
251 || (constructorFunction
&& !*constructorFunction
));
252 assert(factory
!= nullptr && !factory
->is());
253 #if defined DISABLE_DYNLOADING
254 assert(!environment
.isEmpty());
255 if (constructor
.isEmpty()) {
256 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
257 css::uno::Environment
env(getEnvironment(environment
, implementation
));
258 if (!(curEnv
.is() && env
.is())) {
259 throw css::loader::CannotActivateFactoryException(
260 "cannot get environments",
261 css::uno::Reference
<css::uno::XInterface
>());
263 if (curEnv
.get() != env
.get()) {
266 SAL_INFO("cppuhelper.shlib", "prefix=" << prefix
<< " implementation=" << implementation
<< " uri=" << uri
);
267 lib_to_factory_mapping
const * map
= lo_get_factory_map();
268 component_getFactoryFunc fp
= 0;
269 for (int i
= 0; map
[i
].name
!= 0; ++i
) {
270 if (uri
.equalsAscii(map
[i
].name
)) {
271 fp
= map
[i
].component_getFactory_function
;
276 SAL_WARN("cppuhelper", "unknown factory name \"" << uri
<< "\"");
278 NSLog(@
"Unknown factory %s", uri
.toUtf8().getStr());
280 throw css::loader::CannotActivateFactoryException(
281 "unknown factory name \"" + uri
+ "\"",
282 css::uno::Reference
<css::uno::XInterface
>());
284 *factory
= invokeComponentFactory(
285 css::uno::Environment::getCurrent(),
286 getEnvironment(environment
, implementation
), fp
, uri
,
287 implementation
, serviceManager
);
289 SAL_INFO("cppuhelper.shlib", "constructor=" << constructor
);
290 lib_to_constructor_mapping
const * map
= lo_get_constructor_map();
291 for (int i
= 0; map
[i
].name
!= 0; ++i
) {
292 if (constructor
.equalsAscii(map
[i
].name
)) {
294 = reinterpret_cast<ImplementationConstructorFn
*>(
295 map
[i
].constructor_function
);
299 SAL_WARN("cppuhelper", "unknown constructor name \"" << constructor
<< "\"");
301 NSLog(@
"Unknown constructor %s", constructor
.toUtf8().getStr());
303 throw css::loader::CannotActivateFactoryException(
304 "unknown constructor name \"" + constructor
+ "\"",
305 css::uno::Reference
<css::uno::XInterface
>());
308 osl::Module
mod(uri
, SAL_LOADMODULE_LAZY
| SAL_LOADMODULE_GLOBAL
);
310 throw css::loader::CannotActivateFactoryException(
311 "loading component library <" + uri
+ "> failed",
312 css::uno::Reference
<css::uno::XInterface
>());
314 if (constructor
.isEmpty()) {
316 SAL_INFO("cppuhelper.shlib", "prefix=" << prefix
<< " implementation=" << implementation
<< " uri=" << uri
);
317 if (!prefix
.isEmpty()) {
318 sym
= prefix
+ "_" COMPONENT_GETFACTORY
;
320 sym
= COMPONENT_GETFACTORY
;
322 oslGenericFunction fp
= mod
.getFunctionSymbol(sym
);
324 throw css::loader::CannotActivateFactoryException(
325 ("no factory symbol \"" + sym
+ "\" in component library <"
327 css::uno::Reference
<css::uno::XInterface
>());
329 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
330 *factory
= invokeComponentFactory(
332 (environment
.isEmpty()
333 ? getEnvironmentFromModule(mod
, curEnv
, implementation
, prefix
)
334 : getEnvironment(environment
, implementation
)),
335 reinterpret_cast<component_getFactoryFunc
>(fp
), uri
, implementation
,
338 SAL_INFO("cppuhelper.shlib", "constructor=" << constructor
);
339 oslGenericFunction fp
= mod
.getFunctionSymbol(constructor
);
341 throw css::loader::CannotActivateFactoryException(
342 ("no constructor symbol \"" + constructor
343 + "\" in component library <" + uri
+ ">"),
344 css::uno::Reference
<css::uno::XInterface
>());
346 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
347 *constructorFunction
= mapConstructorFn(
349 (environment
.isEmpty()
350 ? getEnvironmentFromModule(mod
, curEnv
, implementation
, prefix
)
351 : getEnvironment(environment
, implementation
)),
352 reinterpret_cast<ImplementationConstructorFn
*>(fp
));
358 css::uno::Reference
<css::uno::XInterface
> cppu::loadSharedLibComponentFactory(
359 OUString
const & uri
, OUString
const & rPath
,
360 OUString
const & rImplName
,
361 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & xMgr
,
362 css::uno::Reference
<css::registry::XRegistryKey
> const & xKey
)
364 assert(rPath
.isEmpty()); (void) rPath
;
365 assert(!xKey
.is()); (void) xKey
;
366 css::uno::Reference
<css::uno::XInterface
> fac
;
367 cppuhelper::detail::loadSharedLibComponentFactory(
368 uri
, u
""_ustr
, u
""_ustr
, rImplName
, u
""_ustr
, xMgr
, nullptr, &fac
);
372 #if !defined DISABLE_DYNLOADING
376 extern "C" void writeInfo(va_list * args
) {
377 component_writeInfoFunc fn
= va_arg(*args
, component_writeInfoFunc
);
378 void * smgr
= va_arg(*args
, void *);
379 void * key
= va_arg(*args
, void *);
380 sal_Bool
* ok
= va_arg(*args
, sal_Bool
*);
381 *ok
= (*fn
)(smgr
, key
);
386 void cppu::writeSharedLibComponentInfo(
387 OUString
const & uri
, OUString
const & rPath
,
388 css::uno::Reference
<css::lang::XMultiServiceFactory
> const & xMgr
,
389 css::uno::Reference
<css::registry::XRegistryKey
> const & xKey
)
391 assert(rPath
.isEmpty()); (void) rPath
;
392 osl::Module
mod(uri
, SAL_LOADMODULE_LAZY
| SAL_LOADMODULE_GLOBAL
);
394 throw css::registry::CannotRegisterImplementationException(
395 "loading component library <" + uri
+ "> failed",
396 css::uno::Reference
<css::uno::XInterface
>());
398 oslGenericFunction fp
= mod
.getFunctionSymbol(COMPONENT_WRITEINFO
);
400 throw css::registry::CannotRegisterImplementationException(
401 ("no symbol \"" COMPONENT_WRITEINFO
"\" in component library <"
403 css::uno::Reference
<css::uno::XInterface
>());
405 css::uno::Environment
curEnv(css::uno::Environment::getCurrent());
406 css::uno::Environment
env(getEnvironmentFromModule(mod
, curEnv
, u
"", u
""_ustr
));
407 if (!(curEnv
.is() && env
.is())) {
408 throw css::registry::CannotRegisterImplementationException(
409 u
"cannot get environments"_ustr
,
410 css::uno::Reference
<css::uno::XInterface
>());
412 css::uno::Mapping
map(curEnv
, env
);
414 throw css::registry::CannotRegisterImplementationException(
415 u
"cannot get mapping"_ustr
, css::uno::Reference
<css::uno::XInterface
>());
417 void * smgr
= map
.mapInterface(
418 xMgr
.get(), cppu::UnoType
<css::lang::XMultiServiceFactory
>::get());
419 void * key
= map
.mapInterface(
420 xKey
.get(), cppu::UnoType
<css::registry::XRegistryKey
>::get());
422 env
.invoke(writeInfo
, fp
, smgr
, key
, &ok
);
423 (*env
.get()->pExtEnv
->releaseInterface
)(env
.get()->pExtEnv
, key
);
424 if (smgr
!= nullptr) {
425 (*env
.get()->pExtEnv
->releaseInterface
)(env
.get()->pExtEnv
, smgr
);
428 throw css::registry::CannotRegisterImplementationException(
429 ("calling \"" COMPONENT_WRITEINFO
"\" in component library <" + uri
430 + "> returned false"),
431 css::uno::Reference
<css::uno::XInterface
>());
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */