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 #ifdef IOS
27 #include <premac.h>
28 #include <Foundation/Foundation.h>
29 #include <postmac.h>
30 #endif
31 
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 <osl/module.hxx>
38 #include <sal/log.hxx>
39 #include <uno/environment.hxx>
40 #include <uno/mapping.hxx>
41 
43 
44 #if defined DISABLE_DYNLOADING
45 #include <osl/detail/component-mapping.h>
46 #endif
47 
48 css::uno::Environment cppuhelper::detail::getEnvironment(
49  OUString const & name, OUString const & implementation)
50 {
51  OUString n(name);
52  if (!implementation.isEmpty()) {
53  static char const * log = std::getenv("UNO_ENV_LOG");
54  if (log != nullptr && *log != 0) {
55  OString imps(log);
56  for (sal_Int32 i = 0; i != -1;) {
57  OString imp(imps.getToken(0, ';', i));
58  //TODO: this assumes UNO_ENV_LOG only contains ASCII characters:
59  if (implementation.equalsAsciiL(imp.getStr(), imp.getLength()))
60  {
61  n += ":log";
62  break;
63  }
64  }
65  }
66  }
67  return css::uno::Environment(n);
68 }
69 
70 namespace {
71 
72 #if !defined DISABLE_DYNLOADING
73 
74 css::uno::Environment getEnvironmentFromModule(
75  osl::Module const & module, css::uno::Environment const & target,
76  OUString const & implementation, OUString const & prefix)
77 {
78  char const * name = nullptr;
79  css::uno::Environment env;
80  OUString fullPrefix(prefix);
81  if (!fullPrefix.isEmpty()) {
82  fullPrefix += "_";
83  }
86  module.getFunctionSymbol(fullPrefix + COMPONENT_GETENVEXT));
87  if (fp1 != nullptr) {
88  (*fp1)(
89  &name, reinterpret_cast<uno_Environment **>(&env),
90  (OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US)
91  .getStr()),
92  target.get());
93  } else {
96  module.getFunctionSymbol(fullPrefix + COMPONENT_GETENV));
97  if (fp2 != nullptr) {
98  (*fp2)(&name, reinterpret_cast<uno_Environment **>(&env));
99  } else {
100  name = CPPU_CURRENT_LANGUAGE_BINDING_NAME; //TODO: fail
101  }
102  }
103  if (!env.is() && name != nullptr) {
105  OUString::createFromAscii(name), implementation);
106  }
107  return env;
108 }
109 
110 #endif
111 
112 extern "C" void getFactory(va_list * args) {
114  OString const * implementation = va_arg(*args, OString const *);
115  void * smgr = va_arg(*args, void *);
116  void ** factory = va_arg(*args, void **);
117  *factory = (*fn)(implementation->getStr(), smgr, nullptr);
118 }
119 
120 css::uno::Reference<css::uno::XInterface> invokeComponentFactory(
121  css::uno::Environment const & source, css::uno::Environment const & target,
122  component_getFactoryFunc function, std::u16string_view uri,
123  std::u16string_view implementation,
124  css::uno::Reference<css::lang::XMultiServiceFactory> const & serviceManager)
125 {
126  if (!(source.is() && target.is())) {
127  throw css::loader::CannotActivateFactoryException(
128  "cannot get environments",
129  css::uno::Reference<css::uno::XInterface>());
130  }
131  OString impl(
132  OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US));
133  if (source.get() == target.get()) {
134  return css::uno::Reference<css::uno::XInterface>(
135  static_cast<css::uno::XInterface *>(
136  (*function)(impl.getStr(), serviceManager.get(), nullptr)),
137  SAL_NO_ACQUIRE);
138  }
139  css::uno::Mapping mapTo(source, target);
140  css::uno::Mapping mapFrom(target, source);
141  if (!(mapTo.is() && mapFrom.is())) {
142  throw css::loader::CannotActivateFactoryException(
143  "cannot get mappings",
144  css::uno::Reference<css::uno::XInterface>());
145  }
146  void * smgr = mapTo.mapInterface(
147  serviceManager.get(),
149  void * factory = nullptr;
150  target.invoke(getFactory, function, &impl, smgr, &factory);
151  if (smgr != nullptr) {
152  (*target.get()->pExtEnv->releaseInterface)(
153  target.get()->pExtEnv, smgr);
154  }
155  if (factory == nullptr) {
156  throw css::loader::CannotActivateFactoryException(
157  (OUString::Concat("calling factory function for \"") + implementation + "\" in <"
158  + uri + "> returned null"),
159  css::uno::Reference<css::uno::XInterface>());
160  }
161  css::uno::Reference<css::uno::XInterface> res;
162  mapFrom.mapInterface(
163  reinterpret_cast<void **>(&res), factory,
165  (*target.get()->pExtEnv->releaseInterface)(
166  target.get()->pExtEnv, factory);
167  return res;
168 }
169 
170 #if !defined DISABLE_DYNLOADING
171 
172 extern "C" void getInstance(va_list * args) {
174  void * ctxt = va_arg(*args, void *);
175  assert(ctxt);
176  void * argseq = va_arg(*args, void *);
177  assert(argseq);
178  void ** instance = va_arg(*args, void **);
179  assert(instance);
180  assert(*instance == nullptr);
181  *instance = (*fn)(static_cast<css::uno::XComponentContext*>(ctxt),
182  *static_cast<css::uno::Sequence<css::uno::Any> const*>(argseq));
183 }
184 
185 cppuhelper::WrapperConstructorFn mapConstructorFn(
186  css::uno::Environment const & source, css::uno::Environment const & target,
187  cppuhelper::ImplementationConstructorFn *const constructorFunction)
188 {
189  if (!(source.is() && target.is())) {
190  throw css::loader::CannotActivateFactoryException(
191  "cannot get environments",
192  css::uno::Reference<css::uno::XInterface>());
193  }
194  if (source.get() == target.get()) {
195  return cppuhelper::WrapperConstructorFn(constructorFunction);
196  }
197  // note: it should be valid to capture these mappings because they are
198  // ref-counted, and the returned closure will always be invoked in the
199  // "source" environment
200  css::uno::Mapping mapTo(source, target);
201  css::uno::Mapping mapFrom(target, source);
202  if (!(mapTo.is() && mapFrom.is())) {
203  throw css::loader::CannotActivateFactoryException(
204  "cannot get mappings",
205  css::uno::Reference<css::uno::XInterface>());
206  }
207  return [mapFrom, mapTo, target, constructorFunction]
208  (css::uno::XComponentContext *const context, css::uno::Sequence<css::uno::Any> const& args)
209  {
210  void *const ctxt = mapTo.mapInterface(
211  context,
213  if (args.hasElements()) {
214  std::abort(); // TODO map args
215  }
216  void * instance = nullptr;
217  target.invoke(getInstance, constructorFunction, ctxt, &args, &instance);
218  if (ctxt != nullptr) {
219  (*target.get()->pExtEnv->releaseInterface)(
220  target.get()->pExtEnv, ctxt);
221  }
222  css::uno::XInterface * res = nullptr;
223  if (instance == nullptr) {
224  return res;
225  }
226  mapFrom.mapInterface(
227  reinterpret_cast<void **>(&res), instance,
229  (*target.get()->pExtEnv->releaseInterface)(
230  target.get()->pExtEnv, instance);
231  return res;
232  };
233 }
234 
235 #endif
236 
237 }
238 
240  OUString const & uri, OUString const & environment,
241  OUString const & prefix, OUString const & implementation,
242  OUString const & constructor,
243  css::uno::Reference<css::lang::XMultiServiceFactory> const & serviceManager,
244  WrapperConstructorFn * constructorFunction,
245  css::uno::Reference<css::uno::XInterface> * factory)
246 {
247  assert(constructor.isEmpty() || !environment.isEmpty());
248  assert(
249  (constructorFunction == nullptr && constructor.isEmpty())
250  || !*constructorFunction);
251  assert(factory != nullptr && !factory->is());
252 #if defined DISABLE_DYNLOADING
253  assert(!environment.isEmpty());
254  if (constructor.isEmpty()) {
255  css::uno::Environment curEnv(css::uno::Environment::getCurrent());
256  css::uno::Environment env(getEnvironment(environment, implementation));
257  if (!(curEnv.is() && env.is())) {
258  throw css::loader::CannotActivateFactoryException(
259  "cannot get environments",
260  css::uno::Reference<css::uno::XInterface>());
261  }
262  if (curEnv.get() != env.get()) {
263  std::abort();//TODO
264  }
265  SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri);
266  lib_to_factory_mapping const * map = lo_get_factory_map();
268  for (int i = 0; map[i].name != 0; ++i) {
269  if (uri.equalsAscii(map[i].name)) {
270  fp = map[i].component_getFactory_function;
271  break;
272  }
273  }
274  if (fp == 0) {
275  SAL_WARN("cppuhelper", "unknown factory name \"" << uri << "\"");
276 #ifdef IOS
277  NSLog(@"Unknown factory %s", uri.toUtf8().getStr());
278 #endif
279  throw css::loader::CannotActivateFactoryException(
280  "unknown factory name \"" + uri + "\"",
281  css::uno::Reference<css::uno::XInterface>());
282  }
283  *factory = invokeComponentFactory(
284  css::uno::Environment::getCurrent(),
285  getEnvironment(environment, implementation), fp, uri,
286  implementation, serviceManager);
287  } else {
288  SAL_INFO("cppuhelper.shlib", "constructor=" << constructor);
289  lib_to_constructor_mapping const * map = lo_get_constructor_map();
290  for (int i = 0; map[i].name != 0; ++i) {
291  if (constructor.equalsAscii(map[i].name)) {
292  *constructorFunction
293  = reinterpret_cast<ImplementationConstructorFn *>(
294  map[i].constructor_function);
295  return;
296  }
297  }
298  SAL_WARN("cppuhelper", "unknown constructor name \"" << constructor << "\"");
299 #ifdef IOS
300  NSLog(@"Unknown constructor %s", constructor.toUtf8().getStr());
301 #endif
302  throw css::loader::CannotActivateFactoryException(
303  "unknown constructor name \"" + constructor + "\"",
304  css::uno::Reference<css::uno::XInterface>());
305  }
306 #else
307  osl::Module mod(uri, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL);
308  if (!mod.is()) {
309  throw css::loader::CannotActivateFactoryException(
310  "loading component library <" + uri + "> failed",
311  css::uno::Reference<css::uno::XInterface>());
312  }
313  if (constructor.isEmpty()) {
314  OUString sym;
315  SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri);
316  if (!prefix.isEmpty()) {
317  sym = prefix + "_" COMPONENT_GETFACTORY;
318  } else {
319  sym = COMPONENT_GETFACTORY;
320  }
321  oslGenericFunction fp = mod.getFunctionSymbol(sym);
322  if (fp == nullptr) {
323  throw css::loader::CannotActivateFactoryException(
324  ("no factory symbol \"" + sym + "\" in component library <"
325  + uri + ">"),
326  css::uno::Reference<css::uno::XInterface>());
327  }
328  css::uno::Environment curEnv(css::uno::Environment::getCurrent());
329  *factory = invokeComponentFactory(
330  curEnv,
331  (environment.isEmpty()
332  ? getEnvironmentFromModule(mod, curEnv, implementation, prefix)
333  : getEnvironment(environment, implementation)),
334  reinterpret_cast<component_getFactoryFunc>(fp), uri, implementation,
335  serviceManager);
336  } else {
337  SAL_INFO("cppuhelper.shlib", "constructor=" << constructor);
338  oslGenericFunction fp = mod.getFunctionSymbol(constructor);
339  if (fp == nullptr) {
340  throw css::loader::CannotActivateFactoryException(
341  ("no constructor symbol \"" + constructor
342  + "\" in component library <" + uri + ">"),
343  css::uno::Reference<css::uno::XInterface>());
344  }
345  css::uno::Environment curEnv(css::uno::Environment::getCurrent());
346  *constructorFunction = mapConstructorFn(
347  curEnv,
348  (environment.isEmpty()
349  ? getEnvironmentFromModule(mod, curEnv, implementation, prefix)
350  : getEnvironment(environment, implementation)),
351  reinterpret_cast<ImplementationConstructorFn *>(fp));
352  }
353  mod.release();
354 #endif
355 }
356 
357 css::uno::Reference<css::uno::XInterface> cppu::loadSharedLibComponentFactory(
358  OUString const & uri, OUString const & rPath,
359  OUString const & rImplName,
360  css::uno::Reference<css::lang::XMultiServiceFactory> const & xMgr,
361  css::uno::Reference<css::registry::XRegistryKey> const & xKey)
362 {
363  assert(rPath.isEmpty()); (void) rPath;
364  assert(!xKey.is()); (void) xKey;
365  css::uno::Reference<css::uno::XInterface> fac;
367  uri, "", "", rImplName, "", xMgr, nullptr, &fac);
368  return fac;
369 }
370 
371 #if !defined DISABLE_DYNLOADING
372 
373 namespace {
374 
375 extern "C" void writeInfo(va_list * args) {
377  void * smgr = va_arg(*args, void *);
378  void * key = va_arg(*args, void *);
379  sal_Bool * ok = va_arg(*args, sal_Bool *);
380  *ok = (*fn)(smgr, key);
381 }
382 
383 }
384 
386  OUString const & uri, OUString const & rPath,
387  css::uno::Reference<css::lang::XMultiServiceFactory> const & xMgr,
388  css::uno::Reference<css::registry::XRegistryKey> const & xKey)
389 {
390  assert(rPath.isEmpty()); (void) rPath;
391  osl::Module mod(uri, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL);
392  if (!mod.is()) {
393  throw css::registry::CannotRegisterImplementationException(
394  "loading component library <" + uri + "> failed",
395  css::uno::Reference<css::uno::XInterface>());
396  }
397  oslGenericFunction fp = mod.getFunctionSymbol(COMPONENT_WRITEINFO);
398  if (fp == nullptr) {
399  throw css::registry::CannotRegisterImplementationException(
400  ("no symbol \"" COMPONENT_WRITEINFO "\" in component library <"
401  + uri + ">"),
402  css::uno::Reference<css::uno::XInterface>());
403  }
404  css::uno::Environment curEnv(css::uno::Environment::getCurrent());
405  css::uno::Environment env(getEnvironmentFromModule(mod, curEnv, "", ""));
406  if (!(curEnv.is() && env.is())) {
407  throw css::registry::CannotRegisterImplementationException(
408  "cannot get environments",
409  css::uno::Reference<css::uno::XInterface>());
410  }
411  css::uno::Mapping map(curEnv, env);
412  if (!map.is()) {
413  throw css::registry::CannotRegisterImplementationException(
414  "cannot get mapping", css::uno::Reference<css::uno::XInterface>());
415  }
416  void * smgr = map.mapInterface(
418  void * key = map.mapInterface(
420  sal_Bool ok;
421  env.invoke(writeInfo, fp, smgr, key, &ok);
422  (*env.get()->pExtEnv->releaseInterface)(env.get()->pExtEnv, key);
423  if (smgr != nullptr) {
424  (*env.get()->pExtEnv->releaseInterface)(env.get()->pExtEnv, smgr);
425  }
426  if (!ok) {
427  throw css::registry::CannotRegisterImplementationException(
428  ("calling \"" COMPONENT_WRITEINFO "\" in component library <" + uri
429  + "> returned false"),
430  css::uno::Reference<css::uno::XInterface>());
431  }
432 }
433 
434 #endif
435 
436 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Environment getEnvironment(OUString const &name, OUString const &implementation)
Definition: shlib.cxx:48
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:239
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