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
)
73 cppuhelper::ServiceManager::Data::Implementation
> > & impls
74 = (*destination
)[rName
];
75 impls
.insert(impls
.end(), rImpls
.begin(), rImpls
.end());
79 void removeFromImplementationMap(
80 cppuhelper::ServiceManager::Data::ImplementationMap
* map
,
81 std::vector
< OUString
> const & elements
,
82 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
83 const & implementation
)
85 // The underlying data structures make this function somewhat inefficient,
86 // but the assumption is that it is rarely called:
87 assert(map
!= nullptr);
88 for (const auto& rElement
: elements
)
90 cppuhelper::ServiceManager::Data::ImplementationMap::iterator
j(
92 assert(j
!= map
->end());
95 cppuhelper::ServiceManager::Data::Implementation
> >::iterator
96 k(std::find(j
->second
.begin(), j
->second
.end(), implementation
));
97 assert(k
!= j
->second
.end());
99 if (j
->second
.empty()) {
105 // For simplicity, this code keeps throwing
106 // css::registry::InvalidRegistryException for invalid XML rdbs (even though
107 // that does not fit the exception's name):
111 OUString
const & uri
,
112 css::uno::Reference
< css::uno::XComponentContext
> alienContext
,
113 cppuhelper::ServiceManager::Data
* data
);
115 Parser(const Parser
&) = delete;
116 const Parser
& operator=(const Parser
&) = delete;
119 void handleComponent();
121 void handleImplementation();
123 void handleService();
125 void handleSingleton();
127 OUString
getNameAttribute();
129 xmlreader::XmlReader reader_
;
130 css::uno::Reference
< css::uno::XComponentContext
> alienContext_
;
131 cppuhelper::ServiceManager::Data
* data_
;
132 OUString attrLoader_
;
134 OUString attrEnvironment_
;
135 OUString attrPrefix_
;
136 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
141 OUString
const & uri
,
142 css::uno::Reference
< css::uno::XComponentContext
> alienContext
,
143 cppuhelper::ServiceManager::Data
* data
):
144 reader_(uri
), alienContext_(std::move(alienContext
)), data_(data
)
146 assert(data
!= nullptr);
147 int ucNsId
= reader_
.registerNamespaceIri(
149 RTL_CONSTASCII_STRINGPARAM(
150 "http://openoffice.org/2010/uno-components")));
152 STATE_BEGIN
, STATE_END
, STATE_COMPONENTS
, STATE_COMPONENT_INITIAL
,
153 STATE_COMPONENT
, STATE_IMPLEMENTATION
, STATE_SERVICE
, STATE_SINGLETON
};
154 for (State state
= STATE_BEGIN
;;) {
155 xmlreader::Span name
;
157 xmlreader::XmlReader::Result res
= reader_
.nextItem(
158 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
161 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
162 && name
.equals(RTL_CONSTASCII_STRINGPARAM("components")))
164 state
= STATE_COMPONENTS
;
167 throw css::registry::InvalidRegistryException(
168 reader_
.getUrl() + ": unexpected item in outer level");
170 if (res
== xmlreader::XmlReader::Result::Done
) {
173 throw css::registry::InvalidRegistryException(
174 reader_
.getUrl() + ": unexpected item in outer level");
175 case STATE_COMPONENTS
:
176 if (res
== xmlreader::XmlReader::Result::End
) {
180 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
181 && name
.equals(RTL_CONSTASCII_STRINGPARAM("component")))
184 state
= STATE_COMPONENT_INITIAL
;
187 throw css::registry::InvalidRegistryException(
188 reader_
.getUrl() + ": unexpected item in <components>");
189 case STATE_COMPONENT
:
190 if (res
== xmlreader::XmlReader::Result::End
) {
191 state
= STATE_COMPONENTS
;
195 case STATE_COMPONENT_INITIAL
:
196 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
197 && name
.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
199 handleImplementation();
200 state
= STATE_IMPLEMENTATION
;
203 throw css::registry::InvalidRegistryException(
204 reader_
.getUrl() + ": unexpected item in <component>");
205 case STATE_IMPLEMENTATION
:
206 if (res
== xmlreader::XmlReader::Result::End
) {
207 state
= STATE_COMPONENT
;
210 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
211 && name
.equals(RTL_CONSTASCII_STRINGPARAM("service")))
214 state
= STATE_SERVICE
;
217 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
218 && name
.equals(RTL_CONSTASCII_STRINGPARAM("singleton")))
221 state
= STATE_SINGLETON
;
224 throw css::registry::InvalidRegistryException(
225 reader_
.getUrl() + ": unexpected item in <implementation>");
227 if (res
== xmlreader::XmlReader::Result::End
) {
228 state
= STATE_IMPLEMENTATION
;
231 throw css::registry::InvalidRegistryException(
232 reader_
.getUrl() + ": unexpected item in <service>");
233 case STATE_SINGLETON
:
234 if (res
== xmlreader::XmlReader::Result::End
) {
235 state
= STATE_IMPLEMENTATION
;
238 throw css::registry::InvalidRegistryException(
239 reader_
.getUrl() + ": unexpected item in <service>");
244 void Parser::handleComponent() {
245 attrLoader_
= OUString();
246 attrUri_
= OUString();
247 attrEnvironment_
= OUString();
248 attrPrefix_
= OUString();
249 xmlreader::Span name
;
251 while (reader_
.nextAttribute(&nsId
, &name
)) {
252 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
253 && name
.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
255 if (!attrLoader_
.isEmpty()) {
256 throw css::registry::InvalidRegistryException(
258 + ": <component> has multiple \"loader\" attributes");
260 attrLoader_
= reader_
.getAttributeValue(false).convertFromUtf8();
261 if (attrLoader_
.isEmpty()) {
262 throw css::registry::InvalidRegistryException(
264 + ": <component> has empty \"loader\" attribute");
266 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
267 && name
.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
269 if (!attrUri_
.isEmpty()) {
270 throw css::registry::InvalidRegistryException(
272 + ": <component> has multiple \"uri\" attributes");
274 attrUri_
= reader_
.getAttributeValue(false).convertFromUtf8();
275 if (attrUri_
.isEmpty()) {
276 throw css::registry::InvalidRegistryException(
278 + ": <component> has empty \"uri\" attribute");
280 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
281 && name
.equals(RTL_CONSTASCII_STRINGPARAM("environment")))
283 if (!attrEnvironment_
.isEmpty()) {
284 throw css::registry::InvalidRegistryException(
286 ": <component> has multiple \"environment\" attributes");
288 attrEnvironment_
= reader_
.getAttributeValue(false)
290 if (attrEnvironment_
.isEmpty()) {
291 throw css::registry::InvalidRegistryException(
293 ": <component> has empty \"environment\" attribute");
295 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
296 && name
.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
298 if (!attrPrefix_
.isEmpty()) {
299 throw css::registry::InvalidRegistryException(
301 ": <component> has multiple \"prefix\" attributes");
303 attrPrefix_
= reader_
.getAttributeValue(false).convertFromUtf8();
304 if (attrPrefix_
.isEmpty()) {
305 throw css::registry::InvalidRegistryException(
307 ": <component> has empty \"prefix\" attribute");
310 throw css::registry::InvalidRegistryException(
311 reader_
.getUrl() + ": unexpected attribute \""
312 + name
.convertFromUtf8() + "\" in <component>");
315 if (attrLoader_
.isEmpty()) {
316 throw css::registry::InvalidRegistryException(
317 reader_
.getUrl() + ": <component> is missing \"loader\" attribute");
319 if (attrUri_
.isEmpty()) {
320 throw css::registry::InvalidRegistryException(
321 reader_
.getUrl() + ": <component> is missing \"uri\" attribute");
323 #ifndef DISABLE_DYNLOADING
325 attrUri_
= rtl::Uri::convertRelToAbs(reader_
.getUrl(), attrUri_
);
326 } catch (const rtl::MalformedUriException
& e
) {
327 throw css::registry::InvalidRegistryException(
328 reader_
.getUrl() + ": bad \"uri\" attribute: " + e
.getMessage());
333 void Parser::handleImplementation() {
335 OUString attrConstructor
;
336 bool attrSingleInstance
= false;
337 xmlreader::Span name
;
339 while (reader_
.nextAttribute(&nsId
, &name
)) {
340 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
341 && name
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
343 if (!attrName
.isEmpty()) {
344 throw css::registry::InvalidRegistryException(
346 + ": <implementation> has multiple \"name\" attributes");
348 attrName
= reader_
.getAttributeValue(false).convertFromUtf8();
349 if (attrName
.isEmpty()) {
350 throw css::registry::InvalidRegistryException(
352 + ": <implementation> has empty \"name\" attribute");
354 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
355 && name
.equals(RTL_CONSTASCII_STRINGPARAM("constructor")))
357 if (!attrConstructor
.isEmpty()) {
358 throw css::registry::InvalidRegistryException(
360 + ": <implementation> has multiple \"constructor\""
363 attrConstructor
= reader_
.getAttributeValue(false)
365 if (attrConstructor
.isEmpty()) {
366 throw css::registry::InvalidRegistryException(
368 + ": element has empty \"constructor\" attribute");
370 if (attrEnvironment_
.isEmpty()) {
371 throw css::registry::InvalidRegistryException(
373 + ": <implementation> has \"constructor\" attribute but"
374 " <component> has no \"environment\" attribute");
376 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
377 && name
.equals(RTL_CONSTASCII_STRINGPARAM("single-instance")))
379 if (attrSingleInstance
) {
380 throw css::registry::InvalidRegistryException(
382 + ": <implementation> has multiple \"single-instance\" attributes");
384 if (!reader_
.getAttributeValue(false).equals(RTL_CONSTASCII_STRINGPARAM("true"))) {
385 throw css::registry::InvalidRegistryException(
386 reader_
.getUrl() + ": <implementation> has bad \"single-instance\" attribute");
388 attrSingleInstance
= true;
390 throw css::registry::InvalidRegistryException(
391 reader_
.getUrl() + ": unexpected element attribute \""
392 + name
.convertFromUtf8() + "\" in <implementation>");
395 if (attrName
.isEmpty()) {
396 throw css::registry::InvalidRegistryException(
398 + ": <implementation> is missing \"name\" attribute");
401 std::make_shared
<cppuhelper::ServiceManager::Data::Implementation
>(
402 attrName
, attrLoader_
, attrUri_
, attrEnvironment_
, attrConstructor
,
403 attrPrefix_
, attrSingleInstance
, alienContext_
, reader_
.getUrl());
404 if (!data_
->namedImplementations
.emplace(attrName
, implementation_
).
407 throw css::registry::InvalidRegistryException(
408 reader_
.getUrl() + ": duplicate <implementation name=\"" + attrName
413 void Parser::handleService() {
414 OUString
name(getNameAttribute());
415 implementation_
->services
.push_back(name
);
416 data_
->services
[name
].push_back(implementation_
);
419 void Parser::handleSingleton() {
420 OUString
name(getNameAttribute());
421 implementation_
->singletons
.push_back(name
);
422 data_
->singletons
[name
].push_back(implementation_
);
425 OUString
Parser::getNameAttribute() {
427 xmlreader::Span name
;
429 while (reader_
.nextAttribute(&nsId
, &name
)) {
430 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
431 || !name
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
433 throw css::registry::InvalidRegistryException(
434 reader_
.getUrl() + ": expected element attribute \"name\"");
436 if (!attrName
.isEmpty()) {
437 throw css::registry::InvalidRegistryException(
439 + ": element has multiple \"name\" attributes");
441 attrName
= reader_
.getAttributeValue(false).convertFromUtf8();
442 if (attrName
.isEmpty()) {
443 throw css::registry::InvalidRegistryException(
444 reader_
.getUrl() + ": element has empty \"name\" attribute");
447 if (attrName
.isEmpty()) {
448 throw css::registry::InvalidRegistryException(
449 reader_
.getUrl() + ": element is missing \"name\" attribute");
454 class ContentEnumeration
:
455 public cppu::WeakImplHelper
< css::container::XEnumeration
>
458 explicit ContentEnumeration(std::vector
< css::uno::Any
>&& factories
):
459 factories_(std::move(factories
)), iterator_(factories_
.begin()) {}
461 ContentEnumeration(const ContentEnumeration
&) = delete;
462 const ContentEnumeration
& operator=(const ContentEnumeration
&) = delete;
465 virtual ~ContentEnumeration() override
{}
467 virtual sal_Bool SAL_CALL
hasMoreElements() override
;
469 virtual css::uno::Any SAL_CALL
nextElement() override
;
472 std::vector
< css::uno::Any
> factories_
;
473 std::vector
< css::uno::Any
>::const_iterator iterator_
;
476 sal_Bool
ContentEnumeration::hasMoreElements()
478 std::scoped_lock
g(mutex_
);
479 return iterator_
!= factories_
.end();
482 css::uno::Any
ContentEnumeration::nextElement()
484 std::scoped_lock
g(mutex_
);
485 if (iterator_
== factories_
.end()) {
486 throw css::container::NoSuchElementException(
487 "Bootstrap service manager service enumerator has no more elements",
488 static_cast< cppu::OWeakObject
* >(this));
493 css::beans::Property
getDefaultContextProperty() {
494 return css::beans::Property(
495 "DefaultContext", -1,
496 cppu::UnoType
< css::uno::XComponentContext
>::get(),
497 css::beans::PropertyAttribute::READONLY
);
500 class SingletonFactory
:
501 public cppu::WeakImplHelper
<css::lang::XSingleComponentFactory
>
505 rtl::Reference
< cppuhelper::ServiceManager
> const & manager
,
507 cppuhelper::ServiceManager::Data::Implementation
> const &
509 manager_(manager
), implementation_(implementation
)
510 { assert(manager
.is()); assert(implementation
); }
512 SingletonFactory(const SingletonFactory
&) = delete;
513 const SingletonFactory
& operator=(const SingletonFactory
&) = delete;
516 virtual ~SingletonFactory() override
{}
518 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
519 createInstanceWithContext(
520 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
522 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
523 createInstanceWithArgumentsAndContext(
524 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
525 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
527 rtl::Reference
< cppuhelper::ServiceManager
> manager_
;
528 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
532 css::uno::Reference
< css::uno::XInterface
>
533 SingletonFactory::createInstanceWithContext(
534 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
536 manager_
->loadImplementation(Context
, implementation_
);
537 return implementation_
->createInstance(Context
, true);
540 css::uno::Reference
< css::uno::XInterface
>
541 SingletonFactory::createInstanceWithArgumentsAndContext(
542 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
543 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
545 manager_
->loadImplementation(Context
, implementation_
);
546 return implementation_
->createInstanceWithArguments(
547 Context
, true, Arguments
);
550 class ImplementationWrapper
:
551 public cppu::WeakImplHelper
<
552 css::lang::XSingleComponentFactory
, css::lang::XSingleServiceFactory
,
553 css::lang::XServiceInfo
>
556 ImplementationWrapper(
557 rtl::Reference
< cppuhelper::ServiceManager
> const & manager
,
559 cppuhelper::ServiceManager::Data::Implementation
> const &
561 manager_(manager
), implementation_(implementation
)
562 { assert(manager
.is()); assert(implementation
); }
564 ImplementationWrapper(const ImplementationWrapper
&) = delete;
565 const ImplementationWrapper
& operator=(const ImplementationWrapper
&) = delete;
568 virtual ~ImplementationWrapper() override
{}
570 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
571 createInstanceWithContext(
572 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
574 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
575 createInstanceWithArgumentsAndContext(
576 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
577 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
579 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
580 createInstance() override
;
582 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
583 createInstanceWithArguments(
584 css::uno::Sequence
< css::uno::Any
> const & Arguments
) override
;
586 virtual OUString SAL_CALL
getImplementationName() override
;
588 virtual sal_Bool SAL_CALL
supportsService(OUString
const & ServiceName
) override
;
590 virtual css::uno::Sequence
< OUString
> SAL_CALL
591 getSupportedServiceNames() override
;
593 rtl::Reference
< cppuhelper::ServiceManager
> manager_
;
594 std::weak_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
598 css::uno::Reference
< css::uno::XInterface
>
599 ImplementationWrapper::createInstanceWithContext(
600 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
602 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
604 manager_
->loadImplementation(Context
, impl
);
605 return impl
->createInstance(Context
, false);
608 css::uno::Reference
< css::uno::XInterface
>
609 ImplementationWrapper::createInstanceWithArgumentsAndContext(
610 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
611 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
613 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
615 manager_
->loadImplementation(Context
, impl
);
616 return impl
->createInstanceWithArguments(
617 Context
, false, Arguments
);
620 css::uno::Reference
< css::uno::XInterface
>
621 ImplementationWrapper::createInstance()
623 return createInstanceWithContext(manager_
->getContext());
626 css::uno::Reference
< css::uno::XInterface
>
627 ImplementationWrapper::createInstanceWithArguments(
628 css::uno::Sequence
< css::uno::Any
> const & Arguments
)
630 return createInstanceWithArgumentsAndContext(
631 Arguments
, manager_
->getContext());
634 OUString
ImplementationWrapper::getImplementationName()
636 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
641 sal_Bool
ImplementationWrapper::supportsService(OUString
const & ServiceName
)
643 return cppu::supportsService(this, ServiceName
);
646 css::uno::Sequence
< OUString
>
647 ImplementationWrapper::getSupportedServiceNames()
649 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
651 if (impl
->services
.size()
652 > o3tl::make_unsigned(SAL_MAX_INT32
))
654 throw css::uno::RuntimeException(
655 ("Implementation " + impl
->name
656 + " supports too many services"),
657 static_cast< cppu::OWeakObject
* >(this));
659 return comphelper::containerToSequence(impl
->services
);
664 css::uno::Reference
<css::uno::XInterface
>
665 cppuhelper::ServiceManager::Data::Implementation::createInstance(
666 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
667 bool singletonRequest
)
669 css::uno::Reference
<css::uno::XInterface
> inst
;
670 if (isSingleInstance
) {
671 std::unique_lock
g(mutex
);
672 if (!singleInstance
.is()) {
673 singleInstance
= doCreateInstance(context
);
675 inst
= singleInstance
;
677 inst
= doCreateInstance(context
);
679 updateDisposeInstance(singletonRequest
, inst
);
683 css::uno::Reference
<css::uno::XInterface
>
684 cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments(
685 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
686 bool singletonRequest
, css::uno::Sequence
<css::uno::Any
> const & arguments
)
688 css::uno::Reference
<css::uno::XInterface
> inst
;
689 if (isSingleInstance
) {
690 std::unique_lock
g(mutex
);
691 if (!singleInstance
.is()) {
692 singleInstance
= doCreateInstanceWithArguments(context
, arguments
);
694 inst
= singleInstance
;
696 inst
= doCreateInstanceWithArguments(context
, arguments
);
698 updateDisposeInstance(singletonRequest
, inst
);
702 css::uno::Reference
<css::uno::XInterface
>
703 cppuhelper::ServiceManager::Data::Implementation::doCreateInstance(
704 css::uno::Reference
<css::uno::XComponentContext
> const & context
)
707 return css::uno::Reference
<css::uno::XInterface
>(
708 constructorFn(context
.get(), css::uno::Sequence
<css::uno::Any
>()),
710 } else if (factory1
.is()) {
711 return factory1
->createInstanceWithContext(context
);
713 assert(factory2
.is());
714 return factory2
->createInstance();
718 css::uno::Reference
<css::uno::XInterface
>
719 cppuhelper::ServiceManager::Data::Implementation::doCreateInstanceWithArguments(
720 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
721 css::uno::Sequence
<css::uno::Any
> const & arguments
)
724 css::uno::Reference
<css::uno::XInterface
> inst(
725 constructorFn(context
.get(), arguments
), SAL_NO_ACQUIRE
);
726 //HACK: The constructor will either observe arguments and return inst
727 // that does not implement XInitialization (or null), or ignore
728 // arguments and return inst that implements XInitialization; this
729 // should be removed again once XInitialization-based implementations
731 css::uno::Reference
<css::lang::XInitialization
> init(
732 inst
, css::uno::UNO_QUERY
);
734 init
->initialize(arguments
);
737 } else if (factory1
.is()) {
738 return factory1
->createInstanceWithArgumentsAndContext(
741 assert(factory2
.is());
742 return factory2
->createInstanceWithArguments(arguments
);
746 void cppuhelper::ServiceManager::Data::Implementation::updateDisposeInstance(
747 bool singletonRequest
,
748 css::uno::Reference
<css::uno::XInterface
> const & instance
)
750 // This is an optimization, to only call dispose once (from the component
751 // context) on a singleton that is obtained both via the component context
752 // and via the service manager; however, there is a harmless race here that
753 // may cause two calls to dispose nevertheless (also, this calls dispose on
754 // at most one of the instances obtained via the service manager, in case
755 // the implementation hands out different instances):
756 if (singletonRequest
) {
757 std::unique_lock
g(mutex
);
758 disposeInstance
.clear();
760 } else if (shallDispose()) {
761 css::uno::Reference
<css::lang::XComponent
> comp(
762 instance
, css::uno::UNO_QUERY
);
764 std::unique_lock
g(mutex
);
766 disposeInstance
= comp
;
772 void cppuhelper::ServiceManager::addSingletonContextEntries(
773 std::vector
< cppu::ContextEntry_Init
> * entries
)
775 assert(entries
!= nullptr);
776 for (const auto& [rName
, rImpls
] : data_
.singletons
)
778 assert(!rImpls
.empty());
781 rImpls
.size() > 1, "cppuhelper",
782 "Arbitrarily choosing " << rImpls
[0]->name
783 << " among multiple implementations for " << rName
);
785 cppu::ContextEntry_Init(
786 "/singletons/" + rName
,
788 css::uno::Reference
<css::lang::XSingleComponentFactory
>(
789 new SingletonFactory(this, rImpls
[0]))),
794 void cppuhelper::ServiceManager::loadImplementation(
795 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
796 std::shared_ptr
< Data::Implementation
> const & implementation
)
798 assert(implementation
);
800 std::unique_lock
g(m_aMutex
);
801 if (implementation
->status
== Data::Implementation::STATUS_LOADED
) {
807 uri
= cppu::bootstrap_expandUri(implementation
->uri
);
808 } catch (css::lang::IllegalArgumentException
& e
) {
809 throw css::uno::DeploymentException(
810 "Cannot expand URI" + implementation
->uri
+ ": " + e
.Message
,
811 static_cast< cppu::OWeakObject
* >(this));
813 cppuhelper::WrapperConstructorFn ctor
;
814 css::uno::Reference
< css::uno::XInterface
> f0
;
815 // Special handling of SharedLibrary loader, with support for environment,
816 // constructor, and prefix arguments:
817 if (!implementation
->alienContext
.is()
818 && implementation
->loader
== "com.sun.star.loader.SharedLibrary")
820 cppuhelper::detail::loadSharedLibComponentFactory(
821 uri
, implementation
->environment
,
822 implementation
->prefix
, implementation
->name
,
823 implementation
->constructorName
, this, &ctor
, &f0
);
825 assert(!implementation
->environment
.isEmpty());
829 !implementation
->environment
.isEmpty(), "cppuhelper",
830 "Loader " << implementation
->loader
831 << " and non-empty environment "
832 << implementation
->environment
);
834 !implementation
->prefix
.isEmpty(), "cppuhelper",
835 "Loader " << implementation
->loader
836 << " and non-empty constructor "
837 << implementation
->constructorName
);
839 !implementation
->prefix
.isEmpty(), "cppuhelper",
840 "Loader " << implementation
->loader
841 << " and non-empty prefix " << implementation
->prefix
);
842 css::uno::Reference
< css::uno::XComponentContext
> ctxt
;
843 css::uno::Reference
< css::lang::XMultiComponentFactory
> smgr
;
844 if (implementation
->alienContext
.is()) {
845 ctxt
= implementation
->alienContext
;
846 smgr
.set(ctxt
->getServiceManager(), css::uno::UNO_SET_THROW
);
848 assert(context
.is());
852 css::uno::Reference
< css::loader::XImplementationLoader
> loader(
853 smgr
->createInstanceWithContext(implementation
->loader
, ctxt
),
854 css::uno::UNO_QUERY_THROW
);
855 f0
= loader
->activate(
856 implementation
->name
, OUString(), uri
,
857 css::uno::Reference
< css::registry::XRegistryKey
>());
859 css::uno::Reference
<css::lang::XSingleComponentFactory
> f1
;
860 css::uno::Reference
<css::lang::XSingleServiceFactory
> f2
;
862 f1
.set(f0
, css::uno::UNO_QUERY
);
864 f2
.set(f0
, css::uno::UNO_QUERY
);
866 throw css::uno::DeploymentException(
867 ("Implementation " + implementation
->name
868 + " does not provide a constructor or factory"),
869 static_cast< cppu::OWeakObject
* >(this));
873 //TODO: There is a race here, as the relevant service factory can be removed
874 // while the mutex is unlocked and loading can thus fail, as the entity from
875 // which to load can disappear once the service factory is removed.
876 std::unique_lock
g(m_aMutex
);
878 || implementation
->status
== Data::Implementation::STATUS_LOADED
))
880 implementation
->status
= Data::Implementation::STATUS_LOADED
;
881 implementation
->constructorFn
= ctor
;
882 implementation
->factory1
= f1
;
883 implementation
->factory2
= f2
;
887 void cppuhelper::ServiceManager::disposing(std::unique_lock
<std::mutex
>& rGuard
) {
888 std::vector
< css::uno::Reference
<css::lang::XComponent
> > sngls
;
889 std::vector
< css::uno::Reference
< css::lang::XComponent
> > comps
;
892 for (const auto& rEntry
: data_
.namedImplementations
)
894 assert(rEntry
.second
);
895 if (rEntry
.second
->shallDispose()) {
896 std::unique_lock
g2(rEntry
.second
->mutex
);
897 if (rEntry
.second
->disposeInstance
.is()) {
898 sngls
.push_back(rEntry
.second
->disposeInstance
);
902 for (const auto& rEntry
: data_
.dynamicImplementations
)
904 assert(rEntry
.second
);
905 if (rEntry
.second
->shallDispose()) {
906 std::unique_lock
g2(rEntry
.second
->mutex
);
907 if (rEntry
.second
->disposeInstance
.is()) {
908 sngls
.push_back(rEntry
.second
->disposeInstance
);
911 if (rEntry
.second
->component
.is()) {
912 comps
.push_back(rEntry
.second
->component
);
915 data_
.namedImplementations
.swap(clear
.namedImplementations
);
916 data_
.dynamicImplementations
.swap(clear
.dynamicImplementations
);
917 data_
.services
.swap(clear
.services
);
918 data_
.singletons
.swap(clear
.singletons
);
921 for (const auto& rxSngl
: sngls
)
925 } catch (css::uno::RuntimeException
& e
) {
926 SAL_WARN("cppuhelper", "Ignoring " << e
<< " while disposing singleton");
929 for (const auto& rxComp
: comps
)
931 removeEventListenerFromComponent(rxComp
);
936 void cppuhelper::ServiceManager::initialize(
937 css::uno::Sequence
<css::uno::Any
> const & aArguments
)
940 if (aArguments
.getLength() != 1 || !(aArguments
[0] >>= arg
)
943 throw css::lang::IllegalArgumentException(
944 "invalid ServiceManager::initialize argument",
945 css::uno::Reference
<css::uno::XInterface
>(), 0);
947 preloadImplementations();
950 OUString
cppuhelper::ServiceManager::getImplementationName()
953 "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager";
956 sal_Bool
cppuhelper::ServiceManager::supportsService(
957 OUString
const & ServiceName
)
959 return cppu::supportsService(this, ServiceName
);
962 css::uno::Sequence
< OUString
>
963 cppuhelper::ServiceManager::getSupportedServiceNames()
965 return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.ServiceManager" };
968 css::uno::Reference
< css::uno::XInterface
>
969 cppuhelper::ServiceManager::createInstance(
970 OUString
const & aServiceSpecifier
)
972 assert(context_
.is());
973 return createInstanceWithContext(aServiceSpecifier
, context_
);
976 css::uno::Reference
< css::uno::XInterface
>
977 cppuhelper::ServiceManager::createInstanceWithArguments(
978 OUString
const & ServiceSpecifier
,
979 css::uno::Sequence
< css::uno::Any
> const & Arguments
)
981 assert(context_
.is());
982 return createInstanceWithArgumentsAndContext(
983 ServiceSpecifier
, Arguments
, context_
);
986 css::uno::Sequence
< OUString
>
987 cppuhelper::ServiceManager::getAvailableServiceNames()
989 std::unique_lock
g(m_aMutex
);
991 return css::uno::Sequence
< OUString
>();
993 if (data_
.services
.size() > o3tl::make_unsigned(SAL_MAX_INT32
)) {
994 throw css::uno::RuntimeException(
995 "getAvailableServiceNames: too many services",
996 static_cast< cppu::OWeakObject
* >(this));
998 return comphelper::mapKeysToSequence(data_
.services
);
1001 css::uno::Reference
< css::uno::XInterface
>
1002 cppuhelper::ServiceManager::createInstanceWithContext(
1003 OUString
const & aServiceSpecifier
,
1004 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
1006 std::shared_ptr
< Data::Implementation
> impl(
1007 findServiceImplementation(Context
, aServiceSpecifier
));
1008 return impl
== nullptr ? css::uno::Reference
<css::uno::XInterface
>()
1009 : impl
->createInstance(Context
, false);
1012 css::uno::Reference
< css::uno::XInterface
>
1013 cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext(
1014 OUString
const & ServiceSpecifier
,
1015 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
1016 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
1018 std::shared_ptr
< Data::Implementation
> impl(
1019 findServiceImplementation(Context
, ServiceSpecifier
));
1020 return impl
== nullptr ? css::uno::Reference
<css::uno::XInterface
>()
1021 : impl
->createInstanceWithArguments(Context
, false, Arguments
);
1024 css::uno::Type
cppuhelper::ServiceManager::getElementType()
1026 return css::uno::Type();
1029 sal_Bool
cppuhelper::ServiceManager::hasElements()
1031 std::unique_lock
g(m_aMutex
);
1033 !(data_
.namedImplementations
.empty()
1034 && data_
.dynamicImplementations
.empty());
1037 css::uno::Reference
< css::container::XEnumeration
>
1038 cppuhelper::ServiceManager::createEnumeration()
1040 throw css::uno::RuntimeException(
1041 "ServiceManager createEnumeration: method not supported",
1042 static_cast< cppu::OWeakObject
* >(this));
1045 sal_Bool
cppuhelper::ServiceManager::has(css::uno::Any
const &)
1047 throw css::uno::RuntimeException(
1048 "ServiceManager has: method not supported",
1049 static_cast< cppu::OWeakObject
* >(this));
1052 void cppuhelper::ServiceManager::insert(css::uno::Any
const & aElement
)
1054 css::uno::Sequence
< css::beans::NamedValue
> args
;
1055 if (aElement
>>= args
) {
1056 std::vector
< OUString
> uris
;
1057 css::uno::Reference
< css::uno::XComponentContext
> alienContext
;
1058 for (const auto & arg
: args
) {
1059 if (arg
.Name
== "uri") {
1061 if (!(arg
.Value
>>= uri
)) {
1062 throw css::lang::IllegalArgumentException(
1064 static_cast< cppu::OWeakObject
* >(this), 0);
1066 uris
.push_back(uri
);
1067 } else if (arg
.Name
== "component-context") {
1068 if (alienContext
.is()) {
1069 throw css::lang::IllegalArgumentException(
1070 "Multiple component-context arguments",
1071 static_cast< cppu::OWeakObject
* >(this), 0);
1073 if (!(arg
.Value
>>= alienContext
) || !alienContext
.is()) {
1074 throw css::lang::IllegalArgumentException(
1075 "Bad component-context argument",
1076 static_cast< cppu::OWeakObject
* >(this), 0);
1079 throw css::lang::IllegalArgumentException(
1080 "Bad argument " + arg
.Name
,
1081 static_cast< cppu::OWeakObject
* >(this), 0);
1084 insertRdbFiles(uris
, alienContext
);
1087 css::uno::Reference
< css::lang::XServiceInfo
> info
;
1088 if ((aElement
>>= info
) && info
.is()) {
1089 insertLegacyFactory(info
);
1093 throw css::lang::IllegalArgumentException(
1094 "Bad insert element", static_cast< cppu::OWeakObject
* >(this), 0);
1097 void cppuhelper::ServiceManager::remove(css::uno::Any
const & aElement
)
1099 css::uno::Sequence
< css::beans::NamedValue
> args
;
1100 if (aElement
>>= args
) {
1101 std::vector
< OUString
> uris
;
1102 for (const auto & i
: args
) {
1103 if (i
.Name
!= "uri") {
1104 throw css::lang::IllegalArgumentException(
1105 "Bad argument " + i
.Name
,
1106 static_cast< cppu::OWeakObject
* >(this), 0);
1109 if (!(i
.Value
>>= uri
)) {
1110 throw css::lang::IllegalArgumentException(
1112 static_cast< cppu::OWeakObject
* >(this), 0);
1114 uris
.push_back(uri
);
1116 removeRdbFiles(uris
);
1119 css::uno::Reference
< css::lang::XServiceInfo
> info
;
1120 if ((aElement
>>= info
) && info
.is()) {
1121 if (!removeLegacyFactory(info
, true)) {
1122 throw css::container::NoSuchElementException(
1123 "Remove non-inserted factory object",
1124 static_cast< cppu::OWeakObject
* >(this));
1129 if (aElement
>>= impl
) {
1130 // For live-removal of extensions:
1131 removeImplementation(impl
);
1134 throw css::lang::IllegalArgumentException(
1135 "Bad remove element", static_cast< cppu::OWeakObject
* >(this), 0);
1138 css::uno::Reference
< css::container::XEnumeration
>
1139 cppuhelper::ServiceManager::createContentEnumeration(
1140 OUString
const & aServiceName
)
1142 std::vector
< std::shared_ptr
< Data::Implementation
> > impls
;
1144 std::unique_lock
g(m_aMutex
);
1145 Data::ImplementationMap::const_iterator
i(
1146 data_
.services
.find(aServiceName
));
1147 if (i
!= data_
.services
.end()) {
1151 std::vector
< css::uno::Any
> factories
;
1152 for (const auto& rxImpl
: impls
)
1154 Data::Implementation
* impl
= rxImpl
.get();
1155 assert(impl
!= nullptr);
1157 std::unique_lock
g(m_aMutex
);
1162 if (impl
->status
== Data::Implementation::STATUS_NEW
) {
1163 // Postpone actual implementation instantiation as long as
1164 // possible (so that e.g. opening LO's "Tools - Macros" menu
1165 // does not try to instantiate a JVM, which can lead to a
1166 // synchronous error dialog when no JVM is specified, and
1167 // showing the dialog while hovering over a menu can cause
1169 impl
->factory1
= new ImplementationWrapper(this, rxImpl
);
1170 impl
->status
= Data::Implementation::STATUS_WRAPPER
;
1172 if (impl
->constructorFn
!= nullptr && !impl
->factory1
.is()) {
1173 impl
->factory1
= new ImplementationWrapper(this, rxImpl
);
1176 if (impl
->factory1
.is()) {
1177 factories
.push_back(css::uno::Any(impl
->factory1
));
1179 assert(impl
->factory2
.is());
1180 factories
.push_back(css::uno::Any(impl
->factory2
));
1183 return new ContentEnumeration(std::move(factories
));
1186 css::uno::Reference
< css::beans::XPropertySetInfo
>
1187 cppuhelper::ServiceManager::getPropertySetInfo()
1192 void cppuhelper::ServiceManager::setPropertyValue(
1193 OUString
const & aPropertyName
, css::uno::Any
const &)
1195 if (aPropertyName
== "DefaultContext") {
1196 throw css::beans::PropertyVetoException(
1197 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1199 throw css::beans::UnknownPropertyException(
1200 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1204 css::uno::Any
cppuhelper::ServiceManager::getPropertyValue(
1205 OUString
const & PropertyName
)
1207 if (PropertyName
!= "DefaultContext") {
1208 throw css::beans::UnknownPropertyException(
1209 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1211 assert(context_
.is());
1212 return css::uno::Any(context_
);
1215 void cppuhelper::ServiceManager::addPropertyChangeListener(
1216 OUString
const & aPropertyName
,
1217 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
1220 if (!aPropertyName
.isEmpty() && aPropertyName
!= "DefaultContext") {
1221 throw css::beans::UnknownPropertyException(
1222 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1224 // DefaultContext does not change, so just treat it as an event listener:
1225 return addEventListener(xListener
);
1228 void cppuhelper::ServiceManager::removePropertyChangeListener(
1229 OUString
const & aPropertyName
,
1230 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
1233 if (!aPropertyName
.isEmpty() && aPropertyName
!= "DefaultContext") {
1234 throw css::beans::UnknownPropertyException(
1235 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1237 // DefaultContext does not change, so just treat it as an event listener:
1238 return removeEventListener(aListener
);
1241 void cppuhelper::ServiceManager::addVetoableChangeListener(
1242 OUString
const & PropertyName
,
1243 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
1246 if (!PropertyName
.isEmpty() && PropertyName
!= "DefaultContext") {
1247 throw css::beans::UnknownPropertyException(
1248 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1250 // DefaultContext does not change, so just treat it as an event listener:
1251 return addEventListener(aListener
);
1254 void cppuhelper::ServiceManager::removeVetoableChangeListener(
1255 OUString
const & PropertyName
,
1256 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
1259 if (!PropertyName
.isEmpty() && PropertyName
!= "DefaultContext") {
1260 throw css::beans::UnknownPropertyException(
1261 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1263 // DefaultContext does not change, so just treat it as an event listener:
1264 return removeEventListener(aListener
);
1267 css::uno::Sequence
< css::beans::Property
>
1268 cppuhelper::ServiceManager::getProperties() {
1269 return { getDefaultContextProperty() };
1272 css::beans::Property
cppuhelper::ServiceManager::getPropertyByName(
1273 OUString
const & aName
)
1275 if (aName
!= "DefaultContext") {
1276 throw css::beans::UnknownPropertyException(
1277 aName
, static_cast< cppu::OWeakObject
* >(this));
1279 return getDefaultContextProperty();
1282 sal_Bool
cppuhelper::ServiceManager::hasPropertyByName(
1283 OUString
const & Name
)
1285 return Name
== "DefaultContext";
1288 cppuhelper::ServiceManager::~ServiceManager() {}
1290 void cppuhelper::ServiceManager::disposing(
1291 css::lang::EventObject
const & Source
)
1293 removeLegacyFactory(
1294 css::uno::Reference
< css::lang::XServiceInfo
>(
1295 Source
.Source
, css::uno::UNO_QUERY_THROW
),
1299 void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1300 css::uno::Reference
< css::lang::XComponent
> const & component
)
1302 assert(component
.is());
1304 component
->removeEventListener(this);
1305 } catch (css::uno::RuntimeException
& e
) {
1308 "Ignored removeEventListener RuntimeException " + e
.Message
);
1312 void cppuhelper::ServiceManager::init(std::u16string_view rdbUris
) {
1313 for (sal_Int32 i
= 0; i
!= -1;) {
1314 std::u16string_view
uri(o3tl::getToken(rdbUris
, 0, ' ', i
));
1320 cppu::decodeRdbUri(&uri
, &optional
, &directory
);
1322 readRdbDirectory(uri
, optional
);
1324 readRdbFile(OUString(uri
), optional
);
1329 void cppuhelper::ServiceManager::readRdbDirectory(
1330 std::u16string_view uri
, bool optional
)
1332 osl::Directory dir
= OUString(uri
);
1333 switch (dir
.open()) {
1334 case osl::FileBase::E_None
:
1336 case osl::FileBase::E_NOENT
:
1338 SAL_INFO("cppuhelper", "Ignored optional " << OUString(uri
));
1343 throw css::uno::DeploymentException(
1344 OUString::Concat("Cannot open directory ") + uri
,
1345 static_cast< cppu::OWeakObject
* >(this));
1349 if (!cppu::nextDirectoryItem(dir
, &url
)) {
1352 readRdbFile(url
, false);
1356 void cppuhelper::ServiceManager::readRdbFile(
1357 OUString
const & uri
, bool optional
)
1361 uri
, css::uno::Reference
< css::uno::XComponentContext
>(), &data_
);
1362 } catch (css::container::NoSuchElementException
&) {
1364 throw css::uno::DeploymentException(
1365 uri
+ ": no such file",
1366 static_cast< cppu::OWeakObject
* >(this));
1368 SAL_INFO("cppuhelper", "Ignored optional " << uri
);
1371 catch (css::registry::InvalidRegistryException
& e
) {
1372 if (!readLegacyRdbFile(uri
)) {
1373 throw css::uno::DeploymentException(
1374 "InvalidRegistryException: " + e
.Message
,
1375 static_cast< cppu::OWeakObject
* >(this));
1377 } catch (css::uno::RuntimeException
&) {
1378 if (!readLegacyRdbFile(uri
)) {
1386 bool cppuhelper::ServiceManager::readLegacyRdbFile(OUString
const & uri
) {
1388 switch (reg
.open(uri
, RegAccessMode::READONLY
)) {
1389 case RegError::NO_ERROR
:
1391 case RegError::REGISTRY_NOT_EXISTS
:
1392 case RegError::INVALID_REGISTRY
:
1394 // Ignore empty rdb files (which are at least seen by subordinate
1395 // uno processes during extension registration; Registry::open can
1396 // fail on them if mmap(2) returns EINVAL for a zero length):
1397 osl::DirectoryItem item
;
1398 if (osl::DirectoryItem::get(uri
, item
) == osl::FileBase::E_None
) {
1399 osl::FileStatus
status(osl_FileStatus_Mask_FileSize
);
1400 if (item
.getFileStatus(status
) == osl::FileBase::E_None
1401 && status
.getFileSize() == 0)
1411 RegistryKey rootKey
;
1412 if (reg
.openRootKey(rootKey
) != RegError::NO_ERROR
) {
1413 throw css::uno::DeploymentException(
1414 "Failure reading legacy rdb file " + uri
,
1415 static_cast< cppu::OWeakObject
* >(this));
1417 RegistryKeyArray impls
;
1418 switch (rootKey
.openSubKeys("IMPLEMENTATIONS", impls
)) {
1419 case RegError::NO_ERROR
:
1421 case RegError::KEY_NOT_EXISTS
:
1424 throw css::uno::DeploymentException(
1425 "Failure reading legacy rdb file " + uri
,
1426 static_cast< cppu::OWeakObject
* >(this));
1428 for (sal_uInt32 i
= 0; i
!= impls
.getLength(); ++i
) {
1429 RegistryKey
implKey(impls
.getElement(i
));
1430 assert(implKey
.getName().match("/IMPLEMENTATIONS/"));
1432 implKey
.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1433 std::shared_ptr
< Data::Implementation
> impl
=
1434 std::make_shared
<Data::Implementation
>(
1435 name
, readLegacyRdbString(uri
, implKey
, "UNO/ACTIVATOR"),
1436 readLegacyRdbString(uri
, implKey
, "UNO/LOCATION"), "", "", "", false,
1437 css::uno::Reference
< css::uno::XComponentContext
>(), uri
);
1438 if (!data_
.namedImplementations
.emplace(name
, impl
).second
)
1440 throw css::registry::InvalidRegistryException(
1441 uri
+ ": duplicate <implementation name=\"" + name
+ "\">");
1443 readLegacyRdbStrings(
1444 uri
, implKey
, "UNO/SERVICES", &impl
->services
);
1445 for (const auto& rService
: impl
->services
)
1447 data_
.services
[rService
].push_back(impl
);
1449 readLegacyRdbStrings(
1450 uri
, implKey
, "UNO/SINGLETONS", &impl
->singletons
);
1451 for (const auto& rSingleton
: impl
->singletons
)
1453 data_
.singletons
[rSingleton
].push_back(impl
);
1459 OUString
cppuhelper::ServiceManager::readLegacyRdbString(
1460 std::u16string_view uri
, RegistryKey
& key
, OUString
const & path
)
1465 if (key
.openKey(path
, subkey
) != RegError::NO_ERROR
1466 || subkey
.getValueInfo(OUString(), &t
, &s
) != RegError::NO_ERROR
1467 || t
!= RegValueType::STRING
1468 || s
== 0 || s
> o3tl::make_unsigned(SAL_MAX_INT32
))
1470 throw css::uno::DeploymentException(
1471 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1472 static_cast< cppu::OWeakObject
* >(this));
1475 std::vector
< char > v(s
); // assuming sal_uInt32 fits into vector::size_type
1476 if (subkey
.getValue(OUString(), v
.data()) != RegError::NO_ERROR
1478 || !rtl_convertStringToUString(
1479 &val
.pData
, v
.data(), static_cast< sal_Int32
>(s
- 1),
1480 RTL_TEXTENCODING_UTF8
,
1481 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1482 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1483 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
1485 throw css::uno::DeploymentException(
1486 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1487 static_cast< cppu::OWeakObject
* >(this));
1492 void cppuhelper::ServiceManager::readLegacyRdbStrings(
1493 std::u16string_view uri
, RegistryKey
& key
, OUString
const & path
,
1494 std::vector
< OUString
> * strings
)
1496 assert(strings
!= nullptr);
1498 switch (key
.openKey(path
, subkey
)) {
1499 case RegError::NO_ERROR
:
1501 case RegError::KEY_NOT_EXISTS
:
1504 throw css::uno::DeploymentException(
1505 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1506 static_cast< cppu::OWeakObject
* >(this));
1508 OUString
prefix(subkey
.getName() + "/");
1509 RegistryKeyNames names
;
1510 if (subkey
.getKeyNames(OUString(), names
) != RegError::NO_ERROR
) {
1511 throw css::uno::DeploymentException(
1512 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1513 static_cast< cppu::OWeakObject
* >(this));
1515 for (sal_uInt32 i
= 0; i
!= names
.getLength(); ++i
) {
1516 assert(names
.getElement(i
).match(prefix
));
1517 strings
->push_back(names
.getElement(i
).copy(prefix
.getLength()));
1522 void cppuhelper::ServiceManager::insertRdbFiles(
1523 std::vector
< OUString
> const & uris
,
1524 css::uno::Reference
< css::uno::XComponentContext
> const & alienContext
)
1527 for (const auto& rUri
: uris
)
1530 Parser(rUri
, alienContext
, &extra
);
1531 } catch (css::container::NoSuchElementException
&) {
1532 throw css::lang::IllegalArgumentException(
1533 rUri
+ ": no such file", static_cast< cppu::OWeakObject
* >(this),
1535 } catch (css::registry::InvalidRegistryException
& e
) {
1536 throw css::lang::IllegalArgumentException(
1537 "InvalidRegistryException: " + e
.Message
,
1538 static_cast< cppu::OWeakObject
* >(this), 0);
1541 insertExtraData(extra
);
1544 void cppuhelper::ServiceManager::insertLegacyFactory(
1545 css::uno::Reference
< css::lang::XServiceInfo
> const & factoryInfo
)
1547 assert(factoryInfo
.is());
1548 OUString
name(factoryInfo
->getImplementationName());
1549 css::uno::Reference
< css::lang::XSingleComponentFactory
> f1(
1550 factoryInfo
, css::uno::UNO_QUERY
);
1551 css::uno::Reference
< css::lang::XSingleServiceFactory
> f2
;
1553 f2
.set(factoryInfo
, css::uno::UNO_QUERY
);
1555 throw css::lang::IllegalArgumentException(
1556 ("Bad XServiceInfo argument implements neither"
1557 " XSingleComponentFactory nor XSingleServiceFactory"),
1558 static_cast< cppu::OWeakObject
* >(this), 0);
1561 css::uno::Reference
< css::lang::XComponent
> comp(
1562 factoryInfo
, css::uno::UNO_QUERY
);
1563 std::shared_ptr
< Data::Implementation
> impl
=
1564 std::make_shared
<Data::Implementation
>(name
, f1
, f2
, comp
);
1566 if (!name
.isEmpty()) {
1567 extra
.namedImplementations
.emplace(name
, impl
);
1569 extra
.dynamicImplementations
.emplace(factoryInfo
, impl
);
1570 const css::uno::Sequence
< OUString
> services(
1571 factoryInfo
->getSupportedServiceNames());
1572 for (const auto & i
: services
) {
1573 impl
->services
.push_back(i
);
1574 extra
.services
[i
].push_back(impl
);
1576 if (insertExtraData(extra
) && comp
.is()) {
1577 comp
->addEventListener(this);
1581 bool cppuhelper::ServiceManager::insertExtraData(Data
const & extra
) {
1583 std::unique_lock
g(m_aMutex
);
1587 auto i
= std::find_if(extra
.namedImplementations
.begin(), extra
.namedImplementations
.end(),
1588 [this](const Data::NamedImplementations::value_type
& rEntry
) {
1589 return data_
.namedImplementations
.find(rEntry
.first
) != data_
.namedImplementations
.end(); });
1590 if (i
!= extra
.namedImplementations
.end())
1592 throw css::lang::IllegalArgumentException(
1593 "Insert duplicate implementation name " + i
->first
,
1594 static_cast< cppu::OWeakObject
* >(this), 0);
1596 bool bDuplicate
= std::any_of(extra
.dynamicImplementations
.begin(), extra
.dynamicImplementations
.end(),
1597 [this](const Data::DynamicImplementations::value_type
& rEntry
) {
1598 return data_
.dynamicImplementations
.find(rEntry
.first
) != data_
.dynamicImplementations
.end(); });
1601 throw css::lang::IllegalArgumentException(
1602 "Insert duplicate factory object",
1603 static_cast< cppu::OWeakObject
* >(this), 0);
1605 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1606 data_
.namedImplementations
.insert(
1607 extra
.namedImplementations
.begin(),
1608 extra
.namedImplementations
.end());
1609 data_
.dynamicImplementations
.insert(
1610 extra
.dynamicImplementations
.begin(),
1611 extra
.dynamicImplementations
.end());
1612 insertImplementationMap(&data_
.services
, extra
.services
);
1613 insertImplementationMap(&data_
.singletons
, extra
.singletons
);
1615 //TODO: Updating the component context singleton data should be part of the
1616 // atomic service manager update:
1617 if (extra
.singletons
.empty())
1620 assert(context_
.is());
1621 css::uno::Reference
< css::container::XNameContainer
> cont(
1622 context_
, css::uno::UNO_QUERY_THROW
);
1623 for (const auto& [rName
, rImpls
] : extra
.singletons
)
1625 OUString
name("/singletons/" + rName
);
1626 //TODO: Update should be atomic:
1628 cont
->removeByName(name
+ "/arguments");
1629 } catch (const css::container::NoSuchElementException
&) {}
1630 assert(!rImpls
.empty());
1633 rImpls
.size() > 1, "cppuhelper",
1634 "Arbitrarily choosing " << rImpls
[0]->name
1635 << " among multiple implementations for singleton "
1639 name
+ "/service", css::uno::Any(rImpls
[0]->name
));
1640 } catch (css::container::ElementExistException
&) {
1641 cont
->replaceByName(
1642 name
+ "/service", css::uno::Any(rImpls
[0]->name
));
1645 cont
->insertByName(name
, css::uno::Any());
1646 } catch (css::container::ElementExistException
&) {
1647 SAL_INFO("cppuhelper", "Overwriting singleton " << rName
);
1648 cont
->replaceByName(name
, css::uno::Any());
1654 void cppuhelper::ServiceManager::removeRdbFiles(
1655 std::vector
< OUString
> const & uris
)
1657 // The underlying data structures make this function somewhat inefficient,
1658 // but the assumption is that it is rarely called (and that if it is called,
1659 // it is called with a uris vector of size one):
1660 std::vector
< std::shared_ptr
< Data::Implementation
> > clear
;
1662 std::unique_lock
g(m_aMutex
);
1663 for (const auto& rUri
: uris
)
1665 for (Data::NamedImplementations::iterator
j(
1666 data_
.namedImplementations
.begin());
1667 j
!= data_
.namedImplementations
.end();)
1670 if (j
->second
->rdbFile
== rUri
) {
1671 clear
.push_back(j
->second
);
1672 //TODO: The below leaves data_ in an inconsistent state upon
1674 removeFromImplementationMap(
1675 &data_
.services
, j
->second
->services
, j
->second
);
1676 removeFromImplementationMap(
1677 &data_
.singletons
, j
->second
->singletons
,
1679 j
= data_
.namedImplementations
.erase(j
);
1686 //TODO: Update the component context singleton data
1689 bool cppuhelper::ServiceManager::removeLegacyFactory(
1690 css::uno::Reference
< css::lang::XServiceInfo
> const & factoryInfo
,
1691 bool removeListener
)
1693 assert(factoryInfo
.is());
1694 std::shared_ptr
< Data::Implementation
> clear
;
1695 css::uno::Reference
< css::lang::XComponent
> comp
;
1697 std::unique_lock
g(m_aMutex
);
1698 Data::DynamicImplementations::iterator
i(
1699 data_
.dynamicImplementations
.find(factoryInfo
));
1700 if (i
== data_
.dynamicImplementations
.end()) {
1705 if (removeListener
) {
1706 comp
= i
->second
->component
;
1708 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1709 removeFromImplementationMap(
1710 &data_
.services
, i
->second
->services
, i
->second
);
1711 removeFromImplementationMap(
1712 &data_
.singletons
, i
->second
->singletons
, i
->second
);
1713 if (!i
->second
->name
.isEmpty()) {
1714 data_
.namedImplementations
.erase(i
->second
->name
);
1716 data_
.dynamicImplementations
.erase(i
);
1719 removeEventListenerFromComponent(comp
);
1724 void cppuhelper::ServiceManager::removeImplementation(const OUString
& name
) {
1725 // The underlying data structures make this function somewhat inefficient,
1726 // but the assumption is that it is rarely called:
1727 std::shared_ptr
< Data::Implementation
> clear
;
1729 std::unique_lock
g(m_aMutex
);
1733 Data::NamedImplementations::iterator
i(
1734 data_
.namedImplementations
.find(name
));
1735 if (i
== data_
.namedImplementations
.end()) {
1736 throw css::container::NoSuchElementException(
1737 "Remove non-inserted implementation " + name
,
1738 static_cast< cppu::OWeakObject
* >(this));
1742 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1743 removeFromImplementationMap(
1744 &data_
.services
, i
->second
->services
, i
->second
);
1745 removeFromImplementationMap(
1746 &data_
.singletons
, i
->second
->singletons
, i
->second
);
1747 auto j
= std::find_if(data_
.dynamicImplementations
.begin(), data_
.dynamicImplementations
.end(),
1748 [&i
](const Data::DynamicImplementations::value_type
& rEntry
) { return rEntry
.second
== i
->second
; });
1749 if (j
!= data_
.dynamicImplementations
.end())
1750 data_
.dynamicImplementations
.erase(j
);
1751 data_
.namedImplementations
.erase(i
);
1755 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
1756 cppuhelper::ServiceManager::findServiceImplementation(
1757 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
1758 OUString
const & specifier
)
1760 std::shared_ptr
< Data::Implementation
> impl
;
1763 std::unique_lock
g(m_aMutex
);
1764 Data::ImplementationMap::const_iterator
i(
1765 data_
.services
.find(specifier
));
1766 if (i
== data_
.services
.end()) {
1767 Data::NamedImplementations::const_iterator
j(
1768 data_
.namedImplementations
.find(specifier
));
1769 if (j
== data_
.namedImplementations
.end()) {
1770 SAL_INFO("cppuhelper", "No implementation for " << specifier
);
1771 return std::shared_ptr
< Data::Implementation
>();
1775 assert(!i
->second
.empty());
1777 i
->second
.size() > 1, "cppuhelper",
1778 "Arbitrarily choosing " << i
->second
[0]->name
1779 << " among multiple implementations for " << i
->first
);
1780 impl
= i
->second
[0];
1783 loaded
= impl
->status
== Data::Implementation::STATUS_LOADED
;
1786 loadImplementation(context
, impl
);
1791 /// Make a simpler unique name for preload / progress reporting.
1792 #ifndef DISABLE_DYNLOADING
1793 static OUString
simplifyModule(std::u16string_view uri
)
1796 OUStringBuffer
edit(uri
);
1797 if ((nIdx
= edit
.lastIndexOf('/')) > 0)
1798 edit
.remove(0,nIdx
+1);
1799 if ((nIdx
= edit
.lastIndexOf(':')) > 0)
1800 edit
.remove(0,nIdx
+1);
1801 if ((nIdx
= edit
.lastIndexOf("lo.so")) > 0)
1802 edit
.truncate(nIdx
);
1803 if ((nIdx
= edit
.lastIndexOf(".3")) > 0)
1804 edit
.truncate(nIdx
);
1805 if ((nIdx
= edit
.lastIndexOf("gcc3.so")) > 0)
1806 edit
.truncate(nIdx
);
1807 if ((nIdx
= edit
.lastIndexOf(".so")) > 0)
1808 edit
.truncate(nIdx
);
1809 if ((nIdx
= edit
.lastIndexOf("_uno")) > 0)
1810 edit
.truncate(nIdx
);
1811 if ((nIdx
= edit
.lastIndexOf(".jar")) > 0)
1812 edit
.truncate(nIdx
);
1813 if (edit
.indexOf("lib") == 0)
1815 return edit
.makeStringAndClear();
1819 /// Used only by LibreOfficeKit when used by Online to pre-initialize
1820 void cppuhelper::ServiceManager::preloadImplementations() {
1821 #ifdef DISABLE_DYNLOADING
1825 std::unique_lock
g(m_aMutex
);
1826 css::uno::Environment
aSourceEnv(css::uno::Environment::getCurrent());
1828 std::cerr
<< "preload:";
1829 std::vector
<OUString
> aReported
;
1830 std::vector
<OUString
> aDisabled
;
1831 OUStringBuffer aDisabledMsg
;
1832 OUStringBuffer aMissingMsg
;
1834 /// Allow external callers & testers to disable certain components
1835 const char *pDisable
= getenv("UNODISABLELIBRARY");
1838 OUString
aDisable(pDisable
, strlen(pDisable
), RTL_TEXTENCODING_UTF8
);
1839 for (sal_Int32 i
= 0; i
>= 0; )
1841 OUString
tok( aDisable
.getToken(0, ' ', i
) );
1844 aDisabled
.push_back(tok
);
1848 // loop all implementations
1849 for (const auto& rEntry
: data_
.namedImplementations
)
1851 if (rEntry
.second
->loader
!= "com.sun.star.loader.SharedLibrary" ||
1852 rEntry
.second
->status
== Data::Implementation::STATUS_LOADED
)
1855 OUString simplified
;
1858 const OUString
&aLibrary
= rEntry
.second
->uri
;
1860 if (aLibrary
.isEmpty())
1863 simplified
= simplifyModule(aLibrary
);
1866 std::find(aDisabled
.begin(), aDisabled
.end(), simplified
) != aDisabled
.end();
1868 if (std::find(aReported
.begin(), aReported
.end(), aLibrary
) == aReported
.end())
1872 aDisabledMsg
.append(simplified
+ " ");
1876 std::cerr
<< " " << simplified
;
1879 aReported
.push_back(aLibrary
);
1885 // expand absolute URI implementation component library
1886 aUri
= cppu::bootstrap_expandUri(aLibrary
);
1888 catch (css::lang::IllegalArgumentException
& aError
)
1890 throw css::uno::DeploymentException(
1891 "Cannot expand URI" + rEntry
.second
->uri
+ ": " + aError
.Message
,
1892 static_cast< cppu::OWeakObject
* >(this));
1895 // load component library
1896 osl::Module
aModule(aUri
, SAL_LOADMODULE_NOW
| SAL_LOADMODULE_GLOBAL
);
1900 aMissingMsg
.append(simplified
+ " ");
1904 !rEntry
.second
->environment
.isEmpty())
1906 oslGenericFunction fpFactory
;
1907 css::uno::Environment aTargetEnv
;
1908 css::uno::Reference
<css::uno::XInterface
> xFactory
;
1910 if(rEntry
.second
->constructorName
.isEmpty())
1912 OUString aSymFactory
;
1913 // expand full name component factory symbol
1914 if (rEntry
.second
->prefix
== "direct")
1915 aSymFactory
= rEntry
.second
->name
.replace('.', '_') + "_" COMPONENT_GETFACTORY
;
1916 else if (!rEntry
.second
->prefix
.isEmpty())
1917 aSymFactory
= rEntry
.second
->prefix
+ "_" COMPONENT_GETFACTORY
;
1919 aSymFactory
= COMPONENT_GETFACTORY
;
1921 // get function symbol component factory
1922 fpFactory
= aModule
.getFunctionSymbol(aSymFactory
);
1923 if (fpFactory
== nullptr)
1925 throw css::loader::CannotActivateFactoryException(
1926 ("no factory symbol \"" + aSymFactory
+ "\" in component library :" + aUri
),
1927 css::uno::Reference
<css::uno::XInterface
>());
1930 aTargetEnv
= cppuhelper::detail::getEnvironment(rEntry
.second
->environment
, rEntry
.second
->name
);
1931 component_getFactoryFunc fpComponentFactory
= reinterpret_cast<component_getFactoryFunc
>(fpFactory
);
1933 if (aSourceEnv
.get() == aTargetEnv
.get())
1935 // invoke function component factory
1936 OString
aImpl(OUStringToOString(rEntry
.second
->name
, RTL_TEXTENCODING_ASCII_US
));
1937 xFactory
.set(css::uno::Reference
<css::uno::XInterface
>(static_cast<css::uno::XInterface
*>(
1938 (*fpComponentFactory
)(aImpl
.getStr(), this, nullptr)), SAL_NO_ACQUIRE
));
1943 // get function symbol component factory
1944 aTargetEnv
= cppuhelper::detail::getEnvironment(rEntry
.second
->environment
, rEntry
.second
->name
);
1945 fpFactory
= (aSourceEnv
.get() == aTargetEnv
.get()) ?
1946 aModule
.getFunctionSymbol(rEntry
.second
->constructorName
) : nullptr;
1949 css::uno::Reference
<css::lang::XSingleComponentFactory
> xSCFactory
;
1950 css::uno::Reference
<css::lang::XSingleServiceFactory
> xSSFactory
;
1952 // query interface XSingleComponentFactory or XSingleServiceFactory
1955 xSCFactory
.set(xFactory
, css::uno::UNO_QUERY
);
1956 if (!xSCFactory
.is())
1958 xSSFactory
.set(xFactory
, css::uno::UNO_QUERY
);
1959 if (!xSSFactory
.is())
1960 throw css::uno::DeploymentException(
1961 ("Implementation " + rEntry
.second
->name
1962 + " does not provide a constructor or factory"),
1963 static_cast< cppu::OWeakObject
* >(this));
1967 if (!rEntry
.second
->constructorName
.isEmpty() && fpFactory
)
1968 rEntry
.second
->constructorFn
= WrapperConstructorFn(reinterpret_cast<ImplementationConstructorFn
*>(fpFactory
));
1970 rEntry
.second
->factory1
= xSCFactory
;
1971 rEntry
.second
->factory2
= xSSFactory
;
1972 rEntry
.second
->status
= Data::Implementation::STATUS_LOADED
;
1976 // Some libraries use other (non-UNO) libraries requiring preinit
1977 oslGenericFunction fpPreload
= aModule
.getFunctionSymbol( "lok_preload_hook" );
1980 static std::vector
<oslGenericFunction
> aPreloaded
;
1981 if (std::find(aPreloaded
.begin(), aPreloaded
.end(), fpPreload
) == aPreloaded
.end())
1983 aPreloaded
.push_back(fpPreload
);
1991 std::cerr
<< std::endl
;
1993 if (aMissingMsg
.getLength() > 0)
1995 OUString aMsg
= aMissingMsg
.makeStringAndClear();
1996 std::cerr
<< "Absent (often optional): " << aMsg
<< "\n";
1998 if (aDisabledMsg
.getLength() > 0)
2000 OUString aMsg
= aDisabledMsg
.makeStringAndClear();
2001 std::cerr
<< "Disabled: " << aMsg
<< "\n";
2005 // Various rather important uno mappings.
2009 const char *mpPurpose
;
2010 } const aMappingLoad
[] = {
2011 { "gcc3", "uno", "" },
2012 { "uno", "gcc3", "" },
2015 static std::vector
<css::uno::Mapping
> maMaps
;
2016 for (auto &it
: aMappingLoad
)
2018 maMaps
.push_back(css::uno::Mapping(
2019 OUString::createFromAscii(it
.mpFrom
),
2020 OUString::createFromAscii(it
.mpTo
),
2021 OUString::createFromAscii(it
.mpPurpose
)));
2026 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */