/* -*- 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 <sal/config.h>
 
#include <string_view>
 
#include <osl/diagnose.h>
#include <sal/log.hxx>
#include <rtl/ustrbuf.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/propertysequence.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/XContentProviderSupplier.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 <cppuhelper/supportsservice.hxx>
#include <cppuhelper/weak.hxx>
#include <ucbhelper/cancelcommandexecution.hxx>
#include <comphelper/diagnose_ex.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(OUString::Concat(std::u16string_view(pCopy, p - 1 - pCopy)) + "&");
                    p += 4;
                    pCopy = p;
                }
                else if (pEnd - p >= 3
                         && p[0] == 'l' && p[1] == 't' && p[2] == ';')
                {
                    aBuffer.append(OUString::Concat(std::u16string_view(pCopy, p - 1 - pCopy)) + "<");
                    p += 3;
                    pCopy = p;
                }
                else if (pEnd - p >= 3
                         && p[0] == 'g' && p[1] == 't' && p[2] == ';')
                {
                    aBuffer.append(OUString::Concat(std::u16string_view(pCopy, p - 1 - pCopy)) + ">");
                    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(std::u16string_view(pCopy, p - 1 - pCopy) + aValue);
                p = q + 1;
                pCopy = p;
                break;
        }
    aBuffer.append(pCopy, pEnd - pCopy);
    *pOutput = aBuffer.makeStringAndClear();
    return true;
}
 
void makeAndAppendXMLName(
                OUStringBuffer & rBuffer, std::u16string_view rIn )
{
    size_t nCount = rIn.size();
    for ( size_t 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(
    std::u16string_view rProvider,
    const uno::Reference< container::XHierarchicalNameAccess >& rxHierNameAccess,
    ContentProviderData & rInfo)
{
    // Obtain service name.
 
    OUString aValue;
    try
    {
        if ( !( rxHierNameAccess->getByHierarchicalName(
                    OUString::Concat(rProvider) +  "/ServiceName" ) >>= aValue ) )
        {
            OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
                        "Error getting item value!" );
        }
    }
    catch (const container::NoSuchElementException&)
    {
        return false;
    }
 
    rInfo.ServiceName = aValue;
 
    // Obtain URL Template.
 
    if ( !( rxHierNameAccess->getByHierarchicalName(
                OUString::Concat(rProvider) + "/URLTemplate" ) >>= aValue ) )
    {
        OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
                    "Error getting item value!" );
    }
 
    rInfo.URLTemplate = aValue;
 
    // Obtain Arguments.
 
    if ( !( rxHierNameAccess->getByHierarchicalName(
                OUString::Concat(rProvider) + "/Arguments" ) >>= 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()
{
}
 
 
// 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 OInterfaceContainerHelper3<css::lang::XEventListener>( 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.
 
OUString SAL_CALL UniversalContentBroker::getImplementationName()
{
    return u"com.sun.star.comp.ucb.UniversalContentBroker"_ustr;
}
sal_Bool SAL_CALL UniversalContentBroker::supportsService( const OUString& ServiceName )
{
    return cppu::supportsService( this, ServiceName );
}
css::uno::Sequence< OUString > SAL_CALL UniversalContentBroker::getSupportedServiceNames()
{
    return { u"com.sun.star.ucb.UniversalContentBroker"_ustr };
}
 
 
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
ucb_UniversalContentBroker_get_implementation(
    css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
{
    return cppu::acquire(new UniversalContentBroker(context));
}
 
 
// XInitialization methods.
 
 
// virtual
void SAL_CALL UniversalContentBroker::initialize( const css::uno::Sequence< Any >& aArguments )
{
    {
        osl::MutexGuard aGuard(m_aMutex);
        if (m_aArguments.hasElements())
        {
            if (aArguments.hasElements()
                && !(m_aArguments.getLength() == 2
                     && aArguments.getLength() == 2
                     && m_aArguments[0] == aArguments[0]
                     && m_aArguments[1] == aArguments[1]))
            {
                throw IllegalArgumentException(
                    u"UCB reinitialized with different arguments"_ustr,
                    getXWeak(), 0);
            }
            return;
        }
        if (!aArguments.hasElements())
        {
            m_aArguments = { Any(u"Local"_ustr), Any(u"Office"_ustr) };
        }
        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();
 
        auto aListIt = std::find_if(rList.begin(), rList.end(),
            [&Provider](const ProviderListEntry_Impl& rEntry) { return rEntry.getProvider() == Provider; });
        if (aListIt != rList.end())
            rList.erase(aListIt);
 
        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(
                    Any( IllegalArgumentException(
                                    u"Wrong argument type!"_ustr,
                                    getXWeak(),
                                    -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(
                Any( IllegalArgumentException(
                                u"Wrong argument type!"_ustr,
                                getXWeak(),
                                -1 ) ),
                Environment );
            // Unreachable
        }
        aRet = checkIn( aCheckinArg, Environment );
    }
    else
    {
 
        // Unknown command
 
 
        ucbhelper::cancelCommandExecution(
            Any( UnsupportedCommandException(
                            OUString(),
                            getXWeak() ) ),
            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 )
{
    if ( !Event.Changes.hasElements() )
        return;
 
    uno::Reference< container::XHierarchicalNameAccess > xHierNameAccess;
    Event.Base >>= xHierNameAccess;
 
    OSL_ASSERT( xHierNameAccess.is() );
 
    ContentProviderDataList aData;
    for ( const util::ElementChange& rElem : Event.Changes )
    {
        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)
{
    for (const auto& rContentProviderData : rData)
    {
        OUString aProviderArguments;
        if (fillPlaceholders(rContentProviderData.Arguments,
                             m_aArguments,
                             &aProviderArguments))
        {
            registerAtUcb(this,
                          m_xContext,
                          rContentProviderData.ServiceName,
                          aProviderArguments,
                          rContentProviderData.URLTemplate);
 
        }
        else
            OSL_FAIL("UniversalContentBroker::prepareAndRegister(): Bad argument placeholders");
    }
}
 
 
bool UniversalContentBroker::getContentProviderData(
            std::u16string_view rKey1,
            std::u16string_view rKey2,
            ContentProviderDataList & rListToFill )
{
    if ( !m_xContext.is() || rKey1.empty() || rKey2.empty() )
    {
        OSL_FAIL( "UniversalContentBroker::getContentProviderData - Invalid argument!" );
        return false;
    }
 
    try
    {
        uno::Reference< lang::XMultiServiceFactory > xConfigProv =
                configuration::theDefaultProvider::get( m_xContext );
 
        OUStringBuffer aFullPath(128);
        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(
                    u"com.sun.star.configuration.ConfigurationAccess"_ustr,
                    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 );
 
        const uno::Sequence< OUString > aElems = xNameAccess->getElementNames();
 
        if ( aElems.hasElements() )
        {
            uno::Reference< container::XHierarchicalNameAccess >
                                xHierNameAccess( xInterface, uno::UNO_QUERY_THROW );
 
            // Iterate over children.
            for ( const auto& rElem : aElems )
            {
 
                try
                {
 
                    ContentProviderData aInfo;
 
                    OUStringBuffer aElemBuffer( "['" );
                    makeAndAppendXMLName( aElemBuffer, rElem );
                    aElemBuffer.append( "']" );
 
                    OSL_VERIFY(
                        createContentProviderData(
                            aElemBuffer, xHierNameAccess,
                            aInfo));
 
                    rListToFill.push_back( aInfo );
                }
                catch (const container::NoSuchElementException&)
                {
                    // getByHierarchicalName
                    OSL_FAIL( "UniversalContentBroker::getContentProviderData - "
                                "caught NoSuchElementException!" );
                }
            }
        }
    }
    catch (const uno::RuntimeException&)
    {
        TOOLS_WARN_EXCEPTION( "ucb", "" );
        return false;
    }
    catch (const uno::Exception&)
    {
        // createInstance, createInstanceWithArguments
 
        TOOLS_WARN_EXCEPTION( "ucb", "" );
        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: */

↑ V530 The return value of function 'append' is required to be utilized.

↑ V530 The return value of function 'append' is required to be utilized.

↑ V530 The return value of function 'append' is required to be utilized.

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

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