Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / cppuhelper / source / servicemanager.cxx
blob8f49b4ecb908fee0cc33ade8c97afa8a57aa47c7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sal/config.h>
12 #include <algorithm>
13 #include <cassert>
14 #include <iostream>
15 #include <vector>
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 <osl/file.hxx>
38 #include <osl/module.hxx>
39 #include <rtl/ref.hxx>
40 #include <rtl/uri.hxx>
41 #include <rtl/ustring.hxx>
42 #include <rtl/ustrbuf.hxx>
43 #include <sal/log.hxx>
44 #include <uno/environment.hxx>
45 #include <uno/mapping.hxx>
47 #include "loadsharedlibcomponentfactory.hxx"
49 #include <registry/registry.hxx>
50 #include <xmlreader/xmlreader.hxx>
52 #include "paths.hxx"
53 #include "servicemanager.hxx"
55 namespace {
57 void insertImplementationMap(
58 cppuhelper::ServiceManager::Data::ImplementationMap * destination,
59 cppuhelper::ServiceManager::Data::ImplementationMap const & source)
61 assert(destination != nullptr);
62 for (const auto& [rName, rImpls] : source)
64 std::vector<
65 std::shared_ptr<
66 cppuhelper::ServiceManager::Data::Implementation > > & impls
67 = (*destination)[rName];
68 impls.insert(impls.end(), rImpls.begin(), rImpls.end());
72 void removeFromImplementationMap(
73 cppuhelper::ServiceManager::Data::ImplementationMap * map,
74 std::vector< OUString > const & elements,
75 std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
76 const & implementation)
78 // The underlying data structures make this function somewhat inefficient,
79 // but the assumption is that it is rarely called:
80 assert(map != nullptr);
81 for (const auto& rElement : elements)
83 cppuhelper::ServiceManager::Data::ImplementationMap::iterator j(
84 map->find(rElement));
85 assert(j != map->end());
86 std::vector<
87 std::shared_ptr<
88 cppuhelper::ServiceManager::Data::Implementation > >::iterator
89 k(std::find(j->second.begin(), j->second.end(), implementation));
90 assert(k != j->second.end());
91 j->second.erase(k);
92 if (j->second.empty()) {
93 map->erase(j);
98 // For simplicity, this code keeps throwing
99 // css::registry::InvalidRegistryException for invalid XML rdbs (even though
100 // that does not fit the exception's name):
101 class Parser {
102 public:
103 Parser(
104 OUString const & uri,
105 css::uno::Reference< css::uno::XComponentContext > const & alienContext,
106 cppuhelper::ServiceManager::Data * data);
108 Parser(const Parser&) = delete;
109 const Parser& operator=(const Parser&) = delete;
111 private:
112 void handleComponent();
114 void handleImplementation();
116 void handleService();
118 void handleSingleton();
120 OUString getNameAttribute();
122 xmlreader::XmlReader reader_;
123 css::uno::Reference< css::uno::XComponentContext > alienContext_;
124 cppuhelper::ServiceManager::Data * data_;
125 OUString attrLoader_;
126 OUString attrUri_;
127 OUString attrEnvironment_;
128 OUString attrPrefix_;
129 std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
130 implementation_;
133 Parser::Parser(
134 OUString const & uri,
135 css::uno::Reference< css::uno::XComponentContext > const & alienContext,
136 cppuhelper::ServiceManager::Data * data):
137 reader_(uri), alienContext_(alienContext), data_(data)
139 assert(data != nullptr);
140 int ucNsId = reader_.registerNamespaceIri(
141 xmlreader::Span(
142 RTL_CONSTASCII_STRINGPARAM(
143 "http://openoffice.org/2010/uno-components")));
144 enum State {
145 STATE_BEGIN, STATE_END, STATE_COMPONENTS, STATE_COMPONENT_INITIAL,
146 STATE_COMPONENT, STATE_IMPLEMENTATION, STATE_SERVICE, STATE_SINGLETON };
147 for (State state = STATE_BEGIN;;) {
148 xmlreader::Span name;
149 int nsId;
150 xmlreader::XmlReader::Result res = reader_.nextItem(
151 xmlreader::XmlReader::Text::NONE, &name, &nsId);
152 switch (state) {
153 case STATE_BEGIN:
154 if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
155 && name.equals(RTL_CONSTASCII_STRINGPARAM("components")))
157 state = STATE_COMPONENTS;
158 break;
160 throw css::registry::InvalidRegistryException(
161 reader_.getUrl() + ": unexpected item in outer level");
162 case STATE_END:
163 if (res == xmlreader::XmlReader::Result::Done) {
164 return;
166 throw css::registry::InvalidRegistryException(
167 reader_.getUrl() + ": unexpected item in outer level");
168 case STATE_COMPONENTS:
169 if (res == xmlreader::XmlReader::Result::End) {
170 state = STATE_END;
171 break;
173 if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
174 && name.equals(RTL_CONSTASCII_STRINGPARAM("component")))
176 handleComponent();
177 state = STATE_COMPONENT_INITIAL;
178 break;
180 throw css::registry::InvalidRegistryException(
181 reader_.getUrl() + ": unexpected item in <components>");
182 case STATE_COMPONENT:
183 if (res == xmlreader::XmlReader::Result::End) {
184 state = STATE_COMPONENTS;
185 break;
187 [[fallthrough]];
188 case STATE_COMPONENT_INITIAL:
189 if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
190 && name.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
192 handleImplementation();
193 state = STATE_IMPLEMENTATION;
194 break;
196 throw css::registry::InvalidRegistryException(
197 reader_.getUrl() + ": unexpected item in <component>");
198 case STATE_IMPLEMENTATION:
199 if (res == xmlreader::XmlReader::Result::End) {
200 state = STATE_COMPONENT;
201 break;
203 if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
204 && name.equals(RTL_CONSTASCII_STRINGPARAM("service")))
206 handleService();
207 state = STATE_SERVICE;
208 break;
210 if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId
211 && name.equals(RTL_CONSTASCII_STRINGPARAM("singleton")))
213 handleSingleton();
214 state = STATE_SINGLETON;
215 break;
217 throw css::registry::InvalidRegistryException(
218 reader_.getUrl() + ": unexpected item in <implementation>");
219 case STATE_SERVICE:
220 if (res == xmlreader::XmlReader::Result::End) {
221 state = STATE_IMPLEMENTATION;
222 break;
224 throw css::registry::InvalidRegistryException(
225 reader_.getUrl() + ": unexpected item in <service>");
226 case STATE_SINGLETON:
227 if (res == xmlreader::XmlReader::Result::End) {
228 state = STATE_IMPLEMENTATION;
229 break;
231 throw css::registry::InvalidRegistryException(
232 reader_.getUrl() + ": unexpected item in <service>");
237 void Parser::handleComponent() {
238 attrLoader_ = OUString();
239 attrUri_ = OUString();
240 attrEnvironment_ = OUString();
241 attrPrefix_ = OUString();
242 xmlreader::Span name;
243 int nsId;
244 while (reader_.nextAttribute(&nsId, &name)) {
245 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
246 && name.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
248 if (!attrLoader_.isEmpty()) {
249 throw css::registry::InvalidRegistryException(
250 reader_.getUrl()
251 + ": <component> has multiple \"loader\" attributes");
253 attrLoader_ = reader_.getAttributeValue(false).convertFromUtf8();
254 if (attrLoader_.isEmpty()) {
255 throw css::registry::InvalidRegistryException(
256 reader_.getUrl()
257 + ": <component> has empty \"loader\" attribute");
259 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
260 && name.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
262 if (!attrUri_.isEmpty()) {
263 throw css::registry::InvalidRegistryException(
264 reader_.getUrl()
265 + ": <component> has multiple \"uri\" attributes");
267 attrUri_ = reader_.getAttributeValue(false).convertFromUtf8();
268 if (attrUri_.isEmpty()) {
269 throw css::registry::InvalidRegistryException(
270 reader_.getUrl()
271 + ": <component> has empty \"uri\" attribute");
273 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
274 && name.equals(RTL_CONSTASCII_STRINGPARAM("environment")))
276 if (!attrEnvironment_.isEmpty()) {
277 throw css::registry::InvalidRegistryException(
278 reader_.getUrl() +
279 ": <component> has multiple \"environment\" attributes");
281 attrEnvironment_ = reader_.getAttributeValue(false)
282 .convertFromUtf8();
283 if (attrEnvironment_.isEmpty()) {
284 throw css::registry::InvalidRegistryException(
285 reader_.getUrl() +
286 ": <component> has empty \"environment\" attribute");
288 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
289 && name.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
291 if (!attrPrefix_.isEmpty()) {
292 throw css::registry::InvalidRegistryException(
293 reader_.getUrl() +
294 ": <component> has multiple \"prefix\" attributes");
296 attrPrefix_ = reader_.getAttributeValue(false).convertFromUtf8();
297 if (attrPrefix_.isEmpty()) {
298 throw css::registry::InvalidRegistryException(
299 reader_.getUrl() +
300 ": <component> has empty \"prefix\" attribute");
302 } else {
303 throw css::registry::InvalidRegistryException(
304 reader_.getUrl() + ": unexpected attribute \""
305 + name.convertFromUtf8() + "\" in <component>");
308 if (attrLoader_.isEmpty()) {
309 throw css::registry::InvalidRegistryException(
310 reader_.getUrl() + ": <component> is missing \"loader\" attribute");
312 if (attrUri_.isEmpty()) {
313 throw css::registry::InvalidRegistryException(
314 reader_.getUrl() + ": <component> is missing \"uri\" attribute");
316 #ifndef DISABLE_DYNLOADING
317 try {
318 attrUri_ = rtl::Uri::convertRelToAbs(reader_.getUrl(), attrUri_);
319 } catch (const rtl::MalformedUriException & e) {
320 throw css::registry::InvalidRegistryException(
321 reader_.getUrl() + ": bad \"uri\" attribute: " + e.getMessage());
323 #endif
326 void Parser::handleImplementation() {
327 OUString attrName;
328 OUString attrConstructor;
329 xmlreader::Span name;
330 int nsId;
331 while (reader_.nextAttribute(&nsId, &name)) {
332 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
333 && name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
335 if (!attrName.isEmpty()) {
336 throw css::registry::InvalidRegistryException(
337 reader_.getUrl()
338 + ": <implementation> has multiple \"name\" attributes");
340 attrName = reader_.getAttributeValue(false).convertFromUtf8();
341 if (attrName.isEmpty()) {
342 throw css::registry::InvalidRegistryException(
343 reader_.getUrl()
344 + ": <implementation> has empty \"name\" attribute");
346 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
347 && name.equals(RTL_CONSTASCII_STRINGPARAM("constructor")))
349 if (!attrConstructor.isEmpty()) {
350 throw css::registry::InvalidRegistryException(
351 reader_.getUrl()
352 + ": <implementation> has multiple \"constructor\""
353 " attributes");
355 attrConstructor = reader_.getAttributeValue(false)
356 .convertFromUtf8();
357 if (attrConstructor.isEmpty()) {
358 throw css::registry::InvalidRegistryException(
359 reader_.getUrl()
360 + ": element has empty \"constructor\" attribute");
362 if (attrEnvironment_.isEmpty()) {
363 throw css::registry::InvalidRegistryException(
364 reader_.getUrl()
365 + ": <implementation> has \"constructor\" attribute but"
366 " <component> has no \"environment\" attribute");
368 } else {
369 throw css::registry::InvalidRegistryException(
370 reader_.getUrl() + ": unexpected element attribute \""
371 + name.convertFromUtf8() + "\" in <implementation>");
374 if (attrName.isEmpty()) {
375 throw css::registry::InvalidRegistryException(
376 reader_.getUrl()
377 + ": <implementation> is missing \"name\" attribute");
379 implementation_.reset(
380 new cppuhelper::ServiceManager::Data::Implementation(
381 attrName, attrLoader_, attrUri_, attrEnvironment_, attrConstructor,
382 attrPrefix_, alienContext_, reader_.getUrl()));
383 if (!data_->namedImplementations.emplace(attrName, implementation_).
384 second)
386 throw css::registry::InvalidRegistryException(
387 reader_.getUrl() + ": duplicate <implementation name=\"" + attrName
388 + "\">");
392 void Parser::handleService() {
393 OUString name(getNameAttribute());
394 implementation_->info->services.push_back(name);
395 data_->services[name].push_back(implementation_);
398 void Parser::handleSingleton() {
399 OUString name(getNameAttribute());
400 implementation_->info->singletons.push_back(name);
401 data_->singletons[name].push_back(implementation_);
404 OUString Parser::getNameAttribute() {
405 OUString attrName;
406 xmlreader::Span name;
407 int nsId;
408 while (reader_.nextAttribute(&nsId, &name)) {
409 if (nsId != xmlreader::XmlReader::NAMESPACE_NONE
410 || !name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
412 throw css::registry::InvalidRegistryException(
413 reader_.getUrl() + ": expected element attribute \"name\"");
415 if (!attrName.isEmpty()) {
416 throw css::registry::InvalidRegistryException(
417 reader_.getUrl()
418 + ": element has multiple \"name\" attributes");
420 attrName = reader_.getAttributeValue(false).convertFromUtf8();
421 if (attrName.isEmpty()) {
422 throw css::registry::InvalidRegistryException(
423 reader_.getUrl() + ": element has empty \"name\" attribute");
426 if (attrName.isEmpty()) {
427 throw css::registry::InvalidRegistryException(
428 reader_.getUrl() + ": element is missing \"name\" attribute");
430 return attrName;
433 class ContentEnumeration:
434 public cppu::WeakImplHelper< css::container::XEnumeration >
436 public:
437 explicit ContentEnumeration(std::vector< css::uno::Any > const & factories):
438 factories_(factories), iterator_(factories_.begin()) {}
440 ContentEnumeration(const ContentEnumeration&) = delete;
441 const ContentEnumeration& operator=(const ContentEnumeration&) = delete;
443 private:
444 virtual ~ContentEnumeration() override {}
446 virtual sal_Bool SAL_CALL hasMoreElements() override;
448 virtual css::uno::Any SAL_CALL nextElement() override;
450 osl::Mutex mutex_;
451 std::vector< css::uno::Any > factories_;
452 std::vector< css::uno::Any >::const_iterator iterator_;
455 sal_Bool ContentEnumeration::hasMoreElements()
457 osl::MutexGuard g(mutex_);
458 return iterator_ != factories_.end();
461 css::uno::Any ContentEnumeration::nextElement()
463 osl::MutexGuard g(mutex_);
464 if (iterator_ == factories_.end()) {
465 throw css::container::NoSuchElementException(
466 "Bootstrap service manager service enumerator has no more elements",
467 static_cast< cppu::OWeakObject * >(this));
469 return *iterator_++;
472 css::beans::Property getDefaultContextProperty() {
473 return css::beans::Property(
474 "DefaultContext", -1,
475 cppu::UnoType< css::uno::XComponentContext >::get(),
476 css::beans::PropertyAttribute::READONLY);
479 class SingletonFactory:
480 public cppu::WeakImplHelper<css::lang::XSingleComponentFactory>
482 public:
483 SingletonFactory(
484 rtl::Reference< cppuhelper::ServiceManager > const & manager,
485 std::shared_ptr<
486 cppuhelper::ServiceManager::Data::Implementation > const &
487 implementation):
488 manager_(manager), implementation_(implementation)
489 { assert(manager.is()); assert(implementation.get() != nullptr); }
491 SingletonFactory(const SingletonFactory&) = delete;
492 const SingletonFactory& operator=(const SingletonFactory&) = delete;
494 private:
495 virtual ~SingletonFactory() override {}
497 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
498 createInstanceWithContext(
499 css::uno::Reference< css::uno::XComponentContext > const & Context) override;
501 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
502 createInstanceWithArgumentsAndContext(
503 css::uno::Sequence< css::uno::Any > const & Arguments,
504 css::uno::Reference< css::uno::XComponentContext > const & Context) override;
506 rtl::Reference< cppuhelper::ServiceManager > manager_;
507 std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
508 implementation_;
511 css::uno::Reference< css::uno::XInterface >
512 SingletonFactory::createInstanceWithContext(
513 css::uno::Reference< css::uno::XComponentContext > const & Context)
515 manager_->loadImplementation(Context, implementation_);
516 return implementation_->createInstance(Context, true);
519 css::uno::Reference< css::uno::XInterface >
520 SingletonFactory::createInstanceWithArgumentsAndContext(
521 css::uno::Sequence< css::uno::Any > const & Arguments,
522 css::uno::Reference< css::uno::XComponentContext > const & Context)
524 manager_->loadImplementation(Context, implementation_);
525 return implementation_->createInstanceWithArguments(
526 Context, true, Arguments);
529 class ImplementationWrapper:
530 public cppu::WeakImplHelper<
531 css::lang::XSingleComponentFactory, css::lang::XSingleServiceFactory,
532 css::lang::XServiceInfo >
534 public:
535 ImplementationWrapper(
536 rtl::Reference< cppuhelper::ServiceManager > const & manager,
537 std::shared_ptr<
538 cppuhelper::ServiceManager::Data::Implementation > const &
539 implementation):
540 manager_(manager), implementation_(implementation)
541 { assert(manager.is()); assert(implementation.get() != nullptr); }
543 ImplementationWrapper(const ImplementationWrapper&) = delete;
544 const ImplementationWrapper& operator=(const ImplementationWrapper&) = delete;
546 private:
547 virtual ~ImplementationWrapper() override {}
549 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
550 createInstanceWithContext(
551 css::uno::Reference< css::uno::XComponentContext > const & Context) override;
553 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
554 createInstanceWithArgumentsAndContext(
555 css::uno::Sequence< css::uno::Any > const & Arguments,
556 css::uno::Reference< css::uno::XComponentContext > const & Context) override;
558 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
559 createInstance() override;
561 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
562 createInstanceWithArguments(
563 css::uno::Sequence< css::uno::Any > const & Arguments) override;
565 virtual OUString SAL_CALL getImplementationName() override;
567 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
569 virtual css::uno::Sequence< OUString > SAL_CALL
570 getSupportedServiceNames() override;
572 rtl::Reference< cppuhelper::ServiceManager > manager_;
573 std::weak_ptr< cppuhelper::ServiceManager::Data::Implementation >
574 implementation_;
577 css::uno::Reference< css::uno::XInterface >
578 ImplementationWrapper::createInstanceWithContext(
579 css::uno::Reference< css::uno::XComponentContext > const & Context)
581 std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
582 assert(impl);
583 manager_->loadImplementation(Context, impl);
584 return impl->createInstance(Context, false);
587 css::uno::Reference< css::uno::XInterface >
588 ImplementationWrapper::createInstanceWithArgumentsAndContext(
589 css::uno::Sequence< css::uno::Any > const & Arguments,
590 css::uno::Reference< css::uno::XComponentContext > const & Context)
592 std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
593 assert(impl);
594 manager_->loadImplementation(Context, impl);
595 return impl->createInstanceWithArguments(
596 Context, false, Arguments);
599 css::uno::Reference< css::uno::XInterface >
600 ImplementationWrapper::createInstance()
602 return createInstanceWithContext(manager_->getContext());
605 css::uno::Reference< css::uno::XInterface >
606 ImplementationWrapper::createInstanceWithArguments(
607 css::uno::Sequence< css::uno::Any > const & Arguments)
609 return createInstanceWithArgumentsAndContext(
610 Arguments, manager_->getContext());
613 OUString ImplementationWrapper::getImplementationName()
615 std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
616 assert(impl);
617 return impl->info->name;
620 sal_Bool ImplementationWrapper::supportsService(OUString const & ServiceName)
622 return cppu::supportsService(this, ServiceName);
625 css::uno::Sequence< OUString >
626 ImplementationWrapper::getSupportedServiceNames()
628 std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
629 assert(impl);
630 if (impl->info->services.size()
631 > static_cast< sal_uInt32 >(SAL_MAX_INT32))
633 throw css::uno::RuntimeException(
634 ("Implementation " + impl->info->name
635 + " supports too many services"),
636 static_cast< cppu::OWeakObject * >(this));
638 return comphelper::containerToSequence(impl->info->services);
643 css::uno::Reference<css::uno::XInterface>
644 cppuhelper::ServiceManager::Data::Implementation::createInstance(
645 css::uno::Reference<css::uno::XComponentContext> const & context,
646 bool singletonRequest)
648 css::uno::Reference<css::uno::XInterface> inst;
649 if (constructor) {
650 inst.set(
651 constructor(context.get(), css::uno::Sequence<css::uno::Any>()),
652 SAL_NO_ACQUIRE);
653 } else if (factory1.is()) {
654 inst = factory1->createInstanceWithContext(context);
655 } else {
656 assert(factory2.is());
657 inst = factory2->createInstance();
659 updateDisposeSingleton(singletonRequest, inst);
660 return inst;
663 css::uno::Reference<css::uno::XInterface>
664 cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments(
665 css::uno::Reference<css::uno::XComponentContext> const & context,
666 bool singletonRequest, css::uno::Sequence<css::uno::Any> const & arguments)
668 css::uno::Reference<css::uno::XInterface> inst;
669 if (constructor) {
670 inst.set(constructor(context.get(), arguments), SAL_NO_ACQUIRE);
671 //HACK: The constructor will either observe arguments and return inst
672 // that does not implement XInitialization (or null), or ignore
673 // arguments and return inst that implements XInitialization; this
674 // should be removed again once XInitialization-based implementations
675 // have become rare:
676 css::uno::Reference<css::lang::XInitialization> init(
677 inst, css::uno::UNO_QUERY);
678 if (init.is()) {
679 init->initialize(arguments);
681 } else if (factory1.is()) {
682 inst = factory1->createInstanceWithArgumentsAndContext(
683 arguments, context);
684 } else {
685 assert(factory2.is());
686 inst = factory2->createInstanceWithArguments(arguments);
688 updateDisposeSingleton(singletonRequest, inst);
689 return inst;
692 void cppuhelper::ServiceManager::Data::Implementation::updateDisposeSingleton(
693 bool singletonRequest,
694 css::uno::Reference<css::uno::XInterface> const & instance)
696 // This is an optimization, to only call dispose once (from the component
697 // context) on a singleton that is obtained both via the component context
698 // and via the service manager; however, there is a harmless race here that
699 // may cause two calls to dispose nevertheless (also, this calls dispose on
700 // at most one of the instances obtained via the service manager, in case
701 // the implementation hands out different instances):
702 if (singletonRequest) {
703 osl::MutexGuard g(mutex);
704 disposeSingleton.clear();
705 dispose = false;
706 } else if (!info->singletons.empty()) {
707 css::uno::Reference<css::lang::XComponent> comp(
708 instance, css::uno::UNO_QUERY);
709 if (comp.is()) {
710 osl::MutexGuard g(mutex);
711 if (dispose) {
712 disposeSingleton = comp;
718 void cppuhelper::ServiceManager::addSingletonContextEntries(
719 std::vector< cppu::ContextEntry_Init > * entries)
721 assert(entries != nullptr);
722 for (const auto& [rName, rImpls] : data_.singletons)
724 assert(!rImpls.empty());
725 assert(rImpls[0].get() != nullptr);
726 SAL_INFO_IF(
727 rImpls.size() > 1, "cppuhelper",
728 "Arbitrarily choosing " << rImpls[0]->info->name
729 << " among multiple implementations for " << rName);
730 entries->push_back(
731 cppu::ContextEntry_Init(
732 "/singletons/" + rName,
733 css::uno::makeAny<
734 css::uno::Reference<css::lang::XSingleComponentFactory> >(
735 new SingletonFactory(this, rImpls[0])),
736 true));
740 void cppuhelper::ServiceManager::loadImplementation(
741 css::uno::Reference< css::uno::XComponentContext > const & context,
742 std::shared_ptr< Data::Implementation > const & implementation)
744 assert(implementation.get() != nullptr);
746 osl::MutexGuard g(rBHelper.rMutex);
747 if (implementation->status == Data::Implementation::STATUS_LOADED) {
748 return;
751 OUString uri;
752 try {
753 uri = cppu::bootstrap_expandUri(implementation->info->uri);
754 } catch (css::lang::IllegalArgumentException & e) {
755 throw css::uno::DeploymentException(
756 "Cannot expand URI" + implementation->info->uri + ": " + e.Message,
757 static_cast< cppu::OWeakObject * >(this));
759 cppuhelper::WrapperConstructorFn ctor;
760 css::uno::Reference< css::uno::XInterface > f0;
761 // Special handling of SharedLibrary loader, with support for environment,
762 // constructor, and prefix arguments:
763 if (!implementation->info->alienContext.is()
764 && implementation->info->loader == "com.sun.star.loader.SharedLibrary")
766 cppuhelper::detail::loadSharedLibComponentFactory(
767 uri, implementation->info->environment,
768 implementation->info->prefix, implementation->info->name,
769 implementation->info->constructor, this, &ctor, &f0);
770 if (ctor) {
771 assert(!implementation->info->environment.isEmpty());
773 } else {
774 SAL_WARN_IF(
775 !implementation->info->environment.isEmpty(), "cppuhelper",
776 "Loader " << implementation->info->loader
777 << " and non-empty environment "
778 << implementation->info->environment);
779 SAL_WARN_IF(
780 !implementation->info->prefix.isEmpty(), "cppuhelper",
781 "Loader " << implementation->info->loader
782 << " and non-empty constructor "
783 << implementation->info->constructor);
784 SAL_WARN_IF(
785 !implementation->info->prefix.isEmpty(), "cppuhelper",
786 "Loader " << implementation->info->loader
787 << " and non-empty prefix " << implementation->info->prefix);
788 css::uno::Reference< css::uno::XComponentContext > ctxt;
789 css::uno::Reference< css::lang::XMultiComponentFactory > smgr;
790 if (implementation->info->alienContext.is()) {
791 ctxt = implementation->info->alienContext;
792 smgr.set(ctxt->getServiceManager(), css::uno::UNO_SET_THROW);
793 } else {
794 assert(context.is());
795 ctxt = context;
796 smgr = this;
798 css::uno::Reference< css::loader::XImplementationLoader > loader(
799 smgr->createInstanceWithContext(implementation->info->loader, ctxt),
800 css::uno::UNO_QUERY_THROW);
801 f0 = loader->activate(
802 implementation->info->name, OUString(), uri,
803 css::uno::Reference< css::registry::XRegistryKey >());
805 css::uno::Reference<css::lang::XSingleComponentFactory> f1;
806 css::uno::Reference<css::lang::XSingleServiceFactory> f2;
807 if (!ctor) {
808 f1.set(f0, css::uno::UNO_QUERY);
809 if (!f1.is()) {
810 f2.set(f0, css::uno::UNO_QUERY);
811 if (!f2.is()) {
812 throw css::uno::DeploymentException(
813 ("Implementation " + implementation->info->name
814 + " does not provide a constructor or factory"),
815 static_cast< cppu::OWeakObject * >(this));
819 //TODO: There is a race here, as the relevant service factory can be removed
820 // while the mutex is unlocked and loading can thus fail, as the entity from
821 // which to load can disappear once the service factory is removed.
822 osl::MutexGuard g(rBHelper.rMutex);
823 if (!(isDisposed()
824 || implementation->status == Data::Implementation::STATUS_LOADED))
826 implementation->status = Data::Implementation::STATUS_LOADED;
827 implementation->constructor = ctor;
828 implementation->factory1 = f1;
829 implementation->factory2 = f2;
833 void cppuhelper::ServiceManager::disposing() {
834 std::vector< css::uno::Reference<css::lang::XComponent> > sngls;
835 std::vector< css::uno::Reference< css::lang::XComponent > > comps;
836 Data clear;
838 osl::MutexGuard g(rBHelper.rMutex);
839 for (const auto& rEntry : data_.namedImplementations)
841 assert(rEntry.second.get() != nullptr);
842 if (!rEntry.second->info->singletons.empty()) {
843 osl::MutexGuard g2(rEntry.second->mutex);
844 if (rEntry.second->disposeSingleton.is()) {
845 sngls.push_back(rEntry.second->disposeSingleton);
849 for (const auto& rEntry : data_.dynamicImplementations)
851 assert(rEntry.second.get() != nullptr);
852 if (!rEntry.second->info->singletons.empty()) {
853 osl::MutexGuard g2(rEntry.second->mutex);
854 if (rEntry.second->disposeSingleton.is()) {
855 sngls.push_back(rEntry.second->disposeSingleton);
858 if (rEntry.second->component.is()) {
859 comps.push_back(rEntry.second->component);
862 data_.namedImplementations.swap(clear.namedImplementations);
863 data_.dynamicImplementations.swap(clear.dynamicImplementations);
864 data_.services.swap(clear.services);
865 data_.singletons.swap(clear.singletons);
867 for (const auto& rxSngl : sngls)
869 try {
870 rxSngl->dispose();
871 } catch (css::uno::RuntimeException & e) {
872 SAL_WARN("cppuhelper", "Ignoring " << e << " while disposing singleton");
875 for (const auto& rxComp : comps)
877 removeEventListenerFromComponent(rxComp);
881 void cppuhelper::ServiceManager::initialize(
882 css::uno::Sequence<css::uno::Any> const & aArguments)
884 OUString arg;
885 if (aArguments.getLength() != 1 || !(aArguments[0] >>= arg)
886 || arg != "preload")
888 throw css::lang::IllegalArgumentException(
889 "invalid ServiceManager::initialize argument",
890 css::uno::Reference<css::uno::XInterface>(), 0);
892 preloadImplementations();
895 OUString cppuhelper::ServiceManager::getImplementationName()
897 return
898 "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager";
901 sal_Bool cppuhelper::ServiceManager::supportsService(
902 OUString const & ServiceName)
904 return cppu::supportsService(this, ServiceName);
907 css::uno::Sequence< OUString >
908 cppuhelper::ServiceManager::getSupportedServiceNames()
910 return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.ServiceManager" };
913 css::uno::Reference< css::uno::XInterface >
914 cppuhelper::ServiceManager::createInstance(
915 OUString const & aServiceSpecifier)
917 assert(context_.is());
918 return createInstanceWithContext(aServiceSpecifier, context_);
921 css::uno::Reference< css::uno::XInterface >
922 cppuhelper::ServiceManager::createInstanceWithArguments(
923 OUString const & ServiceSpecifier,
924 css::uno::Sequence< css::uno::Any > const & Arguments)
926 assert(context_.is());
927 return createInstanceWithArgumentsAndContext(
928 ServiceSpecifier, Arguments, context_);
931 css::uno::Sequence< OUString >
932 cppuhelper::ServiceManager::getAvailableServiceNames()
934 osl::MutexGuard g(rBHelper.rMutex);
935 if (isDisposed()) {
936 return css::uno::Sequence< OUString >();
938 if (data_.services.size() > static_cast< sal_uInt32 >(SAL_MAX_INT32)) {
939 throw css::uno::RuntimeException(
940 "getAvailableServiceNames: too many services",
941 static_cast< cppu::OWeakObject * >(this));
943 return comphelper::mapKeysToSequence(data_.services);
946 css::uno::Reference< css::uno::XInterface >
947 cppuhelper::ServiceManager::createInstanceWithContext(
948 OUString const & aServiceSpecifier,
949 css::uno::Reference< css::uno::XComponentContext > const & Context)
951 std::shared_ptr< Data::Implementation > impl(
952 findServiceImplementation(Context, aServiceSpecifier));
953 return impl == nullptr ? css::uno::Reference<css::uno::XInterface>()
954 : impl->createInstance(Context, false);
957 css::uno::Reference< css::uno::XInterface >
958 cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext(
959 OUString const & ServiceSpecifier,
960 css::uno::Sequence< css::uno::Any > const & Arguments,
961 css::uno::Reference< css::uno::XComponentContext > const & Context)
963 std::shared_ptr< Data::Implementation > impl(
964 findServiceImplementation(Context, ServiceSpecifier));
965 return impl == nullptr ? css::uno::Reference<css::uno::XInterface>()
966 : impl->createInstanceWithArguments(Context, false, Arguments);
969 css::uno::Type cppuhelper::ServiceManager::getElementType()
971 return css::uno::Type();
974 sal_Bool cppuhelper::ServiceManager::hasElements()
976 osl::MutexGuard g(rBHelper.rMutex);
977 return
978 !(data_.namedImplementations.empty()
979 && data_.dynamicImplementations.empty());
982 css::uno::Reference< css::container::XEnumeration >
983 cppuhelper::ServiceManager::createEnumeration()
985 throw css::uno::RuntimeException(
986 "ServiceManager createEnumeration: method not supported",
987 static_cast< cppu::OWeakObject * >(this));
990 sal_Bool cppuhelper::ServiceManager::has(css::uno::Any const &)
992 throw css::uno::RuntimeException(
993 "ServiceManager has: method not supported",
994 static_cast< cppu::OWeakObject * >(this));
997 void cppuhelper::ServiceManager::insert(css::uno::Any const & aElement)
999 css::uno::Sequence< css::beans::NamedValue > args;
1000 if (aElement >>= args) {
1001 std::vector< OUString > uris;
1002 css::uno::Reference< css::uno::XComponentContext > alienContext;
1003 for (sal_Int32 i = 0; i < args.getLength(); ++i) {
1004 if (args[i].Name == "uri") {
1005 OUString uri;
1006 if (!(args[i].Value >>= uri)) {
1007 throw css::lang::IllegalArgumentException(
1008 "Bad uri argument",
1009 static_cast< cppu::OWeakObject * >(this), 0);
1011 uris.push_back(uri);
1012 } else if (args[i].Name == "component-context") {
1013 if (alienContext.is()) {
1014 throw css::lang::IllegalArgumentException(
1015 "Multiple component-context arguments",
1016 static_cast< cppu::OWeakObject * >(this), 0);
1018 if (!(args[i].Value >>= alienContext) || !alienContext.is()) {
1019 throw css::lang::IllegalArgumentException(
1020 "Bad component-context argument",
1021 static_cast< cppu::OWeakObject * >(this), 0);
1023 } else {
1024 throw css::lang::IllegalArgumentException(
1025 "Bad argument " + args[i].Name,
1026 static_cast< cppu::OWeakObject * >(this), 0);
1029 insertRdbFiles(uris, alienContext);
1030 return;
1032 css::uno::Reference< css::lang::XServiceInfo > info;
1033 if ((aElement >>= info) && info.is()) {
1034 insertLegacyFactory(info);
1035 return;
1037 // At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in
1038 // module languagetool) contain an (actively registered) factory that does not
1039 // implement XServiceInfo (see <http://sourceforge.net/tracker/?
1040 // func=detail&aid=3526635&group_id=110216&atid=655717> "SingletonFactory should
1041 // implement XServiceInfo"); the old OServiceManager::insert
1042 // (stoc/source/servicemanager/servicemanager.cxx) silently did not add such
1043 // broken factories to its m_ImplementationNameMap, so ignore them here for
1044 // backwards compatibility of live-insertion of extensions, too.
1046 // (The plan was that this warning would go away (and we would do the
1047 // throw instead) for the incompatible LO 4, but we changed our mind):
1048 css::uno::Reference< css::lang::XSingleComponentFactory > legacy;
1049 if ((aElement >>= legacy) && legacy.is()) {
1050 SAL_WARN(
1051 "cppuhelper",
1052 "Ignored XSingleComponentFactory not implementing XServiceInfo");
1053 return;
1056 throw css::lang::IllegalArgumentException(
1057 "Bad insert element", static_cast< cppu::OWeakObject * >(this), 0);
1060 void cppuhelper::ServiceManager::remove(css::uno::Any const & aElement)
1062 css::uno::Sequence< css::beans::NamedValue > args;
1063 if (aElement >>= args) {
1064 std::vector< OUString > uris;
1065 for (sal_Int32 i = 0; i < args.getLength(); ++i) {
1066 if (args[i].Name != "uri") {
1067 throw css::lang::IllegalArgumentException(
1068 "Bad argument " + args[i].Name,
1069 static_cast< cppu::OWeakObject * >(this), 0);
1071 OUString uri;
1072 if (!(args[i].Value >>= uri)) {
1073 throw css::lang::IllegalArgumentException(
1074 "Bad uri argument",
1075 static_cast< cppu::OWeakObject * >(this), 0);
1077 uris.push_back(uri);
1079 removeRdbFiles(uris);
1080 return;
1082 css::uno::Reference< css::lang::XServiceInfo > info;
1083 if ((aElement >>= info) && info.is()) {
1084 if (!removeLegacyFactory(info, true)) {
1085 throw css::container::NoSuchElementException(
1086 "Remove non-inserted factory object",
1087 static_cast< cppu::OWeakObject * >(this));
1089 return;
1091 OUString impl;
1092 if (aElement >>= impl) {
1093 // For live-removal of extensions:
1094 removeImplementation(impl);
1095 return;
1097 throw css::lang::IllegalArgumentException(
1098 "Bad remove element", static_cast< cppu::OWeakObject * >(this), 0);
1101 css::uno::Reference< css::container::XEnumeration >
1102 cppuhelper::ServiceManager::createContentEnumeration(
1103 OUString const & aServiceName)
1105 std::vector< std::shared_ptr< Data::Implementation > > impls;
1107 osl::MutexGuard g(rBHelper.rMutex);
1108 Data::ImplementationMap::const_iterator i(
1109 data_.services.find(aServiceName));
1110 if (i != data_.services.end()) {
1111 impls = i->second;
1114 std::vector< css::uno::Any > factories;
1115 for (const auto& rxImpl : impls)
1117 Data::Implementation * impl = rxImpl.get();
1118 assert(impl != nullptr);
1120 osl::MutexGuard g(rBHelper.rMutex);
1121 if (isDisposed()) {
1122 factories.clear();
1123 break;
1125 if (impl->status == Data::Implementation::STATUS_NEW) {
1126 // Postpone actual implementation instantiation as long as
1127 // possible (so that e.g. opening LO's "Tools - Macros" menu
1128 // does not try to instantiate a JVM, which can lead to a
1129 // synchronous error dialog when no JVM is specified, and
1130 // showing the dialog while hovering over a menu can cause
1131 // trouble):
1132 impl->factory1 = new ImplementationWrapper(this, rxImpl);
1133 impl->status = Data::Implementation::STATUS_WRAPPER;
1135 if (impl->constructor != nullptr && !impl->factory1.is()) {
1136 impl->factory1 = new ImplementationWrapper(this, rxImpl);
1139 if (impl->factory1.is()) {
1140 factories.push_back(css::uno::Any(impl->factory1));
1141 } else {
1142 assert(impl->factory2.is());
1143 factories.push_back(css::uno::Any(impl->factory2));
1146 return new ContentEnumeration(factories);
1149 css::uno::Reference< css::beans::XPropertySetInfo >
1150 cppuhelper::ServiceManager::getPropertySetInfo()
1152 return this;
1155 void cppuhelper::ServiceManager::setPropertyValue(
1156 OUString const & aPropertyName, css::uno::Any const &)
1158 if (aPropertyName == "DefaultContext") {
1159 throw css::beans::PropertyVetoException(
1160 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1161 } else {
1162 throw css::beans::UnknownPropertyException(
1163 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1167 css::uno::Any cppuhelper::ServiceManager::getPropertyValue(
1168 OUString const & PropertyName)
1170 if (PropertyName != "DefaultContext") {
1171 throw css::beans::UnknownPropertyException(
1172 PropertyName, static_cast< cppu::OWeakObject * >(this));
1174 assert(context_.is());
1175 return css::uno::Any(context_);
1178 void cppuhelper::ServiceManager::addPropertyChangeListener(
1179 OUString const & aPropertyName,
1180 css::uno::Reference< css::beans::XPropertyChangeListener > const &
1181 xListener)
1183 if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1184 throw css::beans::UnknownPropertyException(
1185 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1187 // DefaultContext does not change, so just treat it as an event listener:
1188 return addEventListener(xListener);
1191 void cppuhelper::ServiceManager::removePropertyChangeListener(
1192 OUString const & aPropertyName,
1193 css::uno::Reference< css::beans::XPropertyChangeListener > const &
1194 aListener)
1196 if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1197 throw css::beans::UnknownPropertyException(
1198 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1200 // DefaultContext does not change, so just treat it as an event listener:
1201 return removeEventListener(aListener);
1204 void cppuhelper::ServiceManager::addVetoableChangeListener(
1205 OUString const & PropertyName,
1206 css::uno::Reference< css::beans::XVetoableChangeListener > const &
1207 aListener)
1209 if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1210 throw css::beans::UnknownPropertyException(
1211 PropertyName, static_cast< cppu::OWeakObject * >(this));
1213 // DefaultContext does not change, so just treat it as an event listener:
1214 return addEventListener(aListener);
1217 void cppuhelper::ServiceManager::removeVetoableChangeListener(
1218 OUString const & PropertyName,
1219 css::uno::Reference< css::beans::XVetoableChangeListener > const &
1220 aListener)
1222 if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1223 throw css::beans::UnknownPropertyException(
1224 PropertyName, static_cast< cppu::OWeakObject * >(this));
1226 // DefaultContext does not change, so just treat it as an event listener:
1227 return removeEventListener(aListener);
1230 css::uno::Sequence< css::beans::Property >
1231 cppuhelper::ServiceManager::getProperties() {
1232 css::uno::Sequence< css::beans::Property > props(1);
1233 props[0] = getDefaultContextProperty();
1234 return props;
1237 css::beans::Property cppuhelper::ServiceManager::getPropertyByName(
1238 OUString const & aName)
1240 if (aName != "DefaultContext") {
1241 throw css::beans::UnknownPropertyException(
1242 aName, static_cast< cppu::OWeakObject * >(this));
1244 return getDefaultContextProperty();
1247 sal_Bool cppuhelper::ServiceManager::hasPropertyByName(
1248 OUString const & Name)
1250 return Name == "DefaultContext";
1253 cppuhelper::ServiceManager::~ServiceManager() {}
1255 void cppuhelper::ServiceManager::disposing(
1256 css::lang::EventObject const & Source)
1258 removeLegacyFactory(
1259 css::uno::Reference< css::lang::XServiceInfo >(
1260 Source.Source, css::uno::UNO_QUERY_THROW),
1261 false);
1264 void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1265 css::uno::Reference< css::lang::XComponent > const & component)
1267 assert(component.is());
1268 try {
1269 component->removeEventListener(this);
1270 } catch (css::uno::RuntimeException & e) {
1271 SAL_INFO(
1272 "cppuhelper",
1273 "Ignored removeEventListener RuntimeException " + e.Message);
1277 void cppuhelper::ServiceManager::init(OUString const & rdbUris) {
1278 for (sal_Int32 i = 0; i != -1;) {
1279 OUString uri(rdbUris.getToken(0, ' ', i));
1280 if (uri.isEmpty()) {
1281 continue;
1283 bool optional;
1284 bool directory;
1285 cppu::decodeRdbUri(&uri, &optional, &directory);
1286 if (directory) {
1287 readRdbDirectory(uri, optional);
1288 } else {
1289 readRdbFile(uri, optional);
1294 void cppuhelper::ServiceManager::readRdbDirectory(
1295 OUString const & uri, bool optional)
1297 osl::Directory dir(uri);
1298 switch (dir.open()) {
1299 case osl::FileBase::E_None:
1300 break;
1301 case osl::FileBase::E_NOENT:
1302 if (optional) {
1303 SAL_INFO("cppuhelper", "Ignored optional " << uri);
1304 return;
1306 [[fallthrough]];
1307 default:
1308 throw css::uno::DeploymentException(
1309 "Cannot open directory " + uri,
1310 static_cast< cppu::OWeakObject * >(this));
1312 for (;;) {
1313 OUString url;
1314 if (!cppu::nextDirectoryItem(dir, &url)) {
1315 break;
1317 readRdbFile(url, false);
1321 void cppuhelper::ServiceManager::readRdbFile(
1322 OUString const & uri, bool optional)
1324 try {
1325 Parser(
1326 uri, css::uno::Reference< css::uno::XComponentContext >(), &data_);
1327 } catch (css::container::NoSuchElementException &) {
1328 if (!optional) {
1329 throw css::uno::DeploymentException(
1330 uri + ": no such file",
1331 static_cast< cppu::OWeakObject * >(this));
1333 SAL_INFO("cppuhelper", "Ignored optional " << uri);
1334 } catch (css::registry::InvalidRegistryException & e) {
1335 if (!readLegacyRdbFile(uri)) {
1336 throw css::uno::DeploymentException(
1337 "InvalidRegistryException: " + e.Message,
1338 static_cast< cppu::OWeakObject * >(this));
1340 } catch (css::uno::RuntimeException &) {
1341 if (!readLegacyRdbFile(uri)) {
1342 throw;
1347 bool cppuhelper::ServiceManager::readLegacyRdbFile(OUString const & uri) {
1348 Registry reg;
1349 switch (reg.open(uri, RegAccessMode::READONLY)) {
1350 case RegError::NO_ERROR:
1351 break;
1352 case RegError::REGISTRY_NOT_EXISTS:
1353 case RegError::INVALID_REGISTRY:
1355 // Ignore empty rdb files (which are at least seen by subordinate
1356 // uno processes during extension registration; Registry::open can
1357 // fail on them if mmap(2) returns EINVAL for a zero length):
1358 osl::DirectoryItem item;
1359 if (osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None) {
1360 osl::FileStatus status(osl_FileStatus_Mask_FileSize);
1361 if (item.getFileStatus(status) == osl::FileBase::E_None
1362 && status.getFileSize() == 0)
1364 return true;
1368 [[fallthrough]];
1369 default:
1370 return false;
1372 RegistryKey rootKey;
1373 if (reg.openRootKey(rootKey) != RegError::NO_ERROR) {
1374 throw css::uno::DeploymentException(
1375 "Failure reading legacy rdb file " + uri,
1376 static_cast< cppu::OWeakObject * >(this));
1378 RegistryKeyArray impls;
1379 switch (rootKey.openSubKeys("IMPLEMENTATIONS", impls)) {
1380 case RegError::NO_ERROR:
1381 break;
1382 case RegError::KEY_NOT_EXISTS:
1383 return true;
1384 default:
1385 throw css::uno::DeploymentException(
1386 "Failure reading legacy rdb file " + uri,
1387 static_cast< cppu::OWeakObject * >(this));
1389 for (sal_uInt32 i = 0; i != impls.getLength(); ++i) {
1390 RegistryKey implKey(impls.getElement(i));
1391 assert(implKey.getName().match("/IMPLEMENTATIONS/"));
1392 OUString name(
1393 implKey.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1394 std::shared_ptr< Data::Implementation > impl(
1395 new Data::Implementation(
1396 name, readLegacyRdbString(uri, implKey, "UNO/ACTIVATOR"),
1397 readLegacyRdbString(uri, implKey, "UNO/LOCATION"), "", "", "",
1398 css::uno::Reference< css::uno::XComponentContext >(), uri));
1399 if (!data_.namedImplementations.emplace(name, impl).second)
1401 throw css::registry::InvalidRegistryException(
1402 uri + ": duplicate <implementation name=\"" + name + "\">");
1404 readLegacyRdbStrings(
1405 uri, implKey, "UNO/SERVICES", &impl->info->services);
1406 for (const auto& rService : impl->info->services)
1408 data_.services[rService].push_back(impl);
1410 readLegacyRdbStrings(
1411 uri, implKey, "UNO/SINGLETONS", &impl->info->singletons);
1412 for (const auto& rSingleton : impl->info->singletons)
1414 data_.singletons[rSingleton].push_back(impl);
1417 return true;
1420 OUString cppuhelper::ServiceManager::readLegacyRdbString(
1421 OUString const & uri, RegistryKey & key, OUString const & path)
1423 RegistryKey subkey;
1424 RegValueType t;
1425 sal_uInt32 s(0);
1426 if (key.openKey(path, subkey) != RegError::NO_ERROR
1427 || subkey.getValueInfo(OUString(), &t, &s) != RegError::NO_ERROR
1428 || t != RegValueType::STRING
1429 || s == 0 || s > static_cast< sal_uInt32 >(SAL_MAX_INT32))
1431 throw css::uno::DeploymentException(
1432 "Failure reading legacy rdb file " + uri,
1433 static_cast< cppu::OWeakObject * >(this));
1435 OUString val;
1436 std::vector< char > v(s); // assuming sal_uInt32 fits into vector::size_type
1437 if (subkey.getValue(OUString(), v.data()) != RegError::NO_ERROR
1438 || v.back() != '\0'
1439 || !rtl_convertStringToUString(
1440 &val.pData, v.data(), static_cast< sal_Int32 >(s - 1),
1441 RTL_TEXTENCODING_UTF8,
1442 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1443 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1444 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
1446 throw css::uno::DeploymentException(
1447 "Failure reading legacy rdb file " + uri,
1448 static_cast< cppu::OWeakObject * >(this));
1450 return val;
1453 void cppuhelper::ServiceManager::readLegacyRdbStrings(
1454 OUString const & uri, RegistryKey & key, OUString const & path,
1455 std::vector< OUString > * strings)
1457 assert(strings != nullptr);
1458 RegistryKey subkey;
1459 switch (key.openKey(path, subkey)) {
1460 case RegError::NO_ERROR:
1461 break;
1462 case RegError::KEY_NOT_EXISTS:
1463 return;
1464 default:
1465 throw css::uno::DeploymentException(
1466 "Failure reading legacy rdb file " + uri,
1467 static_cast< cppu::OWeakObject * >(this));
1469 OUString prefix(subkey.getName() + "/");
1470 RegistryKeyNames names;
1471 if (subkey.getKeyNames(OUString(), names) != RegError::NO_ERROR) {
1472 throw css::uno::DeploymentException(
1473 "Failure reading legacy rdb file " + uri,
1474 static_cast< cppu::OWeakObject * >(this));
1476 for (sal_uInt32 i = 0; i != names.getLength(); ++i) {
1477 assert(names.getElement(i).match(prefix));
1478 strings->push_back(names.getElement(i).copy(prefix.getLength()));
1482 void cppuhelper::ServiceManager::insertRdbFiles(
1483 std::vector< OUString > const & uris,
1484 css::uno::Reference< css::uno::XComponentContext > const & alienContext)
1486 Data extra;
1487 for (const auto& rUri : uris)
1489 try {
1490 Parser(rUri, alienContext, &extra);
1491 } catch (css::container::NoSuchElementException &) {
1492 throw css::lang::IllegalArgumentException(
1493 rUri + ": no such file", static_cast< cppu::OWeakObject * >(this),
1495 } catch (css::registry::InvalidRegistryException & e) {
1496 throw css::lang::IllegalArgumentException(
1497 "InvalidRegistryException: " + e.Message,
1498 static_cast< cppu::OWeakObject * >(this), 0);
1501 insertExtraData(extra);
1504 void cppuhelper::ServiceManager::insertLegacyFactory(
1505 css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo)
1507 assert(factoryInfo.is());
1508 OUString name(factoryInfo->getImplementationName());
1509 css::uno::Reference< css::lang::XSingleComponentFactory > f1(
1510 factoryInfo, css::uno::UNO_QUERY);
1511 css::uno::Reference< css::lang::XSingleServiceFactory > f2;
1512 if (!f1.is()) {
1513 f2.set(factoryInfo, css::uno::UNO_QUERY);
1514 if (!f2.is()) {
1515 throw css::lang::IllegalArgumentException(
1516 ("Bad XServiceInfo argument implements neither"
1517 " XSingleComponentFactory nor XSingleServiceFactory"),
1518 static_cast< cppu::OWeakObject * >(this), 0);
1521 css::uno::Reference< css::lang::XComponent > comp(
1522 factoryInfo, css::uno::UNO_QUERY);
1523 std::shared_ptr< Data::Implementation > impl(
1524 new Data::Implementation(name, f1, f2, comp));
1525 Data extra;
1526 if (!name.isEmpty()) {
1527 extra.namedImplementations.emplace(name, impl);
1529 extra.dynamicImplementations.emplace(factoryInfo, impl);
1530 css::uno::Sequence< OUString > services(
1531 factoryInfo->getSupportedServiceNames());
1532 for (sal_Int32 i = 0; i != services.getLength(); ++i) {
1533 impl->info->services.push_back(services[i]);
1534 extra.services[services[i]].push_back(impl);
1536 if (insertExtraData(extra) && comp.is()) {
1537 comp->addEventListener(this);
1541 bool cppuhelper::ServiceManager::insertExtraData(Data const & extra) {
1543 osl::MutexGuard g(rBHelper.rMutex);
1544 if (isDisposed()) {
1545 return false;
1547 auto i = std::find_if(extra.namedImplementations.begin(), extra.namedImplementations.end(),
1548 [this](const Data::NamedImplementations::value_type& rEntry) {
1549 return data_.namedImplementations.find(rEntry.first) != data_.namedImplementations.end(); });
1550 if (i != extra.namedImplementations.end())
1552 throw css::lang::IllegalArgumentException(
1553 "Insert duplicate implementation name " + i->first,
1554 static_cast< cppu::OWeakObject * >(this), 0);
1556 bool bDuplicate = std::any_of(extra.dynamicImplementations.begin(), extra.dynamicImplementations.end(),
1557 [this](const Data::DynamicImplementations::value_type& rEntry) {
1558 return data_.dynamicImplementations.find(rEntry.first) != data_.dynamicImplementations.end(); });
1559 if (bDuplicate)
1561 throw css::lang::IllegalArgumentException(
1562 "Insert duplicate factory object",
1563 static_cast< cppu::OWeakObject * >(this), 0);
1565 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1566 data_.namedImplementations.insert(
1567 extra.namedImplementations.begin(),
1568 extra.namedImplementations.end());
1569 data_.dynamicImplementations.insert(
1570 extra.dynamicImplementations.begin(),
1571 extra.dynamicImplementations.end());
1572 insertImplementationMap(&data_.services, extra.services);
1573 insertImplementationMap(&data_.singletons, extra.singletons);
1575 //TODO: Updating the component context singleton data should be part of the
1576 // atomic service manager update:
1577 if (!extra.singletons.empty()) {
1578 assert(context_.is());
1579 css::uno::Reference< css::container::XNameContainer > cont(
1580 context_, css::uno::UNO_QUERY_THROW);
1581 for (const auto& [rName, rImpls] : extra.singletons)
1583 OUString name("/singletons/" + rName);
1584 //TODO: Update should be atomic:
1585 try {
1586 cont->removeByName(name + "/arguments");
1587 } catch (const css::container::NoSuchElementException &) {}
1588 assert(!rImpls.empty());
1589 assert(rImpls[0].get() != nullptr);
1590 SAL_INFO_IF(
1591 rImpls.size() > 1, "cppuhelper",
1592 "Arbitrarily choosing " << rImpls[0]->info->name
1593 << " among multiple implementations for singleton "
1594 << rName);
1595 try {
1596 cont->insertByName(
1597 name + "/service", css::uno::Any(rImpls[0]->info->name));
1598 } catch (css::container::ElementExistException &) {
1599 cont->replaceByName(
1600 name + "/service", css::uno::Any(rImpls[0]->info->name));
1602 try {
1603 cont->insertByName(name, css::uno::Any());
1604 } catch (css::container::ElementExistException &) {
1605 SAL_INFO("cppuhelper", "Overwriting singleton " << rName);
1606 cont->replaceByName(name, css::uno::Any());
1610 return true;
1613 void cppuhelper::ServiceManager::removeRdbFiles(
1614 std::vector< OUString > const & uris)
1616 // The underlying data structures make this function somewhat inefficient,
1617 // but the assumption is that it is rarely called (and that if it is called,
1618 // it is called with a uris vector of size one):
1619 std::vector< std::shared_ptr< Data::Implementation > > clear;
1621 osl::MutexGuard g(rBHelper.rMutex);
1622 for (const auto& rUri : uris)
1624 for (Data::NamedImplementations::iterator j(
1625 data_.namedImplementations.begin());
1626 j != data_.namedImplementations.end();)
1628 assert(j->second.get() != nullptr);
1629 if (j->second->info->rdbFile == rUri) {
1630 clear.push_back(j->second);
1631 //TODO: The below leaves data_ in an inconsistent state upon
1632 // exceptions:
1633 removeFromImplementationMap(
1634 &data_.services, j->second->info->services, j->second);
1635 removeFromImplementationMap(
1636 &data_.singletons, j->second->info->singletons,
1637 j->second);
1638 j = data_.namedImplementations.erase(j);
1639 } else {
1640 ++j;
1645 //TODO: Update the component context singleton data
1648 bool cppuhelper::ServiceManager::removeLegacyFactory(
1649 css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo,
1650 bool removeListener)
1652 assert(factoryInfo.is());
1653 std::shared_ptr< Data::Implementation > clear;
1654 css::uno::Reference< css::lang::XComponent > comp;
1656 osl::MutexGuard g(rBHelper.rMutex);
1657 Data::DynamicImplementations::iterator i(
1658 data_.dynamicImplementations.find(factoryInfo));
1659 if (i == data_.dynamicImplementations.end()) {
1660 return isDisposed();
1662 assert(i->second.get() != nullptr);
1663 clear = i->second;
1664 if (removeListener) {
1665 comp = i->second->component;
1667 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1668 removeFromImplementationMap(
1669 &data_.services, i->second->info->services, i->second);
1670 removeFromImplementationMap(
1671 &data_.singletons, i->second->info->singletons, i->second);
1672 if (!i->second->info->name.isEmpty()) {
1673 data_.namedImplementations.erase(i->second->info->name);
1675 data_.dynamicImplementations.erase(i);
1677 if (comp.is()) {
1678 removeEventListenerFromComponent(comp);
1680 return true;
1683 void cppuhelper::ServiceManager::removeImplementation(const OUString & name) {
1684 // The underlying data structures make this function somewhat inefficient,
1685 // but the assumption is that it is rarely called:
1686 std::shared_ptr< Data::Implementation > clear;
1688 osl::MutexGuard g(rBHelper.rMutex);
1689 if (isDisposed()) {
1690 return;
1692 Data::NamedImplementations::iterator i(
1693 data_.namedImplementations.find(name));
1694 if (i == data_.namedImplementations.end()) {
1695 throw css::container::NoSuchElementException(
1696 "Remove non-inserted implementation " + name,
1697 static_cast< cppu::OWeakObject * >(this));
1699 assert(i->second.get() != nullptr);
1700 clear = i->second;
1701 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1702 removeFromImplementationMap(
1703 &data_.services, i->second->info->services, i->second);
1704 removeFromImplementationMap(
1705 &data_.singletons, i->second->info->singletons, i->second);
1706 auto j = std::find_if(data_.dynamicImplementations.begin(), data_.dynamicImplementations.end(),
1707 [&i](const Data::DynamicImplementations::value_type& rEntry) { return rEntry.second == i->second; });
1708 if (j != data_.dynamicImplementations.end())
1709 data_.dynamicImplementations.erase(j);
1710 data_.namedImplementations.erase(i);
1714 std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
1715 cppuhelper::ServiceManager::findServiceImplementation(
1716 css::uno::Reference< css::uno::XComponentContext > const & context,
1717 OUString const & specifier)
1719 std::shared_ptr< Data::Implementation > impl;
1720 bool loaded;
1722 osl::MutexGuard g(rBHelper.rMutex);
1723 Data::ImplementationMap::const_iterator i(
1724 data_.services.find(specifier));
1725 if (i == data_.services.end()) {
1726 Data::NamedImplementations::const_iterator j(
1727 data_.namedImplementations.find(specifier));
1728 if (j == data_.namedImplementations.end()) {
1729 SAL_INFO("cppuhelper", "No implementation for " << specifier);
1730 return std::shared_ptr< Data::Implementation >();
1732 impl = j->second;
1733 } else {
1734 assert(!i->second.empty());
1735 SAL_INFO_IF(
1736 i->second.size() > 1, "cppuhelper",
1737 "Arbitrarily choosing " << i->second[0]->info->name
1738 << " among multiple implementations for " << i->first);
1739 impl = i->second[0];
1741 assert(impl.get() != nullptr);
1742 loaded = impl->status == Data::Implementation::STATUS_LOADED;
1744 if (!loaded) {
1745 loadImplementation(context, impl);
1747 return impl;
1750 /// Make a simpler unique name for preload / progress reporting.
1751 #ifndef DISABLE_DYNLOADING
1752 static OUString simplifyModule(const OUString &uri)
1754 sal_Int32 nIdx;
1755 OUStringBuffer edit(uri);
1756 if ((nIdx = edit.lastIndexOf('/')) > 0)
1757 edit.remove(0,nIdx+1);
1758 if ((nIdx = edit.lastIndexOf(':')) > 0)
1759 edit.remove(0,nIdx+1);
1760 if ((nIdx = edit.lastIndexOf("lo.so")) > 0)
1761 edit.truncate(nIdx);
1762 if ((nIdx = edit.lastIndexOf(".3")) > 0)
1763 edit.truncate(nIdx);
1764 if ((nIdx = edit.lastIndexOf("gcc3.so")) > 0)
1765 edit.truncate(nIdx);
1766 if ((nIdx = edit.lastIndexOf(".so")) > 0)
1767 edit.truncate(nIdx);
1768 if ((nIdx = edit.lastIndexOf("_uno")) > 0)
1769 edit.truncate(nIdx);
1770 if ((nIdx = edit.lastIndexOf(".jar")) > 0)
1771 edit.truncate(nIdx);
1772 if (edit.indexOf("lib") == 0)
1773 edit.remove(0,3);
1774 return edit.makeStringAndClear();
1776 #endif
1778 /// Used only by LibreOfficeKit when used by Online to pre-initialize
1779 void cppuhelper::ServiceManager::preloadImplementations() {
1780 #ifdef DISABLE_DYNLOADING
1781 abort();
1782 #else
1783 OUString aUri;
1784 osl::MutexGuard g(rBHelper.rMutex);
1785 css::uno::Environment aSourceEnv(css::uno::Environment::getCurrent());
1787 std::cerr << "preload:";
1788 std::vector<OUString> aReported;
1789 std::vector<OUString> aDisabled;
1790 OUStringBuffer aDisabledMsg;
1792 /// Allow external callers & testers to disable certain components
1793 const char *pDisable = getenv("UNODISABLELIBRARY");
1794 if (pDisable)
1796 OUString aDisable(pDisable, strlen(pDisable), RTL_TEXTENCODING_UTF8);
1797 for (sal_Int32 i = 0; i >= 0; )
1799 OUString tok = aDisable.getToken(0, ' ', i);
1800 tok = tok.trim();
1801 if (!tok.isEmpty())
1802 aDisabled.push_back(tok);
1806 // loop all implementations
1807 for (const auto& rEntry : data_.namedImplementations)
1809 if (rEntry.second->info->loader != "com.sun.star.loader.SharedLibrary" ||
1810 rEntry.second->status == Data::Implementation::STATUS_LOADED)
1811 continue;
1815 const OUString &aLibrary = rEntry.second->info->uri;
1817 if (aLibrary.isEmpty())
1818 continue;
1820 OUString simplified = simplifyModule(aLibrary);
1821 bool bDisabled =
1822 std::find(aDisabled.begin(), aDisabled.end(), simplified) != aDisabled.end();
1824 if (std::find(aReported.begin(), aReported.end(), aLibrary) == aReported.end())
1826 if (bDisabled)
1828 aDisabledMsg.append(simplified);
1829 aDisabledMsg.append(" ");
1831 else
1833 std::cerr << " " << simplified;
1834 std::cerr.flush();
1836 aReported.push_back(aLibrary);
1839 if (bDisabled)
1840 continue;
1842 // expand absolute URI implementation component library
1843 aUri = cppu::bootstrap_expandUri(aLibrary);
1845 catch (css::lang::IllegalArgumentException& aError)
1847 throw css::uno::DeploymentException(
1848 "Cannot expand URI" + rEntry.second->info->uri + ": " + aError.Message,
1849 static_cast< cppu::OWeakObject * >(this));
1852 // load component library
1853 osl::Module aModule(aUri, SAL_LOADMODULE_NOW | SAL_LOADMODULE_GLOBAL);
1855 if (!aModule.is())
1857 std::cerr << ":failed" << std::endl;
1858 std::cerr.flush();
1861 if (aModule.is() &&
1862 !rEntry.second->info->environment.isEmpty())
1864 OUString aSymFactory;
1865 oslGenericFunction fpFactory;
1866 css::uno::Environment aTargetEnv;
1867 css::uno::Reference<css::uno::XInterface> xFactory;
1869 if(rEntry.second->info->constructor.isEmpty())
1871 // expand full name component factory symbol
1872 if (rEntry.second->info->prefix == "direct")
1873 aSymFactory = rEntry.second->info->name.replace('.', '_') + "_" COMPONENT_GETFACTORY;
1874 else if (!rEntry.second->info->prefix.isEmpty())
1875 aSymFactory = rEntry.second->info->prefix + "_" COMPONENT_GETFACTORY;
1876 else
1877 aSymFactory = COMPONENT_GETFACTORY;
1879 // get function symbol component factory
1880 fpFactory = aModule.getFunctionSymbol(aSymFactory);
1881 if (fpFactory == nullptr)
1883 throw css::loader::CannotActivateFactoryException(
1884 ("no factory symbol \"" + aSymFactory + "\" in component library :" + aUri),
1885 css::uno::Reference<css::uno::XInterface>());
1888 aTargetEnv = cppuhelper::detail::getEnvironment(rEntry.second->info->environment, rEntry.second->info->name);
1889 component_getFactoryFunc fpComponentFactory = reinterpret_cast<component_getFactoryFunc>(fpFactory);
1891 if (aSourceEnv.get() == aTargetEnv.get())
1893 // invoke function component factory
1894 OString aImpl(OUStringToOString(rEntry.second->info->name, RTL_TEXTENCODING_ASCII_US));
1895 xFactory.set(css::uno::Reference<css::uno::XInterface>(static_cast<css::uno::XInterface *>(
1896 (*fpComponentFactory)(aImpl.getStr(), this, nullptr)), SAL_NO_ACQUIRE));
1899 else
1901 // get function symbol component factory
1902 aTargetEnv = cppuhelper::detail::getEnvironment(rEntry.second->info->environment, rEntry.second->info->name);
1903 fpFactory = (aSourceEnv.get() == aTargetEnv.get()) ?
1904 aModule.getFunctionSymbol(rEntry.second->info->constructor) : nullptr;
1907 css::uno::Reference<css::lang::XSingleComponentFactory> xSCFactory;
1908 css::uno::Reference<css::lang::XSingleServiceFactory> xSSFactory;
1910 // query interface XSingleComponentFactory or XSingleServiceFactory
1911 if (xFactory.is())
1913 xSCFactory.set(xFactory, css::uno::UNO_QUERY);
1914 if (!xSCFactory.is())
1916 xSSFactory.set(xFactory, css::uno::UNO_QUERY);
1917 if (!xSSFactory.is())
1918 throw css::uno::DeploymentException(
1919 ("Implementation " + rEntry.second->info->name
1920 + " does not provide a constructor or factory"),
1921 static_cast< cppu::OWeakObject * >(this));
1925 if (!rEntry.second->info->constructor.isEmpty() && fpFactory)
1926 rEntry.second->constructor = WrapperConstructorFn(reinterpret_cast<ImplementationConstructorFn *>(fpFactory));
1928 rEntry.second->factory1 = xSCFactory;
1929 rEntry.second->factory2 = xSSFactory;
1930 rEntry.second->status = Data::Implementation::STATUS_LOADED;
1934 // Some libraries use other (non-UNO) libraries requiring preinit
1935 oslGenericFunction fpPreload = aModule.getFunctionSymbol( "lok_preload_hook" );
1936 if (fpPreload)
1938 static std::vector<oslGenericFunction> aPreloaded;
1939 if (std::find(aPreloaded.begin(), aPreloaded.end(), fpPreload) == aPreloaded.end())
1941 aPreloaded.push_back(fpPreload);
1942 fpPreload();
1946 // leak aModule
1947 aModule.release();
1949 std::cerr << std::endl;
1951 if (aDisabledMsg.getLength() > 0)
1953 OUString aMsg = aDisabledMsg.makeStringAndClear();
1954 std::cerr << "Disabled: " << aMsg << "\n";
1956 std::cerr.flush();
1958 // Various rather important uno mappings.
1959 static struct {
1960 const char *mpFrom;
1961 const char *mpTo;
1962 const char *mpPurpose;
1963 } const aMappingLoad[] = {
1964 { "gcc3", "uno", "" },
1965 { "uno", "gcc3", "" },
1968 static std::vector<css::uno::Mapping> maMaps;
1969 for (auto &it : aMappingLoad)
1971 maMaps.push_back(css::uno::Mapping(
1972 OUString::createFromAscii(it.mpFrom),
1973 OUString::createFromAscii(it.mpTo),
1974 OUString::createFromAscii(it.mpPurpose)));
1976 #endif
1979 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */