office-gobmx/stoc/source/implementationregistration/implreg.cxx
Stephan Bergmann 33ecd0d5c4 Change OUStringLiteral from char[] to char16_t[]
This is a prerequisite for making conversion from OUStringLiteral to OUString
more efficient at least for C++20 (by replacing its internals with a constexpr-
generated sal_uString-compatible layout with a SAL_STRING_STATIC_FLAG refCount,
conditionally for C++20 for now).

For a configure-wise bare-bones build on Linux, size reported by `du -bs
instdir` grew by 118792 bytes from 1155636636 to 1155755428.

In most places just a u"..." string literal prefix had to be added.  In some
places

  char const a[] = "...";

variables have been changed to char16_t, and a few places required even further
changes to code (which prompted the addition of include/o3tl/string_view.hxx
helper function o3tl::equalsIgnoreAsciiCase and the additional
OUString::createFromAscii overload).

For all uses of macros expanding to string literals, the relevant uses have been
rewritten as

  u"" MACRO

instead of changing the macro definitions.  It should be possible to change at
least some of those macro definitions (and drop the u"" from their call sites)
in follow-up commits.

Change-Id: Iec4ef1a057d412d22443312d40c6a8a290dc6144
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101483
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2020-08-28 08:07:09 +02:00

1576 lines
51 KiB
C++

/* -*- 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 <string.h>
#include <vector>
#include <cppuhelper/exc_hlp.hxx>
#include <cppuhelper/weak.hxx>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <comphelper/sequence.hxx>
#include <rtl/ustring.hxx>
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/loader/XImplementationLoader.hpp>
#include <com/sun/star/registry/XImplementationRegistration2.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/reflection/XServiceTypeDescription.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include "mergekeys.hxx"
#if defined(_WIN32)
#include <io.h>
#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 {
constexpr OUStringLiteral slash_UNO_slash_REGISTRY_LINKS
= u"/UNO/REGISTRY_LINKS";
constexpr OUStringLiteral slash_IMPLEMENTATIONS
= u"/IMPLEMENTATIONS";
constexpr OUStringLiteral slash_UNO
= u"/UNO";
constexpr OUStringLiteral slash_UNO_slash_SERVICES
= u"/UNO/SERVICES";
constexpr OUStringLiteral slash_UNO_slash_SINGLETONS
= u"/UNO/SINGLETONS";
constexpr OUStringLiteral slash_SERVICES
= u"/SERVICES/";
constexpr OUStringLiteral slash_UNO_slash_LOCATION
= u"/UNO/LOCATION";
constexpr OUStringLiteral slash_UNO_slash_ACTIVATOR
= u"/UNO/ACTIVATOR";
constexpr OUStringLiteral colon_old
= u":old";
constexpr OUStringLiteral com_sun_star_registry_SimpleRegistry
= u"com.sun.star.registry.SimpleRegistry";
constexpr OUStringLiteral Registry
= u"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<OUString> 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<XRegistryKey>& 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<OUString> implEntries = xSuperKey->getAsciiListValue();
sal_Int32 length = implEntries.getLength();
bool bReady = comphelper::findValue(implEntries, value) != -1;
if (bReady)
{
Sequence<OUString> 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<OUString> implEntriesNew(length+1);
implEntriesNew.getArray()[0] = value;
std::copy(implEntries.begin(), implEntries.end(), std::next(implEntriesNew.begin()));
xSuperKey->setAsciiListValue(implEntriesNew);
}
} else
{
Sequence<OUString> 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<OUString> implEntries = xSuperKey->getAsciiListValue();
sal_Int32 length = implEntries.getLength();
sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), value));
bool hasNoImplementations = false;
if (equals == length)
{
hasNoImplementations = true;
} else
{
Sequence<OUString> 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<OUString> 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<OUString> implEntries = xOldKey->getAsciiListValue();
sal_Int32 length = implEntries.getLength();
sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
bool hasNoImplementations = false;
if (equals == length)
{
hasNoImplementations = true;
} else
{
OUString oldImpl;
if (length > equals + 1)
{
Sequence<OUString> 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<OUString> 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<OUString> & 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<OUString> implEntries = xServiceKey->getAsciiListValue();
sal_Int32 length = implEntries.getLength();
sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
if (equals == length)
{
hasNoImplementations = true;
} else
{
if (equals > 0)
{
Sequence<OUString> 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<OUString> 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<OUString>& 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<XInterface > (), 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<decltype(rLoader)>::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<decltype(rReg)>::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<OUString> implNames;
findImplementations(xImpl, implNames);
if (!implNames.empty())
{
Sequence<OUString> seqImpl(comphelper::containerToSequence(implNames));
xImpl->closeKey();
return seqImpl;
}
}
xImpl->closeKey();
}
catch(MergeConflictException&)
{
}
catch(InvalidRegistryException&)
{
}
}
}
}
return Sequence<OUString>();
}
// virtual function checkInstantiation of XImplementationRegistration
Sequence< OUString > ImplementationRegistration::checkInstantiation(const OUString&)
{
OSL_FAIL( "ImplementationRegistration::checkInstantiation not implemented" );
return Sequence<OUString>();
}
// helper function doRegistration
void ImplementationRegistration::doRevoke(
const Reference < XSimpleRegistry >& xDest,
const OUString& locationUrl)
// throw ( InvalidRegistryException, RuntimeException )
{
if( !xDest.is() )
return;
std::vector<OUString> 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<css::uno::Any> const &)
{
return cppu::acquire(new ImplementationRegistration(context));
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */