    /* -*- 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 <svx/dataaccessdescriptor.hxx>
    #include <osl/diagnose.h>
    #include <com/sun/star/sdbc/XConnection.hpp>
    #include <com/sun/star/ucb/XContent.hpp>
    #include <com/sun/star/beans/PropertyAttribute.hpp>
    #include <tools/urlobj.hxx>
    #include <map>

    namespace svx
    {
        using namespace ::com::sun::star::uno;
        using namespace ::com::sun::star::sdbc;
        using namespace ::com::sun::star::beans;
        using namespace ::com::sun::star::ucb;

        struct PropertyMapEntry
        {
            OUString       maName;
            DataAccessDescriptorProperty      mnHandle;
        };

        class ODADescriptorImpl
        {
        protected:
            bool                    m_bSetOutOfDate         : 1;
            bool                    m_bSequenceOutOfDate    : 1;

        public:
            typedef ::std::map< DataAccessDescriptorProperty, Any >     DescriptorValues;
            DescriptorValues            m_aValues;
            Sequence< PropertyValue >   m_aAsSequence;
            Reference< XPropertySet >   m_xAsSet;

            typedef ::std::map< OUString, PropertyMapEntry const * >    MapString2PropertyEntry;

        public:
            ODADescriptorImpl();
            ODADescriptorImpl(const ODADescriptorImpl& _rSource);

            void invalidateExternRepresentations();

            void updateSequence();

            /** builds the descriptor from a property value sequence
                @return <TRUE/>
                    if and only if the sequence contained valid properties only
            */
            bool buildFrom( const Sequence< PropertyValue >& _rValues );

            /** builds the descriptor from a property set
                @return <TRUE/>
                    if and only if the set contained valid properties only
            */
            bool buildFrom( const Reference< XPropertySet >& _rValues );

        protected:
            static PropertyValue                    buildPropertyValue( const DescriptorValues::const_iterator& _rPos );
            static const MapString2PropertyEntry&   getPropertyMap( );
            static PropertyMapEntry const *         getPropertyMapEntry( const DescriptorValues::const_iterator& _rPos );
        };

        ODADescriptorImpl::ODADescriptorImpl()
            :m_bSetOutOfDate(true)
            ,m_bSequenceOutOfDate(true)
        {
        }

        ODADescriptorImpl::ODADescriptorImpl(const ODADescriptorImpl& _rSource)
            :m_bSetOutOfDate( _rSource.m_bSetOutOfDate )
            ,m_bSequenceOutOfDate( _rSource.m_bSequenceOutOfDate )
            ,m_aValues( _rSource.m_aValues )
        {
            if (!m_bSetOutOfDate)
                m_xAsSet = _rSource.m_xAsSet;
            if (!m_bSequenceOutOfDate)
                m_aAsSequence = _rSource.m_aAsSequence;
        }

        bool ODADescriptorImpl::buildFrom( const Sequence< PropertyValue >& _rValues )
        {
            const MapString2PropertyEntry& rProperties = getPropertyMap();

            bool bValidPropsOnly = true;

            // loop through the sequence, and fill our m_aValues
            const PropertyValue* pValues = _rValues.getConstArray();
            const PropertyValue* pValuesEnd = pValues + _rValues.getLength();
            for (;pValues != pValuesEnd; ++pValues)
            {
                MapString2PropertyEntry::const_iterator aPropPos = rProperties.find( pValues->Name );
                if ( aPropPos != rProperties.end() )
                {
                    DataAccessDescriptorProperty eProperty = aPropPos->second->mnHandle;
                    m_aValues[eProperty] = pValues->Value;
                }
                else
                    // unknown property
                    bValidPropsOnly = false;
            }

            if (bValidPropsOnly)
            {
                m_aAsSequence = _rValues;
                m_bSequenceOutOfDate = false;
            }
            else
                m_bSequenceOutOfDate = true;

            return bValidPropsOnly;
        }

        bool ODADescriptorImpl::buildFrom( const Reference< XPropertySet >& _rxValues )
        {
            Reference< XPropertySetInfo > xPropInfo;
            if (_rxValues.is())
                xPropInfo = _rxValues->getPropertySetInfo();
            if (!xPropInfo.is())
            {
                OSL_FAIL("ODADescriptorImpl::buildFrom: invalid property set!");
                return false;
            }

            // build a PropertyValue sequence with the current values
            Sequence< Property > aProperties = xPropInfo->getProperties();
            const Property* pProperty = aProperties.getConstArray();
            const Property* pPropertyEnd = pProperty + aProperties.getLength();

            Sequence< PropertyValue > aValues(aProperties.getLength());
            PropertyValue* pValues = aValues.getArray();

            for (;pProperty != pPropertyEnd; ++pProperty, ++pValues)
            {
                pValues->Name = pProperty->Name;
                pValues->Value = _rxValues->getPropertyValue(pProperty->Name);
            }

            bool bValidPropsOnly = buildFrom(aValues);
            if (bValidPropsOnly)
            {
                m_xAsSet = _rxValues;
                m_bSetOutOfDate = false;
            }
            else
                m_bSetOutOfDate = true;

            return bValidPropsOnly;
        }

        void ODADescriptorImpl::invalidateExternRepresentations()
        {
            m_bSetOutOfDate = true;
            m_bSequenceOutOfDate = true;
        }

        const ODADescriptorImpl::MapString2PropertyEntry& ODADescriptorImpl::getPropertyMap( )
        {
            // the properties we know
            static MapString2PropertyEntry s_aProperties;
            if ( s_aProperties.empty() )
            {
                static PropertyMapEntry const s_aDescriptorProperties[] =
                {
                    { OUString("ActiveConnection"),   DataAccessDescriptorProperty::Connection,            },
                    { OUString("BookmarkSelection"),  DataAccessDescriptorProperty::BookmarkSelection,     },
                    { OUString("Column"),             DataAccessDescriptorProperty::ColumnObject,          },
                    { OUString("ColumnName"),         DataAccessDescriptorProperty::ColumnName,            },
                    { OUString("Command"),            DataAccessDescriptorProperty::Command,               },
                    { OUString("CommandType"),        DataAccessDescriptorProperty::CommandType,           },
                    { OUString("Component"),          DataAccessDescriptorProperty::Component,             },
                    { OUString("ConnectionResource"), DataAccessDescriptorProperty::ConnectionResource,    },
                    { OUString("Cursor"),             DataAccessDescriptorProperty::Cursor,                },
                    { OUString("DataSourceName"),     DataAccessDescriptorProperty::DataSource,            },
                    { OUString("DatabaseLocation"),   DataAccessDescriptorProperty::DatabaseLocation,      },
                    { OUString("EscapeProcessing"),   DataAccessDescriptorProperty::EscapeProcessing,      },
                    { OUString("Filter"),             DataAccessDescriptorProperty::Filter,                },
                    { OUString("Selection"),          DataAccessDescriptorProperty::Selection,             }
                };

                for (unsigned i=0; i<SAL_N_ELEMENTS(s_aDescriptorProperties); ++i)
                    s_aProperties[ s_aDescriptorProperties[i].maName ] = &s_aDescriptorProperties[i];
            }

            return s_aProperties;
        }

        PropertyMapEntry const * ODADescriptorImpl::getPropertyMapEntry( const DescriptorValues::const_iterator& _rPos )
        {
            const MapString2PropertyEntry& rProperties = getPropertyMap();

            DataAccessDescriptorProperty nNeededHandle = _rPos->first;

            for ( MapString2PropertyEntry::const_iterator loop = rProperties.begin();
                  loop != rProperties.end();
                  ++loop
                )
            {
                if ( nNeededHandle == loop->second->mnHandle )
                    return loop->second;
            }
            throw RuntimeException();
        }

        PropertyValue ODADescriptorImpl::buildPropertyValue( const DescriptorValues::const_iterator& _rPos )
        {
            // the map entry
            PropertyMapEntry const * pProperty = getPropertyMapEntry( _rPos );

            // build the property value
            PropertyValue aReturn;
            aReturn.Name    = pProperty->maName;
            aReturn.Handle  = static_cast<sal_Int32>(pProperty->mnHandle);
            aReturn.Value   = _rPos->second;
            aReturn.State   = PropertyState_DIRECT_VALUE;

            // outta here
            return aReturn;
        }

        void ODADescriptorImpl::updateSequence()
        {
            if (!m_bSequenceOutOfDate)
                return;

            m_aAsSequence.realloc(m_aValues.size());
            PropertyValue* pValue = m_aAsSequence.getArray();

            // loop through all our values
            for (   DescriptorValues::const_iterator aLoop = m_aValues.begin();
                    aLoop != m_aValues.end();
                    ++aLoop, ++pValue
                )
            {
                *pValue = buildPropertyValue(aLoop);
            }

            // don't need to rebuild next time
            m_bSequenceOutOfDate = false;
        }

        ODataAccessDescriptor::ODataAccessDescriptor()
            :m_pImpl(new ODADescriptorImpl)
        {
        }

        ODataAccessDescriptor::ODataAccessDescriptor( const ODataAccessDescriptor& _rSource )
            :m_pImpl(new ODADescriptorImpl(*_rSource.m_pImpl))
        {
        }

        ODataAccessDescriptor::ODataAccessDescriptor( ODataAccessDescriptor&& _rSource )
            :m_pImpl(std::move(_rSource.m_pImpl))
        {
        }

        ODataAccessDescriptor& ODataAccessDescriptor::operator=(const ODataAccessDescriptor& _rSource)
        {
            m_pImpl.reset(new ODADescriptorImpl(*_rSource.m_pImpl));
            return *this;
        }

        ODataAccessDescriptor& ODataAccessDescriptor::operator=(ODataAccessDescriptor&& _rSource)
        {
            m_pImpl = std::move(_rSource.m_pImpl);
            return *this;
        }

        ODataAccessDescriptor::ODataAccessDescriptor( const Reference< XPropertySet >& _rValues )
            :m_pImpl(new ODADescriptorImpl)
        {
            m_pImpl->buildFrom(_rValues);
        }

        ODataAccessDescriptor::ODataAccessDescriptor( const Any& _rValues )
            :m_pImpl(new ODADescriptorImpl)
        {
            // check if we know the format in the Any
            Sequence< PropertyValue > aValues;
            Reference< XPropertySet > xValues;
            if ( _rValues >>= aValues )
                m_pImpl->buildFrom( aValues );
            else if ( _rValues >>= xValues )
                m_pImpl->buildFrom( xValues );
        }

        ODataAccessDescriptor::ODataAccessDescriptor( const Sequence< PropertyValue >& _rValues )
            :m_pImpl(new ODADescriptorImpl)
        {
            m_pImpl->buildFrom(_rValues);
        }

        ODataAccessDescriptor::~ODataAccessDescriptor()
        {
        }

        void ODataAccessDescriptor::clear()
        {
            m_pImpl->m_aValues.clear();
        }

        void ODataAccessDescriptor::erase(DataAccessDescriptorProperty _eWhich)
        {
            OSL_ENSURE(has(_eWhich), "ODataAccessDescriptor::erase: invalid call!");
            if (has(_eWhich))
                m_pImpl->m_aValues.erase(_eWhich);
        }

        bool ODataAccessDescriptor::has(DataAccessDescriptorProperty _eWhich) const
        {
            return m_pImpl->m_aValues.find(_eWhich) != m_pImpl->m_aValues.end();
        }

        const Any& ODataAccessDescriptor::operator [] ( DataAccessDescriptorProperty _eWhich ) const
        {
            if (!has(_eWhich))
            {
                OSL_FAIL("ODataAccessDescriptor::operator[]: invalid accessor!");
                static const Any aDummy;
                return aDummy;
            }

            return m_pImpl->m_aValues[_eWhich];
        }

        Any& ODataAccessDescriptor::operator[] ( DataAccessDescriptorProperty _eWhich )
        {
            m_pImpl->invalidateExternRepresentations();
            return m_pImpl->m_aValues[_eWhich];
        }

        void ODataAccessDescriptor::initializeFrom(const Sequence< PropertyValue >& _rValues)
        {
            clear();
            m_pImpl->buildFrom(_rValues);
        }

        Sequence< PropertyValue > const & ODataAccessDescriptor::createPropertyValueSequence()
        {
            m_pImpl->updateSequence();
            return m_pImpl->m_aAsSequence;
        }

        OUString ODataAccessDescriptor::getDataSource() const
        {
            OUString sDataSourceName;
            if ( has(DataAccessDescriptorProperty::DataSource) )
                (*this)[DataAccessDescriptorProperty::DataSource] >>= sDataSourceName;
            else if ( has(DataAccessDescriptorProperty::DatabaseLocation) )
                (*this)[DataAccessDescriptorProperty::DatabaseLocation] >>= sDataSourceName;
            return sDataSourceName;
        }

        void ODataAccessDescriptor::setDataSource(const OUString& _sDataSourceNameOrLocation)
        {
            if ( !_sDataSourceNameOrLocation.isEmpty() )
            {
                INetURLObject aURL(_sDataSourceNameOrLocation);
                (*this)[ (( aURL.GetProtocol() == INetProtocol::File ) ? DataAccessDescriptorProperty::DatabaseLocation : DataAccessDescriptorProperty::DataSource)] <<= _sDataSourceNameOrLocation;
            }
            else
                (*this)[ DataAccessDescriptorProperty::DataSource ] <<= OUString();
        }
    }

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

↑ V794 The assignment operator should be protected from the case of 'this == &_rSource'.