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>
17 #include <com/sun/star/beans/NamedValue.hpp>
18 #include <com/sun/star/beans/PropertyAttribute.hpp>
19 #include <com/sun/star/container/ElementExistException.hpp>
20 #include <com/sun/star/container/XEnumeration.hpp>
21 #include <com/sun/star/container/XNameContainer.hpp>
22 #include <com/sun/star/lang/XInitialization.hpp>
23 #include <com/sun/star/lang/XServiceInfo.hpp>
24 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
25 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
26 #include <com/sun/star/loader/XImplementationLoader.hpp>
27 #include <com/sun/star/registry/InvalidRegistryException.hpp>
28 #include <com/sun/star/uno/DeploymentException.hpp>
29 #include <com/sun/star/uno/Reference.hxx>
30 #include <com/sun/star/uno/XComponentContext.hpp>
31 #include <comphelper/sequence.hxx>
32 #include <cppuhelper/bootstrap.hxx>
33 #include <cppuhelper/component_context.hxx>
34 #include <cppuhelper/implbase.hxx>
35 #include <cppuhelper/supportsservice.hxx>
36 #include <cppuhelper/factory.hxx>
37 #include <o3tl/safeint.hxx>
38 #include <osl/file.hxx>
39 #include <osl/module.hxx>
40 #include <rtl/ref.hxx>
41 #include <rtl/uri.hxx>
42 #include <rtl/ustring.hxx>
43 #include <rtl/ustrbuf.hxx>
44 #include <sal/log.hxx>
45 #include <uno/environment.hxx>
46 #include <uno/mapping.hxx>
48 #include "loadsharedlibcomponentfactory.hxx"
50 #include <registry/registry.hxx>
51 #include <xmlreader/xmlreader.hxx>
54 #include "servicemanager.hxx"
58 void insertImplementationMap(
59 cppuhelper::ServiceManager::Data::ImplementationMap
* destination
,
60 cppuhelper::ServiceManager::Data::ImplementationMap
const & source
)
62 assert(destination
!= nullptr);
63 for (const auto& [rName
, rImpls
] : source
)
67 cppuhelper::ServiceManager::Data::Implementation
> > & impls
68 = (*destination
)[rName
];
69 impls
.insert(impls
.end(), rImpls
.begin(), rImpls
.end());
73 void removeFromImplementationMap(
74 cppuhelper::ServiceManager::Data::ImplementationMap
* map
,
75 std::vector
< OUString
> const & elements
,
76 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
77 const & implementation
)
79 // The underlying data structures make this function somewhat inefficient,
80 // but the assumption is that it is rarely called:
81 assert(map
!= nullptr);
82 for (const auto& rElement
: elements
)
84 cppuhelper::ServiceManager::Data::ImplementationMap::iterator
j(
86 assert(j
!= map
->end());
89 cppuhelper::ServiceManager::Data::Implementation
> >::iterator
90 k(std::find(j
->second
.begin(), j
->second
.end(), implementation
));
91 assert(k
!= j
->second
.end());
93 if (j
->second
.empty()) {
99 // For simplicity, this code keeps throwing
100 // css::registry::InvalidRegistryException for invalid XML rdbs (even though
101 // that does not fit the exception's name):
105 OUString
const & uri
,
106 css::uno::Reference
< css::uno::XComponentContext
> const & alienContext
,
107 cppuhelper::ServiceManager::Data
* data
);
109 Parser(const Parser
&) = delete;
110 const Parser
& operator=(const Parser
&) = delete;
113 void handleComponent();
115 void handleImplementation();
117 void handleService();
119 void handleSingleton();
121 OUString
getNameAttribute();
123 xmlreader::XmlReader reader_
;
124 css::uno::Reference
< css::uno::XComponentContext
> alienContext_
;
125 cppuhelper::ServiceManager::Data
* data_
;
126 OUString attrLoader_
;
128 OUString attrEnvironment_
;
129 OUString attrPrefix_
;
130 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
135 OUString
const & uri
,
136 css::uno::Reference
< css::uno::XComponentContext
> const & alienContext
,
137 cppuhelper::ServiceManager::Data
* data
):
138 reader_(uri
), alienContext_(alienContext
), data_(data
)
140 assert(data
!= nullptr);
141 int ucNsId
= reader_
.registerNamespaceIri(
143 RTL_CONSTASCII_STRINGPARAM(
144 "http://openoffice.org/2010/uno-components")));
146 STATE_BEGIN
, STATE_END
, STATE_COMPONENTS
, STATE_COMPONENT_INITIAL
,
147 STATE_COMPONENT
, STATE_IMPLEMENTATION
, STATE_SERVICE
, STATE_SINGLETON
};
148 for (State state
= STATE_BEGIN
;;) {
149 xmlreader::Span name
;
151 xmlreader::XmlReader::Result res
= reader_
.nextItem(
152 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
155 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
156 && name
.equals(RTL_CONSTASCII_STRINGPARAM("components")))
158 state
= STATE_COMPONENTS
;
161 throw css::registry::InvalidRegistryException(
162 reader_
.getUrl() + ": unexpected item in outer level");
164 if (res
== xmlreader::XmlReader::Result::Done
) {
167 throw css::registry::InvalidRegistryException(
168 reader_
.getUrl() + ": unexpected item in outer level");
169 case STATE_COMPONENTS
:
170 if (res
== xmlreader::XmlReader::Result::End
) {
174 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
175 && name
.equals(RTL_CONSTASCII_STRINGPARAM("component")))
178 state
= STATE_COMPONENT_INITIAL
;
181 throw css::registry::InvalidRegistryException(
182 reader_
.getUrl() + ": unexpected item in <components>");
183 case STATE_COMPONENT
:
184 if (res
== xmlreader::XmlReader::Result::End
) {
185 state
= STATE_COMPONENTS
;
189 case STATE_COMPONENT_INITIAL
:
190 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
191 && name
.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
193 handleImplementation();
194 state
= STATE_IMPLEMENTATION
;
197 throw css::registry::InvalidRegistryException(
198 reader_
.getUrl() + ": unexpected item in <component>");
199 case STATE_IMPLEMENTATION
:
200 if (res
== xmlreader::XmlReader::Result::End
) {
201 state
= STATE_COMPONENT
;
204 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
205 && name
.equals(RTL_CONSTASCII_STRINGPARAM("service")))
208 state
= STATE_SERVICE
;
211 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
212 && name
.equals(RTL_CONSTASCII_STRINGPARAM("singleton")))
215 state
= STATE_SINGLETON
;
218 throw css::registry::InvalidRegistryException(
219 reader_
.getUrl() + ": unexpected item in <implementation>");
221 if (res
== xmlreader::XmlReader::Result::End
) {
222 state
= STATE_IMPLEMENTATION
;
225 throw css::registry::InvalidRegistryException(
226 reader_
.getUrl() + ": unexpected item in <service>");
227 case STATE_SINGLETON
:
228 if (res
== xmlreader::XmlReader::Result::End
) {
229 state
= STATE_IMPLEMENTATION
;
232 throw css::registry::InvalidRegistryException(
233 reader_
.getUrl() + ": unexpected item in <service>");
238 void Parser::handleComponent() {
239 attrLoader_
= OUString();
240 attrUri_
= OUString();
241 attrEnvironment_
= OUString();
242 attrPrefix_
= OUString();
243 xmlreader::Span name
;
245 while (reader_
.nextAttribute(&nsId
, &name
)) {
246 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
247 && name
.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
249 if (!attrLoader_
.isEmpty()) {
250 throw css::registry::InvalidRegistryException(
252 + ": <component> has multiple \"loader\" attributes");
254 attrLoader_
= reader_
.getAttributeValue(false).convertFromUtf8();
255 if (attrLoader_
.isEmpty()) {
256 throw css::registry::InvalidRegistryException(
258 + ": <component> has empty \"loader\" attribute");
260 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
261 && name
.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
263 if (!attrUri_
.isEmpty()) {
264 throw css::registry::InvalidRegistryException(
266 + ": <component> has multiple \"uri\" attributes");
268 attrUri_
= reader_
.getAttributeValue(false).convertFromUtf8();
269 if (attrUri_
.isEmpty()) {
270 throw css::registry::InvalidRegistryException(
272 + ": <component> has empty \"uri\" attribute");
274 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
275 && name
.equals(RTL_CONSTASCII_STRINGPARAM("environment")))
277 if (!attrEnvironment_
.isEmpty()) {
278 throw css::registry::InvalidRegistryException(
280 ": <component> has multiple \"environment\" attributes");
282 attrEnvironment_
= reader_
.getAttributeValue(false)
284 if (attrEnvironment_
.isEmpty()) {
285 throw css::registry::InvalidRegistryException(
287 ": <component> has empty \"environment\" attribute");
289 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
290 && name
.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
292 if (!attrPrefix_
.isEmpty()) {
293 throw css::registry::InvalidRegistryException(
295 ": <component> has multiple \"prefix\" attributes");
297 attrPrefix_
= reader_
.getAttributeValue(false).convertFromUtf8();
298 if (attrPrefix_
.isEmpty()) {
299 throw css::registry::InvalidRegistryException(
301 ": <component> has empty \"prefix\" attribute");
304 throw css::registry::InvalidRegistryException(
305 reader_
.getUrl() + ": unexpected attribute \""
306 + name
.convertFromUtf8() + "\" in <component>");
309 if (attrLoader_
.isEmpty()) {
310 throw css::registry::InvalidRegistryException(
311 reader_
.getUrl() + ": <component> is missing \"loader\" attribute");
313 if (attrUri_
.isEmpty()) {
314 throw css::registry::InvalidRegistryException(
315 reader_
.getUrl() + ": <component> is missing \"uri\" attribute");
317 #ifndef DISABLE_DYNLOADING
319 attrUri_
= rtl::Uri::convertRelToAbs(reader_
.getUrl(), attrUri_
);
320 } catch (const rtl::MalformedUriException
& e
) {
321 throw css::registry::InvalidRegistryException(
322 reader_
.getUrl() + ": bad \"uri\" attribute: " + e
.getMessage());
327 void Parser::handleImplementation() {
329 OUString attrConstructor
;
330 bool attrSingleInstance
= false;
331 xmlreader::Span name
;
333 while (reader_
.nextAttribute(&nsId
, &name
)) {
334 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
335 && name
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
337 if (!attrName
.isEmpty()) {
338 throw css::registry::InvalidRegistryException(
340 + ": <implementation> has multiple \"name\" attributes");
342 attrName
= reader_
.getAttributeValue(false).convertFromUtf8();
343 if (attrName
.isEmpty()) {
344 throw css::registry::InvalidRegistryException(
346 + ": <implementation> has empty \"name\" attribute");
348 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
349 && name
.equals(RTL_CONSTASCII_STRINGPARAM("constructor")))
351 if (!attrConstructor
.isEmpty()) {
352 throw css::registry::InvalidRegistryException(
354 + ": <implementation> has multiple \"constructor\""
357 attrConstructor
= reader_
.getAttributeValue(false)
359 if (attrConstructor
.isEmpty()) {
360 throw css::registry::InvalidRegistryException(
362 + ": element has empty \"constructor\" attribute");
364 if (attrEnvironment_
.isEmpty()) {
365 throw css::registry::InvalidRegistryException(
367 + ": <implementation> has \"constructor\" attribute but"
368 " <component> has no \"environment\" attribute");
370 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
371 && name
.equals(RTL_CONSTASCII_STRINGPARAM("single-instance")))
373 if (attrSingleInstance
) {
374 throw css::registry::InvalidRegistryException(
376 + ": <implementation> has multiple \"single-instance\" attributes");
378 if (!reader_
.getAttributeValue(false).equals(RTL_CONSTASCII_STRINGPARAM("true"))) {
379 throw css::registry::InvalidRegistryException(
380 reader_
.getUrl() + ": <implementation> has bad \"single-instance\" attribute");
382 attrSingleInstance
= true;
384 throw css::registry::InvalidRegistryException(
385 reader_
.getUrl() + ": unexpected element attribute \""
386 + name
.convertFromUtf8() + "\" in <implementation>");
389 if (attrName
.isEmpty()) {
390 throw css::registry::InvalidRegistryException(
392 + ": <implementation> is missing \"name\" attribute");
395 std::make_shared
<cppuhelper::ServiceManager::Data::Implementation
>(
396 attrName
, attrLoader_
, attrUri_
, attrEnvironment_
, attrConstructor
,
397 attrPrefix_
, attrSingleInstance
, alienContext_
, reader_
.getUrl());
398 if (!data_
->namedImplementations
.emplace(attrName
, implementation_
).
401 throw css::registry::InvalidRegistryException(
402 reader_
.getUrl() + ": duplicate <implementation name=\"" + attrName
407 void Parser::handleService() {
408 OUString
name(getNameAttribute());
409 implementation_
->services
.push_back(name
);
410 data_
->services
[name
].push_back(implementation_
);
413 void Parser::handleSingleton() {
414 OUString
name(getNameAttribute());
415 implementation_
->singletons
.push_back(name
);
416 data_
->singletons
[name
].push_back(implementation_
);
419 OUString
Parser::getNameAttribute() {
421 xmlreader::Span name
;
423 while (reader_
.nextAttribute(&nsId
, &name
)) {
424 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
425 || !name
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
427 throw css::registry::InvalidRegistryException(
428 reader_
.getUrl() + ": expected element attribute \"name\"");
430 if (!attrName
.isEmpty()) {
431 throw css::registry::InvalidRegistryException(
433 + ": element has multiple \"name\" attributes");
435 attrName
= reader_
.getAttributeValue(false).convertFromUtf8();
436 if (attrName
.isEmpty()) {
437 throw css::registry::InvalidRegistryException(
438 reader_
.getUrl() + ": element has empty \"name\" attribute");
441 if (attrName
.isEmpty()) {
442 throw css::registry::InvalidRegistryException(
443 reader_
.getUrl() + ": element is missing \"name\" attribute");
448 class ContentEnumeration
:
449 public cppu::WeakImplHelper
< css::container::XEnumeration
>
452 explicit ContentEnumeration(std::vector
< css::uno::Any
> const & factories
):
453 factories_(factories
), iterator_(factories_
.begin()) {}
455 ContentEnumeration(const ContentEnumeration
&) = delete;
456 const ContentEnumeration
& operator=(const ContentEnumeration
&) = delete;
459 virtual ~ContentEnumeration() override
{}
461 virtual sal_Bool SAL_CALL
hasMoreElements() override
;
463 virtual css::uno::Any SAL_CALL
nextElement() override
;
466 std::vector
< css::uno::Any
> factories_
;
467 std::vector
< css::uno::Any
>::const_iterator iterator_
;
470 sal_Bool
ContentEnumeration::hasMoreElements()
472 osl::MutexGuard
g(mutex_
);
473 return iterator_
!= factories_
.end();
476 css::uno::Any
ContentEnumeration::nextElement()
478 osl::MutexGuard
g(mutex_
);
479 if (iterator_
== factories_
.end()) {
480 throw css::container::NoSuchElementException(
481 "Bootstrap service manager service enumerator has no more elements",
482 static_cast< cppu::OWeakObject
* >(this));
487 css::beans::Property
getDefaultContextProperty() {
488 return css::beans::Property(
489 "DefaultContext", -1,
490 cppu::UnoType
< css::uno::XComponentContext
>::get(),
491 css::beans::PropertyAttribute::READONLY
);
494 class SingletonFactory
:
495 public cppu::WeakImplHelper
<css::lang::XSingleComponentFactory
>
499 rtl::Reference
< cppuhelper::ServiceManager
> const & manager
,
501 cppuhelper::ServiceManager::Data::Implementation
> const &
503 manager_(manager
), implementation_(implementation
)
504 { assert(manager
.is()); assert(implementation
); }
506 SingletonFactory(const SingletonFactory
&) = delete;
507 const SingletonFactory
& operator=(const SingletonFactory
&) = delete;
510 virtual ~SingletonFactory() override
{}
512 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
513 createInstanceWithContext(
514 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
516 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
517 createInstanceWithArgumentsAndContext(
518 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
519 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
521 rtl::Reference
< cppuhelper::ServiceManager
> manager_
;
522 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
526 css::uno::Reference
< css::uno::XInterface
>
527 SingletonFactory::createInstanceWithContext(
528 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
530 manager_
->loadImplementation(Context
, implementation_
);
531 return implementation_
->createInstance(Context
, true);
534 css::uno::Reference
< css::uno::XInterface
>
535 SingletonFactory::createInstanceWithArgumentsAndContext(
536 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
537 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
539 manager_
->loadImplementation(Context
, implementation_
);
540 return implementation_
->createInstanceWithArguments(
541 Context
, true, Arguments
);
544 class ImplementationWrapper
:
545 public cppu::WeakImplHelper
<
546 css::lang::XSingleComponentFactory
, css::lang::XSingleServiceFactory
,
547 css::lang::XServiceInfo
>
550 ImplementationWrapper(
551 rtl::Reference
< cppuhelper::ServiceManager
> const & manager
,
553 cppuhelper::ServiceManager::Data::Implementation
> const &
555 manager_(manager
), implementation_(implementation
)
556 { assert(manager
.is()); assert(implementation
); }
558 ImplementationWrapper(const ImplementationWrapper
&) = delete;
559 const ImplementationWrapper
& operator=(const ImplementationWrapper
&) = delete;
562 virtual ~ImplementationWrapper() override
{}
564 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
565 createInstanceWithContext(
566 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
568 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
569 createInstanceWithArgumentsAndContext(
570 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
571 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
573 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
574 createInstance() override
;
576 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
577 createInstanceWithArguments(
578 css::uno::Sequence
< css::uno::Any
> const & Arguments
) override
;
580 virtual OUString SAL_CALL
getImplementationName() override
;
582 virtual sal_Bool SAL_CALL
supportsService(OUString
const & ServiceName
) override
;
584 virtual css::uno::Sequence
< OUString
> SAL_CALL
585 getSupportedServiceNames() override
;
587 rtl::Reference
< cppuhelper::ServiceManager
> manager_
;
588 std::weak_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
592 css::uno::Reference
< css::uno::XInterface
>
593 ImplementationWrapper::createInstanceWithContext(
594 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
596 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
598 manager_
->loadImplementation(Context
, impl
);
599 return impl
->createInstance(Context
, false);
602 css::uno::Reference
< css::uno::XInterface
>
603 ImplementationWrapper::createInstanceWithArgumentsAndContext(
604 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
605 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
607 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
609 manager_
->loadImplementation(Context
, impl
);
610 return impl
->createInstanceWithArguments(
611 Context
, false, Arguments
);
614 css::uno::Reference
< css::uno::XInterface
>
615 ImplementationWrapper::createInstance()
617 return createInstanceWithContext(manager_
->getContext());
620 css::uno::Reference
< css::uno::XInterface
>
621 ImplementationWrapper::createInstanceWithArguments(
622 css::uno::Sequence
< css::uno::Any
> const & Arguments
)
624 return createInstanceWithArgumentsAndContext(
625 Arguments
, manager_
->getContext());
628 OUString
ImplementationWrapper::getImplementationName()
630 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
635 sal_Bool
ImplementationWrapper::supportsService(OUString
const & ServiceName
)
637 return cppu::supportsService(this, ServiceName
);
640 css::uno::Sequence
< OUString
>
641 ImplementationWrapper::getSupportedServiceNames()
643 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
645 if (impl
->services
.size()
646 > o3tl::make_unsigned(SAL_MAX_INT32
))
648 throw css::uno::RuntimeException(
649 ("Implementation " + impl
->name
650 + " supports too many services"),
651 static_cast< cppu::OWeakObject
* >(this));
653 return comphelper::containerToSequence(impl
->services
);
658 css::uno::Reference
<css::uno::XInterface
>
659 cppuhelper::ServiceManager::Data::Implementation::createInstance(
660 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
661 bool singletonRequest
)
663 css::uno::Reference
<css::uno::XInterface
> inst
;
664 if (isSingleInstance
) {
665 osl::MutexGuard
g(mutex
);
666 if (!singleInstance
.is()) {
667 singleInstance
= doCreateInstance(context
);
669 inst
= singleInstance
;
671 inst
= doCreateInstance(context
);
673 updateDisposeInstance(singletonRequest
, inst
);
677 css::uno::Reference
<css::uno::XInterface
>
678 cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments(
679 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
680 bool singletonRequest
, css::uno::Sequence
<css::uno::Any
> const & arguments
)
682 css::uno::Reference
<css::uno::XInterface
> inst
;
683 if (isSingleInstance
) {
684 osl::MutexGuard
g(mutex
);
685 if (!singleInstance
.is()) {
686 singleInstance
= doCreateInstanceWithArguments(context
, arguments
);
688 inst
= singleInstance
;
690 inst
= doCreateInstanceWithArguments(context
, arguments
);
692 updateDisposeInstance(singletonRequest
, inst
);
696 css::uno::Reference
<css::uno::XInterface
>
697 cppuhelper::ServiceManager::Data::Implementation::doCreateInstance(
698 css::uno::Reference
<css::uno::XComponentContext
> const & context
)
701 return css::uno::Reference
<css::uno::XInterface
>(
702 constructorFn(context
.get(), css::uno::Sequence
<css::uno::Any
>()),
704 } else if (factory1
.is()) {
705 return factory1
->createInstanceWithContext(context
);
707 assert(factory2
.is());
708 return factory2
->createInstance();
712 css::uno::Reference
<css::uno::XInterface
>
713 cppuhelper::ServiceManager::Data::Implementation::doCreateInstanceWithArguments(
714 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
715 css::uno::Sequence
<css::uno::Any
> const & arguments
)
718 css::uno::Reference
<css::uno::XInterface
> inst(
719 constructorFn(context
.get(), arguments
), SAL_NO_ACQUIRE
);
720 //HACK: The constructor will either observe arguments and return inst
721 // that does not implement XInitialization (or null), or ignore
722 // arguments and return inst that implements XInitialization; this
723 // should be removed again once XInitialization-based implementations
725 css::uno::Reference
<css::lang::XInitialization
> init(
726 inst
, css::uno::UNO_QUERY
);
728 init
->initialize(arguments
);
731 } else if (factory1
.is()) {
732 return factory1
->createInstanceWithArgumentsAndContext(
735 assert(factory2
.is());
736 return factory2
->createInstanceWithArguments(arguments
);
740 void cppuhelper::ServiceManager::Data::Implementation::updateDisposeInstance(
741 bool singletonRequest
,
742 css::uno::Reference
<css::uno::XInterface
> const & instance
)
744 // This is an optimization, to only call dispose once (from the component
745 // context) on a singleton that is obtained both via the component context
746 // and via the service manager; however, there is a harmless race here that
747 // may cause two calls to dispose nevertheless (also, this calls dispose on
748 // at most one of the instances obtained via the service manager, in case
749 // the implementation hands out different instances):
750 if (singletonRequest
) {
751 osl::MutexGuard
g(mutex
);
752 disposeInstance
.clear();
754 } else if (shallDispose()) {
755 css::uno::Reference
<css::lang::XComponent
> comp(
756 instance
, css::uno::UNO_QUERY
);
758 osl::MutexGuard
g(mutex
);
760 disposeInstance
= comp
;
766 void cppuhelper::ServiceManager::addSingletonContextEntries(
767 std::vector
< cppu::ContextEntry_Init
> * entries
)
769 assert(entries
!= nullptr);
770 for (const auto& [rName
, rImpls
] : data_
.singletons
)
772 assert(!rImpls
.empty());
775 rImpls
.size() > 1, "cppuhelper",
776 "Arbitrarily choosing " << rImpls
[0]->name
777 << " among multiple implementations for " << rName
);
779 cppu::ContextEntry_Init(
780 "/singletons/" + rName
,
782 css::uno::Reference
<css::lang::XSingleComponentFactory
> >(
783 new SingletonFactory(this, rImpls
[0])),
788 void cppuhelper::ServiceManager::loadImplementation(
789 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
790 std::shared_ptr
< Data::Implementation
> const & implementation
)
792 assert(implementation
);
794 osl::MutexGuard
g(rBHelper
.rMutex
);
795 if (implementation
->status
== Data::Implementation::STATUS_LOADED
) {
801 uri
= cppu::bootstrap_expandUri(implementation
->uri
);
802 } catch (css::lang::IllegalArgumentException
& e
) {
803 throw css::uno::DeploymentException(
804 "Cannot expand URI" + implementation
->uri
+ ": " + e
.Message
,
805 static_cast< cppu::OWeakObject
* >(this));
807 cppuhelper::WrapperConstructorFn ctor
;
808 css::uno::Reference
< css::uno::XInterface
> f0
;
809 // Special handling of SharedLibrary loader, with support for environment,
810 // constructor, and prefix arguments:
811 if (!implementation
->alienContext
.is()
812 && implementation
->loader
== "com.sun.star.loader.SharedLibrary")
814 cppuhelper::detail::loadSharedLibComponentFactory(
815 uri
, implementation
->environment
,
816 implementation
->prefix
, implementation
->name
,
817 implementation
->constructorName
, this, &ctor
, &f0
);
819 assert(!implementation
->environment
.isEmpty());
823 !implementation
->environment
.isEmpty(), "cppuhelper",
824 "Loader " << implementation
->loader
825 << " and non-empty environment "
826 << implementation
->environment
);
828 !implementation
->prefix
.isEmpty(), "cppuhelper",
829 "Loader " << implementation
->loader
830 << " and non-empty constructor "
831 << implementation
->constructorName
);
833 !implementation
->prefix
.isEmpty(), "cppuhelper",
834 "Loader " << implementation
->loader
835 << " and non-empty prefix " << implementation
->prefix
);
836 css::uno::Reference
< css::uno::XComponentContext
> ctxt
;
837 css::uno::Reference
< css::lang::XMultiComponentFactory
> smgr
;
838 if (implementation
->alienContext
.is()) {
839 ctxt
= implementation
->alienContext
;
840 smgr
.set(ctxt
->getServiceManager(), css::uno::UNO_SET_THROW
);
842 assert(context
.is());
846 css::uno::Reference
< css::loader::XImplementationLoader
> loader(
847 smgr
->createInstanceWithContext(implementation
->loader
, ctxt
),
848 css::uno::UNO_QUERY_THROW
);
849 f0
= loader
->activate(
850 implementation
->name
, OUString(), uri
,
851 css::uno::Reference
< css::registry::XRegistryKey
>());
853 css::uno::Reference
<css::lang::XSingleComponentFactory
> f1
;
854 css::uno::Reference
<css::lang::XSingleServiceFactory
> f2
;
856 f1
.set(f0
, css::uno::UNO_QUERY
);
858 f2
.set(f0
, css::uno::UNO_QUERY
);
860 throw css::uno::DeploymentException(
861 ("Implementation " + implementation
->name
862 + " does not provide a constructor or factory"),
863 static_cast< cppu::OWeakObject
* >(this));
867 //TODO: There is a race here, as the relevant service factory can be removed
868 // while the mutex is unlocked and loading can thus fail, as the entity from
869 // which to load can disappear once the service factory is removed.
870 osl::MutexGuard
g(rBHelper
.rMutex
);
872 || implementation
->status
== Data::Implementation::STATUS_LOADED
))
874 implementation
->status
= Data::Implementation::STATUS_LOADED
;
875 implementation
->constructorFn
= ctor
;
876 implementation
->factory1
= f1
;
877 implementation
->factory2
= f2
;
881 void cppuhelper::ServiceManager::disposing() {
882 std::vector
< css::uno::Reference
<css::lang::XComponent
> > sngls
;
883 std::vector
< css::uno::Reference
< css::lang::XComponent
> > comps
;
886 osl::MutexGuard
g(rBHelper
.rMutex
);
887 for (const auto& rEntry
: data_
.namedImplementations
)
889 assert(rEntry
.second
);
890 if (rEntry
.second
->shallDispose()) {
891 osl::MutexGuard
g2(rEntry
.second
->mutex
);
892 if (rEntry
.second
->disposeInstance
.is()) {
893 sngls
.push_back(rEntry
.second
->disposeInstance
);
897 for (const auto& rEntry
: data_
.dynamicImplementations
)
899 assert(rEntry
.second
);
900 if (rEntry
.second
->shallDispose()) {
901 osl::MutexGuard
g2(rEntry
.second
->mutex
);
902 if (rEntry
.second
->disposeInstance
.is()) {
903 sngls
.push_back(rEntry
.second
->disposeInstance
);
906 if (rEntry
.second
->component
.is()) {
907 comps
.push_back(rEntry
.second
->component
);
910 data_
.namedImplementations
.swap(clear
.namedImplementations
);
911 data_
.dynamicImplementations
.swap(clear
.dynamicImplementations
);
912 data_
.services
.swap(clear
.services
);
913 data_
.singletons
.swap(clear
.singletons
);
915 for (const auto& rxSngl
: sngls
)
919 } catch (css::uno::RuntimeException
& e
) {
920 SAL_WARN("cppuhelper", "Ignoring " << e
<< " while disposing singleton");
923 for (const auto& rxComp
: comps
)
925 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 "invalid ServiceManager::initialize argument",
938 css::uno::Reference
<css::uno::XInterface
>(), 0);
940 preloadImplementations();
943 OUString
cppuhelper::ServiceManager::getImplementationName()
946 "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager";
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 { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.ServiceManager" };
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 osl::MutexGuard
g(rBHelper
.rMutex
);
984 return css::uno::Sequence
< OUString
>();
986 if (data_
.services
.size() > o3tl::make_unsigned(SAL_MAX_INT32
)) {
987 throw css::uno::RuntimeException(
988 "getAvailableServiceNames: too many services",
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 osl::MutexGuard
g(rBHelper
.rMutex
);
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 "ServiceManager createEnumeration: method not supported",
1035 static_cast< cppu::OWeakObject
* >(this));
1038 sal_Bool
cppuhelper::ServiceManager::has(css::uno::Any
const &)
1040 throw css::uno::RuntimeException(
1041 "ServiceManager has: method not supported",
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
: std::as_const(args
)) {
1052 if (arg
.Name
== "uri") {
1054 if (!(arg
.Value
>>= uri
)) {
1055 throw css::lang::IllegalArgumentException(
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 "Multiple component-context arguments",
1064 static_cast< cppu::OWeakObject
* >(this), 0);
1066 if (!(arg
.Value
>>= alienContext
) || !alienContext
.is()) {
1067 throw css::lang::IllegalArgumentException(
1068 "Bad component-context argument",
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
);
1085 // At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in
1086 // module languagetool) contain an (actively registered) factory that does not
1087 // implement XServiceInfo (see <http://sourceforge.net/tracker/?
1088 // func=detail&aid=3526635&group_id=110216&atid=655717> "SingletonFactory should
1089 // implement XServiceInfo"); the old OServiceManager::insert
1090 // (stoc/source/servicemanager/servicemanager.cxx) silently did not add such
1091 // broken factories to its m_ImplementationNameMap, so ignore them here for
1092 // backwards compatibility of live-insertion of extensions, too.
1094 // (The plan was that this warning would go away (and we would do the
1095 // throw instead) for the incompatible LO 4, but we changed our mind):
1096 css::uno::Reference
< css::lang::XSingleComponentFactory
> legacy
;
1097 if ((aElement
>>= legacy
) && legacy
.is()) {
1100 "Ignored XSingleComponentFactory not implementing XServiceInfo");
1104 throw css::lang::IllegalArgumentException(
1105 "Bad insert element", static_cast< cppu::OWeakObject
* >(this), 0);
1108 void cppuhelper::ServiceManager::remove(css::uno::Any
const & aElement
)
1110 css::uno::Sequence
< css::beans::NamedValue
> args
;
1111 if (aElement
>>= args
) {
1112 std::vector
< OUString
> uris
;
1113 for (const auto & i
: std::as_const(args
)) {
1114 if (i
.Name
!= "uri") {
1115 throw css::lang::IllegalArgumentException(
1116 "Bad argument " + i
.Name
,
1117 static_cast< cppu::OWeakObject
* >(this), 0);
1120 if (!(i
.Value
>>= uri
)) {
1121 throw css::lang::IllegalArgumentException(
1123 static_cast< cppu::OWeakObject
* >(this), 0);
1125 uris
.push_back(uri
);
1127 removeRdbFiles(uris
);
1130 css::uno::Reference
< css::lang::XServiceInfo
> info
;
1131 if ((aElement
>>= info
) && info
.is()) {
1132 if (!removeLegacyFactory(info
, true)) {
1133 throw css::container::NoSuchElementException(
1134 "Remove non-inserted factory object",
1135 static_cast< cppu::OWeakObject
* >(this));
1140 if (aElement
>>= impl
) {
1141 // For live-removal of extensions:
1142 removeImplementation(impl
);
1145 throw css::lang::IllegalArgumentException(
1146 "Bad remove element", static_cast< cppu::OWeakObject
* >(this), 0);
1149 css::uno::Reference
< css::container::XEnumeration
>
1150 cppuhelper::ServiceManager::createContentEnumeration(
1151 OUString
const & aServiceName
)
1153 std::vector
< std::shared_ptr
< Data::Implementation
> > impls
;
1155 osl::MutexGuard
g(rBHelper
.rMutex
);
1156 Data::ImplementationMap::const_iterator
i(
1157 data_
.services
.find(aServiceName
));
1158 if (i
!= data_
.services
.end()) {
1162 std::vector
< css::uno::Any
> factories
;
1163 for (const auto& rxImpl
: impls
)
1165 Data::Implementation
* impl
= rxImpl
.get();
1166 assert(impl
!= nullptr);
1168 osl::MutexGuard
g(rBHelper
.rMutex
);
1173 if (impl
->status
== Data::Implementation::STATUS_NEW
) {
1174 // Postpone actual implementation instantiation as long as
1175 // possible (so that e.g. opening LO's "Tools - Macros" menu
1176 // does not try to instantiate a JVM, which can lead to a
1177 // synchronous error dialog when no JVM is specified, and
1178 // showing the dialog while hovering over a menu can cause
1180 impl
->factory1
= new ImplementationWrapper(this, rxImpl
);
1181 impl
->status
= Data::Implementation::STATUS_WRAPPER
;
1183 if (impl
->constructorFn
!= nullptr && !impl
->factory1
.is()) {
1184 impl
->factory1
= new ImplementationWrapper(this, rxImpl
);
1187 if (impl
->factory1
.is()) {
1188 factories
.push_back(css::uno::Any(impl
->factory1
));
1190 assert(impl
->factory2
.is());
1191 factories
.push_back(css::uno::Any(impl
->factory2
));
1194 return new ContentEnumeration(factories
);
1197 css::uno::Reference
< css::beans::XPropertySetInfo
>
1198 cppuhelper::ServiceManager::getPropertySetInfo()
1203 void cppuhelper::ServiceManager::setPropertyValue(
1204 OUString
const & aPropertyName
, css::uno::Any
const &)
1206 if (aPropertyName
== "DefaultContext") {
1207 throw css::beans::PropertyVetoException(
1208 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1210 throw css::beans::UnknownPropertyException(
1211 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1215 css::uno::Any
cppuhelper::ServiceManager::getPropertyValue(
1216 OUString
const & PropertyName
)
1218 if (PropertyName
!= "DefaultContext") {
1219 throw css::beans::UnknownPropertyException(
1220 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1222 assert(context_
.is());
1223 return css::uno::Any(context_
);
1226 void cppuhelper::ServiceManager::addPropertyChangeListener(
1227 OUString
const & aPropertyName
,
1228 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
1231 if (!aPropertyName
.isEmpty() && aPropertyName
!= "DefaultContext") {
1232 throw css::beans::UnknownPropertyException(
1233 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1235 // DefaultContext does not change, so just treat it as an event listener:
1236 return addEventListener(xListener
);
1239 void cppuhelper::ServiceManager::removePropertyChangeListener(
1240 OUString
const & aPropertyName
,
1241 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
1244 if (!aPropertyName
.isEmpty() && aPropertyName
!= "DefaultContext") {
1245 throw css::beans::UnknownPropertyException(
1246 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1248 // DefaultContext does not change, so just treat it as an event listener:
1249 return removeEventListener(aListener
);
1252 void cppuhelper::ServiceManager::addVetoableChangeListener(
1253 OUString
const & PropertyName
,
1254 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
1257 if (!PropertyName
.isEmpty() && PropertyName
!= "DefaultContext") {
1258 throw css::beans::UnknownPropertyException(
1259 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1261 // DefaultContext does not change, so just treat it as an event listener:
1262 return addEventListener(aListener
);
1265 void cppuhelper::ServiceManager::removeVetoableChangeListener(
1266 OUString
const & PropertyName
,
1267 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
1270 if (!PropertyName
.isEmpty() && PropertyName
!= "DefaultContext") {
1271 throw css::beans::UnknownPropertyException(
1272 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1274 // DefaultContext does not change, so just treat it as an event listener:
1275 return removeEventListener(aListener
);
1278 css::uno::Sequence
< css::beans::Property
>
1279 cppuhelper::ServiceManager::getProperties() {
1280 css::uno::Sequence
< css::beans::Property
> props(1);
1281 props
[0] = getDefaultContextProperty();
1285 css::beans::Property
cppuhelper::ServiceManager::getPropertyByName(
1286 OUString
const & aName
)
1288 if (aName
!= "DefaultContext") {
1289 throw css::beans::UnknownPropertyException(
1290 aName
, static_cast< cppu::OWeakObject
* >(this));
1292 return getDefaultContextProperty();
1295 sal_Bool
cppuhelper::ServiceManager::hasPropertyByName(
1296 OUString
const & Name
)
1298 return Name
== "DefaultContext";
1301 cppuhelper::ServiceManager::~ServiceManager() {}
1303 void cppuhelper::ServiceManager::disposing(
1304 css::lang::EventObject
const & Source
)
1306 removeLegacyFactory(
1307 css::uno::Reference
< css::lang::XServiceInfo
>(
1308 Source
.Source
, css::uno::UNO_QUERY_THROW
),
1312 void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1313 css::uno::Reference
< css::lang::XComponent
> const & component
)
1315 assert(component
.is());
1317 component
->removeEventListener(this);
1318 } catch (css::uno::RuntimeException
& e
) {
1321 "Ignored removeEventListener RuntimeException " + e
.Message
);
1325 void cppuhelper::ServiceManager::init(OUString
const & rdbUris
) {
1326 for (sal_Int32 i
= 0; i
!= -1;) {
1327 OUString
uri(rdbUris
.getToken(0, ' ', i
));
1328 if (uri
.isEmpty()) {
1333 cppu::decodeRdbUri(&uri
, &optional
, &directory
);
1335 readRdbDirectory(uri
, optional
);
1337 readRdbFile(uri
, optional
);
1342 void cppuhelper::ServiceManager::readRdbDirectory(
1343 OUString
const & uri
, bool optional
)
1345 osl::Directory
dir(uri
);
1346 switch (dir
.open()) {
1347 case osl::FileBase::E_None
:
1349 case osl::FileBase::E_NOENT
:
1351 SAL_INFO("cppuhelper", "Ignored optional " << uri
);
1356 throw css::uno::DeploymentException(
1357 "Cannot open directory " + uri
,
1358 static_cast< cppu::OWeakObject
* >(this));
1362 if (!cppu::nextDirectoryItem(dir
, &url
)) {
1365 readRdbFile(url
, false);
1369 void cppuhelper::ServiceManager::readRdbFile(
1370 OUString
const & uri
, bool optional
)
1374 uri
, css::uno::Reference
< css::uno::XComponentContext
>(), &data_
);
1375 } catch (css::container::NoSuchElementException
&) {
1377 throw css::uno::DeploymentException(
1378 uri
+ ": no such file",
1379 static_cast< cppu::OWeakObject
* >(this));
1381 SAL_INFO("cppuhelper", "Ignored optional " << uri
);
1382 } catch (css::registry::InvalidRegistryException
& e
) {
1383 if (!readLegacyRdbFile(uri
)) {
1384 throw css::uno::DeploymentException(
1385 "InvalidRegistryException: " + e
.Message
,
1386 static_cast< cppu::OWeakObject
* >(this));
1388 } catch (css::uno::RuntimeException
&) {
1389 if (!readLegacyRdbFile(uri
)) {
1395 bool cppuhelper::ServiceManager::readLegacyRdbFile(OUString
const & uri
) {
1397 switch (reg
.open(uri
, RegAccessMode::READONLY
)) {
1398 case RegError::NO_ERROR
:
1400 case RegError::REGISTRY_NOT_EXISTS
:
1401 case RegError::INVALID_REGISTRY
:
1403 // Ignore empty rdb files (which are at least seen by subordinate
1404 // uno processes during extension registration; Registry::open can
1405 // fail on them if mmap(2) returns EINVAL for a zero length):
1406 osl::DirectoryItem item
;
1407 if (osl::DirectoryItem::get(uri
, item
) == osl::FileBase::E_None
) {
1408 osl::FileStatus
status(osl_FileStatus_Mask_FileSize
);
1409 if (item
.getFileStatus(status
) == osl::FileBase::E_None
1410 && status
.getFileSize() == 0)
1420 RegistryKey rootKey
;
1421 if (reg
.openRootKey(rootKey
) != RegError::NO_ERROR
) {
1422 throw css::uno::DeploymentException(
1423 "Failure reading legacy rdb file " + uri
,
1424 static_cast< cppu::OWeakObject
* >(this));
1426 RegistryKeyArray impls
;
1427 switch (rootKey
.openSubKeys("IMPLEMENTATIONS", impls
)) {
1428 case RegError::NO_ERROR
:
1430 case RegError::KEY_NOT_EXISTS
:
1433 throw css::uno::DeploymentException(
1434 "Failure reading legacy rdb file " + uri
,
1435 static_cast< cppu::OWeakObject
* >(this));
1437 for (sal_uInt32 i
= 0; i
!= impls
.getLength(); ++i
) {
1438 RegistryKey
implKey(impls
.getElement(i
));
1439 assert(implKey
.getName().match("/IMPLEMENTATIONS/"));
1441 implKey
.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1442 std::shared_ptr
< Data::Implementation
> impl
=
1443 std::make_shared
<Data::Implementation
>(
1444 name
, readLegacyRdbString(uri
, implKey
, "UNO/ACTIVATOR"),
1445 readLegacyRdbString(uri
, implKey
, "UNO/LOCATION"), "", "", "", false,
1446 css::uno::Reference
< css::uno::XComponentContext
>(), uri
);
1447 if (!data_
.namedImplementations
.emplace(name
, impl
).second
)
1449 throw css::registry::InvalidRegistryException(
1450 uri
+ ": duplicate <implementation name=\"" + name
+ "\">");
1452 readLegacyRdbStrings(
1453 uri
, implKey
, "UNO/SERVICES", &impl
->services
);
1454 for (const auto& rService
: impl
->services
)
1456 data_
.services
[rService
].push_back(impl
);
1458 readLegacyRdbStrings(
1459 uri
, implKey
, "UNO/SINGLETONS", &impl
->singletons
);
1460 for (const auto& rSingleton
: impl
->singletons
)
1462 data_
.singletons
[rSingleton
].push_back(impl
);
1468 OUString
cppuhelper::ServiceManager::readLegacyRdbString(
1469 std::u16string_view uri
, RegistryKey
& key
, OUString
const & path
)
1474 if (key
.openKey(path
, subkey
) != RegError::NO_ERROR
1475 || subkey
.getValueInfo(OUString(), &t
, &s
) != RegError::NO_ERROR
1476 || t
!= RegValueType::STRING
1477 || s
== 0 || s
> o3tl::make_unsigned(SAL_MAX_INT32
))
1479 throw css::uno::DeploymentException(
1480 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1481 static_cast< cppu::OWeakObject
* >(this));
1484 std::vector
< char > v(s
); // assuming sal_uInt32 fits into vector::size_type
1485 if (subkey
.getValue(OUString(), v
.data()) != RegError::NO_ERROR
1487 || !rtl_convertStringToUString(
1488 &val
.pData
, v
.data(), static_cast< sal_Int32
>(s
- 1),
1489 RTL_TEXTENCODING_UTF8
,
1490 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1491 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1492 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
1494 throw css::uno::DeploymentException(
1495 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1496 static_cast< cppu::OWeakObject
* >(this));
1501 void cppuhelper::ServiceManager::readLegacyRdbStrings(
1502 std::u16string_view uri
, RegistryKey
& key
, OUString
const & path
,
1503 std::vector
< OUString
> * strings
)
1505 assert(strings
!= nullptr);
1507 switch (key
.openKey(path
, subkey
)) {
1508 case RegError::NO_ERROR
:
1510 case RegError::KEY_NOT_EXISTS
:
1513 throw css::uno::DeploymentException(
1514 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1515 static_cast< cppu::OWeakObject
* >(this));
1517 OUString
prefix(subkey
.getName() + "/");
1518 RegistryKeyNames names
;
1519 if (subkey
.getKeyNames(OUString(), names
) != RegError::NO_ERROR
) {
1520 throw css::uno::DeploymentException(
1521 OUString::Concat("Failure reading legacy rdb file ") + uri
,
1522 static_cast< cppu::OWeakObject
* >(this));
1524 for (sal_uInt32 i
= 0; i
!= names
.getLength(); ++i
) {
1525 assert(names
.getElement(i
).match(prefix
));
1526 strings
->push_back(names
.getElement(i
).copy(prefix
.getLength()));
1530 void cppuhelper::ServiceManager::insertRdbFiles(
1531 std::vector
< OUString
> const & uris
,
1532 css::uno::Reference
< css::uno::XComponentContext
> const & alienContext
)
1535 for (const auto& rUri
: uris
)
1538 Parser(rUri
, alienContext
, &extra
);
1539 } catch (css::container::NoSuchElementException
&) {
1540 throw css::lang::IllegalArgumentException(
1541 rUri
+ ": no such file", static_cast< cppu::OWeakObject
* >(this),
1543 } catch (css::registry::InvalidRegistryException
& e
) {
1544 throw css::lang::IllegalArgumentException(
1545 "InvalidRegistryException: " + e
.Message
,
1546 static_cast< cppu::OWeakObject
* >(this), 0);
1549 insertExtraData(extra
);
1552 void cppuhelper::ServiceManager::insertLegacyFactory(
1553 css::uno::Reference
< css::lang::XServiceInfo
> const & factoryInfo
)
1555 assert(factoryInfo
.is());
1556 OUString
name(factoryInfo
->getImplementationName());
1557 css::uno::Reference
< css::lang::XSingleComponentFactory
> f1(
1558 factoryInfo
, css::uno::UNO_QUERY
);
1559 css::uno::Reference
< css::lang::XSingleServiceFactory
> f2
;
1561 f2
.set(factoryInfo
, css::uno::UNO_QUERY
);
1563 throw css::lang::IllegalArgumentException(
1564 ("Bad XServiceInfo argument implements neither"
1565 " XSingleComponentFactory nor XSingleServiceFactory"),
1566 static_cast< cppu::OWeakObject
* >(this), 0);
1569 css::uno::Reference
< css::lang::XComponent
> comp(
1570 factoryInfo
, css::uno::UNO_QUERY
);
1571 std::shared_ptr
< Data::Implementation
> impl
=
1572 std::make_shared
<Data::Implementation
>(name
, f1
, f2
, comp
);
1574 if (!name
.isEmpty()) {
1575 extra
.namedImplementations
.emplace(name
, impl
);
1577 extra
.dynamicImplementations
.emplace(factoryInfo
, impl
);
1578 const css::uno::Sequence
< OUString
> services(
1579 factoryInfo
->getSupportedServiceNames());
1580 for (const auto & i
: services
) {
1581 impl
->services
.push_back(i
);
1582 extra
.services
[i
].push_back(impl
);
1584 if (insertExtraData(extra
) && comp
.is()) {
1585 comp
->addEventListener(this);
1589 bool cppuhelper::ServiceManager::insertExtraData(Data
const & extra
) {
1591 osl::MutexGuard
g(rBHelper
.rMutex
);
1595 auto i
= std::find_if(extra
.namedImplementations
.begin(), extra
.namedImplementations
.end(),
1596 [this](const Data::NamedImplementations::value_type
& rEntry
) {
1597 return data_
.namedImplementations
.find(rEntry
.first
) != data_
.namedImplementations
.end(); });
1598 if (i
!= extra
.namedImplementations
.end())
1600 throw css::lang::IllegalArgumentException(
1601 "Insert duplicate implementation name " + i
->first
,
1602 static_cast< cppu::OWeakObject
* >(this), 0);
1604 bool bDuplicate
= std::any_of(extra
.dynamicImplementations
.begin(), extra
.dynamicImplementations
.end(),
1605 [this](const Data::DynamicImplementations::value_type
& rEntry
) {
1606 return data_
.dynamicImplementations
.find(rEntry
.first
) != data_
.dynamicImplementations
.end(); });
1609 throw css::lang::IllegalArgumentException(
1610 "Insert duplicate factory object",
1611 static_cast< cppu::OWeakObject
* >(this), 0);
1613 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1614 data_
.namedImplementations
.insert(
1615 extra
.namedImplementations
.begin(),
1616 extra
.namedImplementations
.end());
1617 data_
.dynamicImplementations
.insert(
1618 extra
.dynamicImplementations
.begin(),
1619 extra
.dynamicImplementations
.end());
1620 insertImplementationMap(&data_
.services
, extra
.services
);
1621 insertImplementationMap(&data_
.singletons
, extra
.singletons
);
1623 //TODO: Updating the component context singleton data should be part of the
1624 // atomic service manager update:
1625 if (!extra
.singletons
.empty()) {
1626 assert(context_
.is());
1627 css::uno::Reference
< css::container::XNameContainer
> cont(
1628 context_
, css::uno::UNO_QUERY_THROW
);
1629 for (const auto& [rName
, rImpls
] : extra
.singletons
)
1631 OUString
name("/singletons/" + rName
);
1632 //TODO: Update should be atomic:
1634 cont
->removeByName(name
+ "/arguments");
1635 } catch (const css::container::NoSuchElementException
&) {}
1636 assert(!rImpls
.empty());
1639 rImpls
.size() > 1, "cppuhelper",
1640 "Arbitrarily choosing " << rImpls
[0]->name
1641 << " among multiple implementations for singleton "
1645 name
+ "/service", css::uno::Any(rImpls
[0]->name
));
1646 } catch (css::container::ElementExistException
&) {
1647 cont
->replaceByName(
1648 name
+ "/service", css::uno::Any(rImpls
[0]->name
));
1651 cont
->insertByName(name
, css::uno::Any());
1652 } catch (css::container::ElementExistException
&) {
1653 SAL_INFO("cppuhelper", "Overwriting singleton " << rName
);
1654 cont
->replaceByName(name
, css::uno::Any());
1661 void cppuhelper::ServiceManager::removeRdbFiles(
1662 std::vector
< OUString
> const & uris
)
1664 // The underlying data structures make this function somewhat inefficient,
1665 // but the assumption is that it is rarely called (and that if it is called,
1666 // it is called with a uris vector of size one):
1667 std::vector
< std::shared_ptr
< Data::Implementation
> > clear
;
1669 osl::MutexGuard
g(rBHelper
.rMutex
);
1670 for (const auto& rUri
: uris
)
1672 for (Data::NamedImplementations::iterator
j(
1673 data_
.namedImplementations
.begin());
1674 j
!= data_
.namedImplementations
.end();)
1677 if (j
->second
->rdbFile
== rUri
) {
1678 clear
.push_back(j
->second
);
1679 //TODO: The below leaves data_ in an inconsistent state upon
1681 removeFromImplementationMap(
1682 &data_
.services
, j
->second
->services
, j
->second
);
1683 removeFromImplementationMap(
1684 &data_
.singletons
, j
->second
->singletons
,
1686 j
= data_
.namedImplementations
.erase(j
);
1693 //TODO: Update the component context singleton data
1696 bool cppuhelper::ServiceManager::removeLegacyFactory(
1697 css::uno::Reference
< css::lang::XServiceInfo
> const & factoryInfo
,
1698 bool removeListener
)
1700 assert(factoryInfo
.is());
1701 std::shared_ptr
< Data::Implementation
> clear
;
1702 css::uno::Reference
< css::lang::XComponent
> comp
;
1704 osl::MutexGuard
g(rBHelper
.rMutex
);
1705 Data::DynamicImplementations::iterator
i(
1706 data_
.dynamicImplementations
.find(factoryInfo
));
1707 if (i
== data_
.dynamicImplementations
.end()) {
1708 return isDisposed();
1712 if (removeListener
) {
1713 comp
= i
->second
->component
;
1715 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1716 removeFromImplementationMap(
1717 &data_
.services
, i
->second
->services
, i
->second
);
1718 removeFromImplementationMap(
1719 &data_
.singletons
, i
->second
->singletons
, i
->second
);
1720 if (!i
->second
->name
.isEmpty()) {
1721 data_
.namedImplementations
.erase(i
->second
->name
);
1723 data_
.dynamicImplementations
.erase(i
);
1726 removeEventListenerFromComponent(comp
);
1731 void cppuhelper::ServiceManager::removeImplementation(const OUString
& name
) {
1732 // The underlying data structures make this function somewhat inefficient,
1733 // but the assumption is that it is rarely called:
1734 std::shared_ptr
< Data::Implementation
> clear
;
1736 osl::MutexGuard
g(rBHelper
.rMutex
);
1740 Data::NamedImplementations::iterator
i(
1741 data_
.namedImplementations
.find(name
));
1742 if (i
== data_
.namedImplementations
.end()) {
1743 throw css::container::NoSuchElementException(
1744 "Remove non-inserted implementation " + name
,
1745 static_cast< cppu::OWeakObject
* >(this));
1749 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1750 removeFromImplementationMap(
1751 &data_
.services
, i
->second
->services
, i
->second
);
1752 removeFromImplementationMap(
1753 &data_
.singletons
, i
->second
->singletons
, i
->second
);
1754 auto j
= std::find_if(data_
.dynamicImplementations
.begin(), data_
.dynamicImplementations
.end(),
1755 [&i
](const Data::DynamicImplementations::value_type
& rEntry
) { return rEntry
.second
== i
->second
; });
1756 if (j
!= data_
.dynamicImplementations
.end())
1757 data_
.dynamicImplementations
.erase(j
);
1758 data_
.namedImplementations
.erase(i
);
1762 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
1763 cppuhelper::ServiceManager::findServiceImplementation(
1764 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
1765 OUString
const & specifier
)
1767 std::shared_ptr
< Data::Implementation
> impl
;
1770 osl::MutexGuard
g(rBHelper
.rMutex
);
1771 Data::ImplementationMap::const_iterator
i(
1772 data_
.services
.find(specifier
));
1773 if (i
== data_
.services
.end()) {
1774 Data::NamedImplementations::const_iterator
j(
1775 data_
.namedImplementations
.find(specifier
));
1776 if (j
== data_
.namedImplementations
.end()) {
1777 SAL_INFO("cppuhelper", "No implementation for " << specifier
);
1778 return std::shared_ptr
< Data::Implementation
>();
1782 assert(!i
->second
.empty());
1784 i
->second
.size() > 1, "cppuhelper",
1785 "Arbitrarily choosing " << i
->second
[0]->name
1786 << " among multiple implementations for " << i
->first
);
1787 impl
= i
->second
[0];
1790 loaded
= impl
->status
== Data::Implementation::STATUS_LOADED
;
1793 loadImplementation(context
, impl
);
1798 /// Make a simpler unique name for preload / progress reporting.
1799 #ifndef DISABLE_DYNLOADING
1800 static OUString
simplifyModule(const OUString
&uri
)
1803 OUStringBuffer
edit(uri
);
1804 if ((nIdx
= edit
.lastIndexOf('/')) > 0)
1805 edit
.remove(0,nIdx
+1);
1806 if ((nIdx
= edit
.lastIndexOf(':')) > 0)
1807 edit
.remove(0,nIdx
+1);
1808 if ((nIdx
= edit
.lastIndexOf("lo.so")) > 0)
1809 edit
.truncate(nIdx
);
1810 if ((nIdx
= edit
.lastIndexOf(".3")) > 0)
1811 edit
.truncate(nIdx
);
1812 if ((nIdx
= edit
.lastIndexOf("gcc3.so")) > 0)
1813 edit
.truncate(nIdx
);
1814 if ((nIdx
= edit
.lastIndexOf(".so")) > 0)
1815 edit
.truncate(nIdx
);
1816 if ((nIdx
= edit
.lastIndexOf("_uno")) > 0)
1817 edit
.truncate(nIdx
);
1818 if ((nIdx
= edit
.lastIndexOf(".jar")) > 0)
1819 edit
.truncate(nIdx
);
1820 if (edit
.indexOf("lib") == 0)
1822 return edit
.makeStringAndClear();
1826 /// Used only by LibreOfficeKit when used by Online to pre-initialize
1827 void cppuhelper::ServiceManager::preloadImplementations() {
1828 #ifdef DISABLE_DYNLOADING
1832 osl::MutexGuard
g(rBHelper
.rMutex
);
1833 css::uno::Environment
aSourceEnv(css::uno::Environment::getCurrent());
1835 std::cerr
<< "preload:";
1836 std::vector
<OUString
> aReported
;
1837 std::vector
<OUString
> aDisabled
;
1838 OUStringBuffer aDisabledMsg
;
1839 OUStringBuffer aMissingMsg
;
1841 /// Allow external callers & testers to disable certain components
1842 const char *pDisable
= getenv("UNODISABLELIBRARY");
1845 OUString
aDisable(pDisable
, strlen(pDisable
), RTL_TEXTENCODING_UTF8
);
1846 for (sal_Int32 i
= 0; i
>= 0; )
1848 OUString tok
= aDisable
.getToken(0, ' ', i
);
1851 aDisabled
.push_back(tok
);
1855 // loop all implementations
1856 for (const auto& rEntry
: data_
.namedImplementations
)
1858 if (rEntry
.second
->loader
!= "com.sun.star.loader.SharedLibrary" ||
1859 rEntry
.second
->status
== Data::Implementation::STATUS_LOADED
)
1862 OUString simplified
;
1865 const OUString
&aLibrary
= rEntry
.second
->uri
;
1867 if (aLibrary
.isEmpty())
1870 simplified
= simplifyModule(aLibrary
);
1873 std::find(aDisabled
.begin(), aDisabled
.end(), simplified
) != aDisabled
.end();
1875 if (std::find(aReported
.begin(), aReported
.end(), aLibrary
) == aReported
.end())
1879 aDisabledMsg
.append(simplified
);
1880 aDisabledMsg
.append(" ");
1884 std::cerr
<< " " << simplified
;
1887 aReported
.push_back(aLibrary
);
1893 // expand absolute URI implementation component library
1894 aUri
= cppu::bootstrap_expandUri(aLibrary
);
1896 catch (css::lang::IllegalArgumentException
& aError
)
1898 throw css::uno::DeploymentException(
1899 "Cannot expand URI" + rEntry
.second
->uri
+ ": " + aError
.Message
,
1900 static_cast< cppu::OWeakObject
* >(this));
1903 // load component library
1904 osl::Module
aModule(aUri
, SAL_LOADMODULE_NOW
| SAL_LOADMODULE_GLOBAL
);
1908 aMissingMsg
.append(simplified
);
1909 aMissingMsg
.append(" ");
1913 !rEntry
.second
->environment
.isEmpty())
1915 oslGenericFunction fpFactory
;
1916 css::uno::Environment aTargetEnv
;
1917 css::uno::Reference
<css::uno::XInterface
> xFactory
;
1919 if(rEntry
.second
->constructorName
.isEmpty())
1921 OUString aSymFactory
;
1922 // expand full name component factory symbol
1923 if (rEntry
.second
->prefix
== "direct")
1924 aSymFactory
= rEntry
.second
->name
.replace('.', '_') + "_" COMPONENT_GETFACTORY
;
1925 else if (!rEntry
.second
->prefix
.isEmpty())
1926 aSymFactory
= rEntry
.second
->prefix
+ "_" COMPONENT_GETFACTORY
;
1928 aSymFactory
= COMPONENT_GETFACTORY
;
1930 // get function symbol component factory
1931 fpFactory
= aModule
.getFunctionSymbol(aSymFactory
);
1932 if (fpFactory
== nullptr)
1934 throw css::loader::CannotActivateFactoryException(
1935 ("no factory symbol \"" + aSymFactory
+ "\" in component library :" + aUri
),
1936 css::uno::Reference
<css::uno::XInterface
>());
1939 aTargetEnv
= cppuhelper::detail::getEnvironment(rEntry
.second
->environment
, rEntry
.second
->name
);
1940 component_getFactoryFunc fpComponentFactory
= reinterpret_cast<component_getFactoryFunc
>(fpFactory
);
1942 if (aSourceEnv
.get() == aTargetEnv
.get())
1944 // invoke function component factory
1945 OString
aImpl(OUStringToOString(rEntry
.second
->name
, RTL_TEXTENCODING_ASCII_US
));
1946 xFactory
.set(css::uno::Reference
<css::uno::XInterface
>(static_cast<css::uno::XInterface
*>(
1947 (*fpComponentFactory
)(aImpl
.getStr(), this, nullptr)), SAL_NO_ACQUIRE
));
1952 // get function symbol component factory
1953 aTargetEnv
= cppuhelper::detail::getEnvironment(rEntry
.second
->environment
, rEntry
.second
->name
);
1954 fpFactory
= (aSourceEnv
.get() == aTargetEnv
.get()) ?
1955 aModule
.getFunctionSymbol(rEntry
.second
->constructorName
) : nullptr;
1958 css::uno::Reference
<css::lang::XSingleComponentFactory
> xSCFactory
;
1959 css::uno::Reference
<css::lang::XSingleServiceFactory
> xSSFactory
;
1961 // query interface XSingleComponentFactory or XSingleServiceFactory
1964 xSCFactory
.set(xFactory
, css::uno::UNO_QUERY
);
1965 if (!xSCFactory
.is())
1967 xSSFactory
.set(xFactory
, css::uno::UNO_QUERY
);
1968 if (!xSSFactory
.is())
1969 throw css::uno::DeploymentException(
1970 ("Implementation " + rEntry
.second
->name
1971 + " does not provide a constructor or factory"),
1972 static_cast< cppu::OWeakObject
* >(this));
1976 if (!rEntry
.second
->constructorName
.isEmpty() && fpFactory
)
1977 rEntry
.second
->constructorFn
= WrapperConstructorFn(reinterpret_cast<ImplementationConstructorFn
*>(fpFactory
));
1979 rEntry
.second
->factory1
= xSCFactory
;
1980 rEntry
.second
->factory2
= xSSFactory
;
1981 rEntry
.second
->status
= Data::Implementation::STATUS_LOADED
;
1985 // Some libraries use other (non-UNO) libraries requiring preinit
1986 oslGenericFunction fpPreload
= aModule
.getFunctionSymbol( "lok_preload_hook" );
1989 static std::vector
<oslGenericFunction
> aPreloaded
;
1990 if (std::find(aPreloaded
.begin(), aPreloaded
.end(), fpPreload
) == aPreloaded
.end())
1992 aPreloaded
.push_back(fpPreload
);
2000 std::cerr
<< std::endl
;
2002 if (aMissingMsg
.getLength() > 0)
2004 OUString aMsg
= aMissingMsg
.makeStringAndClear();
2005 std::cerr
<< "Absent (often optional): " << aMsg
<< "\n";
2007 if (aDisabledMsg
.getLength() > 0)
2009 OUString aMsg
= aDisabledMsg
.makeStringAndClear();
2010 std::cerr
<< "Disabled: " << aMsg
<< "\n";
2014 // Various rather important uno mappings.
2018 const char *mpPurpose
;
2019 } const aMappingLoad
[] = {
2020 { "gcc3", "uno", "" },
2021 { "uno", "gcc3", "" },
2024 static std::vector
<css::uno::Mapping
> maMaps
;
2025 for (auto &it
: aMappingLoad
)
2027 maMaps
.push_back(css::uno::Mapping(
2028 OUString::createFromAscii(it
.mpFrom
),
2029 OUString::createFromAscii(it
.mpTo
),
2030 OUString::createFromAscii(it
.mpPurpose
)));
2035 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */