/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mergekeys.hxx" #if defined(_WIN32) #include #endif using namespace com::sun::star; using namespace css::uno; using namespace css::loader; using namespace css::beans; using namespace css::lang; using namespace css::registry; using namespace cppu; using namespace osl; namespace { static constexpr OUStringLiteral slash_UNO_slash_REGISTRY_LINKS = "/UNO/REGISTRY_LINKS"; static constexpr OUStringLiteral slash_IMPLEMENTATIONS = "/IMPLEMENTATIONS"; static constexpr OUStringLiteral slash_UNO = "/UNO"; static constexpr OUStringLiteral slash_UNO_slash_SERVICES = "/UNO/SERVICES"; static constexpr OUStringLiteral slash_UNO_slash_SINGLETONS = "/UNO/SINGLETONS"; static constexpr OUStringLiteral slash_SERVICES = "/SERVICES/"; static constexpr OUStringLiteral slash_UNO_slash_LOCATION = "/UNO/LOCATION"; static constexpr OUStringLiteral slash_UNO_slash_ACTIVATOR = "/UNO/ACTIVATOR"; static constexpr OUStringLiteral colon_old = ":old"; static constexpr OUStringLiteral com_sun_star_registry_SimpleRegistry = "com.sun.star.registry.SimpleRegistry"; static constexpr OUStringLiteral Registry = "Registry"; // static deleteAllLinkReferences() void deleteAllLinkReferences(const Reference < XSimpleRegistry >& xReg, const Reference < XRegistryKey >& xSource) // throw ( InvalidRegistryException, RuntimeException ) { Reference < XRegistryKey > xKey = xSource->openKey( slash_UNO_slash_REGISTRY_LINKS ); if (!(xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST))) return; const Sequence linkNames = xKey->getAsciiListValue(); if (!linkNames.hasElements()) return; OUString aLinkName; OUString aLinkParent; Reference < XRegistryKey > xLinkParent; const sal_Unicode* pTmpName = nullptr; const sal_Unicode* pShortName = nullptr; sal_Int32 sEnd = 0; for (const OUString& rLinkName : linkNames) { aLinkName = rLinkName; pTmpName = aLinkName.getStr(); if (pTmpName[0] != L'/') continue; sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' ); if ( nIndex == -1 ) pShortName = nullptr; else pShortName = pTmpName+nIndex; while (pShortName && pShortName[1] == L'%') { nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' ); if ( nIndex == -1 ) pShortName = nullptr; else pShortName += nIndex+2; } if (pShortName) { aLinkName = aLinkName.copy(0, pShortName - pTmpName); } xReg->getRootKey()->deleteLink(aLinkName); sEnd = aLinkName.lastIndexOf( '/' ); aLinkParent = aLinkName.copy(0, sEnd); while(!aLinkParent.isEmpty()) { xLinkParent = xReg->getRootKey()->openKey(aLinkParent); if (xLinkParent.is() && !xLinkParent->getKeyNames().hasElements()) { aLinkName = aLinkParent; xReg->getRootKey()->deleteKey(aLinkParent); sEnd = aLinkName.lastIndexOf( '/' ); aLinkParent = aLinkName.copy(0, sEnd); } else { break; } } } } // static prepareLink void prepareLink( const Reference < XSimpleRegistry > & xDest, const Reference < XRegistryKey > & xSource, const OUString& link) // throw ( InvalidRegistryException, RuntimeException ) { OUString linkRefName = xSource->getKeyName(); OUString linkName(link); bool isRelativ = false; const sal_Unicode* pTmpName = link.getStr(); const sal_Unicode* pShortName; sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' ); if ( nIndex == -1 ) pShortName = nullptr; else pShortName = pTmpName+nIndex; if (pTmpName[0] != L'/') isRelativ = true; while (pShortName && pShortName[1] == L'%') { nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' ); if ( nIndex == -1 ) pShortName = nullptr; else pShortName += nIndex+2; } if (pShortName) { linkRefName += link.copy(pShortName - pTmpName + 1); linkName = link.copy(0, pShortName - pTmpName); } if (isRelativ) xSource->createLink(linkName, linkRefName); else xDest->getRootKey()->createLink(linkName, linkRefName); } // static searchImplForLink OUString searchImplForLink( const Reference < XRegistryKey > & xRootKey, const OUString& linkName, const OUString& implName ) // throw ( InvalidRegistryException, RuntimeException ) { Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS ); if (xKey.is()) { const Sequence< Reference < XRegistryKey > > subKeys( xKey->openKeys() ); OUString key_name( slash_UNO + linkName ); for (const Reference < XRegistryKey >& xImplKey : subKeys) { try { if (xImplKey->getKeyType( key_name ) == RegistryKeyType_LINK) { OUString oldImplName = xImplKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/")); if (implName != oldImplName) { return oldImplName; } } } catch(InvalidRegistryException&) { } } } return OUString(); } // static searchLinkTargetForImpl OUString searchLinkTargetForImpl(const Reference < XRegistryKey >& xRootKey, const OUString& linkName, const OUString& implName) { Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS ); if (xKey.is()) { Sequence< Reference < XRegistryKey > > subKeys = xKey->openKeys(); OUString qualifiedLinkName( slash_UNO + linkName ); auto pSubKey = std::find_if(subKeys.begin(), subKeys.end(), [&implName, &qualifiedLinkName](const Reference& rSubKey) { OUString tmpImplName = rSubKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/")); return tmpImplName == implName && rSubKey->getKeyType( qualifiedLinkName ) == RegistryKeyType_LINK; }); if (pSubKey != subKeys.end()) return (*pSubKey)->getLinkTarget( qualifiedLinkName ); } return OUString(); } // static createUniqueSubEntry void createUniqueSubEntry(const Reference < XRegistryKey > & xSuperKey, const OUString& value) // throw ( InvalidRegistryException, RuntimeException ) { if (!xSuperKey.is()) return; if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST) { Sequence implEntries = xSuperKey->getAsciiListValue(); sal_Int32 length = implEntries.getLength(); bool bReady = comphelper::findValue(implEntries, value) != -1; if (bReady) { Sequence implEntriesNew(length); implEntriesNew.getArray()[0] = value; std::copy_if(implEntries.begin(), implEntries.end(), std::next(implEntriesNew.begin()), [&value](const OUString& rEntry) { return rEntry != value; }); xSuperKey->setAsciiListValue(implEntriesNew); } else { Sequence implEntriesNew(length+1); implEntriesNew.getArray()[0] = value; std::copy(implEntries.begin(), implEntries.end(), std::next(implEntriesNew.begin())); xSuperKey->setAsciiListValue(implEntriesNew); } } else { Sequence implEntriesNew { value }; xSuperKey->setAsciiListValue(implEntriesNew); } } // static deleteSubEntry bool deleteSubEntry(const Reference < XRegistryKey >& xSuperKey, const OUString& value) // throw ( InvalidRegistryException, RuntimeException ) { if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST) { Sequence implEntries = xSuperKey->getAsciiListValue(); sal_Int32 length = implEntries.getLength(); sal_Int32 equals = static_cast(std::count(implEntries.begin(), implEntries.end(), value)); bool hasNoImplementations = false; if (equals == length) { hasNoImplementations = true; } else { Sequence implEntriesNew(length - equals); std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.begin(), [&value](const OUString& rEntry) { return rEntry != value; }); xSuperKey->setAsciiListValue(implEntriesNew); } if (hasNoImplementations) { return true; } } return false; } // static prepareUserLink void prepareUserLink(const Reference < XSimpleRegistry >& xDest, const OUString& linkName, const OUString& linkTarget, const OUString& implName) { Reference < XRegistryKey > xRootKey = xDest->getRootKey(); if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK) { OUString oldImplName(searchImplForLink(xRootKey, linkName, implName)); if (!oldImplName.isEmpty()) { createUniqueSubEntry(xDest->getRootKey()->createKey( linkName + colon_old ), oldImplName); } } if (xRootKey->isValid()) xRootKey->createLink(linkName, linkTarget); } // static deleteUserLink void deletePathIfPossible(const Reference < XRegistryKey >& xRootKey, const OUString& path) { try { Sequence keyNames(xRootKey->openKey(path)->getKeyNames()); if (!keyNames.hasElements() && xRootKey->openKey(path)->getValueType() == RegistryValueType_NOT_DEFINED) { xRootKey->deleteKey(path); OUString newPath = path.copy(0, path.lastIndexOf('/')); if (newPath.getLength() > 1) deletePathIfPossible(xRootKey, newPath); } } catch(InvalidRegistryException&) { } } // static deleteUserLink void deleteUserLink(const Reference < XRegistryKey >& xRootKey, const OUString& linkName, const OUString& linkTarget, const OUString& implName) // throw ( InvalidRegistryException, RuntimeException ) { bool bClean = false; if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK) { OUString tmpTarget = xRootKey->getLinkTarget(linkName); if (tmpTarget == linkTarget) { xRootKey->deleteLink(linkName); } } Reference < XRegistryKey > xOldKey = xRootKey->openKey( linkName + colon_old ); if (xOldKey.is()) { if (xOldKey->getValueType() == RegistryValueType_ASCIILIST) { Sequence implEntries = xOldKey->getAsciiListValue(); sal_Int32 length = implEntries.getLength(); sal_Int32 equals = static_cast(std::count(implEntries.begin(), implEntries.end(), implName)); bool hasNoImplementations = false; if (equals == length) { hasNoImplementations = true; } else { OUString oldImpl; if (length > equals + 1) { Sequence implEntriesNew(length - equals - 1); sal_Int32 j = 0; bool first = true; for (sal_Int32 i = 0; i < length; i++) { if (implEntries.getConstArray()[i] != implName) { if (first) { oldImpl = implEntries.getConstArray()[i]; first = false; } else { implEntriesNew.getArray()[j++] = implEntries.getConstArray()[i]; } } } xOldKey->setAsciiListValue(implEntriesNew); } else { oldImpl = implEntries.getConstArray()[0]; OUString path(xOldKey->getKeyName()); xOldKey->closeKey(); xRootKey->deleteKey(path); } OUString oldTarget = searchLinkTargetForImpl(xRootKey, linkName, oldImpl); if (!oldTarget.isEmpty()) { xRootKey->createLink(linkName, oldTarget); } } if (hasNoImplementations) { bClean = true; OUString path(xOldKey->getKeyName()); xOldKey->closeKey(); xRootKey->deleteKey(path); } } } else { bClean = true; } if (bClean) { OUString path = linkName.copy(0, linkName.lastIndexOf('/')); deletePathIfPossible(xRootKey, path); } } // static prepareUserKeys void prepareUserKeys(const Reference < XSimpleRegistry >& xDest, const Reference < XRegistryKey >& xUnoKey, const Reference < XRegistryKey >& xKey, const OUString& implName, bool bRegister) { bool hasSubKeys = false; Sequence keyNames = xKey->getKeyNames(); OUString relativKey; if (keyNames.hasElements()) relativKey = keyNames.getConstArray()[0].copy(xKey->getKeyName().getLength()+1); if (keyNames.getLength() == 1 && xKey->getKeyType(relativKey) == RegistryKeyType_LINK) { hasSubKeys = true; OUString linkTarget = xKey->getLinkTarget(relativKey); OUString linkName(xKey->getKeyName().copy(xUnoKey->getKeyName().getLength())); linkName += "/" + relativKey; if (bRegister) { prepareUserLink(xDest, linkName, linkTarget, implName); } else { deleteUserLink(xDest->getRootKey(), linkName, linkTarget, implName); } } else { const Sequence< Reference < XRegistryKey> > subKeys = xKey->openKeys(); if (subKeys.hasElements()) { hasSubKeys = true; for (const Reference < XRegistryKey > & rSubKey : subKeys) { prepareUserKeys(xDest, xUnoKey, rSubKey, implName, bRegister); } } } if (hasSubKeys) return; OUString keyName(xKey->getKeyName().copy(xUnoKey->getKeyName().getLength())); Reference < XRegistryKey > xRootKey = xDest->getRootKey(); if (bRegister) { createUniqueSubEntry(xRootKey->createKey(keyName), implName); } else { Reference< XRegistryKey > rKey = xRootKey->openKey(keyName); if( rKey.is() ) { deleteSubEntry(rKey, implName); xRootKey->deleteKey(keyName); } OUString path = keyName.copy(0, keyName.lastIndexOf('/')); if( !path.isEmpty() ) { deletePathIfPossible(xRootKey, path); } } } // static deleteAllImplementations void deleteAllImplementations( const Reference < XSimpleRegistry >& xReg, const Reference < XRegistryKey >& xSource, const OUString& locationUrl, std::vector & implNames) // throw (InvalidRegistryException, RuntimeException) { Sequence < Reference < XRegistryKey > > subKeys = xSource->openKeys(); if (subKeys.hasElements()) { bool hasLocationUrl = false; for (const Reference < XRegistryKey> & xImplKey : std::as_const(subKeys)) { Reference < XRegistryKey > xKey = xImplKey->openKey( slash_UNO_slash_LOCATION ); if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCII)) { if (xKey->getAsciiValue() == locationUrl) { hasLocationUrl = true; OUString implName(xImplKey->getKeyName().copy(1)); sal_Int32 firstDot = implName.indexOf('/'); if (firstDot >= 0) implName = implName.copy(firstDot + 1); implNames.push_back(implName); deleteAllLinkReferences(xReg, xImplKey); xKey = xImplKey->openKey( slash_UNO ); if (xKey.is()) { const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys(); for (const Reference < XRegistryKey > & rSubKey2 : subKeys2) { if (rSubKey2->getKeyName() != (xImplKey->getKeyName() + slash_UNO_slash_SERVICES ) && rSubKey2->getKeyName() != (xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) && rSubKey2->getKeyName() != (xImplKey->getKeyName() + slash_UNO_slash_ACTIVATOR ) && rSubKey2->getKeyName() != (xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ) && rSubKey2->getKeyName() != (xImplKey->getKeyName() + slash_UNO_slash_LOCATION) ) { prepareUserKeys(xReg, xKey, rSubKey2, implName, false); } } } } } if (hasLocationUrl) { hasLocationUrl = false; OUString path(xImplKey->getKeyName()); xImplKey->closeKey(); xReg->getRootKey()->deleteKey(path); } } subKeys = xSource->openKeys(); if (!subKeys.hasElements()) { OUString path(xSource->getKeyName()); xSource->closeKey(); xReg->getRootKey()->deleteKey(path); } } else { OUString path(xSource->getKeyName()); xSource->closeKey(); xReg->getRootKey()->deleteKey(path); } } void delete_all_singleton_entries( Reference < registry::XRegistryKey > const & xSingletons_section, ::std::vector< OUString > const & impl_names ) // throw (InvalidRegistryException, RuntimeException) { Sequence< Reference< registry::XRegistryKey > > singletons( xSingletons_section->openKeys() ); Reference< registry::XRegistryKey > const * subkeys = singletons.getConstArray(); for ( sal_Int32 nPos = singletons.getLength(); nPos--; ) { Reference< registry::XRegistryKey > const & xSingleton = subkeys[ nPos ]; Reference< registry::XRegistryKey > xRegisteredImplNames( xSingleton->openKey( "REGISTERED_BY" ) ); if (xRegisteredImplNames.is() && xRegisteredImplNames->isValid()) { Sequence< OUString > registered_implnames; try { registered_implnames = xRegisteredImplNames->getAsciiListValue(); } catch (registry::InvalidValueException &) { } OUString const * p = registered_implnames.getConstArray(); sal_Int32 nOrigRegLength = registered_implnames.getLength(); sal_Int32 nNewLength = nOrigRegLength; for ( sal_Int32 n = nOrigRegLength; n--; ) { OUString const & registered_implname = p[ n ]; for (auto const& impl_name : impl_names) { if (impl_name == registered_implname) { registered_implnames[ n ] = p[ nNewLength -1 ]; --nNewLength; } } } if (nNewLength != nOrigRegLength) { if (0 == nNewLength) { // remove whole entry xRegisteredImplNames->closeKey(); xSingleton->deleteKey( "REGISTERED_BY" ); // registry key cannot provide its relative name, only absolute :( OUString abs( xSingleton->getKeyName() ); xSingletons_section->deleteKey( abs.copy( abs.lastIndexOf( '/' ) +1 ) ); } else { registered_implnames.realloc( nNewLength ); xRegisteredImplNames->setAsciiListValue( registered_implnames ); } } } } } // static deleteAllServiceEntries void deleteAllServiceEntries( const Reference < XSimpleRegistry >& xReg, const Reference < XRegistryKey >& xSource, const OUString& implName) // throw ( InvalidRegistryException, RuntimeException ) { Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys(); if (subKeys.hasElements()) { bool hasNoImplementations = false; for (const Reference < XRegistryKey > & xServiceKey : std::as_const(subKeys)) { if (xServiceKey->getValueType() == RegistryValueType_ASCIILIST) { Sequence implEntries = xServiceKey->getAsciiListValue(); sal_Int32 length = implEntries.getLength(); sal_Int32 equals = static_cast(std::count(implEntries.begin(), implEntries.end(), implName)); if (equals == length) { hasNoImplementations = true; } else { if (equals > 0) { Sequence implEntriesNew(length-equals); std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.begin(), [&implName](const OUString& rEntry) { return rEntry != implName; }); xServiceKey->setAsciiListValue(implEntriesNew); } } } if (hasNoImplementations) { hasNoImplementations = false; OUString path(xServiceKey->getKeyName()); xServiceKey->closeKey(); xReg->getRootKey()->deleteKey(path); } } subKeys = xSource->openKeys(); if (!subKeys.hasElements()) { OUString path(xSource->getKeyName()); xSource->closeKey(); xReg->getRootKey()->deleteKey(path); } } else { OUString path(xSource->getKeyName()); xSource->closeKey(); xReg->getRootKey()->deleteKey(path); } } bool is_supported_service( OUString const & service_name, Reference< reflection::XServiceTypeDescription > const & xService_td ) { if (xService_td->getName() == service_name) return true; Sequence< Reference< reflection::XServiceTypeDescription > > seq( xService_td->getMandatoryServices() ); return std::any_of(seq.begin(), seq.end(), [&service_name](const auto& rService) { return is_supported_service( service_name, rService ); }); } void insert_singletons( Reference< registry::XSimpleRegistry > const & xDest, Reference< registry::XRegistryKey > const & xImplKey, Reference< XComponentContext > const & xContext ) // throw( registry::InvalidRegistryException, registry::CannotRegisterImplementationException, RuntimeException ) { // singletons Reference< registry::XRegistryKey > xKey( xImplKey->openKey( "UNO/SINGLETONS" ) ); if (!(xKey.is() && xKey->isValid())) return; OUString implname( xImplKey->getKeyName().copy( sizeof ("/IMPLEMENTATIONS/") -1 ) ); // singleton entries Sequence< Reference< registry::XRegistryKey > > xSingletons_section( xKey->openKeys() ); Reference< registry::XRegistryKey > const * p = xSingletons_section.getConstArray(); for ( sal_Int32 nPos = xSingletons_section.getLength(); nPos--; ) { Reference< registry::XRegistryKey > const & xSingleton = p[ nPos ]; OUString singleton_name( xSingleton->getKeyName().copy( implname.getLength() + sizeof ("/IMPLEMENTATIONS//UNO/SINGLETONS/") -1 ) ); OUString service_name( xSingleton->getStringValue() ); OUString keyname( "/SINGLETONS/" + singleton_name ); Reference< registry::XRegistryKey > xKey2( xDest->getRootKey()->openKey( keyname ) ); if (xKey2.is() && xKey2->isValid()) { try { OUString existing_name( xKey2->getStringValue() ); if ( existing_name != service_name ) { Reference< container::XHierarchicalNameAccess > xTDMgr; OUString the_tdmgr = "/singletons/com.sun.star.reflection.theTypeDescriptionManager"; xContext->getValueByName( the_tdmgr ) >>= xTDMgr; if (! xTDMgr.is()) { throw RuntimeException( "cannot get singleton " + the_tdmgr ); } try { Reference< reflection::XServiceTypeDescription > xExistingService_td; xTDMgr->getByHierarchicalName( existing_name ) >>= xExistingService_td; if (! xExistingService_td.is()) { throw RuntimeException( "cannot get service type description: " + existing_name ); } // everything's fine if existing service entry supports the one // to be registered if (! is_supported_service( service_name, xExistingService_td )) { throw registry::CannotRegisterImplementationException( "existing singleton service (" + singleton_name + "=" + existing_name + ") " " does not support given one: " + service_name); } } catch (const container::NoSuchElementException & exc) { css::uno::Any anyEx = cppu::getCaughtException(); throw css::lang::WrappedTargetRuntimeException( "cannot get service type description: " + exc.Message, nullptr, anyEx ); } } } catch (registry::InvalidValueException &) { // repair xKey2->setStringValue( service_name ); } } else { // insert singleton entry xKey2 = xDest->getRootKey()->createKey( keyname ); xKey2->setStringValue( service_name ); } Reference< registry::XRegistryKey > xRegisteredImplNames( xKey2->openKey( "REGISTERED_BY" ) ); if (!xRegisteredImplNames.is() || !xRegisteredImplNames->isValid()) { // create xRegisteredImplNames = xKey2->createKey( "REGISTERED_BY" ); } Sequence< OUString > implnames; try { implnames = xRegisteredImplNames->getAsciiListValue(); } catch (registry::InvalidValueException &) { } // check implname is already in if (comphelper::findValue(implnames, implname) == -1) { // append and write back implnames.realloc( implnames.getLength() +1 ); implnames[ implnames.getLength() -1 ] = implname; xRegisteredImplNames->setAsciiListValue( implnames ); } } } // static prepareRegistry void prepareRegistry( const Reference < XSimpleRegistry >& xDest, const Reference < XRegistryKey >& xSource, const OUString& implementationLoaderUrl, const OUString& locationUrl, Reference< XComponentContext > const & xContext ) // throw ( InvalidRegistryException, CannotRegisterImplementationException, RuntimeException ) { const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys(); if (!subKeys.hasElements()) { throw InvalidRegistryException( "prepareRegistry(): source registry is empty" ); } for (const Reference < XRegistryKey >& xImplKey : subKeys) { Reference < XRegistryKey > xKey = xImplKey->openKey( slash_UNO_slash_SERVICES ); if (xKey.is()) { // update entries in SERVICES section const Sequence< Reference < XRegistryKey > > serviceKeys = xKey->openKeys(); OUString implName = xImplKey->getKeyName().copy(1); sal_Int32 firstDot = implName.indexOf('/'); if (firstDot >= 0) implName = implName.copy(firstDot + 1); sal_Int32 offset = xKey->getKeyName().getLength() + 1; for (const Reference < XRegistryKey >& rServiceKey : serviceKeys) { OUString serviceName = rServiceKey->getKeyName().copy(offset); createUniqueSubEntry( xDest->getRootKey()->createKey( slash_SERVICES + serviceName ), implName); } xKey = xImplKey->openKey( slash_UNO ); if (xKey.is()) { const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys(); for (const Reference < XRegistryKey >& rSubKey2 : subKeys2) { if (rSubKey2->getKeyName() != (xImplKey->getKeyName() + slash_UNO_slash_SERVICES) && rSubKey2->getKeyName() != (xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) && rSubKey2->getKeyName() != (xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS )) { prepareUserKeys(xDest, xKey, rSubKey2, implName, true); } } } } // update LOCATION entry xKey = xImplKey->createKey( slash_UNO_slash_LOCATION ); if (xKey.is()) { xKey->setAsciiValue(locationUrl); } // update ACTIVATOR entry xKey = xImplKey->createKey( slash_UNO_slash_ACTIVATOR ); if (xKey.is()) { xKey->setAsciiValue(implementationLoaderUrl); } xKey = xImplKey->openKey( slash_UNO_slash_SERVICES ); if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST)) { // update link entries in REGISTRY_LINKS section const Sequence linkNames = xKey->getAsciiListValue(); for (const OUString& rLinkName : linkNames) { prepareLink(xDest, xImplKey, rLinkName); } } insert_singletons( xDest, xImplKey, xContext ); } } void findImplementations( const Reference < XRegistryKey > & xSource, std::vector& implNames) { bool isImplKey = false; try { Reference < XRegistryKey > xKey = xSource->openKey( slash_UNO_slash_SERVICES ); if (xKey.is() && xKey->getKeyNames().hasElements()) { isImplKey = true; OUString implName = xSource->getKeyName().copy(1).replace('/', '.'); sal_Int32 firstDot = implName.indexOf('.'); if (firstDot >= 0) implName = implName.copy(firstDot + 1); implNames.push_back(implName); } } catch(InvalidRegistryException&) { } if (isImplKey) return; try { const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys(); for (const Reference < XRegistryKey >& rSubKey : subKeys) { findImplementations(rSubKey, implNames); } } catch(InvalidRegistryException&) { } } class ImplementationRegistration : public WeakImplHelper< XImplementationRegistration2, XServiceInfo, XInitialization > { public: explicit ImplementationRegistration( const Reference < XComponentContext > & rSMgr ); // XServiceInfo OUString SAL_CALL getImplementationName() override; sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; Sequence< OUString > SAL_CALL getSupportedServiceNames() override; // XImplementationRegistration virtual void SAL_CALL registerImplementation( const OUString& implementationLoader, const OUString& location, const Reference < XSimpleRegistry > & xReg) override; virtual sal_Bool SAL_CALL revokeImplementation( const OUString& location, const Reference < XSimpleRegistry >& xReg) override; virtual Sequence< OUString > SAL_CALL getImplementations( const OUString& implementationLoader, const OUString& location) override; virtual Sequence< OUString > SAL_CALL checkInstantiation( const OUString& implementationName) override; // XImplementationRegistration2 virtual void SAL_CALL registerImplementationWithLocation( const OUString& implementationLoader, const OUString& location, const OUString& registeredLocation, const Reference < XSimpleRegistry > & xReg) override; // XInitialization virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; private: // helper methods void prepareRegister( const OUString& implementationLoader, const OUString& location, const OUString& registeredLocation, const Reference < XSimpleRegistry > & xReg); // throw( CannotRegisterImplementationException, RuntimeException ) static void doRegister( const Reference < XMultiComponentFactory >& xSMgr, const Reference < XComponentContext > &xCtx, const Reference < XImplementationLoader >& xAct, const Reference < XSimpleRegistry >& xDest, const OUString& implementationLoaderUrl, const OUString& locationUrl, const OUString& registeredLocationUrl); /* throw ( InvalidRegistryException, MergeConflictException, CannotRegisterImplementationException, RuntimeException ) */ static void doRevoke( const Reference < XSimpleRegistry >& xDest, const OUString& locationUrl ); // throw( InvalidRegistryException, RuntimeException ) Reference< XSimpleRegistry > getRegistryFromServiceManager() const; static Reference< XSimpleRegistry > createTemporarySimpleRegistry( const Reference< XMultiComponentFactory > &rSMgr, const Reference < XComponentContext > & rCtx ); private: // members Reference < XMultiComponentFactory > m_xSMgr; Reference < XComponentContext > m_xCtx; }; // ImplementationRegistration() ImplementationRegistration::ImplementationRegistration( const Reference < XComponentContext > & xCtx ) : m_xSMgr( xCtx->getServiceManager() ) , m_xCtx( xCtx ) {} // XServiceInfo OUString ImplementationRegistration::getImplementationName() { return "com.sun.star.comp.stoc.ImplementationRegistration"; } // XServiceInfo sal_Bool ImplementationRegistration::supportsService(const OUString& ServiceName) { return cppu::supportsService(this, ServiceName); } // XServiceInfo Sequence< OUString > ImplementationRegistration::getSupportedServiceNames() { return { "com.sun.star.registry.ImplementationRegistration" }; } Reference< XSimpleRegistry > ImplementationRegistration::getRegistryFromServiceManager() const { Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY ); Reference < XSimpleRegistry > xRegistry; if( xPropSet.is() ) { try { // the implementation does not support XIntrospectionAccess ! Any aAny = xPropSet->getPropertyValue( Registry ); if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) { aAny >>= xRegistry; } } catch( UnknownPropertyException & ) { // empty reference is error signal ! } } return xRegistry; } // XInitialization void ImplementationRegistration::initialize( const css::uno::Sequence< css::uno::Any >& aArgs ) { if( aArgs.getLength() != 4 ) { throw IllegalArgumentException( "ImplementationRegistration::initialize() expects 4 parameters, got " + OUString::number( aArgs.getLength() ), Reference (), 0 ); } Reference< XImplementationLoader > rLoader; OUString loaderServiceName; OUString locationUrl; Reference< XSimpleRegistry > rReg; // 1st argument : An instance of an implementation loader if( aArgs.getConstArray()[0].getValueType().getTypeClass() == TypeClass_INTERFACE ) { aArgs.getConstArray()[0] >>= rLoader; } if( !rLoader.is()) { throw IllegalArgumentException( "ImplementationRegistration::initialize() invalid first parameter," "expected " + cppu::UnoType::get().getTypeName() + ", got " + aArgs.getConstArray()[0].getValueTypeName(), Reference< XInterface > (), 0 ); } // 2nd argument : The service name of the loader. This name is written into the registry if( aArgs.getConstArray()[1].getValueType().getTypeClass() == TypeClass_STRING ) { aArgs.getConstArray()[1] >>= loaderServiceName; } if( loaderServiceName.isEmpty() ) { throw IllegalArgumentException( "ImplementationRegistration::initialize() invalid second parameter," "expected string, got " + aArgs.getConstArray()[1].getValueTypeName(), Reference< XInterface > (), 0 ); } // 3rd argument : The file name of the dll, that contains the loader if( aArgs.getConstArray()[2].getValueType().getTypeClass() == TypeClass_STRING ) { aArgs.getConstArray()[2] >>= locationUrl; } if( locationUrl.isEmpty() ) { throw IllegalArgumentException( "ImplementationRegistration::initialize() invalid third parameter," "expected string, got " + aArgs.getConstArray()[2].getValueTypeName(), Reference< XInterface > (), 0 ); } // 4th argument : The registry, the service should be written to if( aArgs.getConstArray()[3].getValueType().getTypeClass() == TypeClass_INTERFACE ) { aArgs.getConstArray()[3] >>= rReg; } if( !rReg.is() ) { rReg = getRegistryFromServiceManager(); if( !rReg.is() ) { throw IllegalArgumentException( "ImplementationRegistration::initialize() invalid fourth parameter," "expected " + cppu::UnoType::get().getTypeName() + ", got " + aArgs.getConstArray()[3].getValueTypeName(), Reference< XInterface > (), 0 ); } } doRegister(m_xSMgr, m_xCtx, rLoader , rReg, loaderServiceName , locationUrl, locationUrl); } // virtual function registerImplementationWithLocation of XImplementationRegistration2 void ImplementationRegistration::registerImplementationWithLocation( const OUString& implementationLoaderUrl, const OUString& locationUrl, const OUString& registeredLocationUrl, const Reference < XSimpleRegistry > & xReg) { prepareRegister( implementationLoaderUrl, locationUrl, registeredLocationUrl, xReg); } // helper function void ImplementationRegistration::prepareRegister( const OUString& implementationLoaderUrl, const OUString& locationUrl, const OUString& registeredLocationUrl, const Reference < XSimpleRegistry > & xReg) // throw( CannotRegisterImplementationException, RuntimeException ) { OUString activatorName; if (!implementationLoaderUrl.isEmpty()) { activatorName = implementationLoaderUrl.getToken(0, ':'); } else { // check locationUrl to find out what kind of loader is needed // set implLoaderUrl } if( !m_xSMgr.is() ) { throw CannotRegisterImplementationException( "ImplementationRegistration::registerImplementation() " "no componentcontext available to instantiate loader" ); } try { Reference < XImplementationLoader > xAct( m_xSMgr->createInstanceWithContext(activatorName, m_xCtx) , UNO_QUERY ); if (!xAct.is()) { throw CannotRegisterImplementationException( "ImplementationRegistration::registerImplementation() - The service " + activatorName + " cannot be instantiated" ); } Reference < XSimpleRegistry > xRegistry; if (xReg.is()) { // registry supplied by user xRegistry = xReg; } else { xRegistry = getRegistryFromServiceManager(); } if ( xRegistry.is()) { doRegister(m_xSMgr, m_xCtx, xAct, xRegistry, implementationLoaderUrl, locationUrl, registeredLocationUrl); } } catch( CannotRegisterImplementationException & ) { throw; } catch( const InvalidRegistryException & e ) { throw CannotRegisterImplementationException( "ImplementationRegistration::registerImplementation() " "InvalidRegistryException during registration (" + e.Message + ")" ); } catch( const MergeConflictException & e ) { throw CannotRegisterImplementationException( "ImplementationRegistration::registerImplementation() " "MergeConflictException during registration (" + e.Message + ")" ); } } // virtual function registerImplementation of XImplementationRegistration void ImplementationRegistration::registerImplementation( const OUString& implementationLoaderUrl, const OUString& locationUrl, const Reference < XSimpleRegistry > & xReg) { prepareRegister(implementationLoaderUrl, locationUrl, locationUrl, xReg); } // virtual function revokeImplementation of XImplementationRegistration sal_Bool ImplementationRegistration::revokeImplementation(const OUString& location, const Reference < XSimpleRegistry >& xReg) { bool ret = false; Reference < XSimpleRegistry > xRegistry; if (xReg.is()) { xRegistry = xReg; } else { Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY ); if( xPropSet.is() ) { try { Any aAny = xPropSet->getPropertyValue( Registry ); if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) { aAny >>= xRegistry; } } catch ( UnknownPropertyException & ) { } } } if (xRegistry.is()) { try { doRevoke(xRegistry, location); ret = true; } catch( InvalidRegistryException & ) { // no way to transport the error, as no exception is specified and a runtime // exception is not appropriate. OSL_FAIL( "InvalidRegistryException during revokeImplementation" ); } } return ret; } // virtual function getImplementations of XImplementationRegistration Sequence< OUString > ImplementationRegistration::getImplementations( const OUString & implementationLoaderUrl, const OUString & locationUrl) { OUString activatorName; if (!implementationLoaderUrl.isEmpty()) { activatorName = implementationLoaderUrl.getToken(0, ':'); } else { // check locationUrl to find out what kind of loader is needed // set implementationLoaderUrl } if( m_xSMgr.is() ) { Reference < XImplementationLoader > xAct( m_xSMgr->createInstanceWithContext( activatorName, m_xCtx ), UNO_QUERY ); if (xAct.is()) { Reference < XSimpleRegistry > xReg = createTemporarySimpleRegistry( m_xSMgr, m_xCtx); if (xReg.is()) { try { xReg->open(OUString() /* in mem */, false, true); Reference < XRegistryKey > xImpl; { // only necessary for deleting the temporary variable of rootkey xImpl = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS ); } if (xAct->writeRegistryInfo(xImpl, implementationLoaderUrl, locationUrl)) { std::vector implNames; findImplementations(xImpl, implNames); if (!implNames.empty()) { Sequence seqImpl(comphelper::containerToSequence(implNames)); xImpl->closeKey(); return seqImpl; } } xImpl->closeKey(); } catch(MergeConflictException&) { } catch(InvalidRegistryException&) { } } } } return Sequence(); } // virtual function checkInstantiation of XImplementationRegistration Sequence< OUString > ImplementationRegistration::checkInstantiation(const OUString&) { OSL_FAIL( "ImplementationRegistration::checkInstantiation not implemented" ); return Sequence(); } // helper function doRegistration void ImplementationRegistration::doRevoke( const Reference < XSimpleRegistry >& xDest, const OUString& locationUrl) // throw ( InvalidRegistryException, RuntimeException ) { if( !xDest.is() ) return; std::vector aNames; Reference < XRegistryKey > xRootKey( xDest->getRootKey() ); Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS ); if (xKey.is() && xKey->isValid()) { deleteAllImplementations(xDest, xKey, locationUrl, aNames); } xKey = xRootKey->openKey( slash_SERVICES ); if (xKey.is()) { for (auto const& name : aNames) { deleteAllServiceEntries(xDest, xKey, name); } } xKey = xRootKey->openKey( "/SINGLETONS" ); if (xKey.is() && xKey->isValid()) { delete_all_singleton_entries( xKey, aNames ); } if (xRootKey.is()) xRootKey->closeKey(); if (xKey.is() && xKey->isValid() ) xKey->closeKey(); } void ImplementationRegistration::doRegister( const Reference< XMultiComponentFactory > & xSMgr, const Reference< XComponentContext > &xCtx, const Reference < XImplementationLoader > & xAct, const Reference < XSimpleRegistry >& xDest, const OUString& implementationLoaderUrl, const OUString& locationUrl, const OUString& registeredLocationUrl) /* throw ( InvalidRegistryException, MergeConflictException, CannotRegisterImplementationException, RuntimeException ) */ { Reference < XSimpleRegistry > xReg = createTemporarySimpleRegistry( xSMgr, xCtx ); Reference < XRegistryKey > xSourceKey; if (!(xAct.is() && xReg.is() && xDest.is())) return; try { xReg->open(OUString() /* in mem */, false, true); { // only necessary for deleting the temporary variable of rootkey xSourceKey = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS ); } bool bSuccess = xAct->writeRegistryInfo(xSourceKey, implementationLoaderUrl, locationUrl); if ( !bSuccess ) { throw CannotRegisterImplementationException( "ImplementationRegistration::doRegistration() component registration signaled failure" ); } prepareRegistry(xDest, xSourceKey, implementationLoaderUrl, registeredLocationUrl, xCtx); xSourceKey->closeKey(); xSourceKey = xReg->getRootKey(); Reference < XRegistryKey > xDestKey = xDest->getRootKey(); stoc_impreg::mergeKeys( xDestKey, xSourceKey ); xDestKey->closeKey(); xSourceKey->closeKey(); // Cleanup Source registry. if ( xSourceKey->isValid() ) xSourceKey->closeKey(); } catch(CannotRegisterImplementationException&) { if ( xSourceKey->isValid() ) xSourceKey->closeKey(); // and throw again throw; } } Reference< XSimpleRegistry > ImplementationRegistration::createTemporarySimpleRegistry( const Reference< XMultiComponentFactory > &rSMgr, const Reference < XComponentContext > & xCtx) { Reference < XSimpleRegistry > xReg( rSMgr->createInstanceWithContext( com_sun_star_registry_SimpleRegistry, xCtx ), UNO_QUERY); OSL_ASSERT( xReg.is() ); return xReg; } } extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_stoc_ImplementationRegistration_get_implementation( css::uno::XComponentContext *context, css::uno::Sequence const &) { return cppu::acquire(new ImplementationRegistration(context)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */