    /* -*- 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 <osl/mutex.hxx>
    #include <cppuhelper/queryinterface.hxx>
    #include <cppuhelper/weak.hxx>
    #include <cppuhelper/implbase.hxx>
    #include <cppuhelper/implbase4.hxx>
    #include <cppuhelper/implementationentry.hxx>
    #include <cppuhelper/supportsservice.hxx>
    #include <registry/registry.hxx>
    #include <rtl/ref.hxx>

    #include <com/sun/star/registry/XSimpleRegistry.hpp>
    #include <com/sun/star/lang/XMultiServiceFactory.hpp>
    #include <com/sun/star/lang/XServiceInfo.hpp>
    #include <com/sun/star/lang/XTypeProvider.hpp>
    #include <com/sun/star/lang/XSingleServiceFactory.hpp>
    #include <com/sun/star/lang/XInitialization.hpp>
    #include <com/sun/star/container/XEnumerationAccess.hpp>

    using namespace css::uno;
    using namespace css::registry;
    using namespace css::lang;
    using namespace css::container;
    using namespace cppu;
    using namespace osl;

    namespace {

    class NestedKeyImpl;

    class NestedRegistryImpl    : public WeakAggImplHelper4 < XSimpleRegistry, XInitialization, XServiceInfo, XEnumerationAccess >
    {
    public:
        NestedRegistryImpl( );

        // XServiceInfo
        virtual OUString SAL_CALL getImplementationName(  ) override;
        virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
        virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(  ) override;

        // XInitialization
        virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;

        // XSimpleRegistry
        virtual OUString SAL_CALL getURL() override;
        virtual void SAL_CALL open( const OUString& rURL, sal_Bool bReadOnly, sal_Bool bCreate ) override;
        virtual sal_Bool SAL_CALL isValid(  ) override;
        virtual void SAL_CALL close(  ) override;
        virtual void SAL_CALL destroy(  ) override;
        virtual Reference< XRegistryKey > SAL_CALL getRootKey(  ) override;
        virtual sal_Bool SAL_CALL isReadOnly(  ) override;
        virtual void SAL_CALL mergeKey( const OUString& aKeyName, const OUString& aUrl ) override;

        // XEnumerationAccess
        virtual Reference< XEnumeration > SAL_CALL createEnumeration(  ) override;
        virtual Type SAL_CALL getElementType(  ) override;
        virtual sal_Bool SAL_CALL hasElements(  ) override;

        friend class NestedKeyImpl;
    protected:
        Mutex                       m_mutex;
        sal_uInt32                  m_state;
        Reference<XSimpleRegistry>  m_localReg;
        Reference<XSimpleRegistry>  m_defaultReg;

    };

    // class NestedKeyImpl the implementation of interface XRegistryKey

    class NestedKeyImpl : public WeakImplHelper< XRegistryKey >
    {
    public:
        NestedKeyImpl( NestedRegistryImpl* pDefaultRegistry,
                       Reference<XRegistryKey>& localKey,
                       Reference<XRegistryKey>& defaultKey);

        NestedKeyImpl( const OUString& aKeyName,
                        NestedKeyImpl* pKey);

        // XRegistryKey
        virtual OUString SAL_CALL getKeyName() override;
        virtual sal_Bool SAL_CALL isReadOnly(  ) override;
        virtual sal_Bool SAL_CALL isValid(  ) override;
        virtual RegistryKeyType SAL_CALL getKeyType( const OUString& rKeyName ) override;
        virtual RegistryValueType SAL_CALL getValueType(  ) override;
        virtual sal_Int32 SAL_CALL getLongValue(  ) override;
        virtual void SAL_CALL setLongValue( sal_Int32 value ) override;
        virtual Sequence< sal_Int32 > SAL_CALL getLongListValue(  ) override;
        virtual void SAL_CALL setLongListValue( const css::uno::Sequence< sal_Int32 >& seqValue ) override;
        virtual OUString SAL_CALL getAsciiValue(  ) override;
        virtual void SAL_CALL setAsciiValue( const OUString& value ) override;
        virtual Sequence< OUString > SAL_CALL getAsciiListValue(  ) override;
        virtual void SAL_CALL setAsciiListValue( const css::uno::Sequence< OUString >& seqValue ) override;
        virtual OUString SAL_CALL getStringValue(  ) override;
        virtual void SAL_CALL setStringValue( const OUString& value ) override;
        virtual Sequence< OUString > SAL_CALL getStringListValue(  ) override;
        virtual void SAL_CALL setStringListValue( const css::uno::Sequence< OUString >& seqValue ) override;
        virtual Sequence< sal_Int8 > SAL_CALL getBinaryValue(  ) override;
        virtual void SAL_CALL setBinaryValue( const css::uno::Sequence< sal_Int8 >& value ) override;
        virtual Reference< XRegistryKey > SAL_CALL openKey( const OUString& aKeyName ) override;
        virtual Reference< XRegistryKey > SAL_CALL createKey( const OUString& aKeyName ) override;
        virtual void SAL_CALL closeKey(  ) override;
        virtual void SAL_CALL deleteKey( const OUString& rKeyName ) override;
        virtual Sequence< Reference< XRegistryKey > > SAL_CALL openKeys(  ) override;
        virtual Sequence< OUString > SAL_CALL getKeyNames(  ) override;
        virtual sal_Bool SAL_CALL createLink( const OUString& aLinkName, const OUString& aLinkTarget ) override;
        virtual void SAL_CALL deleteLink( const OUString& rLinkName ) override;
        virtual OUString SAL_CALL getLinkTarget( const OUString& rLinkName ) override;
        virtual OUString SAL_CALL getResolvedName( const OUString& aKeyName ) override;

    protected:
        void        computeChanges();
        OUString    computeName(const OUString& name);

        OUString                    m_name;
        sal_uInt32                  m_state;
        rtl::Reference<NestedRegistryImpl> m_xRegistry;
        Reference<XRegistryKey>     m_localKey;
        Reference<XRegistryKey>     m_defaultKey;
    };

    NestedKeyImpl::NestedKeyImpl( NestedRegistryImpl* pDefaultRegistry,
                                  Reference<XRegistryKey>& localKey,
                                  Reference<XRegistryKey>& defaultKey )
        : m_xRegistry(pDefaultRegistry)
    {
        m_localKey = localKey;
        m_defaultKey = defaultKey;

        if (m_localKey.is())
        {
            m_name = m_localKey->getKeyName();
        }
        else if (m_defaultKey.is())
        {
            m_name = m_defaultKey->getKeyName();
        }

        m_state = m_xRegistry->m_state;
    }

    NestedKeyImpl::NestedKeyImpl( const OUString& rKeyName,
                                  NestedKeyImpl* pKey)
        : m_xRegistry(pKey->m_xRegistry)
    {
        if (pKey->m_localKey.is() && pKey->m_localKey->isValid())
        {
            m_localKey = pKey->m_localKey->openKey(rKeyName);
        }
        if (pKey->m_defaultKey.is() && pKey->m_defaultKey->isValid())
        {
            m_defaultKey = pKey->m_defaultKey->openKey(rKeyName);
        }

        if (m_localKey.is())
        {
            m_name = m_localKey->getKeyName();
        }
        else if (m_defaultKey.is())
        {
            m_name = m_defaultKey->getKeyName();
        }

        m_state = m_xRegistry->m_state;
    }

    void NestedKeyImpl::computeChanges()
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( m_state != m_xRegistry->m_state )
        {
            Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());

            Reference<XRegistryKey> tmpKey = rootKey->openKey(m_name);

            if ( tmpKey.is() )
            {
                m_localKey = rootKey->openKey(m_name);
            }

            m_state = m_xRegistry->m_state;
        }
    }

    // NestedKey_Impl::computeName()

    OUString NestedKeyImpl::computeName(const OUString& name)
    {
        OUString resLocalName, resDefaultName;

        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        try
        {
            if ( m_localKey.is() && m_localKey->isValid() )
            {
                resLocalName = m_localKey->getResolvedName(name);
            }
            else if ( m_defaultKey.is() && m_defaultKey->isValid() )
            {
                return m_defaultKey->getResolvedName(name);
            }

            if ( !resLocalName.isEmpty() && m_xRegistry->m_defaultReg->isValid() )
            {
                Reference<XRegistryKey> localRoot(m_xRegistry->m_localReg->getRootKey());
                Reference<XRegistryKey> defaultRoot(m_xRegistry->m_defaultReg->getRootKey());

                resDefaultName = defaultRoot->getResolvedName(resLocalName);

                sal_uInt32 count = 100;

                while (resLocalName != resDefaultName && count > 0)
                {
                    count--;

                    if (resLocalName.isEmpty() || resDefaultName.isEmpty())
                        throw InvalidRegistryException();

                    resLocalName = localRoot->getResolvedName(resDefaultName);
                    resDefaultName = defaultRoot->getResolvedName(resLocalName);
                }
            }
        }
        catch(InvalidRegistryException& )
        {
        }

        return resLocalName;
    }

    OUString SAL_CALL NestedKeyImpl::getKeyName()
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        return m_name;
    }

    sal_Bool SAL_CALL NestedKeyImpl::isReadOnly(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( !m_localKey.is() || !m_localKey->isValid() )
            throw InvalidRegistryException();

       return m_localKey->isReadOnly();
    }

    sal_Bool SAL_CALL NestedKeyImpl::isValid(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        return ((m_localKey.is() && m_localKey->isValid()) ||
                (m_defaultKey.is() && m_defaultKey->isValid()) );
    }

    RegistryKeyType SAL_CALL NestedKeyImpl::getKeyType( const OUString& rKeyName )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getKeyType(rKeyName);
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getKeyType(rKeyName);
        }

        return RegistryKeyType_KEY;
    }

    RegistryValueType SAL_CALL NestedKeyImpl::getValueType(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getValueType();
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getValueType();
        }

        return RegistryValueType_NOT_DEFINED;
    }

    sal_Int32 SAL_CALL NestedKeyImpl::getLongValue(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getLongValue();
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getLongValue();
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    void SAL_CALL NestedKeyImpl::setLongValue( sal_Int32 value )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            m_localKey->setLongValue(value);
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
            m_localKey = rootKey->createKey(m_name);
            m_localKey->setLongValue(value);
            m_state = m_xRegistry->m_state++;
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    Sequence< sal_Int32 > SAL_CALL NestedKeyImpl::getLongListValue(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getLongListValue();
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getLongListValue();
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    void SAL_CALL NestedKeyImpl::setLongListValue( const Sequence< sal_Int32 >& seqValue )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            m_localKey->setLongListValue(seqValue);
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
            m_localKey = rootKey->createKey(m_name);
            m_localKey->setLongListValue(seqValue);
            m_state = m_xRegistry->m_state++;
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    OUString SAL_CALL NestedKeyImpl::getAsciiValue(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getAsciiValue();
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getAsciiValue();
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    void SAL_CALL NestedKeyImpl::setAsciiValue( const OUString& value )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            m_localKey->setAsciiValue(value);
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
            m_localKey = rootKey->createKey(m_name);
            m_localKey->setAsciiValue(value);
            m_state = m_xRegistry->m_state++;
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    Sequence< OUString > SAL_CALL NestedKeyImpl::getAsciiListValue(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getAsciiListValue();
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getAsciiListValue();
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    void SAL_CALL NestedKeyImpl::setAsciiListValue( const Sequence< OUString >& seqValue )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            m_localKey->setAsciiListValue(seqValue);
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
            m_localKey = rootKey->createKey(m_name);
            m_localKey->setAsciiListValue(seqValue);
            m_state = m_xRegistry->m_state++;
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    OUString SAL_CALL NestedKeyImpl::getStringValue(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getStringValue();
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getStringValue();
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    void SAL_CALL NestedKeyImpl::setStringValue( const OUString& value )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            m_localKey->setStringValue(value);
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
            m_localKey = rootKey->createKey(m_name);
            m_localKey->setStringValue(value);
            m_state = m_xRegistry->m_state++;
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    Sequence< OUString > SAL_CALL NestedKeyImpl::getStringListValue(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getStringListValue();
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getStringListValue();
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    void SAL_CALL NestedKeyImpl::setStringListValue( const Sequence< OUString >& seqValue )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            m_localKey->setStringListValue(seqValue);
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
            m_localKey = rootKey->createKey(m_name);
            m_localKey->setStringListValue(seqValue);
            m_state = m_xRegistry->m_state++;
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    Sequence< sal_Int8 > SAL_CALL NestedKeyImpl::getBinaryValue(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            return m_localKey->getBinaryValue();
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            return m_defaultKey->getBinaryValue();
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    void SAL_CALL NestedKeyImpl::setBinaryValue( const Sequence< sal_Int8 >& value )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        computeChanges();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            m_localKey->setBinaryValue(value);
        }
        else if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
            m_localKey = rootKey->createKey(m_name);
            m_localKey->setBinaryValue(value);
            m_state = m_xRegistry->m_state++;
        }
        else
        {
            throw InvalidRegistryException();
        }
    }

    Reference< XRegistryKey > SAL_CALL NestedKeyImpl::openKey( const OUString& aKeyName )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( !m_localKey.is() && !m_defaultKey.is() )
        {
            throw InvalidRegistryException();
        }

        OUString resolvedName = computeName(aKeyName);

        if ( resolvedName.isEmpty() )
            throw InvalidRegistryException();

        Reference<XRegistryKey> localKey, defaultKey;

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            localKey = m_xRegistry->m_localReg->getRootKey()->openKey(resolvedName);
        }
        if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);
        }

        if ( localKey.is() || defaultKey.is() )
        {
            return static_cast<XRegistryKey*>(new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey));
        }
        else
        {
            return Reference<XRegistryKey>();
        }
    }

    Reference< XRegistryKey > SAL_CALL NestedKeyImpl::createKey( const OUString& aKeyName )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( (!m_localKey.is() && !m_defaultKey.is()) ||
             (m_localKey.is() && m_localKey->isReadOnly()) )
        {
            throw InvalidRegistryException();
        }

        OUString resolvedName = computeName(aKeyName);

        if ( resolvedName.isEmpty() )
            throw InvalidRegistryException();

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            Reference<XRegistryKey> localKey, defaultKey;

            localKey = m_xRegistry->m_localReg->getRootKey()->createKey(resolvedName);
            if ( localKey.is() )
            {
                if ( m_defaultKey.is() && m_defaultKey->isValid() )
                {
                    defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);
                }

                m_state = m_xRegistry->m_state++;

                return static_cast<XRegistryKey*>(new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey));
            }
        }
        else
        {
            Reference<XRegistryKey> localKey, defaultKey;

            if ( m_defaultKey.is() && m_defaultKey->isValid() )
            {
                Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
                m_localKey = rootKey->createKey(m_name);

                localKey = m_xRegistry->m_localReg->getRootKey()->createKey(resolvedName);

                if ( localKey.is() )
                {
                    defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);

                    m_state = m_xRegistry->m_state++;

                    return static_cast<XRegistryKey*>(new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey));
                }
            }
        }

        return Reference<XRegistryKey>();
    }

    void SAL_CALL NestedKeyImpl::closeKey(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( m_localKey.is() && m_localKey->isValid() )
        {
            m_localKey->closeKey();
        }
        if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            m_defaultKey->closeKey();
        }
    }

    void SAL_CALL NestedKeyImpl::deleteKey( const OUString& rKeyName )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( !m_localKey.is() || !m_localKey->isValid() ||
             m_localKey->isReadOnly() )
        {
            throw InvalidRegistryException();
        }

        OUString resolvedName = computeName(rKeyName);

        if ( resolvedName.isEmpty() )
        {
            throw InvalidRegistryException();
        }

        m_xRegistry->m_localReg->getRootKey()->deleteKey(resolvedName);
    }

    Sequence< Reference< XRegistryKey > > SAL_CALL NestedKeyImpl::openKeys(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( !m_localKey.is() && !m_defaultKey.is() )
        {
            throw InvalidRegistryException();
        }

        Sequence<OUString> localSeq, defaultSeq;

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            localSeq = m_localKey->getKeyNames();
        }
        if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            defaultSeq = m_defaultKey->getKeyNames();
        }

        sal_uInt32 local = localSeq.getLength();
        sal_uInt32 def = defaultSeq.getLength();
        sal_uInt32 len = 0;

        sal_uInt32 i, j;
        for (i=0; i < local; i++)
        {
            for (j=0 ; j < def; j++)
            {
                if ( localSeq.getConstArray()[i] == defaultSeq.getConstArray()[j] )
                {
                    len++;
                    break;
                }
            }
        }

        Sequence< Reference<XRegistryKey> > retSeq(local + def - len);
        OUString                            name;
        sal_Int32                           lastIndex;

        for (i=0; i < local; i++)
        {
            name = localSeq.getConstArray()[i];
            lastIndex = name.lastIndexOf('/');
            name = name.copy(lastIndex);
            retSeq.getArray()[i] =
                static_cast<XRegistryKey*>(new NestedKeyImpl(name, this));
        }

        sal_uInt32 k = local;
        for (i=0; i < def; i++)
        {
            bool insert = true;

            for (j=0 ; j < local; j++)
            {
                if ( retSeq.getConstArray()[j]->getKeyName()
                        == defaultSeq.getConstArray()[i] )
                {
                    insert = false;
                    break;
                }
            }

            if ( insert )
            {
                name = defaultSeq.getConstArray()[i];
                lastIndex = name.lastIndexOf('/');
                name = name.copy(lastIndex);
                retSeq.getArray()[k++] =
                    static_cast<XRegistryKey*>(new NestedKeyImpl(name, this));
            }
        }

        return retSeq;
    }

    Sequence< OUString > SAL_CALL NestedKeyImpl::getKeyNames(  )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( !m_localKey.is() && !m_defaultKey.is() )
        {
            throw InvalidRegistryException();
        }

        Sequence<OUString> localSeq, defaultSeq;

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            localSeq = m_localKey->getKeyNames();
        }
        if ( m_defaultKey.is() && m_defaultKey->isValid() )
        {
            defaultSeq = m_defaultKey->getKeyNames();
        }

        sal_uInt32 local = localSeq.getLength();
        sal_uInt32 def = defaultSeq.getLength();
        sal_uInt32 len = 0;

        sal_uInt32 i, j;
        for (i=0; i < local; i++)
        {
            for (j=0 ; j < def; j++)
            {
                if ( localSeq.getConstArray()[i] == defaultSeq.getConstArray()[j] )
                {
                    len++;
                    break;
                }
            }
        }

        Sequence<OUString>  retSeq(local + def - len);

        for (i=0; i < local; i++)
        {
            retSeq.getArray()[i] = localSeq.getConstArray()[i];
        }

        sal_uInt32 k = local;
        for (i=0; i < def; i++)
        {
            bool insert = true;

            for (j=0 ; j < local; j++)
            {
                if ( retSeq.getConstArray()[j] == defaultSeq.getConstArray()[i] )
                {
                    insert = false;
                    break;
                }
            }

            if ( insert )
                retSeq.getArray()[k++] = defaultSeq.getConstArray()[i];
        }

        return retSeq;
    }

    sal_Bool SAL_CALL NestedKeyImpl::createLink( const OUString& aLinkName, const OUString& aLinkTarget )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );

        bool isCreated = false;
        if ( !m_localKey.is() && !m_defaultKey.is() )
        {
            throw InvalidRegistryException();
        }

        OUString    linkName;
        OUString    resolvedName;
        sal_Int32   lastIndex = aLinkName.lastIndexOf('/');

        if ( lastIndex > 0 )
        {
            linkName = aLinkName.copy(0, lastIndex);

            resolvedName = computeName(linkName);

            if ( resolvedName.isEmpty() )
            {
                throw InvalidRegistryException();
            }

            resolvedName = resolvedName + aLinkName.copy(lastIndex);
        }
        else
        {
            if ( lastIndex == 0 )
                resolvedName = m_name + aLinkName;
            else
                resolvedName = m_name + "/" + aLinkName;
        }

        if ( m_localKey.is() && m_localKey->isValid() )
        {
            isCreated = m_xRegistry->m_localReg->getRootKey()->createLink(resolvedName, aLinkTarget);
        }
        else
        {
            if ( m_defaultKey.is() && m_defaultKey->isValid() )
            {
                Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
                m_localKey = rootKey->createKey(m_name);

                isCreated = m_xRegistry->m_localReg->getRootKey()->createLink(resolvedName, aLinkTarget);
            }
        }

        if ( isCreated )
            m_state = m_xRegistry->m_state++;

        return isCreated;
    }

    void SAL_CALL NestedKeyImpl::deleteLink( const OUString& rLinkName )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( !m_localKey.is() && !m_defaultKey.is() )
        {
            throw InvalidRegistryException();
        }

        OUString    linkName;
        OUString    resolvedName;
        sal_Int32   lastIndex = rLinkName.lastIndexOf('/');

        if ( lastIndex > 0 )
        {
            linkName = rLinkName.copy(0, lastIndex);

            resolvedName = computeName(linkName);

            if ( resolvedName.isEmpty() )
            {
                throw InvalidRegistryException();
            }

            resolvedName = resolvedName + rLinkName.copy(lastIndex);
        }
        else
        {
            if ( lastIndex == 0 )
                resolvedName = m_name + rLinkName;
            else
                resolvedName = m_name + "/" + rLinkName;
        }

        if ( !m_localKey.is() || !m_localKey->isValid() ||
             m_localKey->isReadOnly() )
        {
            throw InvalidRegistryException();
        }

        m_xRegistry->m_localReg->getRootKey()->deleteLink(resolvedName);
    }

    OUString SAL_CALL NestedKeyImpl::getLinkTarget( const OUString& rLinkName )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( !m_localKey.is() && !m_defaultKey.is() )
        {
            throw InvalidRegistryException();
        }

        OUString    linkName;
        OUString    resolvedName;
        sal_Int32   lastIndex = rLinkName.lastIndexOf('/');

        if ( lastIndex > 0 )
        {
            linkName = rLinkName.copy(0, lastIndex);

            resolvedName = computeName(linkName);

            if ( resolvedName.isEmpty() )
            {
                throw InvalidRegistryException();
            }

            resolvedName = resolvedName + rLinkName.copy(lastIndex);
        }
        else
        {
            if ( lastIndex == 0 )
                resolvedName = m_name + rLinkName;
            else
                resolvedName = m_name + "/" + rLinkName;
        }

        OUString linkTarget;
        if ( m_localKey.is() && m_localKey->isValid() )
        {
            try
            {
                linkTarget = m_xRegistry->m_localReg->getRootKey()->getLinkTarget(resolvedName);
                return linkTarget;
            }
            catch(InvalidRegistryException& )
            {
            }
        }

        if ( m_defaultKey.is() && m_defaultKey->isValid() )
            linkTarget = m_xRegistry->m_defaultReg->getRootKey()->getLinkTarget(resolvedName);

        return linkTarget;
    }

    OUString SAL_CALL NestedKeyImpl::getResolvedName( const OUString& aKeyName )
    {
        Guard< Mutex > aGuard( m_xRegistry->m_mutex );
        if ( !m_localKey.is() && !m_defaultKey.is() )
        {
            throw InvalidRegistryException();
        }

        OUString resolvedName = computeName(aKeyName);

        if ( resolvedName.isEmpty() )
        {
            throw InvalidRegistryException();
        }

        return resolvedName;
    }

    // DefaultRegistry Implementation

    NestedRegistryImpl::NestedRegistryImpl( )
        : m_state(0)
    {}

    class RegistryEnumueration : public WeakImplHelper< XEnumeration >
    {
    public:
        RegistryEnumueration(
            const Reference< XSimpleRegistry > &r1,
            const Reference< XSimpleRegistry > &r2 )
            : m_xReg1( r1 ) , m_xReg2( r2 )
            {}
    public:
        virtual sal_Bool SAL_CALL hasMoreElements(  ) override;
        virtual Any SAL_CALL nextElement(  ) override;

    private:
        Reference< XSimpleRegistry > m_xReg1;
        Reference< XSimpleRegistry > m_xReg2;
    };

    sal_Bool RegistryEnumueration::hasMoreElements(  )
    {
        return m_xReg1.is() || m_xReg2.is();
    }

    Any RegistryEnumueration::nextElement(  )
    {
        Any a;
        if( m_xReg1.is() )
        {
            a <<= m_xReg1;
            m_xReg1.clear();
        }
        else if( m_xReg2.is() )
        {
            a <<= m_xReg2;
            m_xReg2.clear();
        }
        else
        {
            throw NoSuchElementException( "NestedRegistry: no nextElement() !" );
        }
        return a;
    }

    Reference< XEnumeration > NestedRegistryImpl::createEnumeration(  )
    {
        MutexGuard guard( m_mutex );
        return new RegistryEnumueration( m_localReg, m_defaultReg );
    }

    Type NestedRegistryImpl::getElementType(  )
    {
        return cppu::UnoType<decltype(m_localReg)>::get();
    }

    sal_Bool SAL_CALL NestedRegistryImpl::hasElements(  )
    {
        MutexGuard guard( m_mutex );
        return m_localReg.is() || m_defaultReg.is();
    }

    OUString SAL_CALL NestedRegistryImpl::getImplementationName(  )
    {
        return OUString("com.sun.star.comp.stoc.NestedRegistry");
    }

    sal_Bool SAL_CALL NestedRegistryImpl::supportsService( const OUString& ServiceName )
    {
        return cppu::supportsService(this, ServiceName);
    }

    Sequence<OUString> SAL_CALL NestedRegistryImpl::getSupportedServiceNames(  )
    {
        Sequence< OUString > seqNames { "com.sun.star.registry.NestedRegistry" };
        return seqNames;
    }

    void SAL_CALL NestedRegistryImpl::initialize( const Sequence< Any >& aArguments )
    {
        Guard< Mutex > aGuard( m_mutex );
        if ( (aArguments.getLength() == 2) &&
             (aArguments[0].getValueType().getTypeClass() == TypeClass_INTERFACE) &&
             (aArguments[1].getValueType().getTypeClass() == TypeClass_INTERFACE) )
        {
            aArguments[0] >>= m_localReg;
            aArguments[1] >>= m_defaultReg;
            if ( m_localReg == m_defaultReg )
                m_defaultReg.clear();
        }
    }

    OUString SAL_CALL NestedRegistryImpl::getURL()
    {
        Guard< Mutex > aGuard( m_mutex );
        try
        {
            if ( m_localReg.is() && m_localReg->isValid() )
                return m_localReg->getURL();
        }
        catch(InvalidRegistryException& )
        {
        }

        return OUString();
    }

    void SAL_CALL NestedRegistryImpl::open( const OUString&, sal_Bool, sal_Bool )
    {
        throw InvalidRegistryException(
                "the 'open' method is not specified for a nested registry" );
    }

    sal_Bool SAL_CALL NestedRegistryImpl::isValid(  )
    {
        Guard< Mutex > aGuard( m_mutex );
        try
        {
            if ( (m_localReg.is() && m_localReg->isValid()) ||
                 (m_defaultReg.is() && m_defaultReg->isValid()) )
                return true;
        }
        catch(InvalidRegistryException& )
        {
        }

        return false;
    }

    void SAL_CALL NestedRegistryImpl::close(  )
    {
        Guard< Mutex > aGuard( m_mutex );
        if ( m_localReg.is() && m_localReg->isValid() )
        {
            m_localReg->close();
        }
        if ( m_defaultReg.is() && m_defaultReg->isValid() )
        {
            m_defaultReg->close();
        }
    }

    void SAL_CALL NestedRegistryImpl::destroy(  )
    {
        throw InvalidRegistryException(
                "the 'destroy' method is not specified for a nested registry" );
    }

    Reference< XRegistryKey > SAL_CALL NestedRegistryImpl::getRootKey(  )
    {
        Guard< Mutex > aGuard( m_mutex );
        if ( !m_localReg.is() || !m_localReg->isValid() )
        {
            throw InvalidRegistryException();
        }

        Reference<XRegistryKey> localKey, defaultKey;

        localKey = m_localReg->getRootKey();

        if ( localKey.is() )
        {
            if ( m_defaultReg.is() && m_defaultReg->isValid() )
            {
                defaultKey = m_defaultReg->getRootKey();
            }

            return static_cast<XRegistryKey*>(new NestedKeyImpl(this, localKey, defaultKey));
        }

        return Reference<XRegistryKey>();
    }

    sal_Bool SAL_CALL NestedRegistryImpl::isReadOnly(  )
    {
        Guard< Mutex > aGuard( m_mutex );
        try
        {
            if ( m_localReg.is() && m_localReg->isValid() )
                return m_localReg->isReadOnly();
        }
        catch(InvalidRegistryException& )
        {
        }

        return false;
    }

    void SAL_CALL NestedRegistryImpl::mergeKey( const OUString& aKeyName, const OUString& aUrl )
    {
        Guard< Mutex > aGuard( m_mutex );
        if ( m_localReg.is() && m_localReg->isValid() )
        {
            m_localReg->mergeKey(aKeyName, aUrl);

            m_state++;
        }
    }

    } // namespace

    extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
    com_sun_star_comp_stoc_NestedRegistry_get_implementation(
        SAL_UNUSED_PARAMETER css::uno::XComponentContext *,
        css::uno::Sequence<css::uno::Any> const &)
    {
        return cppu::acquire(new NestedRegistryImpl);
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V572 It is odd that the object which was created using 'new' operator is immediately cast to another type.

↑ V572 It is odd that the object which was created using 'new' operator is immediately cast to another type.

↑ V572 It is odd that the object which was created using 'new' operator is immediately cast to another type.

↑ V572 It is odd that the object which was created using 'new' operator is immediately cast to another type.

↑ V572 It is odd that the object which was created using 'new' operator is immediately cast to another type.

↑ V572 It is odd that the object which was created using 'new' operator is immediately cast to another type.