    /* -*- 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 .
     */

    /**************************************************************************
                                    TODO
     **************************************************************************

     *************************************************************************/
    #include <osl/diagnose.h>
    #include <sal/log.hxx>
    #include <comphelper/processfactory.hxx>
    #include <comphelper/interfacecontainer2.hxx>
    #include <comphelper/propertysequence.hxx>
    #include <cppuhelper/queryinterface.hxx>
    #include <com/sun/star/lang/IllegalArgumentException.hpp>
    #include <com/sun/star/ucb/DuplicateProviderException.hpp>
    #include <com/sun/star/ucb/GlobalTransferCommandArgument2.hpp>
    #include <com/sun/star/ucb/UnsupportedCommandException.hpp>
    #include <com/sun/star/ucb/XCommandInfo.hpp>
    #include <com/sun/star/ucb/XContentProvider.hpp>
    #include <com/sun/star/ucb/XContentProviderSupplier.hpp>
    #include <com/sun/star/ucb/XParameterizedContentProvider.hpp>
    #include <com/sun/star/ucb/XContentProviderFactory.hpp>
    #include <com/sun/star/beans/PropertyValue.hpp>
    #include <com/sun/star/configuration/theDefaultProvider.hpp>
    #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
    #include <com/sun/star/container/XNameAccess.hpp>
    #include <com/sun/star/uno/Any.hxx>
    #include <ucbhelper/cancelcommandexecution.hxx>
    #include <ucbhelper/getcomponentcontext.hxx>
    #include "identify.hxx"
    #include "ucbcmds.hxx"

    #include "ucb.hxx"

    using namespace comphelper;
    using namespace com::sun::star::uno;
    using namespace com::sun::star::lang;
    using namespace com::sun::star::ucb;
    using namespace ucb_impl;
    using namespace com::sun::star;
    using namespace ucbhelper;

    namespace {

    bool fillPlaceholders(OUString const & rInput,
                          uno::Sequence< uno::Any > const & rReplacements,
                          OUString * pOutput)
    {
        sal_Unicode const * p = rInput.getStr();
        sal_Unicode const * pEnd = p + rInput.getLength();
        sal_Unicode const * pCopy = p;
        OUStringBuffer aBuffer;
        while (p != pEnd)
            switch (*p++)
            {
                case '&':
                    if (pEnd - p >= 4
                        && p[0] == 'a' && p[1] == 'm' && p[2] == 'p'
                        && p[3] == ';')
                    {
                        aBuffer.append(pCopy, p - 1 - pCopy);
                        aBuffer.append('&');
                        p += 4;
                        pCopy = p;
                    }
                    else if (pEnd - p >= 3
                             && p[0] == 'l' && p[1] == 't' && p[2] == ';')
                    {
                        aBuffer.append(pCopy, p - 1 - pCopy);
                        aBuffer.append('<');
                        p += 3;
                        pCopy = p;
                    }
                    else if (pEnd - p >= 3
                             && p[0] == 'g' && p[1] == 't' && p[2] == ';')
                    {
                        aBuffer.append(pCopy, p - 1 - pCopy);
                        aBuffer.append('>');
                        p += 3;
                        pCopy = p;
                    }
                    break;

                case '<':
                    sal_Unicode const * q = p;
                    while (q != pEnd && *q != '>')
                        ++q;
                    if (q == pEnd)
                        break;
                    OUString aKey(p, q - p);
                    OUString aValue;
                    bool bFound = false;
                    for (sal_Int32 i = 2; i + 1 < rReplacements.getLength();
                         i += 2)
                    {
                        OUString aReplaceKey;
                        if ((rReplacements[i] >>= aReplaceKey)
                            && aReplaceKey == aKey
                            && (rReplacements[i + 1] >>= aValue))
                        {
                            bFound = true;
                            break;
                        }
                    }
                    if (!bFound)
                        return false;
                    aBuffer.append(pCopy, p - 1 - pCopy);
                    aBuffer.append(aValue);
                    p = q + 1;
                    pCopy = p;
                    break;
            }
        aBuffer.append(pCopy, pEnd - pCopy);
        *pOutput = aBuffer.makeStringAndClear();
        return true;
    }

    void makeAndAppendXMLName(
                    OUStringBuffer & rBuffer, const OUString & rIn )
    {
        sal_Int32 nCount = rIn.getLength();
        for ( sal_Int32 n = 0; n < nCount; ++n )
        {
            const sal_Unicode c = rIn[ n ];
            switch ( c )
            {
                case '&':
                    rBuffer.append( "&amp;" );
                    break;

                case '"':
                    rBuffer.append( "&quot;" );
                    break;

                case '\'':
                    rBuffer.append( "&apos;" );
                    break;

                case '<':
                    rBuffer.append( "&lt;" );
                    break;

                case '>':
                    rBuffer.append( "&gt;" );
                    break;

                default:
                    rBuffer.append( c );
                    break;
            }
        }
    }

    bool createContentProviderData(
        const OUString & rProvider,
        const uno::Reference< container::XHierarchicalNameAccess >& rxHierNameAccess,
        ContentProviderData & rInfo)
    {
        // Obtain service name.
        OUStringBuffer aKeyBuffer (rProvider);
        aKeyBuffer.append( "/ServiceName" );

        OUString aValue;
        try
        {
            if ( !( rxHierNameAccess->getByHierarchicalName(
                        aKeyBuffer.makeStringAndClear() ) >>= aValue ) )
            {
                OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
                            "Error getting item value!" );
            }
        }
        catch (const container::NoSuchElementException&)
        {
            return false;
        }

        rInfo.ServiceName = aValue;

        // Obtain URL Template.
        aKeyBuffer.append(rProvider);
        aKeyBuffer.append( "/URLTemplate" );

        if ( !( rxHierNameAccess->getByHierarchicalName(
                    aKeyBuffer.makeStringAndClear() ) >>= aValue ) )
        {
            OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
                        "Error getting item value!" );
        }

        rInfo.URLTemplate = aValue;

        // Obtain Arguments.
        aKeyBuffer.append(rProvider);
        aKeyBuffer.append( "/Arguments" );

        if ( !( rxHierNameAccess->getByHierarchicalName(
                    aKeyBuffer.makeStringAndClear() ) >>= aValue ) )
        {
            OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
                        "Error getting item value!" );
        }

        rInfo.Arguments = aValue;
        return true;
    }

    }

    // UniversalContentBroker Implementation.

    UniversalContentBroker::UniversalContentBroker(
        const Reference< css::uno::XComponentContext >& xContext )
    : m_xContext( xContext ),
      m_nCommandId( 0 )
    {
        OSL_ENSURE( m_xContext.is(),
                    "UniversalContentBroker ctor: No service manager" );
    }

    // virtual
    UniversalContentBroker::~UniversalContentBroker()
    {
    }

    // XInterface methods.
    void SAL_CALL UniversalContentBroker::acquire()
        throw()
    {
        OWeakObject::acquire();
    }

    void SAL_CALL UniversalContentBroker::release()
        throw()
    {
        OWeakObject::release();
    }

    css::uno::Any SAL_CALL UniversalContentBroker::queryInterface( const css::uno::Type & rType )
    {
        css::uno::Any aRet = cppu::queryInterface( rType,
                                                   static_cast< XUniversalContentBroker* >(this),
                                                   static_cast< XTypeProvider* >(this),
                                                   static_cast< XComponent* >(this),
                                                   static_cast< XServiceInfo* >(this),
                                                   static_cast< XInitialization* >(this),
                                                   static_cast< XContentProviderManager* >(this),
                                                   static_cast< XContentProvider* >(this),
                                                   static_cast< XContentIdentifierFactory* >(this),
                                                   static_cast< XCommandProcessor* >(this)
                                                   );
        return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
    }

    // XTypeProvider methods.

    XTYPEPROVIDER_IMPL_9( UniversalContentBroker,
                          XUniversalContentBroker,
                          XTypeProvider,
                          XComponent,
                          XServiceInfo,
                          XInitialization,
                          XContentProviderManager,
                          XContentProvider,
                          XContentIdentifierFactory,
                          XCommandProcessor );

    // XComponent methods.

    // virtual
    void SAL_CALL UniversalContentBroker::dispose()
    {
        if ( m_pDisposeEventListeners && m_pDisposeEventListeners->getLength() )
        {
            EventObject aEvt;
            aEvt.Source = static_cast< XComponent* >(this);
            m_pDisposeEventListeners->disposeAndClear( aEvt );
        }

         if ( m_xNotifier.is() )
            m_xNotifier->removeChangesListener( this );
    }

    // virtual
    void SAL_CALL UniversalContentBroker::addEventListener(
                                const Reference< XEventListener >& Listener )
    {
        if ( !m_pDisposeEventListeners )
            m_pDisposeEventListeners.reset( new OInterfaceContainerHelper2( m_aMutex ) );

        m_pDisposeEventListeners->addInterface( Listener );
    }

    // virtual
    void SAL_CALL UniversalContentBroker::removeEventListener(
                                const Reference< XEventListener >& Listener )
    {
        if ( m_pDisposeEventListeners )
            m_pDisposeEventListeners->removeInterface( Listener );

        // Note: Don't want to delete empty container here -> performance.
    }

    // XServiceInfo methods.

    XSERVICEINFO_COMMOM_IMPL( UniversalContentBroker,
                              OUString( "com.sun.star.comp.ucb.UniversalContentBroker" ) )
    /// @throws css::uno::Exception
    static css::uno::Reference< css::uno::XInterface >
    UniversalContentBroker_CreateInstance( const css::uno::Reference< css::lang::XMultiServiceFactory> & rSMgr )
    {
        css::lang::XServiceInfo* pX =
            static_cast<css::lang::XServiceInfo*>(new UniversalContentBroker( ucbhelper::getComponentContext(rSMgr) ));
        return css::uno::Reference< css::uno::XInterface >::query( pX );
    }

    css::uno::Sequence< OUString >
    UniversalContentBroker::getSupportedServiceNames_Static()
    {
        css::uno::Sequence< OUString > aSNS { UCB_SERVICE_NAME };
        return aSNS;
    }

    // Service factory implementation.

    ONE_INSTANCE_SERVICE_FACTORY_IMPL( UniversalContentBroker );

    // XInitialization methods.

    // virtual
    void SAL_CALL UniversalContentBroker::initialize( const css::uno::Sequence< Any >& aArguments )
    {
        {
            osl::MutexGuard aGuard(m_aMutex);
            if (m_aArguments.getLength() != 0)
            {
                if (aArguments.getLength() != 0
                    && !(m_aArguments.getLength() == 2
                         && aArguments.getLength() == 2
                         && m_aArguments[0] == aArguments[0]
                         && m_aArguments[1] == aArguments[1]))
                {
                    throw IllegalArgumentException(
                        "UCB reinitialized with different arguments",
                        static_cast< cppu::OWeakObject * >(this), 0);
                }
                return;
            }
            if (aArguments.getLength() == 0)
            {
                m_aArguments.realloc(2);
                m_aArguments[0] <<= OUString("Local");
                m_aArguments[1] <<= OUString("Office");
            }
            else
            {
                m_aArguments = aArguments;
            }
        }
        configureUcb();
    }

    // XContentProviderManager methods.

    // virtual
    Reference< XContentProvider > SAL_CALL
    UniversalContentBroker::registerContentProvider(
                                const Reference< XContentProvider >& Provider,
                                const OUString& Scheme,
                                sal_Bool ReplaceExisting )
    {
        osl::MutexGuard aGuard(m_aMutex);

        ProviderMap_Impl::iterator aIt;
        try
        {
            aIt = m_aProviders.find(Scheme);
        }
        catch (const IllegalArgumentException&)
        {
            return nullptr; //@@@
        }

        Reference< XContentProvider > xPrevious;
        if (aIt == m_aProviders.end())
        {
            ProviderList_Impl aList;
            aList.push_front( ProviderListEntry_Impl(Provider) );
            try
            {
                m_aProviders.add(Scheme, aList);
            }
            catch (const IllegalArgumentException&)
            {
                return nullptr; //@@@
            }
        }
        else
        {
            if (!ReplaceExisting)
                throw DuplicateProviderException();

            ProviderList_Impl & rList = aIt->getValue();
            xPrevious = rList.front().getProvider();
            rList.push_front( ProviderListEntry_Impl(Provider) );
        }

        return xPrevious;
    }

    // virtual
    void SAL_CALL UniversalContentBroker::deregisterContentProvider(
                                  const Reference< XContentProvider >& Provider,
                                const OUString& Scheme )
    {
        osl::MutexGuard aGuard(m_aMutex);

        ProviderMap_Impl::iterator aMapIt;
        try
        {
            aMapIt = m_aProviders.find(Scheme);
        }
        catch (const IllegalArgumentException&)
        {
            return; //@@@
        }

        if (aMapIt != m_aProviders.end())
        {
            ProviderList_Impl & rList = aMapIt->getValue();

            ProviderList_Impl::iterator aListEnd(rList.end());
            for (ProviderList_Impl::iterator aListIt(rList.begin());
                 aListIt != aListEnd; ++aListIt)
            {
                if ((*aListIt).getProvider() == Provider)
                {
                    rList.erase(aListIt);
                    break;
                }
            }

            if (rList.empty())
                m_aProviders.erase(aMapIt);
        }
    }

    // virtual
    css::uno::Sequence< ContentProviderInfo > SAL_CALL
                                UniversalContentBroker::queryContentProviders()
    {
        // Return a list with information about active(!) content providers.

        osl::MutexGuard aGuard(m_aMutex);

        css::uno::Sequence< ContentProviderInfo > aSeq( m_aProviders.size() );
        ContentProviderInfo* pInfo = aSeq.getArray();

        ProviderMap_Impl::const_iterator end = m_aProviders.end();
        for (ProviderMap_Impl::const_iterator it(m_aProviders.begin()); it != end;
             ++it)
        {
            // Note: Active provider is always the first list element.
            pInfo->ContentProvider = it->getValue().front().getProvider();
            pInfo->Scheme = it->getRegexp();
            ++pInfo;
        }

        return aSeq;
    }

    // virtual
    Reference< XContentProvider > SAL_CALL
            UniversalContentBroker::queryContentProvider( const OUString&
                                                              Identifier )
    {
        return queryContentProvider( Identifier, false );
    }

    // XContentProvider methods.

    // virtual
    Reference< XContent > SAL_CALL UniversalContentBroker::queryContent(
                            const Reference< XContentIdentifier >& Identifier )
    {

        // Let the content provider for the scheme given with the content
        // identifier create the XContent instance.

        if ( !Identifier.is() )
            return Reference< XContent >();

        Reference< XContentProvider > xProv =
            queryContentProvider( Identifier->getContentIdentifier(), true );
        if ( xProv.is() )
            return  xProv->queryContent( Identifier );

        return Reference< XContent >();
    }

    // virtual
    sal_Int32 SAL_CALL UniversalContentBroker::compareContentIds(
                                    const Reference< XContentIdentifier >& Id1,
                                    const Reference< XContentIdentifier >& Id2 )
    {
        OUString aURI1( Id1->getContentIdentifier() );
        OUString aURI2( Id2->getContentIdentifier() );

        Reference< XContentProvider > xProv1
                                = queryContentProvider( aURI1, true );
        Reference< XContentProvider > xProv2
                                = queryContentProvider( aURI2, true );

        // When both identifiers belong to the same provider, let that provider
        // compare them; otherwise, simply compare the URI strings (which must
        // be different):
        if ( xProv1.is() && ( xProv1 == xProv2 ) )
            return xProv1->compareContentIds( Id1, Id2 );
        else
            return aURI1.compareTo( aURI2 );
    }

    // XContentIdentifierFactory methods.

    // virtual
    Reference< XContentIdentifier > SAL_CALL
            UniversalContentBroker::createContentIdentifier(
                                                const OUString& ContentId )
    {

        // Let the content provider for the scheme given with content
        // identifier create the XContentIdentifier instance, if he supports
        // the XContentIdentifierFactory interface. Otherwise create standard
        // implementation object for XContentIdentifier.

        Reference< XContentIdentifier > xIdentifier;

        Reference< XContentProvider > xProv
                                = queryContentProvider( ContentId, true );
        if ( xProv.is() )
        {
            Reference< XContentIdentifierFactory > xFac( xProv, UNO_QUERY );
            if ( xFac.is() )
                xIdentifier = xFac->createContentIdentifier( ContentId );
        }

        if ( !xIdentifier.is() )
            xIdentifier = new ContentIdentifier( ContentId );

        return xIdentifier;
    }

    // XCommandProcessor methods.

    // virtual
    sal_Int32 SAL_CALL UniversalContentBroker::createCommandIdentifier()
    {
        osl::MutexGuard aGuard( m_aMutex );

        // Just increase counter on every call to generate an identifier.
        return ++m_nCommandId;
    }

    // virtual
    Any SAL_CALL UniversalContentBroker::execute(
                              const Command& aCommand,
                              sal_Int32,
                              const Reference< XCommandEnvironment >& Environment )
    {
        Any aRet;

        // Note: Don't forget to adapt ucb_commands::CommandProcessorInfo
        //       ctor in ucbcmds.cxx when adding new commands!

        if ( ( aCommand.Handle == GETCOMMANDINFO_HANDLE ) || aCommand.Name == GETCOMMANDINFO_NAME )
        {

            // getCommandInfo

            aRet <<= getCommandInfo();
        }
        else if ( ( aCommand.Handle == GLOBALTRANSFER_HANDLE ) || aCommand.Name == GLOBALTRANSFER_NAME )
        {

            // globalTransfer

            GlobalTransferCommandArgument2 aTransferArg;
            if ( !( aCommand.Argument >>= aTransferArg ) )
            {
                GlobalTransferCommandArgument aArg;
                if ( !( aCommand.Argument >>= aArg ) )
                {
                    ucbhelper::cancelCommandExecution(
                        makeAny( IllegalArgumentException(
                                        "Wrong argument type!",
                                        static_cast< cppu::OWeakObject * >( this ),
                                        -1 ) ),
                        Environment );
                    // Unreachable
                }

                // Copy infos into the new structure
                aTransferArg.Operation = aArg.Operation;
                aTransferArg.SourceURL = aArg.SourceURL;
                aTransferArg.TargetURL = aArg.TargetURL;
                aTransferArg.NewTitle = aArg.NewTitle;
                aTransferArg.NameClash = aArg.NameClash;
            }

            globalTransfer( aTransferArg, Environment );
        }
        else if ( ( aCommand.Handle == CHECKIN_HANDLE ) || aCommand.Name == CHECKIN_NAME )
        {
            ucb::CheckinArgument aCheckinArg;
            if ( !( aCommand.Argument >>= aCheckinArg ) )
            {
                ucbhelper::cancelCommandExecution(
                    makeAny( IllegalArgumentException(
                                    "Wrong argument type!",
                                    static_cast< cppu::OWeakObject * >( this ),
                                    -1 ) ),
                    Environment );
                // Unreachable
            }
            aRet = checkIn( aCheckinArg, Environment );
        }
        else
        {

            // Unknown command

            ucbhelper::cancelCommandExecution(
                makeAny( UnsupportedCommandException(
                                OUString(),
                                static_cast< cppu::OWeakObject * >( this ) ) ),
                Environment );
            // Unreachable
        }

        return aRet;
    }

    // XCommandProcessor2 methods.

    // virtual
    void SAL_CALL UniversalContentBroker::releaseCommandIdentifier(sal_Int32 /*aCommandId*/)
    {
        // @@@ Not implemented ( yet).
    }

    // virtual
    void SAL_CALL UniversalContentBroker::abort( sal_Int32 )
    {
        // @@@ Not implemented ( yet).
    }

    // XChangesListener methods

    // virtual
    void SAL_CALL UniversalContentBroker::changesOccurred( const util::ChangesEvent& Event )
    {
        sal_Int32 nCount = Event.Changes.getLength();
        if ( nCount )
        {
            uno::Reference< container::XHierarchicalNameAccess > xHierNameAccess;
            Event.Base >>= xHierNameAccess;

            OSL_ASSERT( xHierNameAccess.is() );

            const util::ElementChange* pElementChanges
                = Event.Changes.getConstArray();

            ContentProviderDataList aData;
            for ( sal_Int32 n = 0; n < nCount; ++n )
            {
                const util::ElementChange& rElem = pElementChanges[ n ];
                OUString aKey;
                rElem.Accessor >>= aKey;

                ContentProviderData aInfo;

                // Removal of UCPs from the configuration leads to changesOccurred
                // notifications, too, but it is hard to tell for a given
                // ElementChange whether it is an addition or a removal, so as a
                // heuristic consider as removals those that cause a
                // NoSuchElementException in createContentProviderData.

                // For now, removal of UCPs from the configuration is simply ignored
                // (and not reflected in the UCB's data structures):
                if (createContentProviderData(aKey, xHierNameAccess, aInfo))
                {
                    aData.push_back(aInfo);
                }
            }

            prepareAndRegister(aData);
        }
    }

    // XEventListener methods

    // virtual
    void SAL_CALL UniversalContentBroker::disposing(const lang::EventObject&)
    {
        if ( m_xNotifier.is() )
        {
            osl::Guard< osl::Mutex > aGuard( m_aMutex );

            if ( m_xNotifier.is() )
                m_xNotifier.clear();
        }
    }

    // Non-interface methods

    Reference< XContentProvider > UniversalContentBroker::queryContentProvider(
                                    const OUString& Identifier,
                                    bool bResolved )
    {
        osl::MutexGuard aGuard( m_aMutex );

        ProviderList_Impl const * pList = m_aProviders.map( Identifier );
        return pList ? bResolved ? pList->front().getResolvedProvider()
                                 : pList->front().getProvider()
                     : Reference< XContentProvider >();
    }

    void UniversalContentBroker::configureUcb()
    {
        OUString aKey1;
        OUString aKey2;
        if (m_aArguments.getLength() < 2
            || !(m_aArguments[0] >>= aKey1) || !(m_aArguments[1] >>= aKey2))
        {
            OSL_FAIL("UniversalContentBroker::configureUcb(): Bad arguments");
            return;
        }

        ContentProviderDataList aData;
        if (!getContentProviderData(aKey1, aKey2, aData))
        {
            SAL_WARN( "ucb", "No configuration");
            return;
        }

        prepareAndRegister(aData);
    }

    void UniversalContentBroker::prepareAndRegister(
        const ContentProviderDataList& rData)
    {
        ContentProviderDataList::const_iterator aEnd(rData.end());
        for (ContentProviderDataList::const_iterator aIt(rData.begin());
             aIt != aEnd; ++aIt)
        {
            OUString aProviderArguments;
            if (fillPlaceholders(aIt->Arguments,
                                 m_aArguments,
                                 &aProviderArguments))
            {
                registerAtUcb(this,
                              m_xContext,
                              aIt->ServiceName,
                              aProviderArguments,
                              aIt->URLTemplate);

            }
            else
                OSL_FAIL("UniversalContentBroker::prepareAndRegister(): Bad argument placeholders");
        }
    }

    bool UniversalContentBroker::getContentProviderData(
                const OUString & rKey1,
                const OUString & rKey2,
                ContentProviderDataList & rListToFill )
    {
        if ( !m_xContext.is() || rKey1.isEmpty() || rKey2.isEmpty() )
        {
            OSL_FAIL( "UniversalContentBroker::getContentProviderData - Invalid argument!" );
            return false;
        }

        try
        {
            uno::Reference< lang::XMultiServiceFactory > xConfigProv =
                    configuration::theDefaultProvider::get( m_xContext );

            OUStringBuffer aFullPath;
            aFullPath.append(
                    "/org.openoffice.ucb.Configuration/ContentProviders"
                    "/['" );
            makeAndAppendXMLName( aFullPath, rKey1 );
            aFullPath.append( "']/SecondaryKeys/['" );
            makeAndAppendXMLName( aFullPath, rKey2 );
            aFullPath.append( "']/ProviderData" );

            uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
            {
                {"nodepath", uno::Any(aFullPath.makeStringAndClear())}
            }));

            uno::Reference< uno::XInterface > xInterface(
                    xConfigProv->createInstanceWithArguments(
                        "com.sun.star.configuration.ConfigurationAccess",
                        aArguments ) );

            if ( !m_xNotifier.is() )
            {
                m_xNotifier.set( xInterface, uno::UNO_QUERY_THROW );

                m_xNotifier->addChangesListener( this );
            }

            uno::Reference< container::XNameAccess > xNameAccess(
                                                xInterface, uno::UNO_QUERY_THROW );

            uno::Sequence< OUString > aElems = xNameAccess->getElementNames();
            const OUString* pElems = aElems.getConstArray();
            sal_Int32 nCount = aElems.getLength();

            if ( nCount > 0 )
            {
                uno::Reference< container::XHierarchicalNameAccess >
                                    xHierNameAccess( xInterface, uno::UNO_QUERY_THROW );

                // Iterate over children.
                for ( sal_Int32 n = 0; n < nCount; ++n )
                {

                    try
                    {

                        ContentProviderData aInfo;

                        OUStringBuffer aElemBuffer;
                        aElemBuffer.append( "['" );
                        makeAndAppendXMLName( aElemBuffer, pElems[ n ] );
                        aElemBuffer.append( "']" );

                        OSL_VERIFY(
                            createContentProviderData(
                                aElemBuffer.makeStringAndClear(), xHierNameAccess,
                                aInfo));

                        rListToFill.push_back( aInfo );
                    }
                    catch (const container::NoSuchElementException&)
                    {
                        // getByHierarchicalName
                        OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
                                    "caught NoSuchElementException!" );
                    }
                }
            }
        }
        catch (const uno::RuntimeException&)
        {
            SAL_WARN( "ucb", "caught RuntimeException!" );
            return false;
        }
        catch (const uno::Exception&)
        {
            // createInstance, createInstanceWithArguments

            SAL_WARN( "ucb", "caught Exception!" );
            return false;
        }

        return true;
    }

    // ProviderListEntry_Impl implementation.

    Reference< XContentProvider > const & ProviderListEntry_Impl::resolveProvider() const
    {
        if ( !m_xResolvedProvider.is() )
        {
            Reference< XContentProviderSupplier > xSupplier(
                                                        m_xProvider, UNO_QUERY );
            if ( xSupplier.is() )
                m_xResolvedProvider = xSupplier->getContentProvider();

            if ( !m_xResolvedProvider.is() )
                m_xResolvedProvider = m_xProvider;
        }

        return m_xResolvedProvider;
    }

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

↑ V1019 Compound assignment expression 'm_aArguments[1] >>= aKey2' is used inside condition.

↑ V1019 Compound assignment expression 'm_aArguments[0] >>= aKey1' is used inside condition.