bump product version to 7.2.5.1
[LibreOffice.git] / cppuhelper / source / shlib.cxx
blobb0a938a4abacac2489f88eb6eebcefda20e2daa8
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 #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>
40 #endif
42 css::uno::Environment cppuhelper::detail::getEnvironment(
43 OUString const & name, OUString const & implementation)
45 OUString n(name);
46 if (!implementation.isEmpty()) {
47 static char const * log = std::getenv("UNO_ENV_LOG");
48 if (log != nullptr && *log != 0) {
49 OString imps(log);
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()))
55 n += ":log";
56 break;
61 return css::uno::Environment(n);
64 namespace {
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()) {
76 fullPrefix += "_";
78 component_getImplementationEnvironmentExtFunc fp1
79 = reinterpret_cast<component_getImplementationEnvironmentExtFunc>(
80 module.getFunctionSymbol(fullPrefix + COMPONENT_GETENVEXT));
81 if (fp1 != nullptr) {
82 (*fp1)(
83 &name, reinterpret_cast<uno_Environment **>(&env),
84 (OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US)
85 .getStr()),
86 target.get());
87 } else {
88 component_getImplementationEnvironmentFunc fp2
89 = reinterpret_cast<component_getImplementationEnvironmentFunc>(
90 module.getFunctionSymbol(fullPrefix + COMPONENT_GETENV));
91 if (fp2 != nullptr) {
92 (*fp2)(&name, reinterpret_cast<uno_Environment **>(&env));
93 } else {
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);
101 return env;
104 #endif
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>());
125 OString impl(
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)),
131 SAL_NO_ACQUIRE);
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);
161 return res;
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 *);
169 assert(ctxt);
170 void * argseq = va_arg(*args, void *);
171 assert(argseq);
172 void ** instance = va_arg(*args, void **);
173 assert(instance);
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(
205 context,
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) {
218 return res;
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);
225 return res;
229 #endif
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());
242 assert(
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()) {
257 std::abort();//TODO
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;
265 break;
268 if (fp == 0) {
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);
278 } else {
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)) {
283 *constructorFunction
284 = reinterpret_cast<ImplementationConstructorFn *>(
285 map[i].constructor_function);
286 return;
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>());
294 #else
295 osl::Module mod(uri, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL);
296 if (!mod.is()) {
297 throw css::loader::CannotActivateFactoryException(
298 "loading component library <" + uri + "> failed",
299 css::uno::Reference<css::uno::XInterface>());
301 if (constructor.isEmpty()) {
302 OUString sym;
303 SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri);
304 if (!prefix.isEmpty()) {
305 sym = prefix + "_" COMPONENT_GETFACTORY;
306 } else {
307 sym = COMPONENT_GETFACTORY;
309 oslGenericFunction fp = mod.getFunctionSymbol(sym);
310 if (fp == nullptr) {
311 throw css::loader::CannotActivateFactoryException(
312 ("no factory symbol \"" + sym + "\" in component library <"
313 + uri + ">"),
314 css::uno::Reference<css::uno::XInterface>());
316 css::uno::Environment curEnv(css::uno::Environment::getCurrent());
317 *factory = invokeComponentFactory(
318 curEnv,
319 (environment.isEmpty()
320 ? getEnvironmentFromModule(mod, curEnv, implementation, prefix)
321 : getEnvironment(environment, implementation)),
322 reinterpret_cast<component_getFactoryFunc>(fp), uri, implementation,
323 serviceManager);
324 } else {
325 SAL_INFO("cppuhelper.shlib", "constructor=" << constructor);
326 oslGenericFunction fp = mod.getFunctionSymbol(constructor);
327 if (fp == nullptr) {
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(
335 curEnv,
336 (environment.isEmpty()
337 ? getEnvironmentFromModule(mod, curEnv, implementation, prefix)
338 : getEnvironment(environment, implementation)),
339 reinterpret_cast<ImplementationConstructorFn *>(fp));
341 mod.release();
342 #endif
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);
356 return fac;
359 #if !defined DISABLE_DYNLOADING
361 namespace {
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);
380 if (!mod.is()) {
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);
386 if (fp == nullptr) {
387 throw css::registry::CannotRegisterImplementationException(
388 ("no symbol \"" COMPONENT_WRITEINFO "\" in component library <"
389 + uri + ">"),
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);
400 if (!map.is()) {
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());
408 sal_Bool ok;
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);
414 if (!ok) {
415 throw css::registry::CannotRegisterImplementationException(
416 ("calling \"" COMPONENT_WRITEINFO "\" in component library <" + uri
417 + "> returned false"),
418 css::uno::Reference<css::uno::XInterface>());
422 #endif
424 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */