1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <sal/config.h>
16 #include <string_view>
20 #include <config_fuzzers.h>
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/safeint.hxx>
43 #include <osl/file.hxx>
44 #include <osl/module.hxx>
45 #include <rtl/ref.hxx>
46 #include <rtl/uri.hxx>
47 #include <rtl/ustring.hxx>
48 #include <rtl/ustrbuf.hxx>
49 #include <sal/log.hxx>
50 #include <uno/environment.hxx>
51 #include <uno/mapping.hxx>
52 #include <o3tl/string_view.hxx>
54 #include "loadsharedlibcomponentfactory.hxx"
56 #include <registry/registry.hxx>
57 #include <xmlreader/xmlreader.hxx>
60 #include "servicemanager.hxx"
64 void insertImplementationMap(
65 cppuhelper::ServiceManager::Data::ImplementationMap
* destination
,
66 cppuhelper::ServiceManager::Data::ImplementationMap
const & source
)
68 assert(destination
!= nullptr);
69 for (const auto& [rName
, rImpls
] : source
)
71 auto & impls
= (*destination
)[rName
];
72 impls
.insert(impls
.end(), rImpls
.begin(), rImpls
.end());
76 void removeFromImplementationMap(
77 cppuhelper::ServiceManager::Data::ImplementationMap
* map
,
78 std::vector
< OUString
> const & elements
,
79 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
80 const & implementation
)
82 // The underlying data structures make this function somewhat inefficient,
83 // but the assumption is that it is rarely called:
84 assert(map
!= nullptr);
85 for (const auto& rElement
: elements
)
87 auto j(map
->find(rElement
));
88 assert(j
!= map
->end());
89 auto k(std::find(j
->second
.begin(), j
->second
.end(), implementation
));
90 assert(k
!= j
->second
.end());
92 if (j
->second
.empty()) {
98 // For simplicity, this code keeps throwing
99 // css::registry::InvalidRegistryException for invalid XML rdbs (even though
100 // that does not fit the exception's name):
104 OUString
const & uri
,
105 css::uno::Reference
< css::uno::XComponentContext
> alienContext
,
106 cppuhelper::ServiceManager::Data
* data
);
108 Parser(const Parser
&) = delete;
109 const Parser
& operator=(const Parser
&) = delete;
112 void handleComponent();
114 void handleImplementation();
116 void handleService();
118 void handleSingleton();
120 OUString
getNameAttribute();
122 xmlreader::XmlReader reader_
;
123 css::uno::Reference
< css::uno::XComponentContext
> alienContext_
;
124 cppuhelper::ServiceManager::Data
* data_
;
125 OUString attrLoader_
;
127 OUString attrEnvironment_
;
128 OUString attrPrefix_
;
129 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
134 OUString
const & uri
,
135 css::uno::Reference
< css::uno::XComponentContext
> alienContext
,
136 cppuhelper::ServiceManager::Data
* data
):
137 reader_(uri
), alienContext_(std::move(alienContext
)), data_(data
)
139 assert(data
!= nullptr);
140 int ucNsId
= reader_
.registerNamespaceIri(
142 RTL_CONSTASCII_STRINGPARAM(
143 "http://openoffice.org/2010/uno-components")));
145 STATE_BEGIN
, STATE_END
, STATE_COMPONENTS
, STATE_COMPONENT_INITIAL
,
146 STATE_COMPONENT
, STATE_IMPLEMENTATION
, STATE_SERVICE
, STATE_SINGLETON
};
147 for (State state
= STATE_BEGIN
;;) {
148 xmlreader::Span name
;
150 xmlreader::XmlReader::Result res
= reader_
.nextItem(
151 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
154 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
155 && name
.equals(RTL_CONSTASCII_STRINGPARAM("components")))
157 state
= STATE_COMPONENTS
;
160 throw css::registry::InvalidRegistryException(
161 reader_
.getUrl() + ": unexpected item in outer level");
163 if (res
== xmlreader::XmlReader::Result::Done
) {
166 throw css::registry::InvalidRegistryException(
167 reader_
.getUrl() + ": unexpected item in outer level");
168 case STATE_COMPONENTS
:
169 if (res
== xmlreader::XmlReader::Result::End
) {
173 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
174 && name
.equals(RTL_CONSTASCII_STRINGPARAM("component")))
177 state
= STATE_COMPONENT_INITIAL
;
180 throw css::registry::InvalidRegistryException(
181 reader_
.getUrl() + ": unexpected item in <components>");
182 case STATE_COMPONENT
:
183 if (res
== xmlreader::XmlReader::Result::End
) {
184 state
= STATE_COMPONENTS
;
188 case STATE_COMPONENT_INITIAL
:
189 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
190 && name
.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
192 handleImplementation();
193 state
= STATE_IMPLEMENTATION
;
196 throw css::registry::InvalidRegistryException(
197 reader_
.getUrl() + ": unexpected item in <component>");
198 case STATE_IMPLEMENTATION
:
199 if (res
== xmlreader::XmlReader::Result::End
) {
200 state
= STATE_COMPONENT
;
203 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
204 && name
.equals(RTL_CONSTASCII_STRINGPARAM("service")))
207 state
= STATE_SERVICE
;
210 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
211 && name
.equals(RTL_CONSTASCII_STRINGPARAM("singleton")))
214 state
= STATE_SINGLETON
;
217 throw css::registry::InvalidRegistryException(
218 reader_
.getUrl() + ": unexpected item in <implementation>");
220 if (res
== xmlreader::XmlReader::Result::End
) {
221 state
= STATE_IMPLEMENTATION
;
224 throw css::registry::InvalidRegistryException(
225 reader_
.getUrl() + ": unexpected item in <service>");
226 case STATE_SINGLETON
:
227 if (res
== xmlreader::XmlReader::Result::End
) {
228 state
= STATE_IMPLEMENTATION
;
231 throw css::registry::InvalidRegistryException(
232 reader_
.getUrl() + ": unexpected item in <service>");
237 void Parser::handleComponent() {
238 attrLoader_
= OUString();
239 attrUri_
= OUString();
240 attrEnvironment_
= OUString();
241 attrPrefix_
= OUString();
242 xmlreader::Span name
;
244 while (reader_
.nextAttribute(&nsId
, &name
)) {
245 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
246 && name
.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
248 if (!attrLoader_
.isEmpty()) {
249 throw css::registry::InvalidRegistryException(
251 + ": <component> has multiple \"loader\" attributes");
253 attrLoader_
= reader_
.getAttributeValue(false).convertFromUtf8();
254 if (attrLoader_
.isEmpty()) {
255 throw css::registry::InvalidRegistryException(
257 + ": <component> has empty \"loader\" attribute");
259 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
260 && name
.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
262 if (!attrUri_
.isEmpty()) {
263 throw css::registry::InvalidRegistryException(
265 + ": <component> has multiple \"uri\" attributes");
267 attrUri_
= reader_
.getAttributeValue(false).convertFromUtf8();
268 if (attrUri_
.isEmpty()) {
269 throw css::registry::InvalidRegistryException(
271 + ": <component> has empty \"uri\" attribute");
273 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
274 && name
.equals(RTL_CONSTASCII_STRINGPARAM("environment")))
276 if (!attrEnvironment_
.isEmpty()) {
277 throw css::registry::InvalidRegistryException(
279 ": <component> has multiple \"environment\" attributes");
281 attrEnvironment_
= reader_
.getAttributeValue(false)
283 if (attrEnvironment_
.isEmpty()) {
284 throw css::registry::InvalidRegistryException(
286 ": <component> has empty \"environment\" attribute");
288 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
289 && name
.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
291 if (!attrPrefix_
.isEmpty()) {
292 throw css::registry::InvalidRegistryException(
294 ": <component> has multiple \"prefix\" attributes");
296 attrPrefix_
= reader_
.getAttributeValue(false).convertFromUtf8();
297 if (attrPrefix_
.isEmpty()) {
298 throw css::registry::InvalidRegistryException(
300 ": <component> has empty \"prefix\" attribute");
303 throw css::registry::InvalidRegistryException(
304 reader_
.getUrl() + ": unexpected attribute \""
305 + name
.convertFromUtf8() + "\" in <component>");
308 if (attrLoader_
.isEmpty()) {
309 throw css::registry::InvalidRegistryException(
310 reader_
.getUrl() + ": <component> is missing \"loader\" attribute");
312 if (attrUri_
.isEmpty()) {
313 throw css::registry::InvalidRegistryException(
314 reader_
.getUrl() + ": <component> is missing \"uri\" attribute");
316 #ifndef DISABLE_DYNLOADING
318 attrUri_
= rtl::Uri::convertRelToAbs(reader_
.getUrl(), attrUri_
);
319 } catch (const rtl::MalformedUriException
& e
) {
320 throw css::registry::InvalidRegistryException(
321 reader_
.getUrl() + ": bad \"uri\" attribute: " + e
.getMessage());
326 void Parser::handleImplementation() {
328 OUString attrConstructor
;
329 bool attrSingleInstance
= false;
330 xmlreader::Span name
;
332 while (reader_
.nextAttribute(&nsId
, &name
)) {
333 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
334 && name
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
336 if (!attrName
.isEmpty()) {
337 throw css::registry::InvalidRegistryException(
339 + ": <implementation> has multiple \"name\" attributes");
341 attrName
= reader_
.getAttributeValue(false).convertFromUtf8();
342 if (attrName
.isEmpty()) {
343 throw css::registry::InvalidRegistryException(
345 + ": <implementation> has empty \"name\" attribute");
347 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
348 && name
.equals(RTL_CONSTASCII_STRINGPARAM("constructor")))
350 if (!attrConstructor
.isEmpty()) {
351 throw css::registry::InvalidRegistryException(
353 + ": <implementation> has multiple \"constructor\""
356 attrConstructor
= reader_
.getAttributeValue(false)
358 if (attrConstructor
.isEmpty()) {
359 throw css::registry::InvalidRegistryException(
361 + ": element has empty \"constructor\" attribute");
363 if (attrEnvironment_
.isEmpty()) {
364 throw css::registry::InvalidRegistryException(
366 + ": <implementation> has \"constructor\" attribute but"
367 " <component> has no \"environment\" attribute");
369 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
370 && name
.equals(RTL_CONSTASCII_STRINGPARAM("single-instance")))
372 if (attrSingleInstance
) {
373 throw css::registry::InvalidRegistryException(
375 + ": <implementation> has multiple \"single-instance\" attributes");
377 if (!reader_
.getAttributeValue(false).equals(RTL_CONSTASCII_STRINGPARAM("true"))) {
378 throw css::registry::InvalidRegistryException(
379 reader_
.getUrl() + ": <implementation> has bad \"single-instance\" attribute");
381 attrSingleInstance
= true;
383 throw css::registry::InvalidRegistryException(
384 reader_
.getUrl() + ": unexpected element attribute \""
385 + name
.convertFromUtf8() + "\" in <implementation>");
388 if (attrName
.isEmpty()) {
389 throw css::registry::InvalidRegistryException(
391 + ": <implementation> is missing \"name\" attribute");
394 std::make_shared
<cppuhelper::ServiceManager::Data::Implementation
>(
395 attrName
, attrLoader_
, attrUri_
, attrEnvironment_
, attrConstructor
,
396 attrPrefix_
, attrSingleInstance
, alienContext_
, reader_
.getUrl());
397 if (!data_
->namedImplementations
.emplace(attrName
, implementation_
).
400 throw css::registry::InvalidRegistryException(
401 reader_
.getUrl() + ": duplicate <implementation name=\"" + attrName
406 void Parser::handleService() {
407 OUString
name(getNameAttribute());
408 implementation_
->services
.push_back(name
);
409 data_
->services
[name
].push_back(implementation_
);
412 void Parser::handleSingleton() {
413 OUString
name(getNameAttribute());
414 implementation_
->singletons
.push_back(name
);
415 data_
->singletons
[name
].push_back(implementation_
);
418 OUString
Parser::getNameAttribute() {
420 xmlreader::Span name
;
422 while (reader_
.nextAttribute(&nsId
, &name
)) {
423 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
424 || !name
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
426 throw css::registry::InvalidRegistryException(
427 reader_
.getUrl() + ": expected element attribute \"name\"");
429 if (!attrName
.isEmpty()) {
430 throw css::registry::InvalidRegistryException(
432 + ": element has multiple \"name\" attributes");
434 attrName
= reader_
.getAttributeValue(false).convertFromUtf8();
435 if (attrName
.isEmpty()) {
436 throw css::registry::InvalidRegistryException(
437 reader_
.getUrl() + ": element has empty \"name\" attribute");
440 if (attrName
.isEmpty()) {
441 throw css::registry::InvalidRegistryException(
442 reader_
.getUrl() + ": element is missing \"name\" attribute");
447 class ContentEnumeration
:
448 public cppu::WeakImplHelper
< css::container::XEnumeration
>
451 explicit ContentEnumeration(std::vector
< css::uno::Any
>&& factories
):
452 factories_(std::move(factories
)), iterator_(factories_
.begin()) {}
454 ContentEnumeration(const ContentEnumeration
&) = delete;
455 const ContentEnumeration
& operator=(const ContentEnumeration
&) = delete;
458 virtual ~ContentEnumeration() override
{}
460 virtual sal_Bool SAL_CALL
hasMoreElements() override
;
462 virtual css::uno::Any SAL_CALL
nextElement() override
;
465 std::vector
< css::uno::Any
> factories_
;
466 std::vector
< css::uno::Any
>::const_iterator iterator_
;
469 sal_Bool
ContentEnumeration::hasMoreElements()
471 std::scoped_lock
g(mutex_
);
472 return iterator_
!= factories_
.end();
475 css::uno::Any
ContentEnumeration::nextElement()
477 std::scoped_lock
g(mutex_
);
478 if (iterator_
== factories_
.end()) {
479 throw css::container::NoSuchElementException(
480 u
"Bootstrap service manager service enumerator has no more elements"_ustr
,
481 static_cast< cppu::OWeakObject
* >(this));
486 css::beans::Property
getDefaultContextProperty() {
487 return css::beans::Property(
488 u
"DefaultContext"_ustr
, -1,
489 cppu::UnoType
< css::uno::XComponentContext
>::get(),
490 css::beans::PropertyAttribute::READONLY
);
493 class SingletonFactory
:
494 public cppu::WeakImplHelper
<css::lang::XSingleComponentFactory
>
498 rtl::Reference
< cppuhelper::ServiceManager
> const & manager
,
500 cppuhelper::ServiceManager::Data::Implementation
> const &
502 manager_(manager
), implementation_(implementation
)
503 { assert(manager
.is()); assert(implementation
); }
505 SingletonFactory(const SingletonFactory
&) = delete;
506 const SingletonFactory
& operator=(const SingletonFactory
&) = delete;
509 virtual ~SingletonFactory() override
{}
511 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
512 createInstanceWithContext(
513 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
515 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
516 createInstanceWithArgumentsAndContext(
517 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
518 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
520 rtl::Reference
< cppuhelper::ServiceManager
> manager_
;
521 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
525 css::uno::Reference
< css::uno::XInterface
>
526 SingletonFactory::createInstanceWithContext(
527 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
529 manager_
->loadImplementation(Context
, implementation_
);
530 return implementation_
->createInstance(Context
, true);
533 css::uno::Reference
< css::uno::XInterface
>
534 SingletonFactory::createInstanceWithArgumentsAndContext(
535 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
536 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
538 manager_
->loadImplementation(Context
, implementation_
);
539 return implementation_
->createInstanceWithArguments(
540 Context
, true, Arguments
);
543 class ImplementationWrapper
:
544 public cppu::WeakImplHelper
<
545 css::lang::XSingleComponentFactory
, css::lang::XSingleServiceFactory
,
546 css::lang::XServiceInfo
>
549 ImplementationWrapper(
550 rtl::Reference
< cppuhelper::ServiceManager
> const & manager
,
552 cppuhelper::ServiceManager::Data::Implementation
> const &
554 manager_(manager
), implementation_(implementation
)
555 { assert(manager
.is()); assert(implementation
); }
557 ImplementationWrapper(const ImplementationWrapper
&) = delete;
558 const ImplementationWrapper
& operator=(const ImplementationWrapper
&) = delete;
561 virtual ~ImplementationWrapper() override
{}
563 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
564 createInstanceWithContext(
565 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
567 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
568 createInstanceWithArgumentsAndContext(
569 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
570 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
572 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
573 createInstance() override
;
575 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
576 createInstanceWithArguments(
577 css::uno::Sequence
< css::uno::Any
> const & Arguments
) override
;
579 virtual OUString SAL_CALL
getImplementationName() override
;
581 virtual sal_Bool SAL_CALL
supportsService(OUString
const & ServiceName
) override
;
583 virtual css::uno::Sequence
< OUString
> SAL_CALL
584 getSupportedServiceNames() override
;
586 rtl::Reference
< cppuhelper::ServiceManager
> manager_
;
587 std::weak_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
591 css::uno::Reference
< css::uno::XInterface
>
592 ImplementationWrapper::createInstanceWithContext(
593 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
595 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
597 manager_
->loadImplementation(Context
, impl
);
598 return impl
->createInstance(Context
, false);
601 css::uno::Reference
< css::uno::XInterface
>
602 ImplementationWrapper::createInstanceWithArgumentsAndContext(
603 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
604 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
606 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
608 manager_
->loadImplementation(Context
, impl
);
609 return impl
->createInstanceWithArguments(
610 Context
, false, Arguments
);
613 css::uno::Reference
< css::uno::XInterface
>
614 ImplementationWrapper::createInstance()
616 return createInstanceWithContext(manager_
->getContext());
619 css::uno::Reference
< css::uno::XInterface
>
620 ImplementationWrapper::createInstanceWithArguments(
621 css::uno::Sequence
< css::uno::Any
> const & Arguments
)
623 return createInstanceWithArgumentsAndContext(
624 Arguments
, manager_
->getContext());
627 OUString
ImplementationWrapper::getImplementationName()
629 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
634 sal_Bool
ImplementationWrapper::supportsService(OUString
const & ServiceName
)
636 return cppu::supportsService(this, ServiceName
);
639 css::uno::Sequence
< OUString
>
640 ImplementationWrapper::getSupportedServiceNames()
642 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
644 if (impl
->services
.size()
645 > o3tl::make_unsigned(SAL_MAX_INT32
))
647 throw css::uno::RuntimeException(
648 ("Implementation " + impl
->name
649 + " supports too many services"),
650 static_cast< cppu::OWeakObject
* >(this));
652 return comphelper::containerToSequence(impl
->services
);
657 css::uno::Reference
<css::uno::XInterface
>
658 cppuhelper::ServiceManager::Data::Implementation::createInstance(
659 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
660 bool singletonRequest
)
662 css::uno::Reference
<css::uno::XInterface
> inst
;
663 if (isSingleInstance
) {
664 std::unique_lock
g(mutex
);
665 if (!singleInstance
.is()) {
666 singleInstance
= doCreateInstance(context
);
668 inst
= singleInstance
;
670 inst
= doCreateInstance(context
);
672 updateDisposeInstance(singletonRequest
, inst
);
676 css::uno::Reference
<css::uno::XInterface
>
677 cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments(
678 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
679 bool singletonRequest
, css::uno::Sequence
<css::uno::Any
> const & arguments
)
681 css::uno::Reference
<css::uno::XInterface
> inst
;
682 if (isSingleInstance
) {
683 std::unique_lock
g(mutex
);
684 if (!singleInstance
.is()) {
685 singleInstance
= doCreateInstanceWithArguments(context
, arguments
);
687 inst
= singleInstance
;
689 inst
= doCreateInstanceWithArguments(context
, arguments
);
691 updateDisposeInstance(singletonRequest
, inst
);
695 css::uno::Reference
<css::uno::XInterface
>
696 cppuhelper::ServiceManager::Data::Implementation::doCreateInstance(
697 css::uno::Reference
<css::uno::XComponentContext
> const & context
)
700 return css::uno::Reference
<css::uno::XInterface
>(
701 constructorFn(context
.get(), css::uno::Sequence
<css::uno::Any
>()),
703 } else if (factory1
.is()) {
704 return factory1
->createInstanceWithContext(context
);
706 assert(factory2
.is());
707 return factory2
->createInstance();
711 css::uno::Reference
<css::uno::XInterface
>
712 cppuhelper::ServiceManager::Data::Implementation::doCreateInstanceWithArguments(
713 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
714 css::uno::Sequence
<css::uno::Any
> const & arguments
)
717 css::uno::Reference
<css::uno::XInterface
> inst(
718 constructorFn(context
.get(), arguments
), SAL_NO_ACQUIRE
);
719 //HACK: The constructor will either observe arguments and return inst
720 // that does not implement XInitialization (or null), or ignore
721 // arguments and return inst that implements XInitialization; this
722 // should be removed again once XInitialization-based implementations
724 css::uno::Reference
<css::lang::XInitialization
> init(
725 inst
, css::uno::UNO_QUERY
);
727 init
->initialize(arguments
);
730 } else if (factory1
.is()) {
731 return factory1
->createInstanceWithArgumentsAndContext(
734 assert(factory2
.is());
735 return factory2
->createInstanceWithArguments(arguments
);
739 void cppuhelper::ServiceManager::Data::Implementation::updateDisposeInstance(
740 bool singletonRequest
,
741 css::uno::Reference
<css::uno::XInterface
> const & instance
)
743 // This is an optimization, to only call dispose once (from the component
744 // context) on a singleton that is obtained both via the component context
745 // and via the service manager; however, there is a harmless race here that
746 // may cause two calls to dispose nevertheless (also, this calls dispose on
747 // at most one of the instances obtained via the service manager, in case
748 // the implementation hands out different instances):
749 if (singletonRequest
) {
750 std::unique_lock
g(mutex
);
751 disposeInstance
.clear();
753 } else if (shallDispose()) {
754 css::uno::Reference
<css::lang::XComponent
> comp(
755 instance
, css::uno::UNO_QUERY
);
757 std::unique_lock
g(mutex
);
759 disposeInstance
= comp
;
765 void cppuhelper::ServiceManager::addSingletonContextEntries(
766 std::vector
< cppu::ContextEntry_Init
> * entries
)
768 assert(entries
!= nullptr);
769 for (const auto& [rName
, rImpls
] : data_
.singletons
)
771 assert(!rImpls
.empty());
774 rImpls
.size() > 1, "cppuhelper",
775 "Arbitrarily choosing " << rImpls
[0]->name
776 << " among multiple implementations for " << rName
);
778 cppu::ContextEntry_Init(
779 "/singletons/" + rName
,
781 css::uno::Reference
<css::lang::XSingleComponentFactory
>(
782 new SingletonFactory(this, rImpls
[0]))),
787 void cppuhelper::ServiceManager::loadImplementation(
788 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
789 std::shared_ptr
< Data::Implementation
> const & implementation
)
791 assert(implementation
);
793 std::unique_lock
g(m_aMutex
);
794 if (implementation
->status
== Data::Implementation::STATUS_LOADED
) {
800 uri
= cppu::bootstrap_expandUri(implementation
->uri
);
801 } catch (css::lang::IllegalArgumentException
& e
) {
802 throw css::uno::DeploymentException(
803 "Cannot expand URI" + implementation
->uri
+ ": " + e
.Message
,
804 static_cast< cppu::OWeakObject
* >(this));
806 cppuhelper::WrapperConstructorFn ctor
;
807 css::uno::Reference
< css::uno::XInterface
> f0
;
808 // Special handling of SharedLibrary loader, with support for environment,
809 // constructor, and prefix arguments:
810 if (!implementation
->alienContext
.is()
811 && implementation
->loader
== "com.sun.star.loader.SharedLibrary")
813 cppuhelper::detail::loadSharedLibComponentFactory(
814 uri
, implementation
->environment
,
815 implementation
->prefix
, implementation
->name
,
816 implementation
->constructorName
, this, &ctor
, &f0
);
818 assert(!implementation
->environment
.isEmpty());
822 !implementation
->environment
.isEmpty(), "cppuhelper",
823 "Loader " << implementation
->loader
824 << " and non-empty environment "
825 << implementation
->environment
);
827 !implementation
->prefix
.isEmpty(), "cppuhelper",
828 "Loader " << implementation
->loader
829 << " and non-empty constructor "
830 << implementation
->constructorName
);
832 !implementation
->prefix
.isEmpty(), "cppuhelper",
833 "Loader " << implementation
->loader
834 << " and non-empty prefix " << implementation
->prefix
);
835 css::uno::Reference
< css::uno::XComponentContext
> ctxt
;
836 css::uno::Reference
< css::lang::XMultiComponentFactory
> smgr
;
837 if (implementation
->alienContext
.is()) {
838 ctxt
= implementation
->alienContext
;
839 smgr
.set(ctxt
->getServiceManager(), css::uno::UNO_SET_THROW
);
841 assert(context
.is());
845 css::uno::Reference
< css::loader::XImplementationLoader
> loader(
846 smgr
->createInstanceWithContext(implementation
->loader
, ctxt
),
847 css::uno::UNO_QUERY_THROW
);
848 f0
= loader
->activate(
849 implementation
->name
, OUString(), uri
,
850 css::uno::Reference
< css::registry::XRegistryKey
>());
852 css::uno::Reference
<css::lang::XSingleComponentFactory
> f1
;
853 css::uno::Reference
<css::lang::XSingleServiceFactory
> f2
;
855 f1
.set(f0
, css::uno::UNO_QUERY
);
857 f2
.set(f0
, css::uno::UNO_QUERY
);
859 throw css::uno::DeploymentException(
860 ("Implementation " + implementation
->name
861 + " does not provide a constructor or factory"),
862 static_cast< cppu::OWeakObject
* >(this));
866 //TODO: There is a race here, as the relevant service factory can be removed
867 // while the mutex is unlocked and loading can thus fail, as the entity from
868 // which to load can disappear once the service factory is removed.
869 std::unique_lock
g(m_aMutex
);
871 || implementation
->status
== Data::Implementation::STATUS_LOADED
))
873 implementation
->status
= Data::Implementation::STATUS_LOADED
;
874 implementation
->constructorFn
= ctor
;
875 implementation
->factory1
= f1
;
876 implementation
->factory2
= f2
;
880 void cppuhelper::ServiceManager::disposing(std::unique_lock
<std::mutex
>& rGuard
) {
881 std::vector
< css::uno::Reference
<css::lang::XComponent
> > sngls
;
882 std::vector
< css::uno::Reference
< css::lang::XComponent
> > comps
;
885 for (const auto& rEntry
: data_
.namedImplementations
)
887 assert(rEntry
.second
);
888 if (rEntry
.second
->shallDispose()) {
889 std::unique_lock
g2(rEntry
.second
->mutex
);
890 if (rEntry
.second
->disposeInstance
.is()) {
891 sngls
.push_back(rEntry
.second
->disposeInstance
);
895 for (const auto& rEntry
: data_
.dynamicImplementations
)
897 assert(rEntry
.second
);
898 if (rEntry
.second
->shallDispose()) {
899 std::unique_lock
g2(rEntry
.second
->mutex
);
900 if (rEntry
.second
->disposeInstance
.is()) {
901 sngls
.push_back(rEntry
.second
->disposeInstance
);
904 if (rEntry
.second
->component
.is()) {
905 comps
.push_back(rEntry
.second
->component
);
908 data_
.namedImplementations
.swap(clear
.namedImplementations
);
909 data_
.dynamicImplementations
.swap(clear
.dynamicImplementations
);
910 data_
.services
.swap(clear
.services
);
911 data_
.singletons
.swap(clear
.singletons
);
914 for (const auto& rxSngl
: sngls
)
918 } catch (css::uno::RuntimeException
& e
) {
919 SAL_WARN("cppuhelper", "Ignoring " << e
<< " while disposing singleton");
922 for (const auto& rxComp
: comps
)
924 removeEventListenerFromComponent(rxComp
);
929 void cppuhelper::ServiceManager::initialize(
930 css::uno::Sequence
<css::uno::Any
> const & aArguments
)
933 if (aArguments
.getLength() != 1 || !(aArguments
[0] >>= arg
)
936 throw css::lang::IllegalArgumentException(
937 u
"invalid ServiceManager::initialize argument"_ustr
,
938 css::uno::Reference
<css::uno::XInterface
>(), 0);
940 preloadImplementations();
943 OUString
cppuhelper::ServiceManager::getImplementationName()
946 u
"com.sun.star.comp.cppuhelper.bootstrap.ServiceManager"_ustr
;
949 sal_Bool
cppuhelper::ServiceManager::supportsService(
950 OUString
const & ServiceName
)
952 return cppu::supportsService(this, ServiceName
);
955 css::uno::Sequence
< OUString
>
956 cppuhelper::ServiceManager::getSupportedServiceNames()
958 return { u
"com.sun.star.lang.MultiServiceFactory"_ustr
, u
"com.sun.star.lang.ServiceManager"_ustr
};
961 css::uno::Reference
< css::uno::XInterface
>
962 cppuhelper::ServiceManager::createInstance(
963 OUString
const & aServiceSpecifier
)
965 assert(context_
.is());
966 return createInstanceWithContext(aServiceSpecifier
, context_
);
969 css::uno::Reference
< css::uno::XInterface
>
970 cppuhelper::ServiceManager::createInstanceWithArguments(
971 OUString
const & ServiceSpecifier
,
972 css::uno::Sequence
< css::uno::Any
> const & Arguments
)
974 assert(context_
.is());
975 return createInstanceWithArgumentsAndContext(
976 ServiceSpecifier
, Arguments
, context_
);
979 css::uno::Sequence
< OUString
>
980 cppuhelper::ServiceManager::getAvailableServiceNames()
982 std::unique_lock
g(m_aMutex
);
984 return css::uno::Sequence
< OUString
>();
986 if (data_
.services
.size() > o3tl::make_unsigned(SAL_MAX_INT32
)) {
987 throw css::uno::RuntimeException(
988 u
"getAvailableServiceNames: too many services"_ustr
,
989 static_cast< cppu::OWeakObject
* >(this));
991 return comphelper::mapKeysToSequence(data_
.services
);
994 css::uno::Reference
< css::uno::XInterface
>
995 cppuhelper::ServiceManager::createInstanceWithContext(
996 OUString
const & aServiceSpecifier
,
997 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
999 std::shared_ptr
< Data::Implementation
> impl(
1000 findServiceImplementation(Context
, aServiceSpecifier
));
1001 return impl
== nullptr ? css::uno::Reference
<css::uno::XInterface
>()
1002 : impl
->createInstance(Context
, false);
1005 css::uno::Reference
< css::uno::XInterface
>
1006 cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext(
1007 OUString
const & ServiceSpecifier
,
1008 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
1009 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
1011 std::shared_ptr
< Data::Implementation
> impl(
1012 findServiceImplementation(Context
, ServiceSpecifier
));
1013 return impl
== nullptr ? css::uno::Reference
<css::uno::XInterface
>()
1014 : impl
->createInstanceWithArguments(Context
, false, Arguments
);
1017 css::uno::Type
cppuhelper::ServiceManager::getElementType()
1019 return css::uno::Type();
1022 sal_Bool
cppuhelper::ServiceManager::hasElements()
1024 std::unique_lock
g(m_aMutex
);
1026 !(data_
.namedImplementations
.empty()
1027 && data_
.dynamicImplementations
.empty());
1030 css::uno::Reference
< css::container::XEnumeration
>
1031 cppuhelper::ServiceManager::createEnumeration()
1033 throw css::uno::RuntimeException(
1034 u
"ServiceManager createEnumeration: method not supported"_ustr
,
1035 static_cast< cppu::OWeakObject
* >(this));
1038 sal_Bool
cppuhelper::ServiceManager::has(css::uno::Any
const &)
1040 throw css::uno::RuntimeException(
1041 u
"ServiceManager has: method not supported"_ustr
,
1042 static_cast< cppu::OWeakObject
* >(this));
1045 void cppuhelper::ServiceManager::insert(css::uno::Any
const & aElement
)
1047 css::uno::Sequence
< css::beans::NamedValue
> args
;
1048 if (aElement
>>= args
) {
1049 std::vector
< OUString
> uris
;
1050 css::uno::Reference
< css::uno::XComponentContext
> alienContext
;
1051 for (const auto & arg
: args
) {
1052 if (arg
.Name
== "uri") {
1054 if (!(arg
.Value
>>= uri
)) {
1055 throw css::lang::IllegalArgumentException(
1056 u
"Bad uri argument"_ustr
,
1057 static_cast< cppu::OWeakObject
* >(this), 0);
1059 uris
.push_back(uri
);
1060 } else if (arg
.Name
== "component-context") {
1061 if (alienContext
.is()) {
1062 throw css::lang::IllegalArgumentException(
1063 u
"Multiple component-context arguments"_ustr
,
1064 static_cast< cppu::OWeakObject
* >(this), 0);
1066 if (!(arg
.Value
>>= alienContext
) || !alienContext
.is()) {
1067 throw css::lang::IllegalArgumentException(
1068 u
"Bad component-context argument"_ustr
,
1069 static_cast< cppu::OWeakObject
* >(this), 0);
1072 throw css::lang::IllegalArgumentException(
1073 "Bad argument " + arg
.Name
,
1074 static_cast< cppu::OWeakObject
* >(this), 0);
1077 insertRdbFiles(uris
, alienContext
);
1080 css::uno::Reference
< css::lang::XServiceInfo
> info
;
1081 if ((aElement
>>= info
) && info
.is()) {
1082 insertLegacyFactory(info
);
1086 throw css::lang::IllegalArgumentException(
1087 u
"Bad insert element"_ustr
, static_cast< cppu::OWeakObject
* >(this), 0);
1090 void cppuhelper::ServiceManager::remove(css::uno::Any
const & aElement
)
1092 css::uno::Sequence
< css::beans::NamedValue
> args
;
1093 if (aElement
>>= args
) {
1094 std::vector
< OUString
> uris
;
1095 for (const auto & i
: args
) {
1096 if (i
.Name
!= "uri") {
1097 throw css::lang::IllegalArgumentException(
1098 "Bad argument " + i
.Name
,
1099 static_cast< cppu::OWeakObject
* >(this), 0);
1102 if (!(i
.Value
>>= uri
)) {
1103 throw css::lang::IllegalArgumentException(
1104 u
"Bad uri argument"_ustr
,
1105 static_cast< cppu::OWeakObject
* >(this), 0);
1107 uris
.push_back(uri
);
1109 removeRdbFiles(uris
);
1112 css::uno::Reference
< css::lang::XServiceInfo
> info
;
1113 if ((aElement
>>= info
) && info
.is()) {
1114 if (!removeLegacyFactory(info
, true)) {
1115 throw css::container::NoSuchElementException(
1116 u
"Remove non-inserted factory object"_ustr
,
1117 static_cast< cppu::OWeakObject
* >(this));
1122 if (aElement
>>= impl
) {
1123 // For live-removal of extensions:
1124 removeImplementation(impl
);
1127 throw css::lang::IllegalArgumentException(
1128 u
"Bad remove element"_ustr
, static_cast< cppu::OWeakObject
* >(this), 0);
1131 css::uno::Reference
< css::container::XEnumeration
>
1132 cppuhelper::ServiceManager::createContentEnumeration(
1133 OUString
const & aServiceName
)
1135 boost::container::small_vector
< std::shared_ptr
< Data::Implementation
>, 2 > impls
;
1137 std::unique_lock
g(m_aMutex
);
1138 Data::ImplementationMap::const_iterator
i(
1139 data_
.services
.find(aServiceName
));
1140 if (i
!= data_
.services
.end()) {
1144 std::vector
< css::uno::Any
> factories
;
1145 for (const auto& rxImpl
: impls
)
1147 Data::Implementation
* impl
= rxImpl
.get();
1148 assert(impl
!= nullptr);
1150 std::unique_lock
g(m_aMutex
);
1155 if (impl
->status
== Data::Implementation::STATUS_NEW
) {
1156 // Postpone actual implementation instantiation as long as
1157 // possible (so that e.g. opening LO's "Tools - Macros" menu
1158 // does not try to instantiate a JVM, which can lead to a
1159 // synchronous error dialog when no JVM is specified, and
1160 // showing the dialog while hovering over a menu can cause
1162 impl
->factory1
= new ImplementationWrapper(this, rxImpl
);
1163 impl
->status
= Data::Implementation::STATUS_WRAPPER
;
1165 if (impl
->constructorFn
!= nullptr && !impl
->factory1
.is()) {
1166 impl
->factory1
= new ImplementationWrapper(this, rxImpl
);
1169 if (impl
->factory1
.is()) {
1170 factories
.push_back(css::uno::Any(impl
->factory1
));
1172 assert(impl
->factory2
.is());
1173 factories
.push_back(css::uno::Any(impl
->factory2
));
1176 return new ContentEnumeration(std::move(factories
));
1179 css::uno::Reference
< css::beans::XPropertySetInfo
>
1180 cppuhelper::ServiceManager::getPropertySetInfo()
1185 void cppuhelper::ServiceManager::setPropertyValue(
1186 OUString
const & aPropertyName
, css::uno::Any
const &)
1188 if (aPropertyName
== "DefaultContext") {
1189 throw css::beans::PropertyVetoException(
1190 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1192 throw css::beans::UnknownPropertyException(
1193 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1197 css::uno::Any
cppuhelper::ServiceManager::getPropertyValue(
1198 OUString
const & PropertyName
)
1200 if (PropertyName
!= "DefaultContext") {
1201 throw css::beans::UnknownPropertyException(
1202 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1204 assert(context_
.is());
1205 return css::uno::Any(context_
);
1208 void cppuhelper::ServiceManager::addPropertyChangeListener(
1209 OUString
const & aPropertyName
,
1210 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
1213 if (!aPropertyName
.isEmpty() && aPropertyName
!= "DefaultContext") {
1214 throw css::beans::UnknownPropertyException(
1215 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1217 // DefaultContext does not change, so just treat it as an event listener:
1218 return addEventListener(xListener
);
1221 void cppuhelper::ServiceManager::removePropertyChangeListener(
1222 OUString
const & aPropertyName
,
1223 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
1226 if (!aPropertyName
.isEmpty() && aPropertyName
!= "DefaultContext") {
1227 throw css::beans::UnknownPropertyException(
1228 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1230 // DefaultContext does not change, so just treat it as an event listener:
1231 return removeEventListener(aListener
);
1234 void cppuhelper::ServiceManager::addVetoableChangeListener(
1235 OUString
const & PropertyName
,
1236 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
1239 if (!PropertyName
.isEmpty() && PropertyName
!= "DefaultContext") {
1240 throw css::beans::UnknownPropertyException(
1241 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1243 // DefaultContext does not change, so just treat it as an event listener:
1244 return addEventListener(aListener
);
1247 void cppuhelper::ServiceManager::removeVetoableChangeListener(
1248 OUString
const & PropertyName
,
1249 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
1252 if (!PropertyName
.isEmpty() && PropertyName
!= "DefaultContext") {
1253 throw css::beans::UnknownPropertyException(
1254 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1256 // DefaultContext does not change, so just treat it as an event listener:
1257 return removeEventListener(aListener
);
1260 css::uno::Sequence
< css::beans::Property
>
1261 cppuhelper::ServiceManager::getProperties() {
1262 return { getDefaultContextProperty() };
1265 css::beans::Property
cppuhelper::ServiceManager::getPropertyByName(
1266 OUString
const & aName
)
1268 if (aName
!= "DefaultContext") {
1269 throw css::beans::UnknownPropertyException(
1270 aName
, static_cast< cppu::OWeakObject
* >(this));
1272 return getDefaultContextProperty();
1275 sal_Bool
cppuhelper::ServiceManager::hasPropertyByName(
1276 OUString
const & Name
)
1278 return Name
== "DefaultContext";
1281 cppuhelper::ServiceManager::~ServiceManager() {}
1283 void cppuhelper::ServiceManager::disposing(
1284 css::lang::EventObject
const & Source
)
1286 removeLegacyFactory(
1287 css::uno::Reference
< css::lang::XServiceInfo
>(
1288 Source
.Source
, css::uno::UNO_QUERY_THROW
),
1292 void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1293 css::uno::Reference
< css::lang::XComponent
> const & component
)
1295 assert(component
.is());
1297 component
->removeEventListener(this);
1298 } catch (css::uno::RuntimeException
& e
) {
1301 "Ignored removeEventListener RuntimeException " + e
.Message
);
1305 void cppuhelper::ServiceManager::init(std::u16string_view rdbUris
) {
1306 for (sal_Int32 i
= 0; i
!= -1;) {
1307 std::u16string_view
uri(o3tl::getToken(rdbUris
, 0, ' ', i
));
1313 cppu::decodeRdbUri(&uri
, &optional
, &directory
);
1315 readRdbDirectory(uri
, optional
);
1317 readRdbFile(OUString(uri
), optional
);
1322 void cppuhelper::ServiceManager::readRdbDirectory(
1323 std::u16string_view uri
, bool optional
)
1325 osl::Directory dir
= OUString(uri
);
1326 switch (dir
.open()) {
1327 case osl::FileBase::E_None
:
1329 case osl::FileBase::E_NOENT
:
1331 SAL_INFO("cppuhelper", "Ignored optional " << OUString(uri
));
1336 throw css::uno::DeploymentException(
1337 OUString::Concat("Cannot open directory ") + uri
,
1338 static_cast< cppu::OWeakObject
* >(this));
1342 if (!cppu::nextDirectoryItem(dir
, &url
)) {
1345 readRdbFile(url
, false);
1349 void cppuhelper::ServiceManager::readRdbFile(
1350 OUString
const & uri
, bool optional
)
1354 uri
, css::uno::Reference
< css::uno::XComponentContext
>(), &data_
);
1355 } catch (css::container::NoSuchElementException
&) {
1357 throw css::uno::DeploymentException(
1358 uri
+ ": no such file",
1359 static_cast< cppu::OWeakObject
* >(this));
1361 SAL_INFO("cppuhelper", "Ignored optional " << uri
);
1364 catch (css::registry::InvalidRegistryException
& e
) {
1365 if (!readLegacyRdbFile(uri
)) {
1366 throw css::uno::DeploymentException(
1367 "InvalidRegistryException: " + e
.Message
,
1368 static_cast< cppu::OWeakObject
* >(this));
1370 } catch (css::uno::RuntimeException
&) {
1371 if (!readLegacyRdbFile(uri
)) {
1379 bool cppuhelper::ServiceManager::readLegacyRdbFile(OUString
const & uri
) {
1381 switch (reg
.open(uri
, RegAccessMode::READONLY
)) {
1382 case RegError::NO_ERROR
:
1384 case RegError::REGISTRY_NOT_EXISTS
:
1385 case RegError::INVALID_REGISTRY
:
1387 // Ignore empty rdb files (which are at least seen by subordinate
1388 // uno processes during extension registration; Registry::open can
1389 // fail on them if mmap(2) returns EINVAL for a zero length):
1390 osl::DirectoryItem item
;
1391 if (osl::DirectoryItem::get(uri
, item
) == osl::FileBase::E_None
) {
1392 osl::FileStatus
status(osl_FileStatus_Mask_FileSize
);
1393 if (item
.getFileStatus(status
) == osl::FileBase::E_None
1394 && status
.getFileSize() == 0)
1404 RegistryKey rootKey
;
1405 if (reg
.openRootKey(rootKey
) != RegError::NO_ERROR
) {
1406 throw css::uno::DeploymentException(
1407 "Failure reading legacy rdb file " + uri
,
1408 static_cast< cppu::OWeakObject
* >(this));
1410 RegistryKeyArray impls
;
1411 switch (rootKey
.openSubKeys(u
"IMPLEMENTATIONS"_ustr
, impls
)) {
1412 case RegError::NO_ERROR
:
1414 case RegError::KEY_NOT_EXISTS
:
1417 throw css::uno::DeploymentException(
1418 "Failure reading legacy rdb file " + uri
,
1419 static_cast< cppu::OWeakObject
* >(this));
1421 for (sal_uInt32 i
= 0; i
!= impls
.getLength(); ++i
) {
1422 RegistryKey
implKey(impls
.getElement(i
));
1423 assert(implKey
.getName().match("/IMPLEMENTATIONS/"));
1425 implKey
.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1426 std::shared_ptr
< Data::Implementation
> impl
=
1427 std::make_shared
<Data::Implementation
>(
1428 name
, readLegacyRdbString(uri
, implKey
, u
"UNO/ACTIVATOR"_ustr
),
1429 readLegacyRdbString(uri
, implKey
, u
"UNO/LOCATION"_ustr
), "", "", "", false,
1430 css::uno::Reference
< css::uno::XComponentContext
>(), uri
);
1431 if (!data_
.namedImplementations
.emplace(name
, impl
).second
)
1433 throw css::registry::InvalidRegistryException(
1434 uri
+ ": duplicate <implementation name=\"" + name
+ "\">");
1436 readLegacyRdbStrings(
1437 uri
, implKey
, u
"UNO/SERVICES"_ustr
, &impl
->services
);
1438 for (const auto& rService
: impl
->services
)
1440 data_
.services
[rService
].push_back(impl
);
1442 readLegacyRdbStrings(
1443 uri
, implKey
, u
"UNO/SINGLETONS"_ustr
, &impl
->singletons
);
1444 for (const auto& rSingleton
: impl
->singletons
)
1446 data_
.singletons
[rSingleton
].push_back(impl
);
1452 OUString
cppuhelper::ServiceManager::readLegacyRdbString(
1453 std::u16string_view uri
, RegistryKey
& key
, OUString
const & path
)
1458 if (key
.openKey(path
, subkey
) != RegError::NO_ERROR
1459 || subkey
.getValueInfo(OUString(), &t
, &s
) != RegError::NO_ERROR
1460 || t
!= RegValueType::STRING
1461 || s
== 0 || s
> o3tl::make_unsigned(SAL_MAX_INT32
))
1463 throw css::uno::DeploymentException(
1464 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1465 static_cast< cppu::OWeakObject
* >(this));
1468 std::vector
< char > v(s
); // assuming sal_uInt32 fits into vector::size_type
1469 if (subkey
.getValue(OUString(), v
.data()) != RegError::NO_ERROR
1471 || !rtl_convertStringToUString(
1472 &val
.pData
, v
.data(), static_cast< sal_Int32
>(s
- 1),
1473 RTL_TEXTENCODING_UTF8
,
1474 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1475 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1476 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
1478 throw css::uno::DeploymentException(
1479 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1480 static_cast< cppu::OWeakObject
* >(this));
1485 void cppuhelper::ServiceManager::readLegacyRdbStrings(
1486 std::u16string_view uri
, RegistryKey
& key
, OUString
const & path
,
1487 std::vector
< OUString
> * strings
)
1489 assert(strings
!= nullptr);
1491 switch (key
.openKey(path
, subkey
)) {
1492 case RegError::NO_ERROR
:
1494 case RegError::KEY_NOT_EXISTS
:
1497 throw css::uno::DeploymentException(
1498 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1499 static_cast< cppu::OWeakObject
* >(this));
1501 OUString
prefix(subkey
.getName() + "/");
1502 RegistryKeyNames names
;
1503 if (subkey
.getKeyNames(OUString(), names
) != RegError::NO_ERROR
) {
1504 throw css::uno::DeploymentException(
1505 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1506 static_cast< cppu::OWeakObject
* >(this));
1508 for (sal_uInt32 i
= 0; i
!= names
.getLength(); ++i
) {
1509 assert(names
.getElement(i
).match(prefix
));
1510 strings
->push_back(names
.getElement(i
).copy(prefix
.getLength()));
1515 void cppuhelper::ServiceManager::insertRdbFiles(
1516 std::vector
< OUString
> const & uris
,
1517 css::uno::Reference
< css::uno::XComponentContext
> const & alienContext
)
1520 for (const auto& rUri
: uris
)
1523 Parser(rUri
, alienContext
, &extra
);
1524 } catch (css::container::NoSuchElementException
&) {
1525 throw css::lang::IllegalArgumentException(
1526 rUri
+ ": no such file", static_cast< cppu::OWeakObject
* >(this),
1528 } catch (css::registry::InvalidRegistryException
& e
) {
1529 throw css::lang::IllegalArgumentException(
1530 "InvalidRegistryException: " + e
.Message
,
1531 static_cast< cppu::OWeakObject
* >(this), 0);
1534 insertExtraData(extra
);
1537 void cppuhelper::ServiceManager::insertLegacyFactory(
1538 css::uno::Reference
< css::lang::XServiceInfo
> const & factoryInfo
)
1540 assert(factoryInfo
.is());
1541 OUString
name(factoryInfo
->getImplementationName());
1542 css::uno::Reference
< css::lang::XSingleComponentFactory
> f1(
1543 factoryInfo
, css::uno::UNO_QUERY
);
1544 css::uno::Reference
< css::lang::XSingleServiceFactory
> f2
;
1546 f2
.set(factoryInfo
, css::uno::UNO_QUERY
);
1548 throw css::lang::IllegalArgumentException(
1549 (u
"Bad XServiceInfo argument implements neither"
1550 " XSingleComponentFactory nor XSingleServiceFactory"_ustr
),
1551 static_cast< cppu::OWeakObject
* >(this), 0);
1554 css::uno::Reference
< css::lang::XComponent
> comp(
1555 factoryInfo
, css::uno::UNO_QUERY
);
1556 std::shared_ptr
< Data::Implementation
> impl
=
1557 std::make_shared
<Data::Implementation
>(name
, f1
, f2
, comp
);
1559 if (!name
.isEmpty()) {
1560 extra
.namedImplementations
.emplace(name
, impl
);
1562 extra
.dynamicImplementations
.emplace(factoryInfo
, impl
);
1563 const css::uno::Sequence
< OUString
> services(
1564 factoryInfo
->getSupportedServiceNames());
1565 for (const auto & i
: services
) {
1566 impl
->services
.push_back(i
);
1567 extra
.services
[i
].push_back(impl
);
1569 if (insertExtraData(extra
) && comp
.is()) {
1570 comp
->addEventListener(this);
1574 bool cppuhelper::ServiceManager::insertExtraData(Data
const & extra
) {
1576 std::unique_lock
g(m_aMutex
);
1580 auto i
= std::find_if(extra
.namedImplementations
.begin(), extra
.namedImplementations
.end(),
1581 [this](const Data::NamedImplementations::value_type
& rEntry
) {
1582 return data_
.namedImplementations
.find(rEntry
.first
) != data_
.namedImplementations
.end(); });
1583 if (i
!= extra
.namedImplementations
.end())
1585 throw css::lang::IllegalArgumentException(
1586 "Insert duplicate implementation name " + i
->first
,
1587 static_cast< cppu::OWeakObject
* >(this), 0);
1589 bool bDuplicate
= std::any_of(extra
.dynamicImplementations
.begin(), extra
.dynamicImplementations
.end(),
1590 [this](const Data::DynamicImplementations::value_type
& rEntry
) {
1591 return data_
.dynamicImplementations
.find(rEntry
.first
) != data_
.dynamicImplementations
.end(); });
1594 throw css::lang::IllegalArgumentException(
1595 u
"Insert duplicate factory object"_ustr
,
1596 static_cast< cppu::OWeakObject
* >(this), 0);
1598 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1599 data_
.namedImplementations
.insert(
1600 extra
.namedImplementations
.begin(),
1601 extra
.namedImplementations
.end());
1602 data_
.dynamicImplementations
.insert(
1603 extra
.dynamicImplementations
.begin(),
1604 extra
.dynamicImplementations
.end());
1605 insertImplementationMap(&data_
.services
, extra
.services
);
1606 insertImplementationMap(&data_
.singletons
, extra
.singletons
);
1608 //TODO: Updating the component context singleton data should be part of the
1609 // atomic service manager update:
1610 if (extra
.singletons
.empty())
1613 assert(context_
.is());
1614 css::uno::Reference
< css::container::XNameContainer
> cont(
1615 context_
, css::uno::UNO_QUERY_THROW
);
1616 for (const auto& [rName
, rImpls
] : extra
.singletons
)
1618 OUString
name("/singletons/" + rName
);
1619 //TODO: Update should be atomic:
1621 cont
->removeByName(name
+ "/arguments");
1622 } catch (const css::container::NoSuchElementException
&) {}
1623 assert(!rImpls
.empty());
1626 rImpls
.size() > 1, "cppuhelper",
1627 "Arbitrarily choosing " << rImpls
[0]->name
1628 << " among multiple implementations for singleton "
1632 name
+ "/service", css::uno::Any(rImpls
[0]->name
));
1633 } catch (css::container::ElementExistException
&) {
1634 cont
->replaceByName(
1635 name
+ "/service", css::uno::Any(rImpls
[0]->name
));
1638 cont
->insertByName(name
, css::uno::Any());
1639 } catch (css::container::ElementExistException
&) {
1640 SAL_INFO("cppuhelper", "Overwriting singleton " << rName
);
1641 cont
->replaceByName(name
, css::uno::Any());
1647 void cppuhelper::ServiceManager::removeRdbFiles(
1648 std::vector
< OUString
> const & uris
)
1650 // The underlying data structures make this function somewhat inefficient,
1651 // but the assumption is that it is rarely called (and that if it is called,
1652 // it is called with a uris vector of size one):
1653 std::vector
< std::shared_ptr
< Data::Implementation
> > clear
;
1655 std::unique_lock
g(m_aMutex
);
1656 for (const auto& rUri
: uris
)
1658 for (Data::NamedImplementations::iterator
j(
1659 data_
.namedImplementations
.begin());
1660 j
!= data_
.namedImplementations
.end();)
1663 if (j
->second
->rdbFile
== rUri
) {
1664 clear
.push_back(j
->second
);
1665 //TODO: The below leaves data_ in an inconsistent state upon
1667 removeFromImplementationMap(
1668 &data_
.services
, j
->second
->services
, j
->second
);
1669 removeFromImplementationMap(
1670 &data_
.singletons
, j
->second
->singletons
,
1672 j
= data_
.namedImplementations
.erase(j
);
1679 //TODO: Update the component context singleton data
1682 bool cppuhelper::ServiceManager::removeLegacyFactory(
1683 css::uno::Reference
< css::lang::XServiceInfo
> const & factoryInfo
,
1684 bool removeListener
)
1686 assert(factoryInfo
.is());
1687 std::shared_ptr
< Data::Implementation
> clear
;
1688 css::uno::Reference
< css::lang::XComponent
> comp
;
1690 std::unique_lock
g(m_aMutex
);
1691 Data::DynamicImplementations::iterator
i(
1692 data_
.dynamicImplementations
.find(factoryInfo
));
1693 if (i
== data_
.dynamicImplementations
.end()) {
1698 if (removeListener
) {
1699 comp
= i
->second
->component
;
1701 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1702 removeFromImplementationMap(
1703 &data_
.services
, i
->second
->services
, i
->second
);
1704 removeFromImplementationMap(
1705 &data_
.singletons
, i
->second
->singletons
, i
->second
);
1706 if (!i
->second
->name
.isEmpty()) {
1707 data_
.namedImplementations
.erase(i
->second
->name
);
1709 data_
.dynamicImplementations
.erase(i
);
1712 removeEventListenerFromComponent(comp
);
1717 void cppuhelper::ServiceManager::removeImplementation(const OUString
& name
) {
1718 // The underlying data structures make this function somewhat inefficient,
1719 // but the assumption is that it is rarely called:
1720 std::shared_ptr
< Data::Implementation
> clear
;
1722 std::unique_lock
g(m_aMutex
);
1726 Data::NamedImplementations::iterator
i(
1727 data_
.namedImplementations
.find(name
));
1728 if (i
== data_
.namedImplementations
.end()) {
1729 throw css::container::NoSuchElementException(
1730 "Remove non-inserted implementation " + name
,
1731 static_cast< cppu::OWeakObject
* >(this));
1735 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1736 removeFromImplementationMap(
1737 &data_
.services
, i
->second
->services
, i
->second
);
1738 removeFromImplementationMap(
1739 &data_
.singletons
, i
->second
->singletons
, i
->second
);
1740 auto j
= std::find_if(data_
.dynamicImplementations
.begin(), data_
.dynamicImplementations
.end(),
1741 [&i
](const Data::DynamicImplementations::value_type
& rEntry
) { return rEntry
.second
== i
->second
; });
1742 if (j
!= data_
.dynamicImplementations
.end())
1743 data_
.dynamicImplementations
.erase(j
);
1744 data_
.namedImplementations
.erase(i
);
1748 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
1749 cppuhelper::ServiceManager::findServiceImplementation(
1750 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
1751 OUString
const & specifier
)
1753 std::shared_ptr
< Data::Implementation
> impl
;
1756 std::unique_lock
g(m_aMutex
);
1757 Data::ImplementationMap::const_iterator
i(
1758 data_
.services
.find(specifier
));
1759 if (i
== data_
.services
.end()) {
1760 Data::NamedImplementations::const_iterator
j(
1761 data_
.namedImplementations
.find(specifier
));
1762 if (j
== data_
.namedImplementations
.end()) {
1763 SAL_INFO("cppuhelper", "No implementation for " << specifier
);
1764 return std::shared_ptr
< Data::Implementation
>();
1768 assert(!i
->second
.empty());
1770 i
->second
.size() > 1, "cppuhelper",
1771 "Arbitrarily choosing " << i
->second
[0]->name
1772 << " among multiple implementations for " << i
->first
);
1773 impl
= i
->second
[0];
1776 loaded
= impl
->status
== Data::Implementation::STATUS_LOADED
;
1779 loadImplementation(context
, impl
);
1784 /// Make a simpler unique name for preload / progress reporting.
1785 #ifndef DISABLE_DYNLOADING
1786 static OUString
simplifyModule(std::u16string_view uri
)
1789 OUStringBuffer
edit(uri
);
1790 if ((nIdx
= edit
.lastIndexOf('/')) > 0)
1791 edit
.remove(0,nIdx
+1);
1792 if ((nIdx
= edit
.lastIndexOf(':')) > 0)
1793 edit
.remove(0,nIdx
+1);
1794 if ((nIdx
= edit
.lastIndexOf("lo.so")) > 0)
1795 edit
.truncate(nIdx
);
1796 if ((nIdx
= edit
.lastIndexOf(".3")) > 0)
1797 edit
.truncate(nIdx
);
1798 if ((nIdx
= edit
.lastIndexOf("gcc3.so")) > 0)
1799 edit
.truncate(nIdx
);
1800 if ((nIdx
= edit
.lastIndexOf(".so")) > 0)
1801 edit
.truncate(nIdx
);
1802 if ((nIdx
= edit
.lastIndexOf("_uno")) > 0)
1803 edit
.truncate(nIdx
);
1804 if ((nIdx
= edit
.lastIndexOf(".jar")) > 0)
1805 edit
.truncate(nIdx
);
1806 if (edit
.indexOf("lib") == 0)
1808 return edit
.makeStringAndClear();
1812 /// Used only by LibreOfficeKit when used by Online to pre-initialize
1813 void cppuhelper::ServiceManager::preloadImplementations() {
1814 #ifdef DISABLE_DYNLOADING
1818 std::unique_lock
g(m_aMutex
);
1819 css::uno::Environment
aSourceEnv(css::uno::Environment::getCurrent());
1821 std::cerr
<< "preload:";
1822 std::vector
<OUString
> aReported
;
1823 std::vector
<OUString
> aDisabled
;
1824 OUStringBuffer aDisabledMsg
;
1825 OUStringBuffer aMissingMsg
;
1827 /// Allow external callers & testers to disable certain components
1828 const char *pDisable
= getenv("UNODISABLELIBRARY");
1831 OUString
aDisable(pDisable
, strlen(pDisable
), RTL_TEXTENCODING_UTF8
);
1832 for (sal_Int32 i
= 0; i
>= 0; )
1834 OUString
tok( aDisable
.getToken(0, ' ', i
) );
1837 aDisabled
.push_back(tok
);
1841 // loop all implementations
1842 for (const auto& rEntry
: data_
.namedImplementations
)
1844 if (rEntry
.second
->loader
!= "com.sun.star.loader.SharedLibrary" ||
1845 rEntry
.second
->status
== Data::Implementation::STATUS_LOADED
)
1848 OUString simplified
;
1851 const OUString
&aLibrary
= rEntry
.second
->uri
;
1853 if (aLibrary
.isEmpty())
1856 simplified
= simplifyModule(aLibrary
);
1859 std::find(aDisabled
.begin(), aDisabled
.end(), simplified
) != aDisabled
.end();
1861 if (std::find(aReported
.begin(), aReported
.end(), aLibrary
) == aReported
.end())
1865 aDisabledMsg
.append(simplified
+ " ");
1869 std::cerr
<< " " << simplified
;
1872 aReported
.push_back(aLibrary
);
1878 // expand absolute URI implementation component library
1879 aUri
= cppu::bootstrap_expandUri(aLibrary
);
1881 catch (css::lang::IllegalArgumentException
& aError
)
1883 throw css::uno::DeploymentException(
1884 "Cannot expand URI" + rEntry
.second
->uri
+ ": " + aError
.Message
,
1885 static_cast< cppu::OWeakObject
* >(this));
1888 // load component library
1889 osl::Module
aModule(aUri
, SAL_LOADMODULE_NOW
| SAL_LOADMODULE_GLOBAL
);
1893 aMissingMsg
.append(simplified
+ " ");
1897 !rEntry
.second
->environment
.isEmpty())
1899 oslGenericFunction fpFactory
;
1900 css::uno::Environment aTargetEnv
;
1901 css::uno::Reference
<css::uno::XInterface
> xFactory
;
1903 if(rEntry
.second
->constructorName
.isEmpty())
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
;
1912 aSymFactory
= COMPONENT_GETFACTORY
;
1914 // get function symbol component factory
1915 fpFactory
= aModule
.getFunctionSymbol(aSymFactory
);
1916 if (fpFactory
== nullptr)
1918 throw css::loader::CannotActivateFactoryException(
1919 ("no factory symbol \"" + aSymFactory
+ "\" in component library :" + aUri
),
1920 css::uno::Reference
<css::uno::XInterface
>());
1923 aTargetEnv
= cppuhelper::detail::getEnvironment(rEntry
.second
->environment
, rEntry
.second
->name
);
1924 component_getFactoryFunc fpComponentFactory
= reinterpret_cast<component_getFactoryFunc
>(fpFactory
);
1926 if (aSourceEnv
.get() == aTargetEnv
.get())
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
));
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;
1942 css::uno::Reference
<css::lang::XSingleComponentFactory
> xSCFactory
;
1943 css::uno::Reference
<css::lang::XSingleServiceFactory
> xSSFactory
;
1945 // query interface XSingleComponentFactory or XSingleServiceFactory
1948 xSCFactory
.set(xFactory
, css::uno::UNO_QUERY
);
1949 if (!xSCFactory
.is())
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));
1960 if (!rEntry
.second
->constructorName
.isEmpty() && fpFactory
)
1961 rEntry
.second
->constructorFn
= WrapperConstructorFn(reinterpret_cast<ImplementationConstructorFn
*>(fpFactory
));
1963 rEntry
.second
->factory1
= xSCFactory
;
1964 rEntry
.second
->factory2
= xSSFactory
;
1965 rEntry
.second
->status
= Data::Implementation::STATUS_LOADED
;
1969 // Some libraries use other (non-UNO) libraries requiring preinit
1970 oslGenericFunction fpPreload
= aModule
.getFunctionSymbol( "lok_preload_hook" );
1973 static std::vector
<oslGenericFunction
> aPreloaded
;
1974 if (std::find(aPreloaded
.begin(), aPreloaded
.end(), fpPreload
) == aPreloaded
.end())
1976 aPreloaded
.push_back(fpPreload
);
1977 // unlock because we may be instantiating some services here
1987 std::cerr
<< std::endl
;
1989 if (aMissingMsg
.getLength() > 0)
1991 OUString aMsg
= aMissingMsg
.makeStringAndClear();
1992 std::cerr
<< "Absent (often optional): " << aMsg
<< "\n";
1994 if (aDisabledMsg
.getLength() > 0)
1996 OUString aMsg
= aDisabledMsg
.makeStringAndClear();
1997 std::cerr
<< "Disabled: " << aMsg
<< "\n";
2001 // Various rather important uno mappings.
2006 } constexpr aMappingLoad
[] = {
2007 { u
"gcc3"_ustr
, u
"uno"_ustr
, u
""_ustr
},
2008 { u
"uno"_ustr
, u
"gcc3"_ustr
, u
""_ustr
},
2011 static std::vector
<css::uno::Mapping
> maMaps
;
2012 for (auto &it
: aMappingLoad
)
2014 maMaps
.push_back(css::uno::Mapping(it
.maFrom
, it
.maTo
, it
.maPurpose
));
2019 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */