LibreOffice Module cppuhelper (master)  1
shlib.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <cassert>
23 #include <cstdlib>
24 #include <string_view>
25 
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>
35 
37 
38 #if defined DISABLE_DYNLOADING
39 #include <osl/detail/component-mapping.h>
40 #endif
41 
42 css::uno::Environment cppuhelper::detail::getEnvironment(
43  OUString const & name, OUString const & implementation)
44 {
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()))
54  {
55  n += ":log";
56  break;
57  }
58  }
59  }
60  }
61  return css::uno::Environment(n);
62 }
63 
64 namespace {
65 
66 #if !defined DISABLE_DYNLOADING
67 
68 css::uno::Environment getEnvironmentFromModule(
69  osl::Module const & module, css::uno::Environment const & target,
70  OUString const & implementation, OUString const & prefix)
71 {
72  char const * name = nullptr;
73  css::uno::Environment env;
74  OUString fullPrefix(prefix);
75  if (!fullPrefix.isEmpty()) {
76  fullPrefix += "_";
77  }
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 {
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
95  }
96  }
97  if (!env.is() && name != nullptr) {
99  OUString::createFromAscii(name), implementation);
100  }
101  return env;
102 }
103 
104 #endif
105 
106 extern "C" void getFactory(va_list * args) {
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);
112 }
113 
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)
119 {
120  if (!(source.is() && target.is())) {
121  throw css::loader::CannotActivateFactoryException(
122  "cannot get environments",
123  css::uno::Reference<css::uno::XInterface>());
124  }
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);
132  }
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>());
139  }
140  void * smgr = mapTo.mapInterface(
141  serviceManager.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);
148  }
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>());
154  }
155  css::uno::Reference<css::uno::XInterface> res;
156  mapFrom.mapInterface(
157  reinterpret_cast<void **>(&res), factory,
159  (*target.get()->pExtEnv->releaseInterface)(
160  target.get()->pExtEnv, factory);
161  return res;
162 }
163 
164 #if !defined DISABLE_DYNLOADING
165 
166 extern "C" void getInstance(va_list * args) {
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));
177 }
178 
179 cppuhelper::WrapperConstructorFn mapConstructorFn(
180  css::uno::Environment const & source, css::uno::Environment const & target,
181  cppuhelper::ImplementationConstructorFn *const constructorFunction)
182 {
183  if (!(source.is() && target.is())) {
184  throw css::loader::CannotActivateFactoryException(
185  "cannot get environments",
186  css::uno::Reference<css::uno::XInterface>());
187  }
188  if (source.get() == target.get()) {
189  return cppuhelper::WrapperConstructorFn(constructorFunction);
190  }
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>());
200  }
201  return [mapFrom, mapTo, target, constructorFunction]
202  (css::uno::XComponentContext *const context, css::uno::Sequence<css::uno::Any> const& args)
203  {
204  void *const ctxt = mapTo.mapInterface(
205  context,
207  if (args.hasElements()) {
208  std::abort(); // TODO map args
209  }
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);
215  }
216  css::uno::XInterface * res = nullptr;
217  if (instance == nullptr) {
218  return res;
219  }
220  mapFrom.mapInterface(
221  reinterpret_cast<void **>(&res), instance,
223  (*target.get()->pExtEnv->releaseInterface)(
224  target.get()->pExtEnv, instance);
225  return res;
226  };
227 }
228 
229 #endif
230 
231 }
232 
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)
240 {
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>());
255  }
256  if (curEnv.get() != env.get()) {
257  std::abort();//TODO
258  }
259  SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri);
260  lib_to_factory_mapping const * map = lo_get_factory_map();
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;
266  }
267  }
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>());
273  }
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;
287  }
288  }
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>());
293  }
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>());
300  }
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;
308  }
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>());
315  }
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>());
332  }
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));
340  }
341  mod.release();
342 #endif
343 }
344 
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)
350 {
351  assert(rPath.isEmpty()); (void) rPath;
352  assert(!xKey.is()); (void) xKey;
353  css::uno::Reference<css::uno::XInterface> fac;
355  uri, "", "", rImplName, "", xMgr, nullptr, &fac);
356  return fac;
357 }
358 
359 #if !defined DISABLE_DYNLOADING
360 
361 namespace {
362 
363 extern "C" void writeInfo(va_list * args) {
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);
369 }
370 
371 }
372 
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)
377 {
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>());
384  }
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>());
391  }
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>());
398  }
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>());
403  }
404  void * smgr = map.mapInterface(
406  void * key = map.mapInterface(
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);
413  }
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>());
419  }
420 }
421 
422 #endif
423 
424 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Environment getEnvironment(OUString const &name, OUString const &implementation)
Definition: shlib.cxx:42
struct _uno_Environment uno_Environment
Definition: factory.hxx:49
void(SAL_CALL * component_getImplementationEnvironmentExtFunc)(char const **ppEnvTypeName, uno_Environment **ppEnv, char const *pImplName, uno_Environment *pTargetEnv)
Function pointer declaration.
Definition: factory.hxx:73
sal_Int64 n
void loadSharedLibComponentFactory(OUString const &uri, OUString const &environment, OUString const &prefix, OUString const &implementation, OUString const &constructor, css::uno::Reference< css::lang::XMultiServiceFactory > const &serviceManager, WrapperConstructorFn *constructorFunction, css::uno::Reference< css::uno::XInterface > *factory)
Definition: shlib.cxx:233
void(SAL_CALL * component_getImplementationEnvironmentFunc)(const char **ppEnvTypeName, uno_Environment **ppEnv)
Function pointer declaration.
Definition: factory.hxx:60
tuple log
#define COMPONENT_WRITEINFO
Definition: factory.hxx:46
#define COMPONENT_GETENV
Definition: factory.hxx:44
css::uno::XInterface * ImplementationConstructorFn(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
int i
int fac(int n)
unsigned char sal_Bool
css::uno::Type const & get()
std::function< css::uno::XInterface *(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)> WrapperConstructorFn
CPPUHELPER_DLLPUBLIC void SAL_CALL writeSharedLibComponentInfo(::rtl::OUString const &uri,::rtl::OUString const &rPath, css::uno::Reference< css::lang::XMultiServiceFactory > const &xMgr, css::uno::Reference< css::registry::XRegistryKey > const &xKey)
Invokes component_writeInfo() function of specified component library.
#define COMPONENT_GETFACTORY
Definition: factory.hxx:47
#define SAL_INFO(area, stream)
std::map< OUString, rtl::Reference< Entity > > map
sal_Bool(SAL_CALL * component_writeInfoFunc)(void *pServiceManager, void *pRegistryKey)
Function pointer declaration.
Definition: factory.hxx:102
const char * name
#define SAL_WARN(area, stream)
#define COMPONENT_GETENVEXT
Definition: factory.hxx:45
SAL_DLLPUBLIC_EXPORT css::uno::Reference< css::uno::XInterface > SAL_CALL loadSharedLibComponentFactory(OUString const &, OUString const &, OUString const &, css::uno::Reference< css::lang::XMultiServiceFactory > const &, css::uno::Reference< css::registry::XRegistryKey > const &, OUString const &)
Definition: compat.cxx:104
void *(SAL_CALL * component_getFactoryFunc)(const char *pImplName, void *pServiceManager, void *pRegistryKey)
Function pointer declaration.
Definition: factory.hxx:120
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo