Remove non-const Sequence::begin()/end() in internal code
[LibreOffice.git] / stoc / source / implementationregistration / implreg.cxx
blob912ed434d29ec85671493f197197c61023f04942
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>
30 #include <tools/diagnose_ex.h>
32 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
33 #include <com/sun/star/lang/XServiceInfo.hpp>
34 #include <com/sun/star/lang/XInitialization.hpp>
35 #include <com/sun/star/loader/XImplementationLoader.hpp>
36 #include <com/sun/star/registry/XImplementationRegistration2.hpp>
37 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
38 #include <com/sun/star/reflection/XServiceTypeDescription.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/uno/RuntimeException.hpp>
41 #include <com/sun/star/uno/XComponentContext.hpp>
43 #include "mergekeys.hxx"
45 #if defined(_WIN32)
46 #include <io.h>
47 #endif
50 using namespace com::sun::star;
51 using namespace css::uno;
52 using namespace css::loader;
53 using namespace css::beans;
54 using namespace css::lang;
55 using namespace css::registry;
56 using namespace cppu;
57 using namespace osl;
59 namespace {
61 constexpr OUStringLiteral slash_UNO_slash_REGISTRY_LINKS
62 = u"/UNO/REGISTRY_LINKS";
63 constexpr OUStringLiteral slash_IMPLEMENTATIONS
64 = u"/IMPLEMENTATIONS";
65 constexpr OUStringLiteral slash_UNO
66 = u"/UNO";
67 constexpr OUStringLiteral slash_UNO_slash_SERVICES
68 = u"/UNO/SERVICES";
69 constexpr OUStringLiteral slash_UNO_slash_SINGLETONS
70 = u"/UNO/SINGLETONS";
71 constexpr OUStringLiteral slash_SERVICES
72 = u"/SERVICES/";
73 constexpr OUStringLiteral slash_UNO_slash_LOCATION
74 = u"/UNO/LOCATION";
75 constexpr OUStringLiteral slash_UNO_slash_ACTIVATOR
76 = u"/UNO/ACTIVATOR";
77 constexpr OUStringLiteral colon_old
78 = u":old";
79 constexpr OUStringLiteral com_sun_star_registry_SimpleRegistry
80 = u"com.sun.star.registry.SimpleRegistry";
81 constexpr OUStringLiteral Registry
82 = u"Registry";
84 // static deleteAllLinkReferences()
86 void deleteAllLinkReferences(const Reference < XSimpleRegistry >& xReg,
87 const Reference < XRegistryKey >& xSource)
88 // throw ( InvalidRegistryException, RuntimeException )
90 Reference < XRegistryKey > xKey = xSource->openKey(
91 slash_UNO_slash_REGISTRY_LINKS );
93 if (!(xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST)))
94 return;
96 const Sequence<OUString> linkNames = xKey->getAsciiListValue();
98 if (!linkNames.hasElements())
99 return;
101 OUString aLinkName;
102 OUString aLinkParent;
103 Reference < XRegistryKey > xLinkParent;
104 const sal_Unicode* pTmpName = nullptr;
105 const sal_Unicode* pShortName = nullptr;
106 sal_Int32 sEnd = 0;
108 for (const OUString& rLinkName : linkNames)
110 aLinkName = rLinkName;
112 pTmpName = aLinkName.getStr();
114 if (pTmpName[0] != L'/')
115 continue;
117 sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' );
118 if ( nIndex == -1 )
119 pShortName = nullptr;
120 else
121 pShortName = pTmpName+nIndex;
123 while (pShortName && pShortName[1] == L'%')
125 nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' );
126 if ( nIndex == -1 )
127 pShortName = nullptr;
128 else
129 pShortName += nIndex+2;
132 if (pShortName)
134 aLinkName = aLinkName.copy(0, pShortName - pTmpName);
137 xReg->getRootKey()->deleteLink(aLinkName);
139 sEnd = aLinkName.lastIndexOf( '/' );
141 aLinkParent = aLinkName.copy(0, sEnd);
143 while(!aLinkParent.isEmpty())
145 xLinkParent = xReg->getRootKey()->openKey(aLinkParent);
147 if (xLinkParent.is() && !xLinkParent->getKeyNames().hasElements())
149 aLinkName = aLinkParent;
151 xReg->getRootKey()->deleteKey(aLinkParent);
153 sEnd = aLinkName.lastIndexOf( '/' );
155 aLinkParent = aLinkName.copy(0, sEnd);
157 else
159 break;
166 // static prepareLink
168 void prepareLink( const Reference < XSimpleRegistry > & xDest,
169 const Reference < XRegistryKey > & xSource,
170 const OUString& link)
171 // throw ( InvalidRegistryException, RuntimeException )
173 OUString linkRefName = xSource->getKeyName();
174 OUString linkName(link);
175 bool isRelativ = false;
177 const sal_Unicode* pTmpName = link.getStr();
178 const sal_Unicode* pShortName;
179 sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' );
180 if ( nIndex == -1 )
181 pShortName = nullptr;
182 else
183 pShortName = pTmpName+nIndex;
185 if (pTmpName[0] != L'/')
186 isRelativ = true;
188 while (pShortName && pShortName[1] == L'%')
190 nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' );
191 if ( nIndex == -1 )
192 pShortName = nullptr;
193 else
194 pShortName += nIndex+2;
197 if (pShortName)
199 linkRefName += link.subView(pShortName - pTmpName + 1);
200 linkName = link.copy(0, pShortName - pTmpName);
203 if (isRelativ)
204 xSource->createLink(linkName, linkRefName);
205 else
206 xDest->getRootKey()->createLink(linkName, linkRefName);
210 // static searchImplForLink
212 OUString searchImplForLink(
213 const Reference < XRegistryKey > & xRootKey,
214 std::u16string_view linkName,
215 std::u16string_view implName )
216 // throw ( InvalidRegistryException, RuntimeException )
218 Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS );
219 if (xKey.is())
221 const Sequence< Reference < XRegistryKey > > subKeys( xKey->openKeys() );
222 OUString key_name( slash_UNO + linkName );
224 for (const Reference < XRegistryKey >& xImplKey : subKeys)
228 if (xImplKey->getKeyType( key_name ) == RegistryKeyType_LINK)
230 OUString oldImplName = xImplKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/"));
231 if (implName != oldImplName)
233 return oldImplName;
237 catch(InvalidRegistryException&)
243 return OUString();
247 // static searchLinkTargetForImpl
249 OUString searchLinkTargetForImpl(const Reference < XRegistryKey >& xRootKey,
250 std::u16string_view linkName,
251 const OUString& implName)
253 Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS );
255 if (xKey.is())
257 const Sequence< Reference < XRegistryKey > > subKeys = xKey->openKeys();
259 OUString qualifiedLinkName( slash_UNO + linkName );
261 auto pSubKey = std::find_if(subKeys.begin(), subKeys.end(),
262 [&implName, &qualifiedLinkName](const Reference<XRegistryKey>& rSubKey) {
263 OUString tmpImplName = rSubKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/"));
264 return tmpImplName == implName
265 && rSubKey->getKeyType( qualifiedLinkName ) == RegistryKeyType_LINK;
267 if (pSubKey != subKeys.end())
268 return (*pSubKey)->getLinkTarget( qualifiedLinkName );
271 return OUString();
275 // static createUniqueSubEntry
277 void createUniqueSubEntry(const Reference < XRegistryKey > & xSuperKey,
278 const OUString& value)
279 // throw ( InvalidRegistryException, RuntimeException )
281 if (!xSuperKey.is())
282 return;
284 if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST)
286 const Sequence<OUString> implEntries = xSuperKey->getAsciiListValue();
287 sal_Int32 length = implEntries.getLength();
289 bool bReady = comphelper::findValue(implEntries, value) != -1;
291 if (bReady)
293 Sequence<OUString> implEntriesNew(length);
294 auto it = implEntriesNew.getArray();
295 *it = value;
297 std::copy_if(implEntries.begin(), implEntries.end(), std::next(it),
298 [&value](const OUString& rEntry) { return rEntry != value; });
299 xSuperKey->setAsciiListValue(implEntriesNew);
300 } else
302 Sequence<OUString> implEntriesNew(length+1);
303 auto it = implEntriesNew.getArray();
304 *it = value;
306 std::copy(implEntries.begin(), implEntries.end(), std::next(it));
307 xSuperKey->setAsciiListValue(implEntriesNew);
309 } else
311 Sequence<OUString> implEntriesNew { value };
313 xSuperKey->setAsciiListValue(implEntriesNew);
318 // static deleteSubEntry
320 bool deleteSubEntry(const Reference < XRegistryKey >& xSuperKey, const OUString& value)
321 // throw ( InvalidRegistryException, RuntimeException )
323 if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST)
325 const Sequence<OUString> implEntries = xSuperKey->getAsciiListValue();
326 sal_Int32 length = implEntries.getLength();
327 sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), value));
328 bool hasNoImplementations = false;
330 if (equals == length)
332 hasNoImplementations = true;
333 } else
335 Sequence<OUString> implEntriesNew(length - equals);
337 std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.getArray(),
338 [&value](const OUString& rEntry) { return rEntry != value; });
339 xSuperKey->setAsciiListValue(implEntriesNew);
342 if (hasNoImplementations)
344 return true;
347 return false;
351 // static prepareUserLink
353 void prepareUserLink(const Reference < XSimpleRegistry >& xDest,
354 const OUString& linkName,
355 const OUString& linkTarget,
356 std::u16string_view implName)
358 Reference < XRegistryKey > xRootKey = xDest->getRootKey();
360 if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK)
362 OUString oldImplName(searchImplForLink(xRootKey, linkName, implName));
364 if (!oldImplName.isEmpty())
366 createUniqueSubEntry(xDest->getRootKey()->createKey(
367 linkName + colon_old ), oldImplName);
371 if (xRootKey->isValid())
372 xRootKey->createLink(linkName, linkTarget);
376 // static deleteUserLink
378 void deletePathIfPossible(const Reference < XRegistryKey >& xRootKey,
379 const OUString& path)
383 Sequence<OUString> keyNames(xRootKey->openKey(path)->getKeyNames());
385 if (!keyNames.hasElements() &&
386 xRootKey->openKey(path)->getValueType() == RegistryValueType_NOT_DEFINED)
388 xRootKey->deleteKey(path);
390 OUString newPath = path.copy(0, path.lastIndexOf('/'));
392 if (newPath.getLength() > 1)
393 deletePathIfPossible(xRootKey, newPath);
396 catch(InvalidRegistryException&)
402 // static deleteUserLink
404 void deleteUserLink(const Reference < XRegistryKey >& xRootKey,
405 const OUString& linkName,
406 std::u16string_view linkTarget,
407 const OUString& implName)
408 // throw ( InvalidRegistryException, RuntimeException )
410 bool bClean = false;
412 if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK)
414 OUString tmpTarget = xRootKey->getLinkTarget(linkName);
416 if (tmpTarget == linkTarget)
418 xRootKey->deleteLink(linkName);
422 Reference < XRegistryKey > xOldKey = xRootKey->openKey(
423 linkName + colon_old );
424 if (xOldKey.is())
426 if (xOldKey->getValueType() == RegistryValueType_ASCIILIST)
428 const Sequence<OUString> implEntries = xOldKey->getAsciiListValue();
429 sal_Int32 length = implEntries.getLength();
430 sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
431 bool hasNoImplementations = false;
433 if (equals == length)
435 hasNoImplementations = true;
436 } else
438 OUString oldImpl;
440 if (length > equals + 1)
442 Sequence<OUString> implEntriesNew(length - equals - 1);
443 auto pNewArray = implEntriesNew.getArray();
445 sal_Int32 j = 0;
446 bool first = true;
447 for (sal_Int32 i = 0; i < length; i++)
449 if (implEntries[i] != implName)
451 if (first)
453 oldImpl = implEntries[i];
454 first = false;
455 } else
457 pNewArray[j++] = implEntries[i];
462 xOldKey->setAsciiListValue(implEntriesNew);
463 } else
465 oldImpl = implEntries[0];
466 OUString path(xOldKey->getKeyName());
467 xOldKey->closeKey();
468 xRootKey->deleteKey(path);
471 OUString oldTarget = searchLinkTargetForImpl(xRootKey, linkName, oldImpl);
472 if (!oldTarget.isEmpty())
474 xRootKey->createLink(linkName, oldTarget);
478 if (hasNoImplementations)
480 bClean = true;
481 OUString path(xOldKey->getKeyName());
482 xOldKey->closeKey();
483 xRootKey->deleteKey(path);
486 } else
488 bClean = true;
491 if (bClean)
493 OUString path = linkName.copy(0, linkName.lastIndexOf('/'));
494 deletePathIfPossible(xRootKey, path);
499 // static prepareUserKeys
501 void prepareUserKeys(const Reference < XSimpleRegistry >& xDest,
502 const Reference < XRegistryKey >& xUnoKey,
503 const Reference < XRegistryKey >& xKey,
504 const OUString& implName,
505 bool bRegister)
507 bool hasSubKeys = false;
509 Sequence<OUString> keyNames = xKey->getKeyNames();
511 OUString relativKey;
512 if (keyNames.hasElements())
513 relativKey = keyNames.getConstArray()[0].copy(xKey->getKeyName().getLength()+1);
515 if (keyNames.getLength() == 1 &&
516 xKey->getKeyType(relativKey) == RegistryKeyType_LINK)
518 hasSubKeys = true;
520 OUString linkTarget = xKey->getLinkTarget(relativKey);
521 OUString linkName(xKey->getKeyName().copy(xUnoKey->getKeyName().getLength()));
523 linkName += "/" + relativKey;
525 if (bRegister)
527 prepareUserLink(xDest, linkName, linkTarget, implName);
528 } else
530 deleteUserLink(xDest->getRootKey(), linkName, linkTarget, implName);
532 } else
534 const Sequence< Reference < XRegistryKey> > subKeys = xKey->openKeys();
536 if (subKeys.hasElements())
538 hasSubKeys = true;
540 for (const Reference < XRegistryKey > & rSubKey : subKeys)
542 prepareUserKeys(xDest, xUnoKey, rSubKey, implName, bRegister);
547 if (hasSubKeys)
548 return;
550 OUString keyName(xKey->getKeyName().copy(xUnoKey->getKeyName().getLength()));
552 Reference < XRegistryKey > xRootKey = xDest->getRootKey();
553 if (bRegister)
555 createUniqueSubEntry(xRootKey->createKey(keyName), implName);
557 else
559 Reference< XRegistryKey > rKey = xRootKey->openKey(keyName);
560 if( rKey.is() )
562 deleteSubEntry(rKey, implName);
563 xRootKey->deleteKey(keyName);
566 OUString path = keyName.copy(0, keyName.lastIndexOf('/'));
567 if( !path.isEmpty() )
569 deletePathIfPossible(xRootKey, path);
575 // static deleteAllImplementations
577 void deleteAllImplementations( const Reference < XSimpleRegistry >& xReg,
578 const Reference < XRegistryKey >& xSource,
579 std::u16string_view locationUrl,
580 std::vector<OUString> & implNames)
581 // throw (InvalidRegistryException, RuntimeException)
583 Sequence < Reference < XRegistryKey > > subKeys = xSource->openKeys();
585 if (subKeys.hasElements())
587 bool hasLocationUrl = false;
589 for (const Reference < XRegistryKey> & xImplKey : std::as_const(subKeys))
591 Reference < XRegistryKey > xKey = xImplKey->openKey(
592 slash_UNO_slash_LOCATION );
594 if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCII))
596 if (xKey->getAsciiValue() == locationUrl)
598 hasLocationUrl = true;
600 OUString implName(xImplKey->getKeyName().copy(1));
601 sal_Int32 firstDot = implName.indexOf('/');
603 if (firstDot >= 0)
604 implName = implName.copy(firstDot + 1);
606 implNames.push_back(implName);
608 deleteAllLinkReferences(xReg, xImplKey);
610 xKey = xImplKey->openKey( slash_UNO );
611 if (xKey.is())
613 const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys();
615 for (const Reference < XRegistryKey > & rSubKey2 : subKeys2)
617 if (rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_SERVICES ) &&
618 rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) &&
619 rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_ACTIVATOR ) &&
620 rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ) &&
621 rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_LOCATION) )
623 prepareUserKeys(xReg, xKey, rSubKey2, implName, false);
630 if (hasLocationUrl)
632 hasLocationUrl = false;
633 OUString path(xImplKey->getKeyName());
634 xImplKey->closeKey();
635 xReg->getRootKey()->deleteKey(path);
639 subKeys = xSource->openKeys();
640 if (!subKeys.hasElements())
642 OUString path(xSource->getKeyName());
643 xSource->closeKey();
644 xReg->getRootKey()->deleteKey(path);
646 } else
648 OUString path(xSource->getKeyName());
649 xSource->closeKey();
650 xReg->getRootKey()->deleteKey(path);
655 void delete_all_singleton_entries(
656 Reference < registry::XRegistryKey > const & xSingletons_section,
657 ::std::vector< OUString > const & impl_names )
658 // throw (InvalidRegistryException, RuntimeException)
660 Sequence< Reference< registry::XRegistryKey > > singletons( xSingletons_section->openKeys() );
661 Reference< registry::XRegistryKey > const * subkeys = singletons.getConstArray();
662 for ( sal_Int32 nPos = singletons.getLength(); nPos--; )
664 Reference< registry::XRegistryKey > const & xSingleton = subkeys[ nPos ];
665 Reference< registry::XRegistryKey > xRegisteredImplNames(
666 xSingleton->openKey( "REGISTERED_BY" ) );
667 if (xRegisteredImplNames.is() && xRegisteredImplNames->isValid())
669 Sequence< OUString > registered_implnames;
672 registered_implnames = xRegisteredImplNames->getAsciiListValue();
674 catch (registry::InvalidValueException &)
677 OUString const * p = registered_implnames.getConstArray();
678 sal_Int32 nOrigRegLength = registered_implnames.getLength();
679 sal_Int32 nNewLength = nOrigRegLength;
680 for ( sal_Int32 n = nOrigRegLength; n--; )
682 OUString const & registered_implname = p[ n ];
684 for (auto const& impl_name : impl_names)
686 if (impl_name == registered_implname)
688 registered_implnames[ n ] = p[ nNewLength -1 ];
689 --nNewLength;
694 if (nNewLength != nOrigRegLength)
696 if (0 == nNewLength)
698 // remove whole entry
699 xRegisteredImplNames->closeKey();
700 xSingleton->deleteKey( "REGISTERED_BY" );
701 // registry key cannot provide its relative name, only absolute :(
702 OUString abs( xSingleton->getKeyName() );
703 xSingletons_section->deleteKey( abs.copy( abs.lastIndexOf( '/' ) +1 ) );
705 else
707 registered_implnames.realloc( nNewLength );
708 xRegisteredImplNames->setAsciiListValue( registered_implnames );
716 // static deleteAllServiceEntries
718 void deleteAllServiceEntries( const Reference < XSimpleRegistry >& xReg,
719 const Reference < XRegistryKey >& xSource,
720 const OUString& implName)
721 // throw ( InvalidRegistryException, RuntimeException )
723 Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
725 if (subKeys.hasElements())
727 bool hasNoImplementations = false;
729 for (const Reference < XRegistryKey > & xServiceKey : std::as_const(subKeys))
731 if (xServiceKey->getValueType() == RegistryValueType_ASCIILIST)
733 const Sequence<OUString> implEntries = xServiceKey->getAsciiListValue();
734 sal_Int32 length = implEntries.getLength();
735 sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
737 if (equals == length)
739 hasNoImplementations = true;
740 } else
742 if (equals > 0)
744 Sequence<OUString> implEntriesNew(length-equals);
746 std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.getArray(),
747 [&implName](const OUString& rEntry) { return rEntry != implName; });
749 xServiceKey->setAsciiListValue(implEntriesNew);
754 if (hasNoImplementations)
756 hasNoImplementations = false;
757 OUString path(xServiceKey->getKeyName());
758 xServiceKey->closeKey();
759 xReg->getRootKey()->deleteKey(path);
763 subKeys = xSource->openKeys();
764 if (!subKeys.hasElements())
766 OUString path(xSource->getKeyName());
767 xSource->closeKey();
768 xReg->getRootKey()->deleteKey(path);
770 } else
772 OUString path(xSource->getKeyName());
773 xSource->closeKey();
774 xReg->getRootKey()->deleteKey(path);
779 bool is_supported_service(
780 OUString const & service_name,
781 Reference< reflection::XServiceTypeDescription > const & xService_td )
783 if (xService_td->getName() == service_name)
784 return true;
785 const Sequence< Reference< reflection::XServiceTypeDescription > > seq(
786 xService_td->getMandatoryServices() );
787 return std::any_of(seq.begin(), seq.end(), [&service_name](const auto& rService) {
788 return is_supported_service( service_name, rService ); });
792 void insert_singletons(
793 Reference< registry::XSimpleRegistry > const & xDest,
794 Reference< registry::XRegistryKey > const & xImplKey,
795 Reference< XComponentContext > const & xContext )
796 // throw( registry::InvalidRegistryException, registry::CannotRegisterImplementationException, RuntimeException )
798 // singletons
799 Reference< registry::XRegistryKey > xKey( xImplKey->openKey( "UNO/SINGLETONS" ) );
800 if (!(xKey.is() && xKey->isValid()))
801 return;
803 OUString implname( xImplKey->getKeyName().copy( sizeof ("/IMPLEMENTATIONS/") -1 ) );
804 // singleton entries
805 Sequence< Reference< registry::XRegistryKey > > xSingletons_section( xKey->openKeys() );
806 Reference< registry::XRegistryKey > const * p = xSingletons_section.getConstArray();
807 for ( sal_Int32 nPos = xSingletons_section.getLength(); nPos--; )
809 Reference< registry::XRegistryKey > const & xSingleton = p[ nPos ];
810 OUString singleton_name(
811 xSingleton->getKeyName().copy(
812 implname.getLength() + sizeof ("/IMPLEMENTATIONS//UNO/SINGLETONS/") -1 ) );
813 OUString service_name( xSingleton->getStringValue() );
815 OUString keyname( "/SINGLETONS/" + singleton_name );
816 Reference< registry::XRegistryKey > xKey2( xDest->getRootKey()->openKey( keyname ) );
817 if (xKey2.is() && xKey2->isValid())
821 OUString existing_name( xKey2->getStringValue() );
822 if ( existing_name != service_name )
824 Reference< container::XHierarchicalNameAccess > xTDMgr;
825 OUString the_tdmgr =
826 "/singletons/com.sun.star.reflection.theTypeDescriptionManager";
827 xContext->getValueByName( the_tdmgr ) >>= xTDMgr;
828 if (! xTDMgr.is())
830 throw RuntimeException( "cannot get singleton " + the_tdmgr );
834 Reference< reflection::XServiceTypeDescription > xExistingService_td;
835 xTDMgr->getByHierarchicalName( existing_name ) >>= xExistingService_td;
836 if (! xExistingService_td.is())
838 throw RuntimeException( "cannot get service type description: " + existing_name );
841 // everything's fine if existing service entry supports the one
842 // to be registered
843 if (! is_supported_service( service_name, xExistingService_td ))
845 throw registry::CannotRegisterImplementationException(
846 "existing singleton service (" + singleton_name + "=" + existing_name + ") "
847 " does not support given one: " + service_name);
850 catch (const container::NoSuchElementException & exc)
852 css::uno::Any anyEx = cppu::getCaughtException();
853 throw css::lang::WrappedTargetRuntimeException(
854 "cannot get service type description: " + exc.Message,
855 nullptr, anyEx );
859 catch (registry::InvalidValueException &)
861 // repair
862 xKey2->setStringValue( service_name );
865 else
867 // insert singleton entry
868 xKey2 = xDest->getRootKey()->createKey( keyname );
869 xKey2->setStringValue( service_name );
872 Reference< registry::XRegistryKey > xRegisteredImplNames(
873 xKey2->openKey( "REGISTERED_BY" ) );
874 if (!xRegisteredImplNames.is() || !xRegisteredImplNames->isValid())
876 // create
877 xRegisteredImplNames = xKey2->createKey( "REGISTERED_BY" );
880 Sequence< OUString > implnames;
883 implnames = xRegisteredImplNames->getAsciiListValue();
885 catch (registry::InvalidValueException &)
888 // check implname is already in
889 if (comphelper::findValue(implnames, implname) == -1)
891 // append and write back
892 implnames.realloc( implnames.getLength() +1 );
893 implnames[ implnames.getLength() -1 ] = implname;
894 xRegisteredImplNames->setAsciiListValue( implnames );
900 // static prepareRegistry
902 void prepareRegistry(
903 const Reference < XSimpleRegistry >& xDest,
904 const Reference < XRegistryKey >& xSource,
905 const OUString& implementationLoaderUrl,
906 const OUString& locationUrl,
907 Reference< XComponentContext > const & xContext )
908 // throw ( InvalidRegistryException, CannotRegisterImplementationException, RuntimeException )
910 const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
912 if (!subKeys.hasElements())
914 throw InvalidRegistryException(
915 "prepareRegistry(): source registry is empty" );
918 for (const Reference < XRegistryKey >& xImplKey : subKeys)
920 Reference < XRegistryKey > xKey = xImplKey->openKey(
921 slash_UNO_slash_SERVICES );
923 if (xKey.is())
925 // update entries in SERVICES section
926 const Sequence< Reference < XRegistryKey > > serviceKeys = xKey->openKeys();
928 OUString implName = xImplKey->getKeyName().copy(1);
929 sal_Int32 firstDot = implName.indexOf('/');
931 if (firstDot >= 0)
932 implName = implName.copy(firstDot + 1);
934 sal_Int32 offset = xKey->getKeyName().getLength() + 1;
936 for (const Reference < XRegistryKey >& rServiceKey : serviceKeys)
938 OUString serviceName = rServiceKey->getKeyName().copy(offset);
940 createUniqueSubEntry(
941 xDest->getRootKey()->createKey(
942 slash_SERVICES + serviceName ),
943 implName);
946 xKey = xImplKey->openKey( slash_UNO );
947 if (xKey.is())
949 const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys();
951 for (const Reference < XRegistryKey >& rSubKey2 : subKeys2)
953 if (rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_SERVICES) &&
954 rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) &&
955 rSubKey2->getKeyName() != OUStringConcatenation(xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ))
957 prepareUserKeys(xDest, xKey, rSubKey2, implName, true);
963 // update LOCATION entry
964 xKey = xImplKey->createKey( slash_UNO_slash_LOCATION );
966 if (xKey.is())
968 xKey->setAsciiValue(locationUrl);
971 // update ACTIVATOR entry
972 xKey = xImplKey->createKey( slash_UNO_slash_ACTIVATOR );
974 if (xKey.is())
976 xKey->setAsciiValue(implementationLoaderUrl);
979 xKey = xImplKey->openKey( slash_UNO_slash_SERVICES );
981 if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST))
983 // update link entries in REGISTRY_LINKS section
984 const Sequence<OUString> linkNames = xKey->getAsciiListValue();
986 for (const OUString& rLinkName : linkNames)
988 prepareLink(xDest, xImplKey, rLinkName);
992 insert_singletons( xDest, xImplKey, xContext );
997 void findImplementations( const Reference < XRegistryKey > & xSource,
998 std::vector<OUString>& implNames)
1000 bool isImplKey = false;
1004 Reference < XRegistryKey > xKey = xSource->openKey(
1005 slash_UNO_slash_SERVICES );
1007 if (xKey.is() && xKey->getKeyNames().hasElements())
1009 isImplKey = true;
1011 OUString implName = xSource->getKeyName().copy(1).replace('/', '.');
1012 sal_Int32 firstDot = implName.indexOf('.');
1014 if (firstDot >= 0)
1015 implName = implName.copy(firstDot + 1);
1017 implNames.push_back(implName);
1020 catch(InvalidRegistryException&)
1024 if (isImplKey) return;
1028 const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
1030 for (const Reference < XRegistryKey >& rSubKey : subKeys)
1032 findImplementations(rSubKey, implNames);
1035 catch(InvalidRegistryException&)
1041 class ImplementationRegistration
1042 : public WeakImplHelper< XImplementationRegistration2, XServiceInfo, XInitialization >
1044 public:
1045 explicit ImplementationRegistration( const Reference < XComponentContext > & rSMgr );
1047 // XServiceInfo
1048 OUString SAL_CALL getImplementationName() override;
1049 sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
1050 Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
1052 // XImplementationRegistration
1053 virtual void SAL_CALL registerImplementation(
1054 const OUString& implementationLoader,
1055 const OUString& location,
1056 const Reference < XSimpleRegistry > & xReg) override;
1058 virtual sal_Bool SAL_CALL revokeImplementation(
1059 const OUString& location,
1060 const Reference < XSimpleRegistry >& xReg) override;
1062 virtual Sequence< OUString > SAL_CALL getImplementations(
1063 const OUString& implementationLoader,
1064 const OUString& location) override;
1065 virtual Sequence< OUString > SAL_CALL checkInstantiation(
1066 const OUString& implementationName) override;
1068 // XImplementationRegistration2
1069 virtual void SAL_CALL registerImplementationWithLocation(
1070 const OUString& implementationLoader,
1071 const OUString& location,
1072 const OUString& registeredLocation,
1073 const Reference < XSimpleRegistry > & xReg) override;
1075 // XInitialization
1076 virtual void SAL_CALL initialize(
1077 const css::uno::Sequence< css::uno::Any >& aArguments ) override;
1079 private: // helper methods
1080 void prepareRegister(
1081 const OUString& implementationLoader,
1082 const OUString& location,
1083 const OUString& registeredLocation,
1084 const Reference < XSimpleRegistry > & xReg);
1085 // throw( CannotRegisterImplementationException, RuntimeException )
1087 static void doRegister( const Reference < XMultiComponentFactory >& xSMgr,
1088 const Reference < XComponentContext > &xCtx,
1089 const Reference < XImplementationLoader >& xAct,
1090 const Reference < XSimpleRegistry >& xDest,
1091 const OUString& implementationLoaderUrl,
1092 const OUString& locationUrl,
1093 const OUString& registeredLocationUrl);
1094 /* throw ( InvalidRegistryException,
1095 MergeConflictException,
1096 CannotRegisterImplementationException, RuntimeException ) */
1098 static void doRevoke( const Reference < XSimpleRegistry >& xDest,
1099 std::u16string_view locationUrl );
1100 // throw( InvalidRegistryException, RuntimeException )
1101 Reference< XSimpleRegistry > getRegistryFromServiceManager() const;
1103 static Reference< XSimpleRegistry > createTemporarySimpleRegistry(
1104 const Reference< XMultiComponentFactory > &rSMgr,
1105 const Reference < XComponentContext > & rCtx );
1107 private: // members
1108 Reference < XMultiComponentFactory > m_xSMgr;
1109 Reference < XComponentContext > m_xCtx;
1113 // ImplementationRegistration()
1115 ImplementationRegistration::ImplementationRegistration( const Reference < XComponentContext > & xCtx )
1116 : m_xSMgr( xCtx->getServiceManager() )
1117 , m_xCtx( xCtx )
1120 // XServiceInfo
1121 OUString ImplementationRegistration::getImplementationName()
1123 return "com.sun.star.comp.stoc.ImplementationRegistration";
1126 // XServiceInfo
1127 sal_Bool ImplementationRegistration::supportsService(const OUString& ServiceName)
1129 return cppu::supportsService(this, ServiceName);
1132 // XServiceInfo
1133 Sequence< OUString > ImplementationRegistration::getSupportedServiceNames()
1135 return { "com.sun.star.registry.ImplementationRegistration" };
1138 Reference< XSimpleRegistry > ImplementationRegistration::getRegistryFromServiceManager() const
1140 Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY );
1141 Reference < XSimpleRegistry > xRegistry;
1143 if( xPropSet.is() ) {
1145 try { // the implementation does not support XIntrospectionAccess !
1147 Any aAny = xPropSet->getPropertyValue( Registry );
1149 if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) {
1150 aAny >>= xRegistry;
1153 catch( UnknownPropertyException & ) {
1154 // empty reference is error signal !
1158 return xRegistry;
1162 // XInitialization
1164 void ImplementationRegistration::initialize(
1165 const css::uno::Sequence< css::uno::Any >& aArgs )
1168 if( aArgs.getLength() != 4 ) {
1169 throw IllegalArgumentException(
1170 "ImplementationRegistration::initialize() expects 4 parameters, got " + OUString::number( aArgs.getLength() ),
1171 Reference<XInterface > (), 0 );
1174 Reference< XImplementationLoader > rLoader;
1175 OUString loaderServiceName;
1176 OUString locationUrl;
1177 Reference< XSimpleRegistry > rReg;
1179 // 1st argument : An instance of an implementation loader
1180 if( aArgs.getConstArray()[0].getValueType().getTypeClass() == TypeClass_INTERFACE ) {
1181 aArgs.getConstArray()[0] >>= rLoader;
1183 if( !rLoader.is()) {
1184 throw IllegalArgumentException(
1185 "ImplementationRegistration::initialize() invalid first parameter,"
1186 "expected " + cppu::UnoType<decltype(rLoader)>::get().getTypeName() +
1187 ", got " + aArgs.getConstArray()[0].getValueTypeName(),
1188 Reference< XInterface > (), 0 );
1191 // 2nd argument : The service name of the loader. This name is written into the registry
1192 if( aArgs.getConstArray()[1].getValueType().getTypeClass() == TypeClass_STRING ) {
1193 aArgs.getConstArray()[1] >>= loaderServiceName;
1195 if( loaderServiceName.isEmpty() ) {
1196 throw IllegalArgumentException(
1197 "ImplementationRegistration::initialize() invalid second parameter,"
1198 "expected string, got " + aArgs.getConstArray()[1].getValueTypeName(),
1199 Reference< XInterface > (), 0 );
1202 // 3rd argument : The file name of the dll, that contains the loader
1203 if( aArgs.getConstArray()[2].getValueType().getTypeClass() == TypeClass_STRING ) {
1204 aArgs.getConstArray()[2] >>= locationUrl;
1206 if( locationUrl.isEmpty() ) {
1207 throw IllegalArgumentException(
1208 "ImplementationRegistration::initialize() invalid third parameter,"
1209 "expected string, got " + aArgs.getConstArray()[2].getValueTypeName(),
1210 Reference< XInterface > (), 0 );
1213 // 4th argument : The registry, the service should be written to
1214 if( aArgs.getConstArray()[3].getValueType().getTypeClass() == TypeClass_INTERFACE ) {
1215 aArgs.getConstArray()[3] >>= rReg;
1218 if( !rReg.is() ) {
1219 rReg = getRegistryFromServiceManager();
1220 if( !rReg.is() ) {
1221 throw IllegalArgumentException(
1222 "ImplementationRegistration::initialize() invalid fourth parameter,"
1223 "expected " + cppu::UnoType<decltype(rReg)>::get().getTypeName() +
1224 ", got " + aArgs.getConstArray()[3].getValueTypeName(),
1225 Reference< XInterface > (), 0 );
1229 doRegister(m_xSMgr, m_xCtx, rLoader , rReg, loaderServiceName , locationUrl, locationUrl);
1233 // virtual function registerImplementationWithLocation of XImplementationRegistration2
1235 void ImplementationRegistration::registerImplementationWithLocation(
1236 const OUString& implementationLoaderUrl,
1237 const OUString& locationUrl,
1238 const OUString& registeredLocationUrl,
1239 const Reference < XSimpleRegistry > & xReg)
1241 prepareRegister(
1242 implementationLoaderUrl, locationUrl, registeredLocationUrl, xReg);
1245 // helper function
1246 void ImplementationRegistration::prepareRegister(
1247 const OUString& implementationLoaderUrl,
1248 const OUString& locationUrl,
1249 const OUString& registeredLocationUrl,
1250 const Reference < XSimpleRegistry > & xReg)
1251 // throw( CannotRegisterImplementationException, RuntimeException )
1253 OUString activatorName;
1255 if (!implementationLoaderUrl.isEmpty())
1257 activatorName = implementationLoaderUrl.getToken(0, ':');
1258 } else
1260 // check locationUrl to find out what kind of loader is needed
1261 // set implLoaderUrl
1264 if( !m_xSMgr.is() ) {
1265 throw CannotRegisterImplementationException(
1266 "ImplementationRegistration::registerImplementation() "
1267 "no componentcontext available to instantiate loader" );
1272 Reference < XImplementationLoader > xAct(
1273 m_xSMgr->createInstanceWithContext(activatorName, m_xCtx) , UNO_QUERY );
1274 if (!xAct.is())
1276 throw CannotRegisterImplementationException(
1277 "ImplementationRegistration::registerImplementation() - The service "
1278 + activatorName + " cannot be instantiated" );
1281 Reference < XSimpleRegistry > xRegistry;
1283 if (xReg.is())
1285 // registry supplied by user
1286 xRegistry = xReg;
1288 else
1290 xRegistry = getRegistryFromServiceManager();
1293 if ( xRegistry.is())
1295 doRegister(m_xSMgr, m_xCtx, xAct, xRegistry, implementationLoaderUrl,
1296 locationUrl, registeredLocationUrl);
1300 catch( CannotRegisterImplementationException & )
1302 throw;
1304 catch( const InvalidRegistryException & e )
1306 throw CannotRegisterImplementationException(
1307 "ImplementationRegistration::registerImplementation() "
1308 "InvalidRegistryException during registration (" + e.Message + ")" );
1310 catch( const MergeConflictException & e )
1312 throw CannotRegisterImplementationException(
1313 "ImplementationRegistration::registerImplementation() "
1314 "MergeConflictException during registration (" + e.Message + ")" );
1320 // virtual function registerImplementation of XImplementationRegistration
1322 void ImplementationRegistration::registerImplementation(
1323 const OUString& implementationLoaderUrl,
1324 const OUString& locationUrl,
1325 const Reference < XSimpleRegistry > & xReg)
1327 prepareRegister(implementationLoaderUrl, locationUrl, locationUrl, xReg);
1331 // virtual function revokeImplementation of XImplementationRegistration
1333 sal_Bool ImplementationRegistration::revokeImplementation(const OUString& location,
1334 const Reference < XSimpleRegistry >& xReg)
1336 bool ret = false;
1338 Reference < XSimpleRegistry > xRegistry;
1340 if (xReg.is()) {
1341 xRegistry = xReg;
1343 else {
1344 Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY );
1345 if( xPropSet.is() ) {
1346 try {
1347 Any aAny = xPropSet->getPropertyValue( Registry );
1349 if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE )
1351 aAny >>= xRegistry;
1354 catch ( UnknownPropertyException & ) {
1359 if (xRegistry.is())
1363 doRevoke(xRegistry, location);
1364 ret = true;
1366 catch( InvalidRegistryException & )
1368 // no way to transport the error, as no exception is specified and a runtime
1369 // exception is not appropriate.
1370 TOOLS_WARN_EXCEPTION( "stoc", "InvalidRegistryException during revokeImplementation" );
1374 return ret;
1378 // virtual function getImplementations of XImplementationRegistration
1380 Sequence< OUString > ImplementationRegistration::getImplementations(
1381 const OUString & implementationLoaderUrl,
1382 const OUString & locationUrl)
1384 OUString activatorName;
1386 if (!implementationLoaderUrl.isEmpty())
1388 activatorName = implementationLoaderUrl.getToken(0, ':');
1389 } else
1391 // check locationUrl to find out what kind of loader is needed
1392 // set implementationLoaderUrl
1395 if( m_xSMgr.is() ) {
1397 Reference < XImplementationLoader > xAct(
1398 m_xSMgr->createInstanceWithContext( activatorName, m_xCtx ), UNO_QUERY );
1400 if (xAct.is())
1403 Reference < XSimpleRegistry > xReg =
1404 createTemporarySimpleRegistry( m_xSMgr, m_xCtx);
1406 if (xReg.is())
1410 xReg->open(OUString() /* in mem */, false, true);
1411 Reference < XRegistryKey > xImpl;
1413 { // only necessary for deleting the temporary variable of rootkey
1414 xImpl = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS );
1416 if (xAct->writeRegistryInfo(xImpl, implementationLoaderUrl, locationUrl))
1418 std::vector<OUString> implNames;
1420 findImplementations(xImpl, implNames);
1422 if (!implNames.empty())
1424 Sequence<OUString> seqImpl(comphelper::containerToSequence(implNames));
1425 xImpl->closeKey();
1426 return seqImpl;
1430 xImpl->closeKey();
1432 catch(MergeConflictException&)
1435 catch(InvalidRegistryException&)
1442 return Sequence<OUString>();
1446 // virtual function checkInstantiation of XImplementationRegistration
1448 Sequence< OUString > ImplementationRegistration::checkInstantiation(const OUString&)
1450 OSL_FAIL( "ImplementationRegistration::checkInstantiation not implemented" );
1451 return Sequence<OUString>();
1455 // helper function doRegistration
1458 void ImplementationRegistration::doRevoke(
1459 const Reference < XSimpleRegistry >& xDest,
1460 std::u16string_view locationUrl)
1461 // throw ( InvalidRegistryException, RuntimeException )
1463 if( !xDest.is() )
1464 return;
1466 std::vector<OUString> aNames;
1468 Reference < XRegistryKey > xRootKey( xDest->getRootKey() );
1470 Reference < XRegistryKey > xKey =
1471 xRootKey->openKey( slash_IMPLEMENTATIONS );
1472 if (xKey.is() && xKey->isValid())
1474 deleteAllImplementations(xDest, xKey, locationUrl, aNames);
1477 xKey = xRootKey->openKey( slash_SERVICES );
1478 if (xKey.is())
1480 for (auto const& name : aNames)
1482 deleteAllServiceEntries(xDest, xKey, name);
1486 xKey = xRootKey->openKey( "/SINGLETONS" );
1487 if (xKey.is() && xKey->isValid())
1489 delete_all_singleton_entries( xKey, aNames );
1492 if (xRootKey.is())
1493 xRootKey->closeKey();
1494 if (xKey.is() && xKey->isValid() )
1495 xKey->closeKey();
1498 void ImplementationRegistration::doRegister(
1499 const Reference< XMultiComponentFactory > & xSMgr,
1500 const Reference< XComponentContext > &xCtx,
1501 const Reference < XImplementationLoader > & xAct,
1502 const Reference < XSimpleRegistry >& xDest,
1503 const OUString& implementationLoaderUrl,
1504 const OUString& locationUrl,
1505 const OUString& registeredLocationUrl)
1506 /* throw ( InvalidRegistryException,
1507 MergeConflictException,
1508 CannotRegisterImplementationException, RuntimeException ) */
1510 Reference < XSimpleRegistry > xReg =
1511 createTemporarySimpleRegistry( xSMgr, xCtx );
1512 Reference < XRegistryKey > xSourceKey;
1514 if (!(xAct.is() && xReg.is() && xDest.is()))
1515 return;
1519 xReg->open(OUString() /* in mem */, false, true);
1521 { // only necessary for deleting the temporary variable of rootkey
1522 xSourceKey = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS );
1525 bool bSuccess =
1526 xAct->writeRegistryInfo(xSourceKey, implementationLoaderUrl, locationUrl);
1527 if ( !bSuccess )
1529 throw CannotRegisterImplementationException(
1530 "ImplementationRegistration::doRegistration() component registration signaled failure" );
1533 prepareRegistry(xDest, xSourceKey, implementationLoaderUrl, registeredLocationUrl, xCtx);
1535 xSourceKey->closeKey();
1537 xSourceKey = xReg->getRootKey();
1538 Reference < XRegistryKey > xDestKey = xDest->getRootKey();
1539 stoc_impreg::mergeKeys( xDestKey, xSourceKey );
1540 xDestKey->closeKey();
1541 xSourceKey->closeKey();
1544 // Cleanup Source registry.
1545 if ( xSourceKey->isValid() )
1546 xSourceKey->closeKey();
1548 catch(CannotRegisterImplementationException&)
1550 if ( xSourceKey->isValid() )
1551 xSourceKey->closeKey();
1552 // and throw again
1553 throw;
1558 Reference< XSimpleRegistry > ImplementationRegistration::createTemporarySimpleRegistry(
1559 const Reference< XMultiComponentFactory > &rSMgr,
1560 const Reference < XComponentContext > & xCtx)
1563 Reference < XSimpleRegistry > xReg(
1564 rSMgr->createInstanceWithContext(
1565 com_sun_star_registry_SimpleRegistry, xCtx ),
1566 UNO_QUERY);
1567 OSL_ASSERT( xReg.is() );
1568 return xReg;
1573 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1574 com_sun_star_comp_stoc_ImplementationRegistration_get_implementation(
1575 css::uno::XComponentContext *context,
1576 css::uno::Sequence<css::uno::Any> const &)
1578 return cppu::acquire(new ImplementationRegistration(context));
1581 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */