Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/cppuhelper/source/servicemanager.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
10
#include <sal/config.h>
11
12
#include <algorithm>
13
#include <cassert>
14
#include <iostream>
15
#include <mutex>
16
#include <string_view>
17
#include <utility>
18
#include <vector>
19
20
#include <config_fuzzers.h>
21
22
#include <com/sun/star/beans/NamedValue.hpp>
23
#include <com/sun/star/beans/PropertyAttribute.hpp>
24
#include <com/sun/star/container/ElementExistException.hpp>
25
#include <com/sun/star/container/XEnumeration.hpp>
26
#include <com/sun/star/container/XNameContainer.hpp>
27
#include <com/sun/star/lang/XInitialization.hpp>
28
#include <com/sun/star/lang/XServiceInfo.hpp>
29
#include <com/sun/star/lang/XSingleComponentFactory.hpp>
30
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
31
#include <com/sun/star/loader/XImplementationLoader.hpp>
32
#include <com/sun/star/registry/InvalidRegistryException.hpp>
33
#include <com/sun/star/uno/DeploymentException.hpp>
34
#include <com/sun/star/uno/Reference.hxx>
35
#include <com/sun/star/uno/XComponentContext.hpp>
36
#include <comphelper/sequence.hxx>
37
#include <cppuhelper/bootstrap.hxx>
38
#include <cppuhelper/component_context.hxx>
39
#include <cppuhelper/implbase.hxx>
40
#include <cppuhelper/supportsservice.hxx>
41
#include <cppuhelper/factory.hxx>
42
#include <o3tl/environment.hxx>
43
#include <o3tl/safeint.hxx>
44
#include <osl/file.hxx>
45
#include <osl/module.hxx>
46
#include <rtl/ref.hxx>
47
#include <rtl/uri.hxx>
48
#include <rtl/ustring.hxx>
49
#include <rtl/ustrbuf.hxx>
50
#include <sal/log.hxx>
51
#include <uno/environment.hxx>
52
#include <uno/mapping.hxx>
53
#include <o3tl/string_view.hxx>
54
55
#include "loadsharedlibcomponentfactory.hxx"
56
57
#include <registry/registry.hxx>
58
#include <xmlreader/xmlreader.hxx>
59
60
#include "paths.hxx"
61
#include "servicemanager.hxx"
62
63
namespace {
64
65
void insertImplementationMap(
66
    cppuhelper::ServiceManager::Data::ImplementationMap * destination,
67
    cppuhelper::ServiceManager::Data::ImplementationMap const & source)
68
312
{
69
312
    assert(destination != nullptr);
70
312
    for (const auto& [rName, rImpls] : source)
71
156
    {
72
156
        auto & impls = (*destination)[rName];
73
156
        impls.insert(impls.end(), rImpls.begin(), rImpls.end());
74
156
    }
75
312
}
76
77
void removeFromImplementationMap(
78
    cppuhelper::ServiceManager::Data::ImplementationMap * map,
79
    std::vector< OUString > const & elements,
80
    std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
81
        const & implementation)
82
0
{
83
    // The underlying data structures make this function somewhat inefficient,
84
    // but the assumption is that it is rarely called:
85
0
    assert(map != nullptr);
86
0
    for (const auto& rElement : elements)
87
0
    {
88
0
        auto j(map->find(rElement));
89
0
        assert(j != map->end());
90
0
        auto k(std::find(j->second.begin(), j->second.end(), implementation));
91
0
        assert(k != j->second.end());
92
0
        j->second.erase(k);
93
0
        if (j->second.empty()) {
94
0
            map->erase(j);
95
0
        }
96
0
    }
97
0
}
98
99
// For simplicity, this code keeps throwing
100
// css::registry::InvalidRegistryException for invalid XML rdbs (even though
101
// that does not fit the exception's name):
102
class Parser {
103
public:
104
    Parser(
105
        OUString const & uri,
106
        css::uno::Reference< css::uno::XComponentContext > alienContext,
107
        cppuhelper::ServiceManager::Data * data);
108
109
    Parser(const Parser&) = delete;
110
    const Parser& operator=(const Parser&) = delete;
111
112
private:
113
    void handleComponent();
114
115
    void handleImplementation();
116
117
    void handleService();
118
119
    void handleSingleton();
120
121
    OUString getNameAttribute();
122
123
    xmlreader::XmlReader reader_;
124
    css::uno::Reference< css::uno::XComponentContext > alienContext_;
125
    cppuhelper::ServiceManager::Data * data_;
126
    OUString attrLoader_;
127
    OUString attrUri_;
128
    OUString attrEnvironment_;
129
    OUString attrPrefix_;
130
    std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
131
        implementation_;
132
};
133
134
Parser::Parser(
135
    OUString const & uri,
136
    css::uno::Reference< css::uno::XComponentContext > alienContext,
137
    cppuhelper::ServiceManager::Data * data):
138
108
    reader_(uri), alienContext_(std::move(alienContext)), data_(data)
139
108
{
140
108
    assert(data != nullptr);
141
108
    int ucNsId = reader_.registerNamespaceIri(
142
108
        xmlreader::Span(
143
108
            RTL_CONSTASCII_STRINGPARAM(
144
108
                "http://openoffice.org/2010/uno-components")));
145
108
    enum State {
146
108
        STATE_BEGIN, STATE_END, STATE_COMPONENTS, STATE_COMPONENT_INITIAL,
147
108
        STATE_COMPONENT, STATE_IMPLEMENTATION, STATE_SERVICE, STATE_SINGLETON };
148
480k
    for (State state = STATE_BEGIN;;) {
149
480k
        xmlreader::Span name;
150
480k
        int nsId;
151
480k
        xmlreader::XmlReader::Result res = reader_.nextItem(
152
480k
            xmlreader::XmlReader::Text::NONE, &name, &nsId);
153
480k
        switch (state) {
154
108
        case STATE_BEGIN:
155
108
            if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
156
108
                && name.equals(RTL_CONSTASCII_STRINGPARAM("components")))
157
108
            {
158
108
                state = STATE_COMPONENTS;
159
108
                break;
160
108
            }
161
0
            throw css::registry::InvalidRegistryException(
162
0
                reader_.getUrl() + ": unexpected item in outer level");
163
108
        case STATE_END:
164
108
            if (res == xmlreader::XmlReader::Result::Done) {
165
108
                return;
166
108
            }
167
0
            throw css::registry::InvalidRegistryException(
168
0
                reader_.getUrl() + ": unexpected item in outer level");
169
15.3k
        case STATE_COMPONENTS:
170
15.3k
            if (res == xmlreader::XmlReader::Result::End) {
171
108
                state = STATE_END;
172
108
                break;
173
108
            }
174
15.2k
            if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
175
15.2k
                && name.equals(RTL_CONSTASCII_STRINGPARAM("component")))
176
15.2k
            {
177
15.2k
                handleComponent();
178
15.2k
                state = STATE_COMPONENT_INITIAL;
179
15.2k
                break;
180
15.2k
            }
181
0
            throw css::registry::InvalidRegistryException(
182
0
                reader_.getUrl() + ": unexpected item in <components>");
183
96.0k
        case STATE_COMPONENT:
184
96.0k
            if (res == xmlreader::XmlReader::Result::End) {
185
15.2k
                state = STATE_COMPONENTS;
186
15.2k
                break;
187
15.2k
            }
188
80.7k
            [[fallthrough]];
189
96.0k
        case STATE_COMPONENT_INITIAL:
190
96.0k
            if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
191
96.0k
                && name.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
192
96.0k
            {
193
96.0k
                handleImplementation();
194
96.0k
                state = STATE_IMPLEMENTATION;
195
96.0k
                break;
196
96.0k
            }
197
0
            throw css::registry::InvalidRegistryException(
198
0
                reader_.getUrl() + ": unexpected item in <component>");
199
225k
        case STATE_IMPLEMENTATION:
200
225k
            if (res == xmlreader::XmlReader::Result::End) {
201
96.0k
                state = STATE_COMPONENT;
202
96.0k
                break;
203
96.0k
            }
204
129k
            if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
205
129k
                && name.equals(RTL_CONSTASCII_STRINGPARAM("service")))
206
125k
            {
207
125k
                handleService();
208
125k
                state = STATE_SERVICE;
209
125k
                break;
210
125k
            }
211
3.24k
            if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
212
3.24k
                && name.equals(RTL_CONSTASCII_STRINGPARAM("singleton")))
213
3.24k
            {
214
3.24k
                handleSingleton();
215
3.24k
                state = STATE_SINGLETON;
216
3.24k
                break;
217
3.24k
            }
218
0
            throw css::registry::InvalidRegistryException(
219
0
                reader_.getUrl() + ": unexpected item in <implementation>");
220
125k
        case STATE_SERVICE:
221
125k
            if (res == xmlreader::XmlReader::Result::End) {
222
125k
                state = STATE_IMPLEMENTATION;
223
125k
                break;
224
125k
            }
225
0
            throw css::registry::InvalidRegistryException(
226
0
                reader_.getUrl() + ": unexpected item in <service>");
227
3.24k
        case STATE_SINGLETON:
228
3.24k
            if (res == xmlreader::XmlReader::Result::End) {
229
3.24k
                state = STATE_IMPLEMENTATION;
230
3.24k
                break;
231
3.24k
            }
232
0
            throw css::registry::InvalidRegistryException(
233
0
                reader_.getUrl() + ": unexpected item in <service>");
234
480k
        }
235
480k
    }
236
108
}
237
238
15.2k
void Parser::handleComponent() {
239
15.2k
    attrLoader_ = OUString();
240
15.2k
    attrUri_ = OUString();
241
15.2k
    attrEnvironment_ = OUString();
242
15.2k
    attrPrefix_ = OUString();
243
15.2k
    xmlreader::Span name;
244
15.2k
    int nsId;
245
60.9k
    while (reader_.nextAttribute(&nsId, &name)) {
246
45.6k
        if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
247
45.6k
            && name.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
248
15.2k
        {
249
15.2k
            if (!attrLoader_.isEmpty()) {
250
0
                throw css::registry::InvalidRegistryException(
251
0
                    reader_.getUrl()
252
0
                     + ": <component> has multiple \"loader\" attributes");
253
0
            }
254
15.2k
            attrLoader_ = reader_.getAttributeValue(false).convertFromUtf8();
255
15.2k
            if (attrLoader_.isEmpty()) {
256
0
                throw css::registry::InvalidRegistryException(
257
0
                    reader_.getUrl()
258
0
                     + ": <component> has empty \"loader\" attribute");
259
0
            }
260
30.4k
        } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
261
30.4k
                   && name.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
262
15.2k
        {
263
15.2k
            if (!attrUri_.isEmpty()) {
264
0
                throw css::registry::InvalidRegistryException(
265
0
                    reader_.getUrl()
266
0
                     + ": <component> has multiple \"uri\" attributes");
267
0
            }
268
15.2k
            attrUri_ = reader_.getAttributeValue(false).convertFromUtf8();
269
15.2k
            if (attrUri_.isEmpty()) {
270
0
                throw css::registry::InvalidRegistryException(
271
0
                    reader_.getUrl()
272
0
                     + ": <component> has empty \"uri\" attribute");
273
0
            }
274
15.2k
        } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
275
15.2k
                   && name.equals(RTL_CONSTASCII_STRINGPARAM("environment")))
276
14.9k
        {
277
14.9k
            if (!attrEnvironment_.isEmpty()) {
278
0
                throw css::registry::InvalidRegistryException(
279
0
                    reader_.getUrl() +
280
0
                     ": <component> has multiple \"environment\" attributes");
281
0
            }
282
14.9k
            attrEnvironment_ = reader_.getAttributeValue(false)
283
14.9k
                .convertFromUtf8();
284
14.9k
            if (attrEnvironment_.isEmpty()) {
285
0
                throw css::registry::InvalidRegistryException(
286
0
                    reader_.getUrl() +
287
0
                     ": <component> has empty \"environment\" attribute");
288
0
            }
289
14.9k
        } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
290
324
                   && name.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
291
324
        {
292
324
            if (!attrPrefix_.isEmpty()) {
293
0
                throw css::registry::InvalidRegistryException(
294
0
                    reader_.getUrl() +
295
0
                     ": <component> has multiple \"prefix\" attributes");
296
0
            }
297
324
            attrPrefix_ = reader_.getAttributeValue(false).convertFromUtf8();
298
324
            if (attrPrefix_.isEmpty()) {
299
0
                throw css::registry::InvalidRegistryException(
300
0
                    reader_.getUrl() +
301
0
                     ": <component> has empty \"prefix\" attribute");
302
0
            }
303
324
        } else {
304
0
            throw css::registry::InvalidRegistryException(
305
0
                reader_.getUrl() + ": unexpected attribute \""
306
0
                 + name.convertFromUtf8() + "\" in <component>");
307
0
        }
308
45.6k
    }
309
15.2k
    if (attrLoader_.isEmpty()) {
310
0
        throw css::registry::InvalidRegistryException(
311
0
            reader_.getUrl() + ": <component> is missing \"loader\" attribute");
312
0
    }
313
15.2k
    if (attrUri_.isEmpty()) {
314
0
        throw css::registry::InvalidRegistryException(
315
0
            reader_.getUrl() + ": <component> is missing \"uri\" attribute");
316
0
    }
317
#ifndef DISABLE_DYNLOADING
318
    try {
319
        attrUri_ = rtl::Uri::convertRelToAbs(reader_.getUrl(), attrUri_);
320
    } catch (const rtl::MalformedUriException & e) {
321
        throw css::registry::InvalidRegistryException(
322
            reader_.getUrl() + ": bad \"uri\" attribute: " + e.getMessage());
323
    }
324
#endif
325
15.2k
}
326
327
96.0k
void Parser::handleImplementation() {
328
96.0k
    OUString attrName;
329
96.0k
    OUString attrConstructor;
330
96.0k
    bool attrSingleInstance = false;
331
96.0k
    xmlreader::Span name;
332
96.0k
    int nsId;
333
292k
    while (reader_.nextAttribute(&nsId, &name)) {
334
196k
        if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
335
196k
            && name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
336
96.0k
        {
337
96.0k
            if (!attrName.isEmpty()) {
338
0
                throw css::registry::InvalidRegistryException(
339
0
                    reader_.getUrl()
340
0
                     + ": <implementation> has multiple \"name\" attributes");
341
0
            }
342
96.0k
            attrName = reader_.getAttributeValue(false).convertFromUtf8();
343
96.0k
            if (attrName.isEmpty()) {
344
0
                throw css::registry::InvalidRegistryException(
345
0
                    reader_.getUrl()
346
0
                    + ": <implementation> has empty \"name\" attribute");
347
0
            }
348
100k
        } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
349
100k
                   && name.equals(RTL_CONSTASCII_STRINGPARAM("constructor")))
350
93.7k
        {
351
93.7k
            if (!attrConstructor.isEmpty()) {
352
0
                throw css::registry::InvalidRegistryException(
353
0
                    reader_.getUrl()
354
0
                     + ": <implementation> has multiple \"constructor\""
355
0
                        " attributes");
356
0
            }
357
93.7k
            attrConstructor = reader_.getAttributeValue(false)
358
93.7k
                .convertFromUtf8();
359
93.7k
            if (attrConstructor.isEmpty()) {
360
0
                throw css::registry::InvalidRegistryException(
361
0
                    reader_.getUrl()
362
0
                     + ": element has empty \"constructor\" attribute");
363
0
            }
364
93.7k
            if (attrEnvironment_.isEmpty()) {
365
0
                throw css::registry::InvalidRegistryException(
366
0
                    reader_.getUrl()
367
0
                     + ": <implementation> has \"constructor\" attribute but"
368
0
                        " <component> has no \"environment\" attribute");
369
0
            }
370
93.7k
        } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
371
7.02k
                   && name.equals(RTL_CONSTASCII_STRINGPARAM("single-instance")))
372
7.02k
        {
373
7.02k
            if (attrSingleInstance) {
374
0
                throw css::registry::InvalidRegistryException(
375
0
                    reader_.getUrl()
376
0
                    + ": <implementation> has multiple \"single-instance\" attributes");
377
0
            }
378
7.02k
            if (!reader_.getAttributeValue(false).equals(RTL_CONSTASCII_STRINGPARAM("true"))) {
379
0
                throw css::registry::InvalidRegistryException(
380
0
                    reader_.getUrl() + ": <implementation> has bad \"single-instance\" attribute");
381
0
            }
382
7.02k
            attrSingleInstance = true;
383
7.02k
        } else {
384
0
            throw css::registry::InvalidRegistryException(
385
0
                reader_.getUrl() + ": unexpected element attribute \""
386
0
                 + name.convertFromUtf8() + "\" in <implementation>");
387
0
        }
388
196k
    }
389
96.0k
    if (attrName.isEmpty()) {
390
0
        throw css::registry::InvalidRegistryException(
391
0
            reader_.getUrl()
392
0
             + ": <implementation> is missing \"name\" attribute");
393
0
    }
394
96.0k
    implementation_ =
395
96.0k
        std::make_shared<cppuhelper::ServiceManager::Data::Implementation>(
396
96.0k
            attrName, attrLoader_, attrUri_, attrEnvironment_, attrConstructor,
397
96.0k
            attrPrefix_, attrSingleInstance, alienContext_, reader_.getUrl());
398
96.0k
    if (!data_->namedImplementations.emplace(attrName, implementation_).
399
96.0k
        second)
400
0
    {
401
0
        throw css::registry::InvalidRegistryException(
402
0
            reader_.getUrl() + ": duplicate <implementation name=\"" + attrName
403
0
             + "\">");
404
0
    }
405
96.0k
}
406
407
125k
void Parser::handleService() {
408
125k
    OUString name(getNameAttribute());
409
125k
    implementation_->services.push_back(name);
410
125k
    data_->services[name].push_back(implementation_);
411
125k
}
412
413
3.24k
void Parser::handleSingleton() {
414
3.24k
    OUString name(getNameAttribute());
415
3.24k
    implementation_->singletons.push_back(name);
416
3.24k
    data_->singletons[name].push_back(implementation_);
417
3.24k
}
418
419
129k
OUString Parser::getNameAttribute() {
420
129k
    OUString attrName;
421
129k
    xmlreader::Span name;
422
129k
    int nsId;
423
258k
    while (reader_.nextAttribute(&nsId, &name)) {
424
129k
        if (nsId != xmlreader::XmlReader::NAMESPACE_NONE
425
129k
            || !name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
426
0
        {
427
0
            throw css::registry::InvalidRegistryException(
428
0
                reader_.getUrl() + ": expected element attribute \"name\"");
429
0
        }
430
129k
        if (!attrName.isEmpty()) {
431
0
            throw css::registry::InvalidRegistryException(
432
0
                reader_.getUrl()
433
0
                 + ": element has multiple \"name\" attributes");
434
0
        }
435
129k
        attrName = reader_.getAttributeValue(false).convertFromUtf8();
436
129k
        if (attrName.isEmpty()) {
437
0
            throw css::registry::InvalidRegistryException(
438
0
                reader_.getUrl() + ": element has empty \"name\" attribute");
439
0
        }
440
129k
    }
441
129k
    if (attrName.isEmpty()) {
442
0
        throw css::registry::InvalidRegistryException(
443
0
            reader_.getUrl() + ": element is missing \"name\" attribute");
444
0
    }
445
129k
    return attrName;
446
129k
}
447
448
class ContentEnumeration:
449
    public cppu::WeakImplHelper< css::container::XEnumeration >
450
{
451
public:
452
    explicit ContentEnumeration(std::vector< css::uno::Any >&& factories):
453
13
        factories_(std::move(factories)), iterator_(factories_.begin()) {}
454
455
    ContentEnumeration(const ContentEnumeration&) = delete;
456
    const ContentEnumeration& operator=(const ContentEnumeration&) = delete;
457
458
private:
459
13
    virtual ~ContentEnumeration() override {}
460
461
    virtual sal_Bool SAL_CALL hasMoreElements() override;
462
463
    virtual css::uno::Any SAL_CALL nextElement() override;
464
465
    std::mutex mutex_;
466
    std::vector< css::uno::Any > factories_;
467
    std::vector< css::uno::Any >::const_iterator iterator_;
468
};
469
470
sal_Bool ContentEnumeration::hasMoreElements()
471
45
{
472
45
    std::scoped_lock g(mutex_);
473
45
    return iterator_ != factories_.end();
474
45
}
475
476
css::uno::Any ContentEnumeration::nextElement()
477
32
{
478
32
    std::scoped_lock g(mutex_);
479
32
    if (iterator_ == factories_.end()) {
480
0
        throw css::container::NoSuchElementException(
481
0
            u"Bootstrap service manager service enumerator has no more elements"_ustr,
482
0
            static_cast< cppu::OWeakObject * >(this));
483
0
    }
484
32
    return *iterator_++;
485
32
}
486
487
0
css::beans::Property getDefaultContextProperty() {
488
0
    return css::beans::Property(
489
0
        u"DefaultContext"_ustr, -1,
490
0
        cppu::UnoType< css::uno::XComponentContext >::get(),
491
0
        css::beans::PropertyAttribute::READONLY);
492
0
}
493
494
class SingletonFactory:
495
    public cppu::WeakImplHelper<css::lang::XSingleComponentFactory>
496
{
497
public:
498
    SingletonFactory(
499
        rtl::Reference< cppuhelper::ServiceManager > const & manager,
500
        std::shared_ptr<
501
            cppuhelper::ServiceManager::Data::Implementation > const &
502
            implementation):
503
3.24k
        manager_(manager), implementation_(implementation)
504
3.24k
    { assert(manager.is()); assert(implementation); }
505
506
    SingletonFactory(const SingletonFactory&) = delete;
507
    const SingletonFactory& operator=(const SingletonFactory&) = delete;
508
509
private:
510
0
    virtual ~SingletonFactory() override {}
511
512
    virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
513
    createInstanceWithContext(
514
        css::uno::Reference< css::uno::XComponentContext > const & Context) override;
515
516
    virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
517
    createInstanceWithArgumentsAndContext(
518
        css::uno::Sequence< css::uno::Any > const & Arguments,
519
        css::uno::Reference< css::uno::XComponentContext > const & Context) override;
520
521
    rtl::Reference< cppuhelper::ServiceManager > manager_;
522
    std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
523
        implementation_;
524
};
525
526
css::uno::Reference< css::uno::XInterface >
527
SingletonFactory::createInstanceWithContext(
528
    css::uno::Reference< css::uno::XComponentContext > const & Context)
529
57
{
530
57
    manager_->loadImplementation(Context, implementation_);
531
57
    return implementation_->createInstance(Context, true);
532
57
}
533
534
css::uno::Reference< css::uno::XInterface >
535
SingletonFactory::createInstanceWithArgumentsAndContext(
536
    css::uno::Sequence< css::uno::Any > const & Arguments,
537
    css::uno::Reference< css::uno::XComponentContext > const & Context)
538
0
{
539
0
    manager_->loadImplementation(Context, implementation_);
540
0
    return implementation_->createInstanceWithArguments(
541
0
        Context, true, Arguments);
542
0
}
543
544
class ImplementationWrapper:
545
    public cppu::WeakImplHelper<
546
        css::lang::XSingleComponentFactory, css::lang::XSingleServiceFactory,
547
        css::lang::XServiceInfo >
548
{
549
public:
550
    ImplementationWrapper(
551
        rtl::Reference< cppuhelper::ServiceManager > const & manager,
552
        std::shared_ptr<
553
            cppuhelper::ServiceManager::Data::Implementation > const &
554
            implementation):
555
32
        manager_(manager), implementation_(implementation)
556
32
    { assert(manager.is()); assert(implementation); }
557
558
    ImplementationWrapper(const ImplementationWrapper&) = delete;
559
    const ImplementationWrapper& operator=(const ImplementationWrapper&) = delete;
560
561
private:
562
17
    virtual ~ImplementationWrapper() override {}
563
564
    virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
565
    createInstanceWithContext(
566
        css::uno::Reference< css::uno::XComponentContext > const & Context) override;
567
568
    virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
569
    createInstanceWithArgumentsAndContext(
570
        css::uno::Sequence< css::uno::Any > const & Arguments,
571
        css::uno::Reference< css::uno::XComponentContext > const & Context) override;
572
573
    virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
574
    createInstance() override;
575
576
    virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
577
    createInstanceWithArguments(
578
        css::uno::Sequence< css::uno::Any > const & Arguments) override;
579
580
    virtual OUString SAL_CALL getImplementationName() override;
581
582
    virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
583
584
    virtual css::uno::Sequence< OUString > SAL_CALL
585
    getSupportedServiceNames() override;
586
587
    rtl::Reference< cppuhelper::ServiceManager > manager_;
588
    std::weak_ptr< cppuhelper::ServiceManager::Data::Implementation >
589
        implementation_;
590
};
591
592
css::uno::Reference< css::uno::XInterface >
593
ImplementationWrapper::createInstanceWithContext(
594
    css::uno::Reference< css::uno::XComponentContext > const & Context)
595
27
{
596
27
    std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
597
27
    assert(impl);
598
27
    manager_->loadImplementation(Context, impl);
599
27
    return impl->createInstance(Context, false);
600
27
}
601
602
css::uno::Reference< css::uno::XInterface >
603
ImplementationWrapper::createInstanceWithArgumentsAndContext(
604
    css::uno::Sequence< css::uno::Any > const & Arguments,
605
    css::uno::Reference< css::uno::XComponentContext > const & Context)
606
0
{
607
0
    std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
608
0
    assert(impl);
609
0
    manager_->loadImplementation(Context, impl);
610
0
    return impl->createInstanceWithArguments(
611
0
        Context, false, Arguments);
612
0
}
613
614
css::uno::Reference< css::uno::XInterface >
615
ImplementationWrapper::createInstance()
616
0
{
617
0
    return createInstanceWithContext(manager_->getContext());
618
0
}
619
620
css::uno::Reference< css::uno::XInterface >
621
ImplementationWrapper::createInstanceWithArguments(
622
    css::uno::Sequence< css::uno::Any > const & Arguments)
623
0
{
624
0
    return createInstanceWithArgumentsAndContext(
625
0
        Arguments, manager_->getContext());
626
0
}
627
628
OUString ImplementationWrapper::getImplementationName()
629
6
{
630
6
    std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
631
6
    assert(impl);
632
6
    return impl->name;
633
6
}
634
635
sal_Bool ImplementationWrapper::supportsService(OUString const & ServiceName)
636
0
{
637
0
    return cppu::supportsService(this, ServiceName);
638
0
}
639
640
css::uno::Sequence< OUString >
641
ImplementationWrapper::getSupportedServiceNames()
642
0
{
643
0
    std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
644
0
    assert(impl);
645
0
    if (impl->services.size()
646
0
        > o3tl::make_unsigned(SAL_MAX_INT32))
647
0
    {
648
0
        throw css::uno::RuntimeException(
649
0
            ("Implementation " + impl->name
650
0
             + " supports too many services"),
651
0
            static_cast< cppu::OWeakObject * >(this));
652
0
    }
653
0
    return comphelper::containerToSequence(impl->services);
654
0
}
655
656
}
657
658
css::uno::Reference<css::uno::XInterface>
659
cppuhelper::ServiceManager::Data::Implementation::createInstance(
660
    css::uno::Reference<css::uno::XComponentContext> const & context,
661
    bool singletonRequest)
662
20.4M
{
663
20.4M
    css::uno::Reference<css::uno::XInterface> inst;
664
20.4M
    if (isSingleInstance) {
665
15.3M
        std::unique_lock g(mutex);
666
15.3M
        if (!singleInstance.is()) {
667
50.2k
            singleInstance = doCreateInstance(context);
668
50.2k
        }
669
15.3M
        inst = singleInstance;
670
15.3M
    } else {
671
5.06M
        inst = doCreateInstance(context);
672
5.06M
    }
673
20.4M
    updateDisposeInstance(singletonRequest, inst);
674
20.4M
    return inst;
675
20.4M
}
676
677
css::uno::Reference<css::uno::XInterface>
678
cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments(
679
    css::uno::Reference<css::uno::XComponentContext> const & context,
680
    bool singletonRequest, css::uno::Sequence<css::uno::Any> const & arguments)
681
950k
{
682
950k
    css::uno::Reference<css::uno::XInterface> inst;
683
950k
    if (isSingleInstance) {
684
232k
        std::unique_lock g(mutex);
685
232k
        if (!singleInstance.is()) {
686
9
            singleInstance = doCreateInstanceWithArguments(context, arguments);
687
9
        }
688
232k
        inst = singleInstance;
689
718k
    } else {
690
718k
        inst = doCreateInstanceWithArguments(context, arguments);
691
718k
    }
692
950k
    updateDisposeInstance(singletonRequest, inst);
693
950k
    return inst;
694
950k
}
695
696
css::uno::Reference<css::uno::XInterface>
697
cppuhelper::ServiceManager::Data::Implementation::doCreateInstance(
698
    css::uno::Reference<css::uno::XComponentContext> const & context)
699
5.11M
{
700
5.11M
    if (constructorFn) {
701
5.11M
        return css::uno::Reference<css::uno::XInterface>(
702
5.11M
            constructorFn(context.get(), css::uno::Sequence<css::uno::Any>()),
703
5.11M
            SAL_NO_ACQUIRE);
704
5.11M
    } else if (factory1.is()) {
705
0
        return factory1->createInstanceWithContext(context);
706
0
    } else {
707
0
        assert(factory2.is());
708
0
        return factory2->createInstance();
709
0
    }
710
5.11M
}
711
712
css::uno::Reference<css::uno::XInterface>
713
cppuhelper::ServiceManager::Data::Implementation::doCreateInstanceWithArguments(
714
    css::uno::Reference<css::uno::XComponentContext> const & context,
715
    css::uno::Sequence<css::uno::Any> const & arguments)
716
718k
{
717
718k
    if (constructorFn) {
718
718k
        css::uno::Reference<css::uno::XInterface> inst(
719
718k
            constructorFn(context.get(), arguments), SAL_NO_ACQUIRE);
720
        //HACK: The constructor will either observe arguments and return inst
721
        // that does not implement XInitialization (or null), or ignore
722
        // arguments and return inst that implements XInitialization; this
723
        // should be removed again once XInitialization-based implementations
724
        // have become rare:
725
718k
        css::uno::Reference<css::lang::XInitialization> init(
726
718k
            inst, css::uno::UNO_QUERY);
727
718k
        if (init.is()) {
728
652k
            init->initialize(arguments);
729
652k
        }
730
718k
        return inst;
731
718k
    } else if (factory1.is()) {
732
0
        return factory1->createInstanceWithArgumentsAndContext(
733
0
            arguments, context);
734
0
    } else {
735
0
        assert(factory2.is());
736
0
        return factory2->createInstanceWithArguments(arguments);
737
0
    }
738
718k
}
739
740
void cppuhelper::ServiceManager::Data::Implementation::updateDisposeInstance(
741
    bool singletonRequest,
742
    css::uno::Reference<css::uno::XInterface> const & instance)
743
21.3M
{
744
    // This is an optimization, to only call dispose once (from the component
745
    // context) on a singleton that is obtained both via the component context
746
    // and via the service manager; however, there is a harmless race here that
747
    // may cause two calls to dispose nevertheless (also, this calls dispose on
748
    // at most one of the instances obtained via the service manager, in case
749
    // the implementation hands out different instances):
750
21.3M
    if (singletonRequest) {
751
43
        std::unique_lock g(mutex);
752
43
        disposeInstance.clear();
753
43
        dispose = false;
754
21.3M
    } else if (shallDispose()) {
755
15.6M
        css::uno::Reference<css::lang::XComponent> comp(
756
15.6M
            instance, css::uno::UNO_QUERY);
757
15.6M
        if (comp.is()) {
758
277k
            std::unique_lock g(mutex);
759
277k
            if (dispose) {
760
277k
                disposeInstance = std::move(comp);
761
277k
            }
762
277k
        }
763
15.6M
    }
764
21.3M
}
765
766
void cppuhelper::ServiceManager::addSingletonContextEntries(
767
    std::vector< cppu::ContextEntry_Init > * entries)
768
108
{
769
108
    assert(entries != nullptr);
770
108
    for (const auto& [rName, rImpls] : data_.singletons)
771
3.24k
    {
772
3.24k
        assert(!rImpls.empty());
773
3.24k
        assert(rImpls[0]);
774
3.24k
        SAL_INFO_IF(
775
3.24k
            rImpls.size() > 1, "cppuhelper",
776
3.24k
            "Arbitrarily choosing " << rImpls[0]->name
777
3.24k
                << " among multiple implementations for " << rName);
778
3.24k
        entries->push_back(
779
3.24k
            cppu::ContextEntry_Init(
780
3.24k
                "/singletons/" + rName,
781
3.24k
                css::uno::Any(
782
3.24k
                    css::uno::Reference<css::lang::XSingleComponentFactory>(
783
3.24k
                        new SingletonFactory(this, rImpls[0]))),
784
3.24k
                true));
785
3.24k
    }
786
108
}
787
788
void cppuhelper::ServiceManager::loadImplementation(
789
        css::uno::Reference< css::uno::XComponentContext > const & context,
790
        std::shared_ptr< Data::Implementation > const & implementation)
791
279k
{
792
279k
    assert(implementation);
793
279k
    {
794
279k
        std::unique_lock g(m_aMutex);
795
279k
        if (implementation->status == Data::Implementation::STATUS_LOADED) {
796
0
            return;
797
0
        }
798
279k
    }
799
279k
    OUString uri;
800
279k
    try {
801
279k
        uri = cppu::bootstrap_expandUri(implementation->uri);
802
279k
    } catch (css::lang::IllegalArgumentException & e) {
803
0
        throw css::uno::DeploymentException(
804
0
            "Cannot expand URI" + implementation->uri + ": " + e.Message,
805
0
            static_cast< cppu::OWeakObject * >(this));
806
0
    }
807
279k
    cppuhelper::WrapperConstructorFn ctor;
808
279k
    css::uno::Reference< css::uno::XInterface > f0;
809
    // Special handling of SharedLibrary loader, with support for environment,
810
    // constructor, and prefix arguments:
811
279k
    if (!implementation->alienContext.is()
812
279k
        && implementation->loader == "com.sun.star.loader.SharedLibrary")
813
279k
    {
814
279k
        cppuhelper::detail::loadSharedLibComponentFactory(
815
279k
            uri, implementation->environment,
816
279k
            implementation->prefix, implementation->name,
817
279k
            implementation->constructorName, this, &ctor, &f0);
818
279k
        if (ctor) {
819
690
            assert(!implementation->environment.isEmpty());
820
690
        }
821
279k
    } else {
822
0
        SAL_WARN_IF(
823
0
            !implementation->environment.isEmpty(), "cppuhelper",
824
0
            "Loader " << implementation->loader
825
0
                << " and non-empty environment "
826
0
                << implementation->environment);
827
0
        SAL_WARN_IF(
828
0
            !implementation->prefix.isEmpty(), "cppuhelper",
829
0
            "Loader " << implementation->loader
830
0
                << " and non-empty constructor "
831
0
                << implementation->constructorName);
832
0
        SAL_WARN_IF(
833
0
            !implementation->prefix.isEmpty(), "cppuhelper",
834
0
            "Loader " << implementation->loader
835
0
                << " and non-empty prefix " << implementation->prefix);
836
0
        css::uno::Reference< css::uno::XComponentContext > ctxt;
837
0
        css::uno::Reference< css::lang::XMultiComponentFactory > smgr;
838
0
        if (implementation->alienContext.is()) {
839
0
            ctxt = implementation->alienContext;
840
0
            smgr.set(ctxt->getServiceManager(), css::uno::UNO_SET_THROW);
841
0
        } else {
842
0
            assert(context.is());
843
0
            ctxt = context;
844
0
            smgr = this;
845
0
        }
846
0
        css::uno::Reference< css::loader::XImplementationLoader > loader(
847
0
            smgr->createInstanceWithContext(implementation->loader, ctxt),
848
0
            css::uno::UNO_QUERY_THROW);
849
0
        f0 = loader->activate(
850
0
            implementation->name, OUString(), uri,
851
0
            css::uno::Reference< css::registry::XRegistryKey >());
852
0
    }
853
279k
    css::uno::Reference<css::lang::XSingleComponentFactory> f1;
854
279k
    css::uno::Reference<css::lang::XSingleServiceFactory> f2;
855
279k
    if (!ctor) {
856
0
        f1.set(f0, css::uno::UNO_QUERY);
857
0
        if (!f1.is()) {
858
0
            f2.set(f0, css::uno::UNO_QUERY);
859
0
            if (!f2.is()) {
860
0
                throw css::uno::DeploymentException(
861
0
                    ("Implementation " + implementation->name
862
0
                     + " does not provide a constructor or factory"),
863
0
                    static_cast< cppu::OWeakObject * >(this));
864
0
            }
865
0
        }
866
0
    }
867
    //TODO: There is a race here, as the relevant service factory can be removed
868
    // while the mutex is unlocked and loading can thus fail, as the entity from
869
    // which to load can disappear once the service factory is removed.
870
279k
    std::unique_lock g(m_aMutex);
871
279k
    if (!(m_bDisposed
872
690
          || implementation->status == Data::Implementation::STATUS_LOADED))
873
690
    {
874
690
        implementation->status = Data::Implementation::STATUS_LOADED;
875
690
        implementation->constructorFn = std::move(ctor);
876
690
        implementation->factory1 = std::move(f1);
877
690
        implementation->factory2 = std::move(f2);
878
690
    }
879
279k
}
880
881
0
void cppuhelper::ServiceManager::disposing(std::unique_lock<std::mutex>& rGuard) {
882
0
    std::vector< css::uno::Reference<css::lang::XComponent> > sngls;
883
0
    std::vector< css::uno::Reference< css::lang::XComponent > > comps;
884
0
    Data clear;
885
0
    {
886
0
        for (const auto& rEntry : data_.namedImplementations)
887
0
        {
888
0
            assert(rEntry.second);
889
0
            if (rEntry.second->shallDispose()) {
890
0
                std::unique_lock g2(rEntry.second->mutex);
891
0
                if (rEntry.second->disposeInstance.is()) {
892
0
                    sngls.push_back(rEntry.second->disposeInstance);
893
0
                }
894
0
            }
895
0
        }
896
0
        for (const auto& rEntry : data_.dynamicImplementations)
897
0
        {
898
0
            assert(rEntry.second);
899
0
            if (rEntry.second->shallDispose()) {
900
0
                std::unique_lock g2(rEntry.second->mutex);
901
0
                if (rEntry.second->disposeInstance.is()) {
902
0
                    sngls.push_back(rEntry.second->disposeInstance);
903
0
                }
904
0
            }
905
0
            if (rEntry.second->component.is()) {
906
0
                comps.push_back(rEntry.second->component);
907
0
            }
908
0
        }
909
0
        data_.namedImplementations.swap(clear.namedImplementations);
910
0
        data_.dynamicImplementations.swap(clear.dynamicImplementations);
911
0
        data_.services.swap(clear.services);
912
0
        data_.singletons.swap(clear.singletons);
913
0
    }
914
0
    rGuard.unlock();
915
0
    for (const auto& rxSngl : sngls)
916
0
    {
917
0
        try {
918
0
            rxSngl->dispose();
919
0
        } catch (css::uno::RuntimeException & e) {
920
0
            SAL_WARN("cppuhelper", "Ignoring " << e << " while disposing singleton");
921
0
        }
922
0
    }
923
0
    for (const auto& rxComp : comps)
924
0
    {
925
0
        removeEventListenerFromComponent(rxComp);
926
0
    }
927
0
    rGuard.lock();
928
0
}
929
930
void cppuhelper::ServiceManager::initialize(
931
    css::uno::Sequence<css::uno::Any> const & aArguments)
932
0
{
933
0
    OUString arg;
934
0
    if (aArguments.getLength() != 1 || !(aArguments[0] >>= arg)
935
0
        || arg != "preload")
936
0
    {
937
0
        throw css::lang::IllegalArgumentException(
938
0
            u"invalid ServiceManager::initialize argument"_ustr,
939
0
            css::uno::Reference<css::uno::XInterface>(), 0);
940
0
    }
941
0
    preloadImplementations();
942
0
}
943
944
OUString cppuhelper::ServiceManager::getImplementationName()
945
0
{
946
0
    return
947
0
        u"com.sun.star.comp.cppuhelper.bootstrap.ServiceManager"_ustr;
948
0
}
949
950
sal_Bool cppuhelper::ServiceManager::supportsService(
951
    OUString const & ServiceName)
952
0
{
953
0
    return cppu::supportsService(this, ServiceName);
954
0
}
955
956
css::uno::Sequence< OUString >
957
cppuhelper::ServiceManager::getSupportedServiceNames()
958
0
{
959
0
    return { u"com.sun.star.lang.MultiServiceFactory"_ustr, u"com.sun.star.lang.ServiceManager"_ustr };
960
0
}
961
962
css::uno::Reference< css::uno::XInterface >
963
cppuhelper::ServiceManager::createInstance(
964
    OUString const & aServiceSpecifier)
965
154k
{
966
154k
    assert(context_.is());
967
154k
    return createInstanceWithContext(aServiceSpecifier, context_);
968
154k
}
969
970
css::uno::Reference< css::uno::XInterface >
971
cppuhelper::ServiceManager::createInstanceWithArguments(
972
    OUString const & ServiceSpecifier,
973
    css::uno::Sequence< css::uno::Any > const & Arguments)
974
27.2k
{
975
27.2k
    assert(context_.is());
976
27.2k
    return createInstanceWithArgumentsAndContext(
977
27.2k
        ServiceSpecifier, Arguments, context_);
978
27.2k
}
979
980
css::uno::Sequence< OUString >
981
cppuhelper::ServiceManager::getAvailableServiceNames()
982
0
{
983
0
    std::unique_lock g(m_aMutex);
984
0
    if (m_bDisposed) {
985
0
        return css::uno::Sequence< OUString >();
986
0
    }
987
0
    if (data_.services.size() > o3tl::make_unsigned(SAL_MAX_INT32)) {
988
0
        throw css::uno::RuntimeException(
989
0
            u"getAvailableServiceNames: too many services"_ustr,
990
0
            static_cast< cppu::OWeakObject * >(this));
991
0
    }
992
0
    return comphelper::mapKeysToSequence(data_.services);
993
0
}
994
995
css::uno::Reference< css::uno::XInterface >
996
cppuhelper::ServiceManager::createInstanceWithContext(
997
    OUString const & aServiceSpecifier,
998
    css::uno::Reference< css::uno::XComponentContext > const & Context)
999
22.7M
{
1000
22.7M
    std::shared_ptr< Data::Implementation > impl(
1001
22.7M
        findServiceImplementation(Context, aServiceSpecifier));
1002
22.7M
    return impl == nullptr ? css::uno::Reference<css::uno::XInterface>()
1003
22.7M
                           : impl->createInstance(Context, false);
1004
22.7M
}
1005
1006
css::uno::Reference< css::uno::XInterface >
1007
cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext(
1008
    OUString const & ServiceSpecifier,
1009
    css::uno::Sequence< css::uno::Any > const & Arguments,
1010
    css::uno::Reference< css::uno::XComponentContext > const & Context)
1011
1.01M
{
1012
1.01M
    std::shared_ptr< Data::Implementation > impl(
1013
1.01M
        findServiceImplementation(Context, ServiceSpecifier));
1014
1.01M
    return impl == nullptr ? css::uno::Reference<css::uno::XInterface>()
1015
1.01M
                           : impl->createInstanceWithArguments(Context, false, Arguments);
1016
1.01M
}
1017
1018
css::uno::Type cppuhelper::ServiceManager::getElementType()
1019
0
{
1020
0
    return css::uno::Type();
1021
0
}
1022
1023
sal_Bool cppuhelper::ServiceManager::hasElements()
1024
0
{
1025
0
    std::unique_lock g(m_aMutex);
1026
0
    return
1027
0
        !(data_.namedImplementations.empty()
1028
0
          && data_.dynamicImplementations.empty());
1029
0
}
1030
1031
css::uno::Reference< css::container::XEnumeration >
1032
cppuhelper::ServiceManager::createEnumeration()
1033
0
{
1034
0
    throw css::uno::RuntimeException(
1035
0
        u"ServiceManager createEnumeration: method not supported"_ustr,
1036
0
        static_cast< cppu::OWeakObject * >(this));
1037
0
}
1038
1039
sal_Bool cppuhelper::ServiceManager::has(css::uno::Any const &)
1040
0
{
1041
0
    throw css::uno::RuntimeException(
1042
0
        u"ServiceManager has: method not supported"_ustr,
1043
0
        static_cast< cppu::OWeakObject * >(this));
1044
0
}
1045
1046
void cppuhelper::ServiceManager::insert(css::uno::Any const & aElement)
1047
156
{
1048
156
    css::uno::Sequence< css::beans::NamedValue > args;
1049
156
    if (aElement >>= args) {
1050
0
        std::vector< OUString > uris;
1051
0
        css::uno::Reference< css::uno::XComponentContext > alienContext;
1052
0
        for (const auto & arg : args) {
1053
0
            if (arg.Name == "uri") {
1054
0
                OUString uri;
1055
0
                if (!(arg.Value >>= uri)) {
1056
0
                    throw css::lang::IllegalArgumentException(
1057
0
                        u"Bad uri argument"_ustr,
1058
0
                        static_cast< cppu::OWeakObject * >(this), 0);
1059
0
                }
1060
0
                uris.push_back(uri);
1061
0
            } else if (arg.Name == "component-context") {
1062
0
                if (alienContext.is()) {
1063
0
                    throw css::lang::IllegalArgumentException(
1064
0
                        u"Multiple component-context arguments"_ustr,
1065
0
                        static_cast< cppu::OWeakObject * >(this), 0);
1066
0
                }
1067
0
                if (!(arg.Value >>= alienContext) || !alienContext.is()) {
1068
0
                    throw css::lang::IllegalArgumentException(
1069
0
                        u"Bad component-context argument"_ustr,
1070
0
                        static_cast< cppu::OWeakObject * >(this), 0);
1071
0
                }
1072
0
            } else {
1073
0
                throw css::lang::IllegalArgumentException(
1074
0
                    "Bad argument " + arg.Name,
1075
0
                    static_cast< cppu::OWeakObject * >(this), 0);
1076
0
            }
1077
0
        }
1078
0
        insertRdbFiles(uris, alienContext);
1079
0
        return;
1080
0
    }
1081
156
    css::uno::Reference< css::lang::XServiceInfo > info;
1082
156
    if ((aElement >>= info) && info.is()) {
1083
156
        insertLegacyFactory(info);
1084
156
        return;
1085
156
    }
1086
1087
0
    throw css::lang::IllegalArgumentException(
1088
0
        u"Bad insert element"_ustr, static_cast< cppu::OWeakObject * >(this), 0);
1089
156
}
1090
1091
void cppuhelper::ServiceManager::remove(css::uno::Any const & aElement)
1092
0
{
1093
0
    css::uno::Sequence< css::beans::NamedValue > args;
1094
0
    if (aElement >>= args) {
1095
0
        std::vector< OUString > uris;
1096
0
        for (const auto & i : args) {
1097
0
            if (i.Name != "uri") {
1098
0
                throw css::lang::IllegalArgumentException(
1099
0
                    "Bad argument " + i.Name,
1100
0
                    static_cast< cppu::OWeakObject * >(this), 0);
1101
0
            }
1102
0
            OUString uri;
1103
0
            if (!(i.Value >>= uri)) {
1104
0
                throw css::lang::IllegalArgumentException(
1105
0
                    u"Bad uri argument"_ustr,
1106
0
                    static_cast< cppu::OWeakObject * >(this), 0);
1107
0
            }
1108
0
            uris.push_back(uri);
1109
0
        }
1110
0
        removeRdbFiles(uris);
1111
0
        return;
1112
0
    }
1113
0
    css::uno::Reference< css::lang::XServiceInfo > info;
1114
0
    if ((aElement >>= info) && info.is()) {
1115
0
        if (!removeLegacyFactory(info, true)) {
1116
0
            throw css::container::NoSuchElementException(
1117
0
                u"Remove non-inserted factory object"_ustr,
1118
0
                static_cast< cppu::OWeakObject * >(this));
1119
0
        }
1120
0
        return;
1121
0
    }
1122
0
    OUString impl;
1123
0
    if (aElement >>= impl) {
1124
        // For live-removal of extensions:
1125
0
        removeImplementation(impl);
1126
0
        return;
1127
0
    }
1128
0
    throw css::lang::IllegalArgumentException(
1129
0
        u"Bad remove element"_ustr, static_cast< cppu::OWeakObject * >(this), 0);
1130
0
}
1131
1132
css::uno::Reference< css::container::XEnumeration >
1133
cppuhelper::ServiceManager::createContentEnumeration(
1134
    OUString const & aServiceName)
1135
13
{
1136
13
    boost::container::small_vector< std::shared_ptr< Data::Implementation >, 2 > impls;
1137
13
    {
1138
13
        std::unique_lock g(m_aMutex);
1139
13
        Data::ImplementationMap::const_iterator i(
1140
13
            data_.services.find(aServiceName));
1141
13
        if (i != data_.services.end()) {
1142
11
            impls = i->second;
1143
11
        }
1144
13
    }
1145
13
    std::vector< css::uno::Any > factories;
1146
13
    for (const auto& rxImpl : impls)
1147
32
    {
1148
32
        Data::Implementation * impl = rxImpl.get();
1149
32
        assert(impl != nullptr);
1150
32
        {
1151
32
            std::unique_lock g(m_aMutex);
1152
32
            if (m_bDisposed) {
1153
0
                factories.clear();
1154
0
                break;
1155
0
            }
1156
32
            if (impl->status == Data::Implementation::STATUS_NEW) {
1157
                // Postpone actual implementation instantiation as long as
1158
                // possible (so that e.g. opening LO's "Tools - Macros" menu
1159
                // does not try to instantiate a JVM, which can lead to a
1160
                // synchronous error dialog when no JVM is specified, and
1161
                // showing the dialog while hovering over a menu can cause
1162
                // trouble):
1163
32
                impl->factory1 = new ImplementationWrapper(this, rxImpl);
1164
32
                impl->status = Data::Implementation::STATUS_WRAPPER;
1165
32
            }
1166
32
            if (impl->constructorFn != nullptr && !impl->factory1.is()) {
1167
0
                impl->factory1 = new ImplementationWrapper(this, rxImpl);
1168
0
            }
1169
32
        }
1170
32
        if (impl->factory1.is()) {
1171
32
            factories.push_back(css::uno::Any(impl->factory1));
1172
32
        } else {
1173
0
            assert(impl->factory2.is());
1174
0
            factories.push_back(css::uno::Any(impl->factory2));
1175
0
        }
1176
32
    }
1177
13
    return new ContentEnumeration(std::move(factories));
1178
13
}
1179
1180
css::uno::Reference< css::beans::XPropertySetInfo >
1181
cppuhelper::ServiceManager::getPropertySetInfo()
1182
0
{
1183
0
    return this;
1184
0
}
1185
1186
void cppuhelper::ServiceManager::setPropertyValue(
1187
    OUString const & aPropertyName, css::uno::Any const &)
1188
0
{
1189
0
    if (aPropertyName == "DefaultContext") {
1190
0
        throw css::beans::PropertyVetoException(
1191
0
            aPropertyName, static_cast< cppu::OWeakObject * >(this));
1192
0
    } else {
1193
0
        throw css::beans::UnknownPropertyException(
1194
0
            aPropertyName, static_cast< cppu::OWeakObject * >(this));
1195
0
    }
1196
0
}
1197
1198
css::uno::Any cppuhelper::ServiceManager::getPropertyValue(
1199
    OUString const & PropertyName)
1200
61
{
1201
61
    if (PropertyName != "DefaultContext") {
1202
0
        throw css::beans::UnknownPropertyException(
1203
0
            PropertyName, static_cast< cppu::OWeakObject * >(this));
1204
0
    }
1205
61
    assert(context_.is());
1206
61
    return css::uno::Any(context_);
1207
61
}
1208
1209
void cppuhelper::ServiceManager::addPropertyChangeListener(
1210
    OUString const & aPropertyName,
1211
    css::uno::Reference< css::beans::XPropertyChangeListener > const &
1212
        xListener)
1213
0
{
1214
0
    if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1215
0
        throw css::beans::UnknownPropertyException(
1216
0
            aPropertyName, static_cast< cppu::OWeakObject * >(this));
1217
0
    }
1218
    // DefaultContext does not change, so just treat it as an event listener:
1219
0
    return addEventListener(xListener);
1220
0
}
1221
1222
void cppuhelper::ServiceManager::removePropertyChangeListener(
1223
    OUString const & aPropertyName,
1224
    css::uno::Reference< css::beans::XPropertyChangeListener > const &
1225
        aListener)
1226
0
{
1227
0
    if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1228
0
        throw css::beans::UnknownPropertyException(
1229
0
            aPropertyName, static_cast< cppu::OWeakObject * >(this));
1230
0
    }
1231
    // DefaultContext does not change, so just treat it as an event listener:
1232
0
    return removeEventListener(aListener);
1233
0
}
1234
1235
void cppuhelper::ServiceManager::addVetoableChangeListener(
1236
    OUString const & PropertyName,
1237
    css::uno::Reference< css::beans::XVetoableChangeListener > const &
1238
        aListener)
1239
0
{
1240
0
    if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1241
0
        throw css::beans::UnknownPropertyException(
1242
0
            PropertyName, static_cast< cppu::OWeakObject * >(this));
1243
0
    }
1244
    // DefaultContext does not change, so just treat it as an event listener:
1245
0
    return addEventListener(aListener);
1246
0
}
1247
1248
void cppuhelper::ServiceManager::removeVetoableChangeListener(
1249
    OUString const & PropertyName,
1250
    css::uno::Reference< css::beans::XVetoableChangeListener > const &
1251
        aListener)
1252
0
{
1253
0
    if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1254
0
        throw css::beans::UnknownPropertyException(
1255
0
            PropertyName, static_cast< cppu::OWeakObject * >(this));
1256
0
    }
1257
    // DefaultContext does not change, so just treat it as an event listener:
1258
0
    return removeEventListener(aListener);
1259
0
}
1260
1261
css::uno::Sequence< css::beans::Property >
1262
0
cppuhelper::ServiceManager::getProperties() {
1263
0
    return { getDefaultContextProperty() };
1264
0
}
1265
1266
css::beans::Property cppuhelper::ServiceManager::getPropertyByName(
1267
    OUString const & aName)
1268
0
{
1269
0
    if (aName != "DefaultContext") {
1270
0
        throw css::beans::UnknownPropertyException(
1271
0
            aName, static_cast< cppu::OWeakObject * >(this));
1272
0
    }
1273
0
    return getDefaultContextProperty();
1274
0
}
1275
1276
sal_Bool cppuhelper::ServiceManager::hasPropertyByName(
1277
    OUString const & Name)
1278
0
{
1279
0
    return Name == "DefaultContext";
1280
0
}
1281
1282
0
cppuhelper::ServiceManager::~ServiceManager() {}
1283
1284
void cppuhelper::ServiceManager::disposing(
1285
    css::lang::EventObject const & Source)
1286
0
{
1287
0
    removeLegacyFactory(
1288
0
        css::uno::Reference< css::lang::XServiceInfo >(
1289
0
            Source.Source, css::uno::UNO_QUERY_THROW),
1290
0
        false);
1291
0
}
1292
1293
void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1294
    css::uno::Reference< css::lang::XComponent > const & component)
1295
0
{
1296
0
    assert(component.is());
1297
0
    try {
1298
0
        component->removeEventListener(this);
1299
0
    } catch (css::uno::RuntimeException & e) {
1300
0
        SAL_INFO(
1301
0
            "cppuhelper",
1302
0
            "Ignored removeEventListener RuntimeException " + e.Message);
1303
0
    }
1304
0
}
1305
1306
108
void cppuhelper::ServiceManager::init(std::u16string_view rdbUris) {
1307
216
    for (sal_Int32 i = 0; i != -1;) {
1308
108
        std::u16string_view uri(o3tl::getToken(rdbUris, 0, ' ', i));
1309
108
        if (uri.empty()) {
1310
0
            continue;
1311
0
        }
1312
108
        bool optional;
1313
108
        bool directory;
1314
108
        cppu::decodeRdbUri(&uri, &optional, &directory);
1315
108
        if (directory) {
1316
0
            readRdbDirectory(uri, optional);
1317
108
        } else {
1318
108
            readRdbFile(OUString(uri), optional);
1319
108
        }
1320
108
    }
1321
108
}
1322
1323
void cppuhelper::ServiceManager::readRdbDirectory(
1324
    std::u16string_view uri, bool optional)
1325
0
{
1326
0
    osl::Directory dir = OUString(uri);
1327
0
    switch (dir.open()) {
1328
0
    case osl::FileBase::E_None:
1329
0
        break;
1330
0
    case osl::FileBase::E_NOENT:
1331
0
        if (optional) {
1332
0
            SAL_INFO("cppuhelper", "Ignored optional " << OUString(uri));
1333
0
            return;
1334
0
        }
1335
0
        [[fallthrough]];
1336
0
    default:
1337
0
        throw css::uno::DeploymentException(
1338
0
            OUString::Concat("Cannot open directory ") + uri,
1339
0
            static_cast< cppu::OWeakObject * >(this));
1340
0
    }
1341
0
    for (;;) {
1342
0
        OUString url;
1343
0
        if (!cppu::nextDirectoryItem(dir, &url)) {
1344
0
            break;
1345
0
        }
1346
0
        readRdbFile(url, false);
1347
0
    }
1348
0
}
1349
1350
void cppuhelper::ServiceManager::readRdbFile(
1351
    OUString const & uri, bool optional)
1352
108
{
1353
108
    try {
1354
108
        Parser(
1355
108
            uri, css::uno::Reference< css::uno::XComponentContext >(), &data_);
1356
108
    } catch (css::container::NoSuchElementException &) {
1357
0
        if (!optional) {
1358
0
            throw css::uno::DeploymentException(
1359
0
                uri + ": no such file",
1360
0
                static_cast< cppu::OWeakObject * >(this));
1361
0
        }
1362
0
        SAL_INFO("cppuhelper", "Ignored optional " << uri);
1363
0
    }
1364
#if !ENABLE_FUZZERS
1365
    catch (css::registry::InvalidRegistryException & e) {
1366
        if (!readLegacyRdbFile(uri)) {
1367
            throw css::uno::DeploymentException(
1368
                "InvalidRegistryException: " + e.Message,
1369
                static_cast< cppu::OWeakObject * >(this));
1370
        }
1371
    } catch (css::uno::RuntimeException &) {
1372
        if (!readLegacyRdbFile(uri)) {
1373
            throw;
1374
        }
1375
    }
1376
#endif
1377
108
}
1378
1379
#if !ENABLE_FUZZERS
1380
bool cppuhelper::ServiceManager::readLegacyRdbFile(OUString const & uri) {
1381
    Registry reg;
1382
    switch (reg.open(uri, RegAccessMode::READONLY)) {
1383
    case RegError::NO_ERROR:
1384
        break;
1385
    case RegError::REGISTRY_NOT_EXISTS:
1386
    case RegError::INVALID_REGISTRY:
1387
        {
1388
            // Ignore empty rdb files (which are at least seen by subordinate
1389
            // uno processes during extension registration; Registry::open can
1390
            // fail on them if mmap(2) returns EINVAL for a zero length):
1391
            osl::DirectoryItem item;
1392
            if (osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None) {
1393
                osl::FileStatus status(osl_FileStatus_Mask_FileSize);
1394
                if (item.getFileStatus(status) == osl::FileBase::E_None
1395
                    && status.getFileSize() == 0)
1396
                {
1397
                    return true;
1398
                }
1399
            }
1400
        }
1401
        [[fallthrough]];
1402
    default:
1403
        return false;
1404
    }
1405
    RegistryKey rootKey;
1406
    if (reg.openRootKey(rootKey) != RegError::NO_ERROR) {
1407
        throw css::uno::DeploymentException(
1408
            "Failure reading legacy rdb file " + uri,
1409
            static_cast< cppu::OWeakObject * >(this));
1410
    }
1411
    RegistryKeyArray impls;
1412
    switch (rootKey.openSubKeys(u"IMPLEMENTATIONS"_ustr, impls)) {
1413
    case RegError::NO_ERROR:
1414
        break;
1415
    case RegError::KEY_NOT_EXISTS:
1416
        return true;
1417
    default:
1418
        throw css::uno::DeploymentException(
1419
            "Failure reading legacy rdb file " + uri,
1420
            static_cast< cppu::OWeakObject * >(this));
1421
    }
1422
    for (sal_uInt32 i = 0; i != impls.getLength(); ++i) {
1423
        RegistryKey implKey(impls.getElement(i));
1424
        assert(implKey.getName().match("/IMPLEMENTATIONS/"));
1425
        OUString name(
1426
            implKey.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1427
        std::shared_ptr< Data::Implementation > impl =
1428
            std::make_shared<Data::Implementation>(
1429
                name, readLegacyRdbString(uri, implKey, u"UNO/ACTIVATOR"_ustr),
1430
                readLegacyRdbString(uri, implKey, u"UNO/LOCATION"_ustr), "", "", "", false,
1431
                css::uno::Reference< css::uno::XComponentContext >(), uri);
1432
        if (!data_.namedImplementations.emplace(name, impl).second)
1433
        {
1434
            throw css::registry::InvalidRegistryException(
1435
                uri + ": duplicate <implementation name=\"" + name + "\">");
1436
        }
1437
        readLegacyRdbStrings(
1438
            uri, implKey, u"UNO/SERVICES"_ustr, &impl->services);
1439
        for (const auto& rService : impl->services)
1440
        {
1441
            data_.services[rService].push_back(impl);
1442
        }
1443
        readLegacyRdbStrings(
1444
            uri, implKey, u"UNO/SINGLETONS"_ustr, &impl->singletons);
1445
        for (const auto& rSingleton : impl->singletons)
1446
        {
1447
            data_.singletons[rSingleton].push_back(impl);
1448
        }
1449
    }
1450
    return true;
1451
}
1452
1453
OUString cppuhelper::ServiceManager::readLegacyRdbString(
1454
    std::u16string_view uri, RegistryKey & key, OUString const & path)
1455
{
1456
    RegistryKey subkey;
1457
    RegValueType t;
1458
    sal_uInt32 s(0);
1459
    if (key.openKey(path, subkey) != RegError::NO_ERROR
1460
        || subkey.getValueInfo(OUString(), &t, &s) != RegError::NO_ERROR
1461
        || t != RegValueType::STRING
1462
        || s == 0 || s > o3tl::make_unsigned(SAL_MAX_INT32))
1463
    {
1464
        throw css::uno::DeploymentException(
1465
            OUString::Concat("Failure reading legacy rdb file ") + uri,
1466
            static_cast< cppu::OWeakObject * >(this));
1467
    }
1468
    OUString val;
1469
    std::vector< char > v(s); // assuming sal_uInt32 fits into vector::size_type
1470
    assert(s > 0 && "throw above otherwise");
1471
    if (subkey.getValue(OUString(), v.data()) != RegError::NO_ERROR
1472
        || v.back() != '\0'
1473
        || !rtl_convertStringToUString(
1474
            &val.pData, v.data(), static_cast< sal_Int32 >(s - 1),
1475
            RTL_TEXTENCODING_UTF8,
1476
            (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1477
             | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1478
             | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
1479
    {
1480
        throw css::uno::DeploymentException(
1481
            OUString::Concat("Failure reading legacy rdb file ") + uri,
1482
            static_cast< cppu::OWeakObject * >(this));
1483
    }
1484
    return val;
1485
}
1486
1487
void cppuhelper::ServiceManager::readLegacyRdbStrings(
1488
    std::u16string_view uri, RegistryKey & key, OUString const & path,
1489
    std::vector< OUString > * strings)
1490
{
1491
    assert(strings != nullptr);
1492
    RegistryKey subkey;
1493
    switch (key.openKey(path, subkey)) {
1494
    case RegError::NO_ERROR:
1495
        break;
1496
    case RegError::KEY_NOT_EXISTS:
1497
        return;
1498
    default:
1499
        throw css::uno::DeploymentException(
1500
            OUString::Concat("Failure reading legacy rdb file ") + uri,
1501
            static_cast< cppu::OWeakObject * >(this));
1502
    }
1503
    OUString prefix(subkey.getName() + "/");
1504
    RegistryKeyNames names;
1505
    if (subkey.getKeyNames(OUString(), names) != RegError::NO_ERROR) {
1506
        throw css::uno::DeploymentException(
1507
            OUString::Concat("Failure reading legacy rdb file ") + uri,
1508
            static_cast< cppu::OWeakObject * >(this));
1509
    }
1510
    for (sal_uInt32 i = 0; i != names.getLength(); ++i) {
1511
        assert(names.getElement(i).match(prefix));
1512
        strings->push_back(names.getElement(i).copy(prefix.getLength()));
1513
    }
1514
}
1515
#endif
1516
1517
void cppuhelper::ServiceManager::insertRdbFiles(
1518
    std::vector< OUString > const & uris,
1519
    css::uno::Reference< css::uno::XComponentContext > const & alienContext)
1520
0
{
1521
0
    Data extra;
1522
0
    for (const auto& rUri : uris)
1523
0
    {
1524
0
        try {
1525
0
            Parser(rUri, alienContext, &extra);
1526
0
        } catch (css::container::NoSuchElementException &) {
1527
0
            throw css::lang::IllegalArgumentException(
1528
0
                rUri + ": no such file", static_cast< cppu::OWeakObject * >(this),
1529
0
                0);
1530
0
        } catch (css::registry::InvalidRegistryException & e) {
1531
0
            throw css::lang::IllegalArgumentException(
1532
0
                "InvalidRegistryException: " + e.Message,
1533
0
                static_cast< cppu::OWeakObject * >(this), 0);
1534
0
        }
1535
0
    }
1536
0
    insertExtraData(extra);
1537
0
}
1538
1539
void cppuhelper::ServiceManager::insertLegacyFactory(
1540
    css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo)
1541
156
{
1542
156
    assert(factoryInfo.is());
1543
156
    OUString name(factoryInfo->getImplementationName());
1544
156
    css::uno::Reference< css::lang::XSingleComponentFactory > f1(
1545
156
        factoryInfo, css::uno::UNO_QUERY);
1546
156
    css::uno::Reference< css::lang::XSingleServiceFactory > f2;
1547
156
    if (!f1.is()) {
1548
0
        f2.set(factoryInfo, css::uno::UNO_QUERY);
1549
0
        if (!f2.is()) {
1550
0
            throw css::lang::IllegalArgumentException(
1551
0
                (u"Bad XServiceInfo argument implements neither"
1552
0
                 " XSingleComponentFactory nor XSingleServiceFactory"_ustr),
1553
0
                static_cast< cppu::OWeakObject * >(this), 0);
1554
0
        }
1555
0
    }
1556
156
    css::uno::Reference< css::lang::XComponent > comp(
1557
156
        factoryInfo, css::uno::UNO_QUERY);
1558
156
    std::shared_ptr< Data::Implementation > impl =
1559
156
        std::make_shared<Data::Implementation>(name, f1, f2, comp);
1560
156
    Data extra;
1561
156
    if (!name.isEmpty()) {
1562
26
        extra.namedImplementations.emplace(name, impl);
1563
26
    }
1564
156
    extra.dynamicImplementations.emplace(factoryInfo, impl);
1565
156
    const css::uno::Sequence< OUString > services(
1566
156
        factoryInfo->getSupportedServiceNames());
1567
156
    for (const auto & i : services) {
1568
156
        impl->services.push_back(i);
1569
156
        extra.services[i].push_back(impl);
1570
156
    }
1571
156
    if (insertExtraData(extra) && comp.is()) {
1572
156
        comp->addEventListener(this);
1573
156
    }
1574
156
}
1575
1576
156
bool cppuhelper::ServiceManager::insertExtraData(Data const & extra) {
1577
156
    {
1578
156
        std::unique_lock g(m_aMutex);
1579
156
        if (m_bDisposed) {
1580
0
            return false;
1581
0
        }
1582
156
        auto i = std::find_if(extra.namedImplementations.begin(), extra.namedImplementations.end(),
1583
156
            [this](const Data::NamedImplementations::value_type& rEntry) {
1584
26
                return data_.namedImplementations.find(rEntry.first) != data_.namedImplementations.end(); });
1585
156
        if (i != extra.namedImplementations.end())
1586
0
        {
1587
0
            throw css::lang::IllegalArgumentException(
1588
0
                "Insert duplicate implementation name " + i->first,
1589
0
                static_cast< cppu::OWeakObject * >(this), 0);
1590
0
        }
1591
156
        bool bDuplicate = std::any_of(extra.dynamicImplementations.begin(), extra.dynamicImplementations.end(),
1592
156
            [this](const Data::DynamicImplementations::value_type& rEntry) {
1593
156
                return data_.dynamicImplementations.find(rEntry.first) != data_.dynamicImplementations.end(); });
1594
156
        if (bDuplicate)
1595
0
        {
1596
0
            throw css::lang::IllegalArgumentException(
1597
0
                u"Insert duplicate factory object"_ustr,
1598
0
                static_cast< cppu::OWeakObject * >(this), 0);
1599
0
        }
1600
        //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1601
156
        data_.namedImplementations.insert(
1602
156
            extra.namedImplementations.begin(),
1603
156
            extra.namedImplementations.end());
1604
156
        data_.dynamicImplementations.insert(
1605
156
            extra.dynamicImplementations.begin(),
1606
156
            extra.dynamicImplementations.end());
1607
156
        insertImplementationMap(&data_.services, extra.services);
1608
156
        insertImplementationMap(&data_.singletons, extra.singletons);
1609
156
    }
1610
    //TODO: Updating the component context singleton data should be part of the
1611
    // atomic service manager update:
1612
156
    if (extra.singletons.empty())
1613
156
        return true;
1614
1615
156
    assert(context_.is());
1616
0
    css::uno::Reference< css::container::XNameContainer > cont(
1617
0
        context_, css::uno::UNO_QUERY_THROW);
1618
0
    for (const auto& [rName, rImpls] : extra.singletons)
1619
0
    {
1620
0
        OUString name("/singletons/" + rName);
1621
        //TODO: Update should be atomic:
1622
0
        try {
1623
0
            cont->removeByName(name + "/arguments");
1624
0
        } catch (const css::container::NoSuchElementException &) {}
1625
0
        assert(!rImpls.empty());
1626
0
        assert(rImpls[0]);
1627
0
        SAL_INFO_IF(
1628
0
            rImpls.size() > 1, "cppuhelper",
1629
0
            "Arbitrarily choosing " << rImpls[0]->name
1630
0
                << " among multiple implementations for singleton "
1631
0
                << rName);
1632
0
        try {
1633
0
            cont->insertByName(
1634
0
                name + "/service", css::uno::Any(rImpls[0]->name));
1635
0
        } catch (css::container::ElementExistException &) {
1636
0
            cont->replaceByName(
1637
0
                name + "/service", css::uno::Any(rImpls[0]->name));
1638
0
        }
1639
0
        try {
1640
0
            cont->insertByName(name, css::uno::Any());
1641
0
        } catch (css::container::ElementExistException &) {
1642
0
            SAL_INFO("cppuhelper", "Overwriting singleton " << rName);
1643
0
            cont->replaceByName(name, css::uno::Any());
1644
0
        }
1645
0
    }
1646
0
    return true;
1647
0
}
1648
1649
void cppuhelper::ServiceManager::removeRdbFiles(
1650
    std::vector< OUString > const & uris)
1651
0
{
1652
    // The underlying data structures make this function somewhat inefficient,
1653
    // but the assumption is that it is rarely called (and that if it is called,
1654
    // it is called with a uris vector of size one):
1655
0
    std::vector< std::shared_ptr< Data::Implementation > > clear;
1656
0
    {
1657
0
        std::unique_lock g(m_aMutex);
1658
0
        for (const auto& rUri : uris)
1659
0
        {
1660
0
            for (Data::NamedImplementations::iterator j(
1661
0
                     data_.namedImplementations.begin());
1662
0
                 j != data_.namedImplementations.end();)
1663
0
            {
1664
0
                assert(j->second);
1665
0
                if (j->second->rdbFile == rUri) {
1666
0
                    clear.push_back(j->second);
1667
                    //TODO: The below leaves data_ in an inconsistent state upon
1668
                    // exceptions:
1669
0
                    removeFromImplementationMap(
1670
0
                        &data_.services, j->second->services, j->second);
1671
0
                    removeFromImplementationMap(
1672
0
                        &data_.singletons, j->second->singletons,
1673
0
                        j->second);
1674
0
                    j = data_.namedImplementations.erase(j);
1675
0
                } else {
1676
0
                    ++j;
1677
0
                }
1678
0
            }
1679
0
        }
1680
0
    }
1681
    //TODO: Update the component context singleton data
1682
0
}
1683
1684
bool cppuhelper::ServiceManager::removeLegacyFactory(
1685
    css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo,
1686
    bool removeListener)
1687
0
{
1688
0
    assert(factoryInfo.is());
1689
0
    std::shared_ptr< Data::Implementation > clear;
1690
0
    css::uno::Reference< css::lang::XComponent > comp;
1691
0
    {
1692
0
        std::unique_lock g(m_aMutex);
1693
0
        Data::DynamicImplementations::iterator i(
1694
0
            data_.dynamicImplementations.find(factoryInfo));
1695
0
        if (i == data_.dynamicImplementations.end()) {
1696
0
            return m_bDisposed;
1697
0
        }
1698
0
        assert(i->second);
1699
0
        clear = i->second;
1700
0
        if (removeListener) {
1701
0
            comp = i->second->component;
1702
0
        }
1703
        //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1704
0
        removeFromImplementationMap(
1705
0
            &data_.services, i->second->services, i->second);
1706
0
        removeFromImplementationMap(
1707
0
            &data_.singletons, i->second->singletons, i->second);
1708
0
        if (!i->second->name.isEmpty()) {
1709
0
            data_.namedImplementations.erase(i->second->name);
1710
0
        }
1711
0
        data_.dynamicImplementations.erase(i);
1712
0
    }
1713
0
    if (comp.is()) {
1714
0
        removeEventListenerFromComponent(comp);
1715
0
    }
1716
0
    return true;
1717
0
}
1718
1719
0
void cppuhelper::ServiceManager::removeImplementation(const OUString & name) {
1720
    // The underlying data structures make this function somewhat inefficient,
1721
    // but the assumption is that it is rarely called:
1722
0
    std::shared_ptr< Data::Implementation > clear;
1723
0
    {
1724
0
        std::unique_lock g(m_aMutex);
1725
0
        if (m_bDisposed) {
1726
0
            return;
1727
0
        }
1728
0
        Data::NamedImplementations::iterator i(
1729
0
            data_.namedImplementations.find(name));
1730
0
        if (i == data_.namedImplementations.end()) {
1731
0
            throw css::container::NoSuchElementException(
1732
0
                "Remove non-inserted implementation " + name,
1733
0
                static_cast< cppu::OWeakObject * >(this));
1734
0
        }
1735
0
        assert(i->second);
1736
0
        clear = i->second;
1737
        //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1738
0
        removeFromImplementationMap(
1739
0
            &data_.services, i->second->services, i->second);
1740
0
        removeFromImplementationMap(
1741
0
            &data_.singletons, i->second->singletons, i->second);
1742
0
        auto j = std::find_if(data_.dynamicImplementations.begin(), data_.dynamicImplementations.end(),
1743
0
            [&i](const Data::DynamicImplementations::value_type& rEntry) { return rEntry.second == i->second; });
1744
0
        if (j != data_.dynamicImplementations.end())
1745
0
            data_.dynamicImplementations.erase(j);
1746
0
        data_.namedImplementations.erase(i);
1747
0
    }
1748
0
}
1749
1750
std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
1751
cppuhelper::ServiceManager::findServiceImplementation(
1752
    css::uno::Reference< css::uno::XComponentContext > const & context,
1753
    OUString const & specifier)
1754
23.7M
{
1755
23.7M
    std::shared_ptr< Data::Implementation > impl;
1756
23.7M
    bool loaded;
1757
23.7M
    {
1758
23.7M
        std::unique_lock g(m_aMutex);
1759
23.7M
        Data::ImplementationMap::const_iterator i(
1760
23.7M
            data_.services.find(specifier));
1761
23.7M
        if (i == data_.services.end()) {
1762
2.48M
            Data::NamedImplementations::const_iterator j(
1763
2.48M
                data_.namedImplementations.find(specifier));
1764
2.48M
            if (j == data_.namedImplementations.end()) {
1765
2.04M
                SAL_INFO("cppuhelper", "No implementation for " << specifier);
1766
2.04M
                return std::shared_ptr< Data::Implementation >();
1767
2.04M
            }
1768
444k
            impl = j->second;
1769
21.2M
        } else {
1770
21.2M
            assert(!i->second.empty());
1771
21.2M
            SAL_INFO_IF(
1772
21.2M
                i->second.size() > 1, "cppuhelper",
1773
21.2M
                "Arbitrarily choosing " << i->second[0]->name
1774
21.2M
                    << " among multiple implementations for " << i->first);
1775
21.2M
            impl = i->second[0];
1776
21.2M
        }
1777
23.7M
        assert(impl);
1778
21.6M
        loaded = impl->status == Data::Implementation::STATUS_LOADED;
1779
21.6M
    }
1780
21.6M
    if (!loaded) {
1781
278k
        loadImplementation(context, impl);
1782
278k
    }
1783
21.6M
    return impl;
1784
23.7M
}
1785
1786
/// Make a simpler unique name for preload / progress reporting.
1787
#ifndef DISABLE_DYNLOADING
1788
static OUString simplifyModule(std::u16string_view uri)
1789
{
1790
    sal_Int32 nIdx;
1791
    OUStringBuffer edit(uri);
1792
    if ((nIdx = edit.lastIndexOf('/')) > 0)
1793
        edit.remove(0,nIdx+1);
1794
    if ((nIdx = edit.lastIndexOf(':')) > 0)
1795
        edit.remove(0,nIdx+1);
1796
    if ((nIdx = edit.lastIndexOf("lo.so")) > 0)
1797
        edit.truncate(nIdx);
1798
    if ((nIdx = edit.lastIndexOf(".3")) > 0)
1799
        edit.truncate(nIdx);
1800
    if ((nIdx = edit.lastIndexOf("gcc3.so")) > 0)
1801
        edit.truncate(nIdx);
1802
    if ((nIdx = edit.lastIndexOf(".so")) > 0)
1803
        edit.truncate(nIdx);
1804
    if ((nIdx = edit.lastIndexOf("_uno")) > 0)
1805
        edit.truncate(nIdx);
1806
    if ((nIdx = edit.lastIndexOf(".jar")) > 0)
1807
        edit.truncate(nIdx);
1808
    if (edit.indexOf("lib") == 0)
1809
        edit.remove(0,3);
1810
    return edit.makeStringAndClear();
1811
}
1812
#endif
1813
1814
/// Used only by LibreOfficeKit when used by Online to pre-initialize
1815
0
void cppuhelper::ServiceManager::preloadImplementations() {
1816
0
#ifdef DISABLE_DYNLOADING
1817
0
    abort();
1818
#else
1819
    OUString aUri;
1820
    std::unique_lock g(m_aMutex);
1821
    css::uno::Environment aSourceEnv(css::uno::Environment::getCurrent());
1822
1823
    std::cerr << "preload:";
1824
    std::vector<OUString> aReported;
1825
    std::vector<OUString> aDisabled;
1826
    OUStringBuffer aDisabledMsg;
1827
    OUStringBuffer aMissingMsg;
1828
1829
    /// Allow external callers & testers to disable certain components
1830
    if (OUString aDisable = o3tl::getEnvironment(u"UNODISABLELIBRARY"_ustr); !aDisable.isEmpty())
1831
    {
1832
        for (sal_Int32 i = 0; i >= 0; )
1833
        {
1834
            OUString tok( aDisable.getToken(0, ' ', i) );
1835
            tok = tok.trim();
1836
            if (!tok.isEmpty())
1837
                aDisabled.push_back(tok);
1838
        }
1839
    }
1840
1841
    // loop all implementations
1842
    for (const auto& rEntry : data_.namedImplementations)
1843
    {
1844
        if (rEntry.second->loader != "com.sun.star.loader.SharedLibrary" ||
1845
            rEntry.second->status == Data::Implementation::STATUS_LOADED)
1846
            continue;
1847
1848
        OUString simplified;
1849
        try
1850
        {
1851
            const OUString &aLibrary = rEntry.second->uri;
1852
1853
            if (aLibrary.isEmpty())
1854
                continue;
1855
1856
            simplified = simplifyModule(aLibrary);
1857
1858
            bool bDisabled =
1859
                std::find(aDisabled.begin(), aDisabled.end(), simplified) != aDisabled.end();
1860
1861
            if (std::find(aReported.begin(), aReported.end(), aLibrary) == aReported.end())
1862
            {
1863
                if (bDisabled)
1864
                {
1865
                    aDisabledMsg.append(simplified + " ");
1866
                }
1867
                else
1868
                {
1869
                    std::cerr << " " << simplified;
1870
                    std::cerr.flush();
1871
                }
1872
                aReported.push_back(aLibrary);
1873
            }
1874
1875
            if (bDisabled)
1876
                continue;
1877
1878
            // expand absolute URI implementation component library
1879
            aUri = cppu::bootstrap_expandUri(aLibrary);
1880
        }
1881
        catch (css::lang::IllegalArgumentException& aError)
1882
        {
1883
            throw css::uno::DeploymentException(
1884
                "Cannot expand URI" + rEntry.second->uri + ": " + aError.Message,
1885
                static_cast< cppu::OWeakObject * >(this));
1886
        }
1887
1888
        // load component library
1889
        osl::Module aModule(aUri, SAL_LOADMODULE_NOW | SAL_LOADMODULE_GLOBAL);
1890
1891
        if (!aModule.is())
1892
        {
1893
            aMissingMsg.append(simplified + " ");
1894
        }
1895
1896
        if (aModule.is() &&
1897
            !rEntry.second->environment.isEmpty())
1898
        {
1899
            oslGenericFunction fpFactory;
1900
            css::uno::Environment aTargetEnv;
1901
            css::uno::Reference<css::uno::XInterface> xFactory;
1902
1903
            if(rEntry.second->constructorName.isEmpty())
1904
            {
1905
                OUString aSymFactory;
1906
                // expand full name component factory symbol
1907
                if (rEntry.second->prefix == "direct")
1908
                    aSymFactory = rEntry.second->name.replace('.', '_') + "_" COMPONENT_GETFACTORY;
1909
                else if (!rEntry.second->prefix.isEmpty())
1910
                    aSymFactory = rEntry.second->prefix + "_" COMPONENT_GETFACTORY;
1911
                else
1912
                    aSymFactory = COMPONENT_GETFACTORY;
1913
1914
                // get function symbol component factory
1915
                fpFactory = aModule.getFunctionSymbol(aSymFactory);
1916
                if (fpFactory == nullptr)
1917
                {
1918
                    throw css::loader::CannotActivateFactoryException(
1919
                        ("no factory symbol \"" + aSymFactory + "\" in component library :" + aUri),
1920
                        css::uno::Reference<css::uno::XInterface>());
1921
                }
1922
1923
                aTargetEnv = cppuhelper::detail::getEnvironment(rEntry.second->environment, rEntry.second->name);
1924
                component_getFactoryFunc fpComponentFactory = reinterpret_cast<component_getFactoryFunc>(fpFactory);
1925
1926
                if (aSourceEnv.get() == aTargetEnv.get())
1927
                {
1928
                    // invoke function component factory
1929
                    OString aImpl(OUStringToOString(rEntry.second->name, RTL_TEXTENCODING_ASCII_US));
1930
                    xFactory.set(css::uno::Reference<css::uno::XInterface>(static_cast<css::uno::XInterface *>(
1931
                        (*fpComponentFactory)(aImpl.getStr(), this, nullptr)), SAL_NO_ACQUIRE));
1932
                }
1933
            }
1934
            else
1935
            {
1936
                // get function symbol component factory
1937
                aTargetEnv = cppuhelper::detail::getEnvironment(rEntry.second->environment, rEntry.second->name);
1938
                fpFactory = (aSourceEnv.get() == aTargetEnv.get()) ?
1939
                    aModule.getFunctionSymbol(rEntry.second->constructorName) : nullptr;
1940
            }
1941
1942
            css::uno::Reference<css::lang::XSingleComponentFactory> xSCFactory;
1943
            css::uno::Reference<css::lang::XSingleServiceFactory> xSSFactory;
1944
1945
            // query interface XSingleComponentFactory or XSingleServiceFactory
1946
            if (xFactory.is())
1947
            {
1948
                xSCFactory.set(xFactory, css::uno::UNO_QUERY);
1949
                if (!xSCFactory.is())
1950
                {
1951
                    xSSFactory.set(xFactory, css::uno::UNO_QUERY);
1952
                    if (!xSSFactory.is())
1953
                        throw css::uno::DeploymentException(
1954
                            ("Implementation " + rEntry.second->name
1955
                             + " does not provide a constructor or factory"),
1956
                            static_cast< cppu::OWeakObject * >(this));
1957
                }
1958
            }
1959
1960
            if (!rEntry.second->constructorName.isEmpty() && fpFactory)
1961
                rEntry.second->constructorFn = WrapperConstructorFn(reinterpret_cast<ImplementationConstructorFn *>(fpFactory));
1962
1963
            rEntry.second->factory1 = std::move(xSCFactory);
1964
            rEntry.second->factory2 = std::move(xSSFactory);
1965
            rEntry.second->status = Data::Implementation::STATUS_LOADED;
1966
1967
        }
1968
1969
        // Some libraries use other (non-UNO) libraries requiring preinit
1970
        oslGenericFunction fpPreload = aModule.getFunctionSymbol( "lok_preload_hook" );
1971
        if (fpPreload)
1972
        {
1973
            static std::vector<oslGenericFunction> aPreloaded;
1974
            if (std::find(aPreloaded.begin(), aPreloaded.end(), fpPreload) == aPreloaded.end())
1975
            {
1976
                aPreloaded.push_back(fpPreload);
1977
                // unlock because we may be instantiating some services here
1978
                g.unlock();
1979
                fpPreload();
1980
                g.lock();
1981
            }
1982
        }
1983
1984
        // leak aModule
1985
        aModule.release();
1986
    }
1987
    std::cerr << std::endl;
1988
1989
    if (aMissingMsg.getLength() > 0)
1990
    {
1991
        OUString aMsg = aMissingMsg.makeStringAndClear();
1992
        std::cerr << "Absent (often optional): " << aMsg << "\n";
1993
    }
1994
    if (aDisabledMsg.getLength() > 0)
1995
    {
1996
        OUString aMsg = aDisabledMsg.makeStringAndClear();
1997
        std::cerr << "Disabled: " << aMsg << "\n";
1998
    }
1999
    std::cerr.flush();
2000
2001
    // Various rather important uno mappings.
2002
    static struct {
2003
        OUString maFrom;
2004
        OUString maTo;
2005
        OUString maPurpose;
2006
    } constexpr aMappingLoad[] = {
2007
        { u"gcc3"_ustr, u"uno"_ustr,  u""_ustr },
2008
        { u"uno"_ustr,  u"gcc3"_ustr, u""_ustr },
2009
    };
2010
2011
    static std::vector<css::uno::Mapping> maMaps;
2012
    for (auto &it : aMappingLoad)
2013
    {
2014
        maMaps.push_back(css::uno::Mapping(it.maFrom, it.maTo, it.maPurpose));
2015
    }
2016
#endif
2017
0
}
2018
2019
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */