cid#1607171 Data race condition
[LibreOffice.git] / stoc / source / implementationregistration / implreg.cxx
blob993574928a8f623b3e4a8dc51713f3de48ec105a
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <string.h>
21 #include <string_view>
22 #include <vector>
24 #include <cppuhelper/exc_hlp.hxx>
25 #include <cppuhelper/weak.hxx>
26 #include <cppuhelper/implbase.hxx>
27 #include <cppuhelper/supportsservice.hxx>
28 #include <comphelper/sequence.hxx>
29 #include <rtl/ustring.hxx>
31 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
32 #include <com/sun/star/lang/XServiceInfo.hpp>
33 #include <com/sun/star/lang/XInitialization.hpp>
34 #include <com/sun/star/loader/XImplementationLoader.hpp>
35 #include <com/sun/star/registry/XImplementationRegistration2.hpp>
36 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
37 #include <com/sun/star/reflection/XServiceTypeDescription.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/uno/RuntimeException.hpp>
40 #include <com/sun/star/uno/XComponentContext.hpp>
42 #include "mergekeys.hxx"
44 #if defined(_WIN32)
45 #include <io.h>
46 #endif
49 using namespace com::sun::star;
50 using namespace css::uno;
51 using namespace css::loader;
52 using namespace css::beans;
53 using namespace css::lang;
54 using namespace css::registry;
55 using namespace cppu;
57 namespace {
59 constexpr OUString slash_UNO_slash_REGISTRY_LINKS
60 = u"/UNO/REGISTRY_LINKS"_ustr;
61 constexpr OUString slash_IMPLEMENTATIONS
62 = u"/IMPLEMENTATIONS"_ustr;
63 constexpr OUString slash_UNO
64 = u"/UNO"_ustr;
65 constexpr OUString slash_UNO_slash_SERVICES
66 = u"/UNO/SERVICES"_ustr;
67 constexpr OUString slash_UNO_slash_SINGLETONS
68 = u"/UNO/SINGLETONS"_ustr;
69 constexpr OUString slash_SERVICES
70 = u"/SERVICES/"_ustr;
71 constexpr OUString slash_UNO_slash_LOCATION
72 = u"/UNO/LOCATION"_ustr;
73 constexpr OUString slash_UNO_slash_ACTIVATOR
74 = u"/UNO/ACTIVATOR"_ustr;
75 constexpr OUString colon_old
76 = u":old"_ustr;
77 constexpr OUStringLiteral com_sun_star_registry_SimpleRegistry
78 = u"com.sun.star.registry.SimpleRegistry";
79 constexpr OUString Registry
80 = u"Registry"_ustr;
82 // static deleteAllLinkReferences()
84 void deleteAllLinkReferences(const Reference < XSimpleRegistry >& xReg,
85 const Reference < XRegistryKey >& xSource)
86 // throw ( InvalidRegistryException, RuntimeException )
88 Reference < XRegistryKey > xKey = xSource->openKey(
89 slash_UNO_slash_REGISTRY_LINKS );
91 if (!(xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST)))
92 return;
94 const Sequence<OUString> linkNames = xKey->getAsciiListValue();
96 if (!linkNames.hasElements())
97 return;
99 OUString aLinkName;
100 OUString aLinkParent;
101 Reference < XRegistryKey > xLinkParent;
102 const sal_Unicode* pTmpName = nullptr;
103 const sal_Unicode* pShortName = nullptr;
104 sal_Int32 sEnd = 0;
106 for (const OUString& rLinkName : linkNames)
108 aLinkName = rLinkName;
110 pTmpName = aLinkName.getStr();
112 if (pTmpName[0] != L'/')
113 continue;
115 sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' );
116 if ( nIndex == -1 )
117 pShortName = nullptr;
118 else
119 pShortName = pTmpName+nIndex;
121 while (pShortName && pShortName[1] == L'%')
123 nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' );
124 if ( nIndex == -1 )
125 pShortName = nullptr;
126 else
127 pShortName += nIndex+2;
130 if (pShortName)
132 aLinkName = aLinkName.copy(0, pShortName - pTmpName);
135 xReg->getRootKey()->deleteLink(aLinkName);
137 sEnd = aLinkName.lastIndexOf( '/' );
139 aLinkParent = aLinkName.copy(0, sEnd);
141 while(!aLinkParent.isEmpty())
143 xLinkParent = xReg->getRootKey()->openKey(aLinkParent);
145 if (xLinkParent.is() && !xLinkParent->getKeyNames().hasElements())
147 aLinkName = aLinkParent;
149 xReg->getRootKey()->deleteKey(aLinkParent);
151 sEnd = aLinkName.lastIndexOf( '/' );
153 aLinkParent = aLinkName.copy(0, sEnd);
155 else
157 break;
164 // static prepareLink
166 void prepareLink( const Reference < XSimpleRegistry > & xDest,
167 const Reference < XRegistryKey > & xSource,
168 const OUString& link)
169 // throw ( InvalidRegistryException, RuntimeException )
171 OUString linkRefName = xSource->getKeyName();
172 OUString linkName(link);
173 bool isRelativ = false;
175 const sal_Unicode* pTmpName = link.getStr();
176 const sal_Unicode* pShortName;
177 sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' );
178 if ( nIndex == -1 )
179 pShortName = nullptr;
180 else
181 pShortName = pTmpName+nIndex;
183 if (pTmpName[0] != L'/')
184 isRelativ = true;
186 while (pShortName && pShortName[1] == L'%')
188 nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' );
189 if ( nIndex == -1 )
190 pShortName = nullptr;
191 else
192 pShortName += nIndex+2;
195 if (pShortName)
197 linkRefName += link.subView(pShortName - pTmpName + 1);
198 linkName = link.copy(0, pShortName - pTmpName);
201 if (isRelativ)
202 xSource->createLink(linkName, linkRefName);
203 else
204 xDest->getRootKey()->createLink(linkName, linkRefName);
208 // static searchImplForLink
210 OUString searchImplForLink(
211 const Reference < XRegistryKey > & xRootKey,
212 std::u16string_view linkName,
213 std::u16string_view implName )
214 // throw ( InvalidRegistryException, RuntimeException )
216 Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS );
217 if (xKey.is())
219 const Sequence< Reference < XRegistryKey > > subKeys( xKey->openKeys() );
220 OUString key_name( slash_UNO + linkName );
222 for (const Reference < XRegistryKey >& xImplKey : subKeys)
226 if (xImplKey->getKeyType( key_name ) == RegistryKeyType_LINK)
228 OUString oldImplName = xImplKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/"));
229 if (implName != oldImplName)
231 return oldImplName;
235 catch(InvalidRegistryException&)
241 return OUString();
245 // static searchLinkTargetForImpl
247 OUString searchLinkTargetForImpl(const Reference < XRegistryKey >& xRootKey,
248 std::u16string_view linkName,
249 const OUString& implName)
251 Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS );
253 if (xKey.is())
255 const Sequence< Reference < XRegistryKey > > subKeys = xKey->openKeys();
257 OUString qualifiedLinkName( slash_UNO + linkName );
259 auto pSubKey = std::find_if(subKeys.begin(), subKeys.end(),
260 [&implName, &qualifiedLinkName](const Reference<XRegistryKey>& rSubKey) {
261 OUString tmpImplName = rSubKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/"));
262 return tmpImplName == implName
263 && rSubKey->getKeyType( qualifiedLinkName ) == RegistryKeyType_LINK;
265 if (pSubKey != subKeys.end())
266 return (*pSubKey)->getLinkTarget( qualifiedLinkName );
269 return OUString();
273 // static createUniqueSubEntry
275 void createUniqueSubEntry(const Reference < XRegistryKey > & xSuperKey,
276 const OUString& value)
277 // throw ( InvalidRegistryException, RuntimeException )
279 if (!xSuperKey.is())
280 return;
282 if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST)
284 const Sequence<OUString> implEntries = xSuperKey->getAsciiListValue();
285 sal_Int32 length = implEntries.getLength();
287 bool bReady = comphelper::findValue(implEntries, value) != -1;
289 if (bReady)
291 Sequence<OUString> implEntriesNew(length);
292 auto it = implEntriesNew.getArray();
293 *it = value;
295 std::copy_if(implEntries.begin(), implEntries.end(), std::next(it),
296 [&value](const OUString& rEntry) { return rEntry != value; });
297 xSuperKey->setAsciiListValue(implEntriesNew);
298 } else
300 Sequence<OUString> implEntriesNew(length+1);
301 auto it = implEntriesNew.getArray();
302 *it = value;
304 std::copy(implEntries.begin(), implEntries.end(), std::next(it));
305 xSuperKey->setAsciiListValue(implEntriesNew);
307 } else
309 Sequence<OUString> implEntriesNew { value };
311 xSuperKey->setAsciiListValue(implEntriesNew);
316 // static deleteSubEntry
318 bool deleteSubEntry(const Reference < XRegistryKey >& xSuperKey, const OUString& value)
319 // throw ( InvalidRegistryException, RuntimeException )
321 if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST)
323 const Sequence<OUString> implEntries = xSuperKey->getAsciiListValue();
324 sal_Int32 length = implEntries.getLength();
325 sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), value));
326 bool hasNoImplementations = false;
328 if (equals == length)
330 hasNoImplementations = true;
331 } else
333 Sequence<OUString> implEntriesNew(length - equals);
335 std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.getArray(),
336 [&value](const OUString& rEntry) { return rEntry != value; });
337 xSuperKey->setAsciiListValue(implEntriesNew);
340 if (hasNoImplementations)
342 return true;
345 return false;
349 // static prepareUserLink
351 void prepareUserLink(const Reference < XSimpleRegistry >& xDest,
352 const OUString& linkName,
353 const OUString& linkTarget,
354 std::u16string_view implName)
356 Reference < XRegistryKey > xRootKey = xDest->getRootKey();
358 if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK)
360 OUString oldImplName(searchImplForLink(xRootKey, linkName, implName));
362 if (!oldImplName.isEmpty())
364 createUniqueSubEntry(xDest->getRootKey()->createKey(
365 linkName + colon_old ), oldImplName);
369 if (xRootKey->isValid())
370 xRootKey->createLink(linkName, linkTarget);
374 // static deleteUserLink
376 void deletePathIfPossible(const Reference < XRegistryKey >& xRootKey,
377 const OUString& path)
381 Sequence<OUString> keyNames(xRootKey->openKey(path)->getKeyNames());
383 if (!keyNames.hasElements() &&
384 xRootKey->openKey(path)->getValueType() == RegistryValueType_NOT_DEFINED)
386 xRootKey->deleteKey(path);
388 OUString newPath = path.copy(0, path.lastIndexOf('/'));
390 if (newPath.getLength() > 1)
391 deletePathIfPossible(xRootKey, newPath);
394 catch(InvalidRegistryException&)
400 // static deleteUserLink
402 void deleteUserLink(const Reference < XRegistryKey >& xRootKey,
403 const OUString& linkName,
404 std::u16string_view linkTarget,
405 const OUString& implName)
406 // throw ( InvalidRegistryException, RuntimeException )
408 bool bClean = false;
410 if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK)
412 OUString tmpTarget = xRootKey->getLinkTarget(linkName);
414 if (tmpTarget == linkTarget)
416 xRootKey->deleteLink(linkName);
420 Reference < XRegistryKey > xOldKey = xRootKey->openKey(
421 linkName + colon_old );
422 if (xOldKey.is())
424 if (xOldKey->getValueType() == RegistryValueType_ASCIILIST)
426 const Sequence<OUString> implEntries = xOldKey->getAsciiListValue();
427 sal_Int32 length = implEntries.getLength();
428 sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
429 bool hasNoImplementations = false;
431 if (equals == length)
433 hasNoImplementations = true;
434 } else
436 OUString oldImpl;
438 if (length > equals + 1)
440 Sequence<OUString> implEntriesNew(length - equals - 1);
441 auto pNewArray = implEntriesNew.getArray();
443 sal_Int32 j = 0;
444 bool first = true;
445 for (sal_Int32 i = 0; i < length; i++)
447 if (implEntries[i] != implName)
449 if (first)
451 oldImpl = implEntries[i];
452 first = false;
453 } else
455 pNewArray[j++] = implEntries[i];
460 xOldKey->setAsciiListValue(implEntriesNew);
461 } else
463 oldImpl = implEntries[0];
464 OUString path(xOldKey->getKeyName());
465 xOldKey->closeKey();
466 xRootKey->deleteKey(path);
469 OUString oldTarget = searchLinkTargetForImpl(xRootKey, linkName, oldImpl);
470 if (!oldTarget.isEmpty())
472 xRootKey->createLink(linkName, oldTarget);
476 if (hasNoImplementations)
478 bClean = true;
479 OUString path(xOldKey->getKeyName());
480 xOldKey->closeKey();
481 xRootKey->deleteKey(path);
484 } else
486 bClean = true;
489 if (bClean)
491 OUString path = linkName.copy(0, linkName.lastIndexOf('/'));
492 deletePathIfPossible(xRootKey, path);
497 // static prepareUserKeys
499 void prepareUserKeys(const Reference < XSimpleRegistry >& xDest,
500 const Reference < XRegistryKey >& xUnoKey,
501 const Reference < XRegistryKey >& xKey,
502 const OUString& implName,
503 bool bRegister)
505 bool hasSubKeys = false;
507 Sequence<OUString> keyNames = xKey->getKeyNames();
509 OUString relativKey;
510 if (keyNames.hasElements())
511 relativKey = keyNames[0].copy(xKey->getKeyName().getLength()+1);
513 if (keyNames.getLength() == 1 &&
514 xKey->getKeyType(relativKey) == RegistryKeyType_LINK)
516 hasSubKeys = true;
518 OUString linkTarget = xKey->getLinkTarget(relativKey);
519 OUString linkName(
520 OUString::Concat(xKey->getKeyName().subView(xUnoKey->getKeyName().getLength()))
521 + "/" + relativKey);
523 if (bRegister)
525 prepareUserLink(xDest, linkName, linkTarget, implName);
526 } else
528 deleteUserLink(xDest->getRootKey(), linkName, linkTarget, implName);
530 } else
532 const Sequence< Reference < XRegistryKey> > subKeys = xKey->openKeys();
534 if (subKeys.hasElements())
536 hasSubKeys = true;
538 for (const Reference < XRegistryKey > & rSubKey : subKeys)
540 prepareUserKeys(xDest, xUnoKey, rSubKey, implName, bRegister);
545 if (hasSubKeys)
546 return;
548 OUString keyName(xKey->getKeyName().copy(xUnoKey->getKeyName().getLength()));
550 Reference < XRegistryKey > xRootKey = xDest->getRootKey();
551 if (bRegister)
553 createUniqueSubEntry(xRootKey->createKey(keyName), implName);
555 else
557 Reference< XRegistryKey > rKey = xRootKey->openKey(keyName);
558 if( rKey.is() )
560 deleteSubEntry(rKey, implName);
561 xRootKey->deleteKey(keyName);
564 OUString path = keyName.copy(0, keyName.lastIndexOf('/'));
565 if( !path.isEmpty() )
567 deletePathIfPossible(xRootKey, path);
573 // static deleteAllImplementations
575 void deleteAllImplementations( const Reference < XSimpleRegistry >& xReg,
576 const Reference < XRegistryKey >& xSource,
577 std::u16string_view locationUrl,
578 std::vector<OUString> & implNames)
579 // throw (InvalidRegistryException, RuntimeException)
581 Sequence < Reference < XRegistryKey > > subKeys = xSource->openKeys();
583 if (subKeys.hasElements())
585 bool hasLocationUrl = false;
587 for (const Reference<XRegistryKey>& xImplKey : subKeys)
589 Reference < XRegistryKey > xKey = xImplKey->openKey(
590 slash_UNO_slash_LOCATION );
592 if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCII))
594 if (xKey->getAsciiValue() == locationUrl)
596 hasLocationUrl = true;
598 OUString implName(xImplKey->getKeyName().copy(1));
599 sal_Int32 firstDot = implName.indexOf('/');
601 if (firstDot >= 0)
602 implName = implName.copy(firstDot + 1);
604 implNames.push_back(implName);
606 deleteAllLinkReferences(xReg, xImplKey);
608 xKey = xImplKey->openKey( slash_UNO );
609 if (xKey.is())
611 const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys();
613 for (const Reference < XRegistryKey > & rSubKey2 : subKeys2)
615 if (rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_SERVICES ) &&
616 rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) &&
617 rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_ACTIVATOR ) &&
618 rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ) &&
619 rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_LOCATION) )
621 prepareUserKeys(xReg, xKey, rSubKey2, implName, false);
628 if (hasLocationUrl)
630 hasLocationUrl = false;
631 OUString path(xImplKey->getKeyName());
632 xImplKey->closeKey();
633 xReg->getRootKey()->deleteKey(path);
637 subKeys = xSource->openKeys();
638 if (!subKeys.hasElements())
640 OUString path(xSource->getKeyName());
641 xSource->closeKey();
642 xReg->getRootKey()->deleteKey(path);
644 } else
646 OUString path(xSource->getKeyName());
647 xSource->closeKey();
648 xReg->getRootKey()->deleteKey(path);
653 void delete_all_singleton_entries(
654 Reference < registry::XRegistryKey > const & xSingletons_section,
655 ::std::vector< OUString > const & impl_names )
656 // throw (InvalidRegistryException, RuntimeException)
658 Sequence< Reference< registry::XRegistryKey > > singletons( xSingletons_section->openKeys() );
659 for ( sal_Int32 nPos = singletons.getLength(); nPos--; )
661 Reference<registry::XRegistryKey> const& xSingleton = singletons[nPos];
662 Reference< registry::XRegistryKey > xRegisteredImplNames(
663 xSingleton->openKey( u"REGISTERED_BY"_ustr ) );
664 if (xRegisteredImplNames.is() && xRegisteredImplNames->isValid())
666 Sequence< OUString > registered_implnames;
669 registered_implnames = xRegisteredImplNames->getAsciiListValue();
671 catch (registry::InvalidValueException &)
674 auto aNonConstRange = asNonConstRange(registered_implnames);
675 sal_Int32 nOrigRegLength = registered_implnames.getLength();
676 sal_Int32 nNewLength = nOrigRegLength;
677 for ( sal_Int32 n = nOrigRegLength; n--; )
679 OUString const & registered_implname = registered_implnames[ n ];
681 for (auto const& impl_name : impl_names)
683 if (impl_name == registered_implname)
685 aNonConstRange[ n ] = registered_implnames[ nNewLength -1 ];
686 --nNewLength;
691 if (nNewLength != nOrigRegLength)
693 if (0 == nNewLength)
695 // remove whole entry
696 xRegisteredImplNames->closeKey();
697 xSingleton->deleteKey( u"REGISTERED_BY"_ustr );
698 // registry key cannot provide its relative name, only absolute :(
699 OUString abs( xSingleton->getKeyName() );
700 xSingletons_section->deleteKey( abs.copy( abs.lastIndexOf( '/' ) +1 ) );
702 else
704 registered_implnames.realloc( nNewLength );
705 xRegisteredImplNames->setAsciiListValue( registered_implnames );
713 // static deleteAllServiceEntries
715 void deleteAllServiceEntries( const Reference < XSimpleRegistry >& xReg,
716 const Reference < XRegistryKey >& xSource,
717 const OUString& implName)
718 // throw ( InvalidRegistryException, RuntimeException )
720 Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
722 if (subKeys.hasElements())
724 bool hasNoImplementations = false;
726 for (const Reference<XRegistryKey>& xServiceKey : subKeys)
728 if (xServiceKey->getValueType() == RegistryValueType_ASCIILIST)
730 const Sequence<OUString> implEntries = xServiceKey->getAsciiListValue();
731 sal_Int32 length = implEntries.getLength();
732 sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
734 if (equals == length)
736 hasNoImplementations = true;
737 } else
739 if (equals > 0)
741 Sequence<OUString> implEntriesNew(length-equals);
743 std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.getArray(),
744 [&implName](const OUString& rEntry) { return rEntry != implName; });
746 xServiceKey->setAsciiListValue(implEntriesNew);
751 if (hasNoImplementations)
753 hasNoImplementations = false;
754 OUString path(xServiceKey->getKeyName());
755 xServiceKey->closeKey();
756 xReg->getRootKey()->deleteKey(path);
760 subKeys = xSource->openKeys();
761 if (!subKeys.hasElements())
763 OUString path(xSource->getKeyName());
764 xSource->closeKey();
765 xReg->getRootKey()->deleteKey(path);
767 } else
769 OUString path(xSource->getKeyName());
770 xSource->closeKey();
771 xReg->getRootKey()->deleteKey(path);
776 bool is_supported_service(
777 OUString const & service_name,
778 Reference< reflection::XServiceTypeDescription > const & xService_td )
780 if (xService_td->getName() == service_name)
781 return true;
782 const Sequence< Reference< reflection::XServiceTypeDescription > > seq(
783 xService_td->getMandatoryServices() );
784 return std::any_of(seq.begin(), seq.end(), [&service_name](const auto& rService) {
785 return is_supported_service( service_name, rService ); });
789 void insert_singletons(
790 Reference< registry::XSimpleRegistry > const & xDest,
791 Reference< registry::XRegistryKey > const & xImplKey,
792 Reference< XComponentContext > const & xContext )
793 // throw( registry::InvalidRegistryException, registry::CannotRegisterImplementationException, RuntimeException )
795 // singletons
796 Reference< registry::XRegistryKey > xKey( xImplKey->openKey( u"UNO/SINGLETONS"_ustr ) );
797 if (!(xKey.is() && xKey->isValid()))
798 return;
800 OUString implname( xImplKey->getKeyName().copy( sizeof ("/IMPLEMENTATIONS/") -1 ) );
801 // singleton entries
802 Sequence< Reference< registry::XRegistryKey > > xSingletons_section( xKey->openKeys() );
803 for ( sal_Int32 nPos = xSingletons_section.getLength(); nPos--; )
805 Reference<registry::XRegistryKey> const& xSingleton = xSingletons_section[nPos];
806 OUString singleton_name(
807 xSingleton->getKeyName().copy(
808 implname.getLength() + sizeof ("/IMPLEMENTATIONS//UNO/SINGLETONS/") -1 ) );
809 OUString service_name( xSingleton->getStringValue() );
811 OUString keyname( "/SINGLETONS/" + singleton_name );
812 Reference< registry::XRegistryKey > xKey2( xDest->getRootKey()->openKey( keyname ) );
813 if (xKey2.is() && xKey2->isValid())
817 OUString existing_name( xKey2->getStringValue() );
818 if ( existing_name != service_name )
820 Reference< container::XHierarchicalNameAccess > xTDMgr;
821 OUString the_tdmgr =
822 u"/singletons/com.sun.star.reflection.theTypeDescriptionManager"_ustr;
823 xContext->getValueByName( the_tdmgr ) >>= xTDMgr;
824 if (! xTDMgr.is())
826 throw RuntimeException( "cannot get singleton " + the_tdmgr );
830 Reference< reflection::XServiceTypeDescription > xExistingService_td;
831 xTDMgr->getByHierarchicalName( existing_name ) >>= xExistingService_td;
832 if (! xExistingService_td.is())
834 throw RuntimeException( "cannot get service type description: " + existing_name );
837 // everything's fine if existing service entry supports the one
838 // to be registered
839 if (! is_supported_service( service_name, xExistingService_td ))
841 throw registry::CannotRegisterImplementationException(
842 "existing singleton service (" + singleton_name + "=" + existing_name + ") "
843 " does not support given one: " + service_name);
846 catch (const container::NoSuchElementException & exc)
848 css::uno::Any anyEx = cppu::getCaughtException();
849 throw css::lang::WrappedTargetRuntimeException(
850 "cannot get service type description: " + exc.Message,
851 nullptr, anyEx );
855 catch (registry::InvalidValueException &)
857 // repair
858 xKey2->setStringValue( service_name );
861 else
863 // insert singleton entry
864 xKey2 = xDest->getRootKey()->createKey( keyname );
865 xKey2->setStringValue( service_name );
868 Reference< registry::XRegistryKey > xRegisteredImplNames(
869 xKey2->openKey( u"REGISTERED_BY"_ustr ) );
870 if (!xRegisteredImplNames.is() || !xRegisteredImplNames->isValid())
872 // create
873 xRegisteredImplNames = xKey2->createKey( u"REGISTERED_BY"_ustr );
876 Sequence< OUString > implnames;
879 implnames = xRegisteredImplNames->getAsciiListValue();
881 catch (registry::InvalidValueException &)
884 // check implname is already in
885 if (comphelper::findValue(implnames, implname) == -1)
887 // append and write back
888 implnames.realloc( implnames.getLength() +1 );
889 implnames.getArray()[ implnames.getLength() -1 ] = implname;
890 xRegisteredImplNames->setAsciiListValue( implnames );
896 // static prepareRegistry
898 void prepareRegistry(
899 const Reference < XSimpleRegistry >& xDest,
900 const Reference < XRegistryKey >& xSource,
901 const OUString& implementationLoaderUrl,
902 const OUString& locationUrl,
903 Reference< XComponentContext > const & xContext )
904 // throw ( InvalidRegistryException, CannotRegisterImplementationException, RuntimeException )
906 const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
908 if (!subKeys.hasElements())
910 throw InvalidRegistryException(
911 u"prepareRegistry(): source registry is empty"_ustr );
914 for (const Reference < XRegistryKey >& xImplKey : subKeys)
916 Reference < XRegistryKey > xKey = xImplKey->openKey(
917 slash_UNO_slash_SERVICES );
919 if (xKey.is())
921 // update entries in SERVICES section
922 const Sequence< Reference < XRegistryKey > > serviceKeys = xKey->openKeys();
924 OUString implName = xImplKey->getKeyName().copy(1);
925 sal_Int32 firstDot = implName.indexOf('/');
927 if (firstDot >= 0)
928 implName = implName.copy(firstDot + 1);
930 sal_Int32 offset = xKey->getKeyName().getLength() + 1;
932 for (const Reference < XRegistryKey >& rServiceKey : serviceKeys)
934 OUString serviceName = rServiceKey->getKeyName().copy(offset);
936 createUniqueSubEntry(
937 xDest->getRootKey()->createKey(
938 slash_SERVICES + serviceName ),
939 implName);
942 xKey = xImplKey->openKey( slash_UNO );
943 if (xKey.is())
945 const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys();
947 for (const Reference < XRegistryKey >& rSubKey2 : subKeys2)
949 if (rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_SERVICES) &&
950 rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) &&
951 rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ))
953 prepareUserKeys(xDest, xKey, rSubKey2, implName, true);
959 // update LOCATION entry
960 xKey = xImplKey->createKey( slash_UNO_slash_LOCATION );
962 if (xKey.is())
964 xKey->setAsciiValue(locationUrl);
967 // update ACTIVATOR entry
968 xKey = xImplKey->createKey( slash_UNO_slash_ACTIVATOR );
970 if (xKey.is())
972 xKey->setAsciiValue(implementationLoaderUrl);
975 xKey = xImplKey->openKey( slash_UNO_slash_SERVICES );
977 if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST))
979 // update link entries in REGISTRY_LINKS section
980 const Sequence<OUString> linkNames = xKey->getAsciiListValue();
982 for (const OUString& rLinkName : linkNames)
984 prepareLink(xDest, xImplKey, rLinkName);
988 insert_singletons( xDest, xImplKey, xContext );
993 void findImplementations( const Reference < XRegistryKey > & xSource,
994 std::vector<OUString>& implNames)
996 bool isImplKey = false;
1000 Reference < XRegistryKey > xKey = xSource->openKey(
1001 slash_UNO_slash_SERVICES );
1003 if (xKey.is() && xKey->getKeyNames().hasElements())
1005 isImplKey = true;
1007 OUString implName = xSource->getKeyName().copy(1).replace('/', '.');
1008 sal_Int32 firstDot = implName.indexOf('.');
1010 if (firstDot >= 0)
1011 implName = implName.copy(firstDot + 1);
1013 implNames.push_back(implName);
1016 catch(InvalidRegistryException&)
1020 if (isImplKey) return;
1024 const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
1026 for (const Reference < XRegistryKey >& rSubKey : subKeys)
1028 findImplementations(rSubKey, implNames);
1031 catch(InvalidRegistryException&)
1037 class ImplementationRegistration
1038 : public WeakImplHelper< XImplementationRegistration2, XServiceInfo, XInitialization >
1040 public:
1041 explicit ImplementationRegistration( const Reference < XComponentContext > & rSMgr );
1043 // XServiceInfo
1044 OUString SAL_CALL getImplementationName() override;
1045 sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
1046 Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
1048 // XImplementationRegistration
1049 virtual void SAL_CALL registerImplementation(
1050 const OUString& implementationLoader,
1051 const OUString& location,
1052 const Reference < XSimpleRegistry > & xReg) override;
1054 virtual sal_Bool SAL_CALL revokeImplementation(
1055 const OUString& location,
1056 const Reference < XSimpleRegistry >& xReg) override;
1058 virtual Sequence< OUString > SAL_CALL getImplementations(
1059 const OUString& implementationLoader,
1060 const OUString& location) override;
1061 virtual Sequence< OUString > SAL_CALL checkInstantiation(
1062 const OUString& implementationName) override;
1064 // XImplementationRegistration2
1065 virtual void SAL_CALL registerImplementationWithLocation(
1066 const OUString& implementationLoader,
1067 const OUString& location,
1068 const OUString& registeredLocation,
1069 const Reference < XSimpleRegistry > & xReg) override;
1071 // XInitialization
1072 virtual void SAL_CALL initialize(
1073 const css::uno::Sequence< css::uno::Any >& aArguments ) override;
1075 private: // helper methods
1076 void prepareRegister(
1077 const OUString& implementationLoader,
1078 const OUString& location,
1079 const OUString& registeredLocation,
1080 const Reference < XSimpleRegistry > & xReg);
1081 // throw( CannotRegisterImplementationException, RuntimeException )
1083 static void doRegister( const Reference < XMultiComponentFactory >& xSMgr,
1084 const Reference < XComponentContext > &xCtx,
1085 const Reference < XImplementationLoader >& xAct,
1086 const Reference < XSimpleRegistry >& xDest,
1087 const OUString& implementationLoaderUrl,
1088 const OUString& locationUrl,
1089 const OUString& registeredLocationUrl);
1090 /* throw ( InvalidRegistryException,
1091 MergeConflictException,
1092 CannotRegisterImplementationException, RuntimeException ) */
1094 static void doRevoke( const Reference < XSimpleRegistry >& xDest,
1095 std::u16string_view locationUrl );
1096 // throw( InvalidRegistryException, RuntimeException )
1097 Reference< XSimpleRegistry > getRegistryFromServiceManager() const;
1099 static Reference< XSimpleRegistry > createTemporarySimpleRegistry(
1100 const Reference< XMultiComponentFactory > &rSMgr,
1101 const Reference < XComponentContext > & rCtx );
1103 private: // members
1104 Reference < XMultiComponentFactory > m_xSMgr;
1105 Reference < XComponentContext > m_xCtx;
1109 // ImplementationRegistration()
1111 ImplementationRegistration::ImplementationRegistration( const Reference < XComponentContext > & xCtx )
1112 : m_xSMgr( xCtx->getServiceManager() )
1113 , m_xCtx( xCtx )
1116 // XServiceInfo
1117 OUString ImplementationRegistration::getImplementationName()
1119 return u"com.sun.star.comp.stoc.ImplementationRegistration"_ustr;
1122 // XServiceInfo
1123 sal_Bool ImplementationRegistration::supportsService(const OUString& ServiceName)
1125 return cppu::supportsService(this, ServiceName);
1128 // XServiceInfo
1129 Sequence< OUString > ImplementationRegistration::getSupportedServiceNames()
1131 return { u"com.sun.star.registry.ImplementationRegistration"_ustr };
1134 Reference< XSimpleRegistry > ImplementationRegistration::getRegistryFromServiceManager() const
1136 Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY );
1137 Reference < XSimpleRegistry > xRegistry;
1139 if( xPropSet.is() ) {
1141 try { // the implementation does not support XIntrospectionAccess !
1143 Any aAny = xPropSet->getPropertyValue( Registry );
1145 if( aAny.getValueTypeClass() == TypeClass_INTERFACE ) {
1146 aAny >>= xRegistry;
1149 catch( UnknownPropertyException & ) {
1150 // empty reference is error signal !
1154 return xRegistry;
1158 // XInitialization
1160 void ImplementationRegistration::initialize(
1161 const css::uno::Sequence< css::uno::Any >& aArgs )
1164 if( aArgs.getLength() != 4 ) {
1165 throw IllegalArgumentException(
1166 "ImplementationRegistration::initialize() expects 4 parameters, got " + OUString::number( aArgs.getLength() ),
1167 Reference<XInterface > (), 0 );
1170 Reference< XImplementationLoader > rLoader;
1171 OUString loaderServiceName;
1172 OUString locationUrl;
1173 Reference< XSimpleRegistry > rReg;
1175 // 1st argument : An instance of an implementation loader
1176 if( aArgs[0].getValueTypeClass() == TypeClass_INTERFACE ) {
1177 aArgs[0] >>= rLoader;
1179 if( !rLoader.is()) {
1180 throw IllegalArgumentException(
1181 "ImplementationRegistration::initialize() invalid first parameter,"
1182 "expected " + cppu::UnoType<decltype(rLoader)>::get().getTypeName() +
1183 ", got " + aArgs[0].getValueTypeName(),
1184 Reference< XInterface > (), 0 );
1187 // 2nd argument : The service name of the loader. This name is written into the registry
1188 if( aArgs[1].getValueTypeClass() == TypeClass_STRING ) {
1189 aArgs[1] >>= loaderServiceName;
1191 if( loaderServiceName.isEmpty() ) {
1192 throw IllegalArgumentException(
1193 "ImplementationRegistration::initialize() invalid second parameter,"
1194 "expected string, got " + aArgs[1].getValueTypeName(),
1195 Reference< XInterface > (), 0 );
1198 // 3rd argument : The file name of the dll, that contains the loader
1199 if( aArgs[2].getValueTypeClass() == TypeClass_STRING ) {
1200 aArgs[2] >>= locationUrl;
1202 if( locationUrl.isEmpty() ) {
1203 throw IllegalArgumentException(
1204 "ImplementationRegistration::initialize() invalid third parameter,"
1205 "expected string, got " + aArgs[2].getValueTypeName(),
1206 Reference< XInterface > (), 0 );
1209 // 4th argument : The registry, the service should be written to
1210 if( aArgs[3].getValueTypeClass() == TypeClass_INTERFACE ) {
1211 aArgs[3] >>= rReg;
1214 if( !rReg.is() ) {
1215 rReg = getRegistryFromServiceManager();
1216 if( !rReg.is() ) {
1217 throw IllegalArgumentException(
1218 "ImplementationRegistration::initialize() invalid fourth parameter,"
1219 "expected " + cppu::UnoType<decltype(rReg)>::get().getTypeName() +
1220 ", got " + aArgs[3].getValueTypeName(),
1221 Reference< XInterface > (), 0 );
1225 doRegister(m_xSMgr, m_xCtx, rLoader , rReg, loaderServiceName , locationUrl, locationUrl);
1229 // virtual function registerImplementationWithLocation of XImplementationRegistration2
1231 void ImplementationRegistration::registerImplementationWithLocation(
1232 const OUString& implementationLoaderUrl,
1233 const OUString& locationUrl,
1234 const OUString& registeredLocationUrl,
1235 const Reference < XSimpleRegistry > & xReg)
1237 prepareRegister(
1238 implementationLoaderUrl, locationUrl, registeredLocationUrl, xReg);
1241 // helper function
1242 void ImplementationRegistration::prepareRegister(
1243 const OUString& implementationLoaderUrl,
1244 const OUString& locationUrl,
1245 const OUString& registeredLocationUrl,
1246 const Reference < XSimpleRegistry > & xReg)
1247 // throw( CannotRegisterImplementationException, RuntimeException )
1249 OUString activatorName;
1251 if (!implementationLoaderUrl.isEmpty())
1253 activatorName = implementationLoaderUrl.getToken(0, ':');
1254 } else
1256 // check locationUrl to find out what kind of loader is needed
1257 // set implLoaderUrl
1260 if( !m_xSMgr.is() ) {
1261 throw CannotRegisterImplementationException(
1262 u"ImplementationRegistration::registerImplementation() "
1263 "no componentcontext available to instantiate loader"_ustr );
1268 Reference < XImplementationLoader > xAct(
1269 m_xSMgr->createInstanceWithContext(activatorName, m_xCtx) , UNO_QUERY );
1270 if (!xAct.is())
1272 throw CannotRegisterImplementationException(
1273 "ImplementationRegistration::registerImplementation() - The service "
1274 + activatorName + " cannot be instantiated" );
1277 Reference < XSimpleRegistry > xRegistry;
1279 if (xReg.is())
1281 // registry supplied by user
1282 xRegistry = xReg;
1284 else
1286 xRegistry = getRegistryFromServiceManager();
1289 if ( xRegistry.is())
1291 doRegister(m_xSMgr, m_xCtx, xAct, xRegistry, implementationLoaderUrl,
1292 locationUrl, registeredLocationUrl);
1296 catch( CannotRegisterImplementationException & )
1298 throw;
1300 catch( const InvalidRegistryException & e )
1302 throw CannotRegisterImplementationException(
1303 "ImplementationRegistration::registerImplementation() "
1304 "InvalidRegistryException during registration (" + e.Message + ")" );
1306 catch( const MergeConflictException & e )
1308 throw CannotRegisterImplementationException(
1309 "ImplementationRegistration::registerImplementation() "
1310 "MergeConflictException during registration (" + e.Message + ")" );
1316 // virtual function registerImplementation of XImplementationRegistration
1318 void ImplementationRegistration::registerImplementation(
1319 const OUString& implementationLoaderUrl,
1320 const OUString& locationUrl,
1321 const Reference < XSimpleRegistry > & xReg)
1323 prepareRegister(implementationLoaderUrl, locationUrl, locationUrl, xReg);
1327 // virtual function revokeImplementation of XImplementationRegistration
1329 sal_Bool ImplementationRegistration::revokeImplementation(const OUString& location,
1330 const Reference < XSimpleRegistry >& xReg)
1332 bool ret = false;
1334 Reference < XSimpleRegistry > xRegistry;
1336 if (xReg.is()) {
1337 xRegistry = xReg;
1339 else {
1340 Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY );
1341 if( xPropSet.is() ) {
1342 try {
1343 Any aAny = xPropSet->getPropertyValue( Registry );
1345 if( aAny.getValueTypeClass() == TypeClass_INTERFACE )
1347 aAny >>= xRegistry;
1350 catch ( UnknownPropertyException & ) {
1355 if (xRegistry.is())
1359 doRevoke(xRegistry, location);
1360 ret = true;
1362 catch( InvalidRegistryException & )
1364 // no way to transport the error, as no exception is specified and a runtime
1365 // exception is not appropriate.
1366 OSL_FAIL( "InvalidRegistryException during revokeImplementation" );
1370 return ret;
1374 // virtual function getImplementations of XImplementationRegistration
1376 Sequence< OUString > ImplementationRegistration::getImplementations(
1377 const OUString & implementationLoaderUrl,
1378 const OUString & locationUrl)
1380 OUString activatorName;
1382 if (!implementationLoaderUrl.isEmpty())
1384 activatorName = implementationLoaderUrl.getToken(0, ':');
1385 } else
1387 // check locationUrl to find out what kind of loader is needed
1388 // set implementationLoaderUrl
1391 if( m_xSMgr.is() ) {
1393 Reference < XImplementationLoader > xAct(
1394 m_xSMgr->createInstanceWithContext( activatorName, m_xCtx ), UNO_QUERY );
1396 if (xAct.is())
1399 Reference < XSimpleRegistry > xReg =
1400 createTemporarySimpleRegistry( m_xSMgr, m_xCtx);
1402 if (xReg.is())
1406 xReg->open(OUString() /* in mem */, false, true);
1407 Reference < XRegistryKey > xImpl;
1409 { // only necessary for deleting the temporary variable of rootkey
1410 xImpl = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS );
1412 if (xAct->writeRegistryInfo(xImpl, implementationLoaderUrl, locationUrl))
1414 std::vector<OUString> implNames;
1416 findImplementations(xImpl, implNames);
1418 if (!implNames.empty())
1420 Sequence<OUString> seqImpl(comphelper::containerToSequence(implNames));
1421 xImpl->closeKey();
1422 return seqImpl;
1426 xImpl->closeKey();
1428 catch(MergeConflictException&)
1431 catch(InvalidRegistryException&)
1438 return Sequence<OUString>();
1442 // virtual function checkInstantiation of XImplementationRegistration
1444 Sequence< OUString > ImplementationRegistration::checkInstantiation(const OUString&)
1446 OSL_FAIL( "ImplementationRegistration::checkInstantiation not implemented" );
1447 return Sequence<OUString>();
1451 // helper function doRegistration
1454 void ImplementationRegistration::doRevoke(
1455 const Reference < XSimpleRegistry >& xDest,
1456 std::u16string_view locationUrl)
1457 // throw ( InvalidRegistryException, RuntimeException )
1459 if( !xDest.is() )
1460 return;
1462 std::vector<OUString> aNames;
1464 Reference < XRegistryKey > xRootKey( xDest->getRootKey() );
1466 Reference < XRegistryKey > xKey =
1467 xRootKey->openKey( slash_IMPLEMENTATIONS );
1468 if (xKey.is() && xKey->isValid())
1470 deleteAllImplementations(xDest, xKey, locationUrl, aNames);
1473 xKey = xRootKey->openKey( slash_SERVICES );
1474 if (xKey.is())
1476 for (auto const& name : aNames)
1478 deleteAllServiceEntries(xDest, xKey, name);
1482 xKey = xRootKey->openKey( u"/SINGLETONS"_ustr );
1483 if (xKey.is() && xKey->isValid())
1485 delete_all_singleton_entries( xKey, aNames );
1488 if (xRootKey.is())
1489 xRootKey->closeKey();
1490 if (xKey.is() && xKey->isValid() )
1491 xKey->closeKey();
1494 void ImplementationRegistration::doRegister(
1495 const Reference< XMultiComponentFactory > & xSMgr,
1496 const Reference< XComponentContext > &xCtx,
1497 const Reference < XImplementationLoader > & xAct,
1498 const Reference < XSimpleRegistry >& xDest,
1499 const OUString& implementationLoaderUrl,
1500 const OUString& locationUrl,
1501 const OUString& registeredLocationUrl)
1502 /* throw ( InvalidRegistryException,
1503 MergeConflictException,
1504 CannotRegisterImplementationException, RuntimeException ) */
1506 Reference < XSimpleRegistry > xReg =
1507 createTemporarySimpleRegistry( xSMgr, xCtx );
1508 Reference < XRegistryKey > xSourceKey;
1510 if (!(xAct.is() && xReg.is() && xDest.is()))
1511 return;
1515 xReg->open(OUString() /* in mem */, false, true);
1517 { // only necessary for deleting the temporary variable of rootkey
1518 xSourceKey = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS );
1521 bool bSuccess =
1522 xAct->writeRegistryInfo(xSourceKey, implementationLoaderUrl, locationUrl);
1523 if ( !bSuccess )
1525 throw CannotRegisterImplementationException(
1526 u"ImplementationRegistration::doRegistration() component registration signaled failure"_ustr );
1529 prepareRegistry(xDest, xSourceKey, implementationLoaderUrl, registeredLocationUrl, xCtx);
1531 xSourceKey->closeKey();
1533 xSourceKey = xReg->getRootKey();
1534 Reference < XRegistryKey > xDestKey = xDest->getRootKey();
1535 stoc_impreg::mergeKeys( xDestKey, xSourceKey );
1536 xDestKey->closeKey();
1537 xSourceKey->closeKey();
1540 // Cleanup Source registry.
1541 if ( xSourceKey->isValid() )
1542 xSourceKey->closeKey();
1544 catch(CannotRegisterImplementationException&)
1546 if ( xSourceKey->isValid() )
1547 xSourceKey->closeKey();
1548 // and throw again
1549 throw;
1554 Reference< XSimpleRegistry > ImplementationRegistration::createTemporarySimpleRegistry(
1555 const Reference< XMultiComponentFactory > &rSMgr,
1556 const Reference < XComponentContext > & xCtx)
1559 Reference < XSimpleRegistry > xReg(
1560 rSMgr->createInstanceWithContext(
1561 com_sun_star_registry_SimpleRegistry, xCtx ),
1562 UNO_QUERY);
1563 OSL_ASSERT( xReg.is() );
1564 return xReg;
1569 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1570 com_sun_star_comp_stoc_ImplementationRegistration_get_implementation(
1571 css::uno::XComponentContext *context,
1572 css::uno::Sequence<css::uno::Any> const &)
1574 return cppu::acquire(new ImplementationRegistration(context));
1577 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */