Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */