/src/libreoffice/cppuhelper/source/shlib.cxx
Line | Count | Source |
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 <o3tl/environment.hxx> |
38 | | #include <o3tl/string_view.hxx> |
39 | | #include <osl/module.hxx> |
40 | | #include <sal/log.hxx> |
41 | | #include <uno/environment.hxx> |
42 | | #include <uno/mapping.hxx> |
43 | | |
44 | | #include "loadsharedlibcomponentfactory.hxx" |
45 | | |
46 | | #if defined DISABLE_DYNLOADING |
47 | | #include <osl/detail/component-mapping.h> |
48 | | #endif |
49 | | |
50 | | css::uno::Environment cppuhelper::detail::getEnvironment( |
51 | | OUString const & name, std::u16string_view implementation) |
52 | 0 | { |
53 | 0 | OUString n(name); |
54 | 0 | if (!implementation.empty()) { |
55 | 0 | OUString imps = o3tl::getEnvironment(u"UNO_ENV_LOG"_ustr); |
56 | 0 | if (!imps.isEmpty()) { |
57 | 0 | for (sal_Int32 i = 0; i != -1;) { |
58 | 0 | std::u16string_view imp(o3tl::getToken(imps, 0, ';', i)); |
59 | 0 | if (implementation == imp) |
60 | 0 | { |
61 | 0 | n += ":log"; |
62 | 0 | break; |
63 | 0 | } |
64 | 0 | } |
65 | 0 | } |
66 | 0 | } |
67 | 0 | return css::uno::Environment(n); |
68 | 0 | } |
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 | | std::u16string_view 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 | | } |
84 | | component_getImplementationEnvironmentExtFunc fp1 |
85 | | = reinterpret_cast<component_getImplementationEnvironmentExtFunc>( |
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 { |
94 | | component_getImplementationEnvironmentFunc fp2 |
95 | | = reinterpret_cast<component_getImplementationEnvironmentFunc>( |
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) { |
104 | | env = cppuhelper::detail::getEnvironment( |
105 | | OUString::createFromAscii(name), implementation); |
106 | | } |
107 | | return env; |
108 | | } |
109 | | |
110 | | #endif |
111 | | |
112 | 0 | extern "C" void getFactory(va_list * args) { |
113 | 0 | component_getFactoryFunc fn = va_arg(*args, component_getFactoryFunc); |
114 | 0 | OString const * implementation = va_arg(*args, OString const *); |
115 | 0 | void * smgr = va_arg(*args, void *); |
116 | 0 | void ** factory = va_arg(*args, void **); |
117 | 0 | *factory = (*fn)(implementation->getStr(), smgr, nullptr); |
118 | 0 | } |
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 | 0 | { |
126 | 0 | if (!(source.is() && target.is())) { |
127 | 0 | throw css::loader::CannotActivateFactoryException( |
128 | 0 | u"cannot get environments"_ustr, |
129 | 0 | css::uno::Reference<css::uno::XInterface>()); |
130 | 0 | } |
131 | 0 | OString impl( |
132 | 0 | OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US)); |
133 | 0 | if (source.get() == target.get()) { |
134 | 0 | return css::uno::Reference<css::uno::XInterface>( |
135 | 0 | static_cast<css::uno::XInterface *>( |
136 | 0 | (*function)(impl.getStr(), serviceManager.get(), nullptr)), |
137 | 0 | SAL_NO_ACQUIRE); |
138 | 0 | } |
139 | 0 | css::uno::Mapping mapTo(source, target); |
140 | 0 | css::uno::Mapping mapFrom(target, source); |
141 | 0 | if (!(mapTo.is() && mapFrom.is())) { |
142 | 0 | throw css::loader::CannotActivateFactoryException( |
143 | 0 | u"cannot get mappings"_ustr, |
144 | 0 | css::uno::Reference<css::uno::XInterface>()); |
145 | 0 | } |
146 | 0 | void * smgr = mapTo.mapInterface( |
147 | 0 | serviceManager.get(), |
148 | 0 | cppu::UnoType<css::lang::XMultiServiceFactory>::get()); |
149 | 0 | void * factory = nullptr; |
150 | 0 | target.invoke(getFactory, function, &impl, smgr, &factory); |
151 | 0 | if (smgr != nullptr) { |
152 | 0 | (*target.get()->pExtEnv->releaseInterface)( |
153 | 0 | target.get()->pExtEnv, smgr); |
154 | 0 | } |
155 | 0 | if (factory == nullptr) { |
156 | 0 | throw css::loader::CannotActivateFactoryException( |
157 | 0 | (OUString::Concat("calling factory function for \"") + implementation + "\" in <" |
158 | 0 | + uri + "> returned null"), |
159 | 0 | css::uno::Reference<css::uno::XInterface>()); |
160 | 0 | } |
161 | 0 | css::uno::Reference<css::uno::XInterface> res; |
162 | 0 | mapFrom.mapInterface( |
163 | 0 | reinterpret_cast<void **>(&res), factory, |
164 | 0 | cppu::UnoType<css::uno::XInterface>::get()); |
165 | 0 | (*target.get()->pExtEnv->releaseInterface)( |
166 | 0 | target.get()->pExtEnv, factory); |
167 | 0 | return res; |
168 | 0 | } |
169 | | |
170 | | #if !defined DISABLE_DYNLOADING |
171 | | |
172 | | extern "C" void getInstance(va_list * args) { |
173 | | cppuhelper::ImplementationConstructorFn * fn = va_arg(*args, cppuhelper::ImplementationConstructorFn *); |
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 | | u"cannot get environments"_ustr, |
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 | | u"cannot get mappings"_ustr, |
205 | | css::uno::Reference<css::uno::XInterface>()); |
206 | | } |
207 | | return [mapFrom=std::move(mapFrom), mapTo=std::move(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, |
212 | | cppu::UnoType<css::uno::XComponentContext>::get()); |
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, |
228 | | cppu::UnoType<css::uno::XInterface>::get()); |
229 | | (*target.get()->pExtEnv->releaseInterface)( |
230 | | target.get()->pExtEnv, instance); |
231 | | return res; |
232 | | }; |
233 | | } |
234 | | |
235 | | #endif |
236 | | |
237 | | } |
238 | | |
239 | | void cppuhelper::detail::loadSharedLibComponentFactory( |
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 | 327k | { |
247 | 327k | assert(constructor.isEmpty() || !environment.isEmpty()); |
248 | 327k | assert( |
249 | 327k | (constructorFunction == nullptr && constructor.isEmpty()) |
250 | 327k | || (constructorFunction && !*constructorFunction)); |
251 | 327k | assert(factory != nullptr && !factory->is()); |
252 | 327k | #if defined DISABLE_DYNLOADING |
253 | 327k | assert(!environment.isEmpty()); |
254 | 327k | if (constructor.isEmpty()) { |
255 | 0 | css::uno::Environment curEnv(css::uno::Environment::getCurrent()); |
256 | 0 | css::uno::Environment env(getEnvironment(environment, implementation)); |
257 | 0 | if (!(curEnv.is() && env.is())) { |
258 | 0 | throw css::loader::CannotActivateFactoryException( |
259 | 0 | "cannot get environments", |
260 | 0 | css::uno::Reference<css::uno::XInterface>()); |
261 | 0 | } |
262 | 0 | if (curEnv.get() != env.get()) { |
263 | 0 | std::abort();//TODO |
264 | 0 | } |
265 | 0 | SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri); |
266 | 0 | lib_to_factory_mapping const * map = lo_get_factory_map(); |
267 | 0 | component_getFactoryFunc fp = 0; |
268 | 0 | for (int i = 0; map[i].name != 0; ++i) { |
269 | 0 | if (uri.equalsAscii(map[i].name)) { |
270 | 0 | fp = map[i].component_getFactory_function; |
271 | 0 | break; |
272 | 0 | } |
273 | 0 | } |
274 | 0 | if (fp == 0) { |
275 | 0 | SAL_WARN("cppuhelper", "unknown factory name \"" << uri << "\""); |
276 | | #ifdef IOS |
277 | | NSLog(@"Unknown factory %s", uri.toUtf8().getStr()); |
278 | | #endif |
279 | 0 | throw css::loader::CannotActivateFactoryException( |
280 | 0 | "unknown factory name \"" + uri + "\"", |
281 | 0 | css::uno::Reference<css::uno::XInterface>()); |
282 | 0 | } |
283 | 0 | *factory = invokeComponentFactory( |
284 | 0 | css::uno::Environment::getCurrent(), |
285 | 0 | getEnvironment(environment, implementation), fp, uri, |
286 | 0 | implementation, serviceManager); |
287 | 327k | } else { |
288 | 327k | SAL_INFO("cppuhelper.shlib", "constructor=" << constructor); |
289 | 327k | lib_to_constructor_mapping const * map = lo_get_constructor_map(); |
290 | 21.7M | for (int i = 0; map[i].name != 0; ++i) { |
291 | 21.4M | if (constructor.equalsAscii(map[i].name)) { |
292 | 684 | *constructorFunction |
293 | 684 | = reinterpret_cast<ImplementationConstructorFn *>( |
294 | 684 | map[i].constructor_function); |
295 | 684 | return; |
296 | 684 | } |
297 | 21.4M | } |
298 | 327k | SAL_WARN("cppuhelper", "unknown constructor name \"" << constructor << "\""); |
299 | | #ifdef IOS |
300 | | NSLog(@"Unknown constructor %s", constructor.toUtf8().getStr()); |
301 | | #endif |
302 | 327k | throw css::loader::CannotActivateFactoryException( |
303 | 327k | "unknown constructor name \"" + constructor + "\"", |
304 | 327k | css::uno::Reference<css::uno::XInterface>()); |
305 | 327k | } |
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 | 327k | } |
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 | 0 | { |
363 | 0 | assert(rPath.isEmpty()); (void) rPath; |
364 | | assert(!xKey.is()); (void) xKey; |
365 | 0 | css::uno::Reference<css::uno::XInterface> fac; |
366 | 0 | cppuhelper::detail::loadSharedLibComponentFactory( |
367 | 0 | uri, u""_ustr, u""_ustr, rImplName, u""_ustr, xMgr, nullptr, &fac); |
368 | 0 | return fac; |
369 | 0 | } |
370 | | |
371 | | #if !defined DISABLE_DYNLOADING |
372 | | |
373 | | namespace { |
374 | | |
375 | | extern "C" void writeInfo(va_list * args) { |
376 | | component_writeInfoFunc fn = va_arg(*args, component_writeInfoFunc); |
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 | | |
385 | | void cppu::writeSharedLibComponentInfo( |
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, u"", u""_ustr)); |
406 | | if (!(curEnv.is() && env.is())) { |
407 | | throw css::registry::CannotRegisterImplementationException( |
408 | | u"cannot get environments"_ustr, |
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 | | u"cannot get mapping"_ustr, css::uno::Reference<css::uno::XInterface>()); |
415 | | } |
416 | | void * smgr = map.mapInterface( |
417 | | xMgr.get(), cppu::UnoType<css::lang::XMultiServiceFactory>::get()); |
418 | | void * key = map.mapInterface( |
419 | | xKey.get(), cppu::UnoType<css::registry::XRegistryKey>::get()); |
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: */ |