Branch libreoffice-24-8-3
[LibreOffice.git] / cppuhelper / source / shlib.cxx
blobc1a66ae667043664d844598568355a61f8c9567e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <cassert>
23 #include <cstdlib>
24 #include <string_view>
26 #ifdef IOS
27 #include <premac.h>
28 #include <Foundation/Foundation.h>
29 #include <postmac.h>
30 #endif
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>
47 #endif
49 css::uno::Environment cppuhelper::detail::getEnvironment(
50 OUString const & name, std::u16string_view implementation)
52 OUString n(name);
53 if (!implementation.empty()) {
54 static char const * log = std::getenv("UNO_ENV_LOG");
55 if (log != nullptr && *log != 0) {
56 OString imps(log);
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))
62 n += ":log";
63 break;
68 return css::uno::Environment(n);
71 namespace {
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()) {
83 fullPrefix += "_";
85 component_getImplementationEnvironmentExtFunc fp1
86 = reinterpret_cast<component_getImplementationEnvironmentExtFunc>(
87 module.getFunctionSymbol(fullPrefix + COMPONENT_GETENVEXT));
88 if (fp1 != nullptr) {
89 (*fp1)(
90 &name, reinterpret_cast<uno_Environment **>(&env),
91 (OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US)
92 .getStr()),
93 target.get());
94 } else {
95 component_getImplementationEnvironmentFunc fp2
96 = reinterpret_cast<component_getImplementationEnvironmentFunc>(
97 module.getFunctionSymbol(fullPrefix + COMPONENT_GETENV));
98 if (fp2 != nullptr) {
99 (*fp2)(&name, reinterpret_cast<uno_Environment **>(&env));
100 } else {
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);
108 return env;
111 #endif
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>());
132 OString impl(
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)),
138 SAL_NO_ACQUIRE);
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);
168 return res;
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 *);
176 assert(ctxt);
177 void * argseq = va_arg(*args, void *);
178 assert(argseq);
179 void ** instance = va_arg(*args, void **);
180 assert(instance);
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(
212 context,
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) {
225 return res;
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);
232 return res;
236 #endif
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());
249 assert(
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()) {
264 std::abort();//TODO
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;
272 break;
275 if (fp == 0) {
276 SAL_WARN("cppuhelper", "unknown factory name \"" << uri << "\"");
277 #ifdef IOS
278 NSLog(@"Unknown factory %s", uri.toUtf8().getStr());
279 #endif
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);
288 } else {
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)) {
293 *constructorFunction
294 = reinterpret_cast<ImplementationConstructorFn *>(
295 map[i].constructor_function);
296 return;
299 SAL_WARN("cppuhelper", "unknown constructor name \"" << constructor << "\"");
300 #ifdef IOS
301 NSLog(@"Unknown constructor %s", constructor.toUtf8().getStr());
302 #endif
303 throw css::loader::CannotActivateFactoryException(
304 "unknown constructor name \"" + constructor + "\"",
305 css::uno::Reference<css::uno::XInterface>());
307 #else
308 osl::Module mod(uri, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL);
309 if (!mod.is()) {
310 throw css::loader::CannotActivateFactoryException(
311 "loading component library <" + uri + "> failed",
312 css::uno::Reference<css::uno::XInterface>());
314 if (constructor.isEmpty()) {
315 OUString sym;
316 SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri);
317 if (!prefix.isEmpty()) {
318 sym = prefix + "_" COMPONENT_GETFACTORY;
319 } else {
320 sym = COMPONENT_GETFACTORY;
322 oslGenericFunction fp = mod.getFunctionSymbol(sym);
323 if (fp == nullptr) {
324 throw css::loader::CannotActivateFactoryException(
325 ("no factory symbol \"" + sym + "\" in component library <"
326 + uri + ">"),
327 css::uno::Reference<css::uno::XInterface>());
329 css::uno::Environment curEnv(css::uno::Environment::getCurrent());
330 *factory = invokeComponentFactory(
331 curEnv,
332 (environment.isEmpty()
333 ? getEnvironmentFromModule(mod, curEnv, implementation, prefix)
334 : getEnvironment(environment, implementation)),
335 reinterpret_cast<component_getFactoryFunc>(fp), uri, implementation,
336 serviceManager);
337 } else {
338 SAL_INFO("cppuhelper.shlib", "constructor=" << constructor);
339 oslGenericFunction fp = mod.getFunctionSymbol(constructor);
340 if (fp == nullptr) {
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(
348 curEnv,
349 (environment.isEmpty()
350 ? getEnvironmentFromModule(mod, curEnv, implementation, prefix)
351 : getEnvironment(environment, implementation)),
352 reinterpret_cast<ImplementationConstructorFn *>(fp));
354 mod.release();
355 #endif
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);
369 return fac;
372 #if !defined DISABLE_DYNLOADING
374 namespace {
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);
393 if (!mod.is()) {
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);
399 if (fp == nullptr) {
400 throw css::registry::CannotRegisterImplementationException(
401 ("no symbol \"" COMPONENT_WRITEINFO "\" in component library <"
402 + uri + ">"),
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);
413 if (!map.is()) {
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());
421 sal_Bool ok;
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);
427 if (!ok) {
428 throw css::registry::CannotRegisterImplementationException(
429 ("calling \"" COMPONENT_WRITEINFO "\" in component library <" + uri
430 + "> returned false"),
431 css::uno::Reference<css::uno::XInterface>());
435 #endif
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */