Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/xmloff/source/style/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 42 kB image not shown  

Quelle  xmlexppr.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <memory>
#include <optional>
#include <string_view>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/xml/AttributeData.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertyState.hpp>
#include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/beans/XTolerantMultiPropertySet.hpp>
#include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
#include <comphelper/anycompare.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <cppuhelper/weakref.hxx>
#include <osl/diagnose.h>
#include <list>
#include <map>
#include <o3tl/sorted_vector.hxx>

#include <utility>
#include <xmloff/xmlexppr.hxx>
#include <xmloff/xmltoken.hxx>
#include <xmloff/namespacemap.hxx>
#include <xmloff/xmlnamespace.hxx>
#include <xmloff/xmlexp.hxx>
#include <xmloff/xmlprmap.hxx>
#include <xmloff/maptype.hxx>
#include <xmloff/xmltypes.hxx>
#include <xmloff/xmlprhdl.hxx>

using namespace ::com::sun::star;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::uno;
using namespace ::xmloff::token;

#define GET_PROP_TYPE( f ) static_cast<sal_uInt16>((f & XML_TYPE_PROP_MASK) >> XML_TYPE_PROP_SHIFT)

namespace {

struct XMLPropTokens_Impl
{
    sal_uInt16 nType;
    XMLTokenEnum eToken;
};

const sal_uInt16 MAX_PROP_TYPES =
    (XML_TYPE_PROP_END >> XML_TYPE_PROP_SHIFT) -
    (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT);

XMLPropTokens_Impl const aPropTokens[MAX_PROP_TYPES] =
{
    { GET_PROP_TYPE(XML_TYPE_PROP_CHART), XML_CHART_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_GRAPHIC), XML_GRAPHIC_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_TABLE), XML_TABLE_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_COLUMN), XML_TABLE_COLUMN_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_ROW), XML_TABLE_ROW_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_TABLE_CELL), XML_TABLE_CELL_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_LIST_LEVEL), XML_LIST_LEVEL_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_PARAGRAPH), XML_PARAGRAPH_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_TEXT), XML_TEXT_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_DRAWING_PAGE), XML_DRAWING_PAGE_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_PAGE_LAYOUT), XML_PAGE_LAYOUT_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_HEADER_FOOTER), XML_HEADER_FOOTER_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_RUBY), XML_RUBY_PROPERTIES },
    { GET_PROP_TYPE(XML_TYPE_PROP_SECTION), XML_SECTION_PROPERTIES }
};

// public methods

// Take all properties of the XPropertySet which are also found in the
// XMLPropertyMapEntry-array and which are not set to their default-value,
// if a state is available.
// After that I call the method 'ContextFilter'.

struct ComparePropertyState
{
    bool operator()(XMLPropertyState const& lhs, XMLPropertyState const& rhs)
    {
        return lhs.mnIndex < rhs.mnIndex;
    }
};
class XMLPropertyStates_Impl
{
    o3tl::sorted_vector<XMLPropertyState, ComparePropertyState> aPropStates;
public:
    XMLPropertyStates_Impl();
    void AddPropertyState(const XMLPropertyState& rPropState);
    void FillPropertyStateVector(std::vector<XMLPropertyState>& rVector);
};

XMLPropertyStates_Impl::XMLPropertyStates_Impl()
{
}

void XMLPropertyStates_Impl::AddPropertyState(
        const XMLPropertyState& rPropState)
{
    aPropStates.insert(rPropState);
}

void XMLPropertyStates_Impl::FillPropertyStateVector(
        std::vector<XMLPropertyState>& rVector)
{
    rVector.insert( rVector.begin(), aPropStates.begin(), aPropStates.end() );
}

class FilterPropertyInfo_Impl
{
    OUString                msApiName;
    std::vector<sal_uInt32> maIndexes;

public:

    FilterPropertyInfo_Impl( OUString aApiName,
                             const sal_uInt32 nIndex);

    const OUString& GetApiName() const { return msApiName; }
    std::vector<sal_uInt32>& GetIndexes() { return maIndexes; }

    // for sort
    bool operator< ( const FilterPropertyInfo_Impl& rArg ) const
    {
        return (GetApiName() < rArg.GetApiName());
    }
};

FilterPropertyInfo_Impl::FilterPropertyInfo_Impl(
        OUString aApiName,
        const sal_uInt32 nIndex ) :
    msApiName(std::move( aApiName ))
{
    maIndexes.push_back(nIndex);
}

typedef std::list<FilterPropertyInfo_Impl> FilterPropertyInfoList_Impl;

class FilterPropertiesInfo_Impl
{
    FilterPropertyInfoList_Impl             aPropInfos;

    std::optional<Sequence<OUString>>     mxApiNames;

public:
    FilterPropertiesInfo_Impl();

    void AddProperty(const OUString& rApiName, const sal_uInt32 nIndex);
    const uno::Sequence<OUString>& GetApiNames();
    void FillPropertyStateArray(
            std::vector< XMLPropertyState >& rPropStates,
            const Reference< XPropertySet >& xPropSet,
            const rtl::Reference< XMLPropertySetMapper >& maPropMapper,
            const bool bDefault);
    sal_uInt32 GetPropertyCount() const { return aPropInfos.size(); }
};

FilterPropertiesInfo_Impl::FilterPropertiesInfo_Impl()
{
}

void FilterPropertiesInfo_Impl::AddProperty(
        const OUString& rApiName, const sal_uInt32 nIndex)
{
    aPropInfos.emplace_back(rApiName, nIndex);

    OSL_ENSURE( !mxApiNames, "performance warning: API names already retrieved" );
    mxApiNames.reset();
}

const uno::Sequence<OUString>& FilterPropertiesInfo_Impl::GetApiNames()
{
    if( !mxApiNames )
    {
        // we have to do three things:
        // 1) sort API names,
        // 2) merge duplicates,
        // 3) construct sequence

        // sort names
        aPropInfos.sort();

        // merge duplicates
        if ( aPropInfos.size() > 1 )
        {
            FilterPropertyInfoList_Impl::iterator aOld = aPropInfos.begin();
            FilterPropertyInfoList_Impl::iterator aEnd = aPropInfos.end();
            FilterPropertyInfoList_Impl::iterator aCurrent = aOld;
            ++aCurrent;

            while ( aCurrent != aEnd )
            {
                // equal to next element?
                if ( aOld->GetApiName() == aCurrent->GetApiName() )
                {
                    // if equal: merge index lists
                    std::vector<sal_uInt32> aMerged;
                    std::merge(aOld->GetIndexes().begin(), aOld->GetIndexes().end(),
                               aCurrent->GetIndexes().begin(), aCurrent->GetIndexes().end(),
                               std::back_inserter(aMerged));
                    aOld->GetIndexes() = std::move(aMerged);
                    aCurrent->GetIndexes().clear();
                    // erase element, and continue with next
                    aCurrent = aPropInfos.erase( aCurrent );
                }
                else
                {
                    // remember old element and continue with next
                    aOld = aCurrent;
                    ++aCurrent;
                }
            }
        }

        // construct sequence
        mxApiNames.emplace( aPropInfos.size() );
        OUString *pNames = mxApiNames->getArray();

        for (auto const& propInfo : aPropInfos)
        {
            *pNames = propInfo.GetApiName();
            ++pNames;
        }
    }

    return *mxApiNames;
}

void FilterPropertiesInfo_Impl::FillPropertyStateArray(
        std::vector< XMLPropertyState >& rPropStates,
        const Reference< XPropertySet >& rPropSet,
        const rtl::Reference< XMLPropertySetMapper >& rPropMapper,
        const bool bDefault )
{
    XMLPropertyStates_Impl aPropStates;

    const uno::Sequence<OUString>& rApiNames = GetApiNames();

    Reference < XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY );
    if (xTolPropSet.is())
    {
        if (!bDefault)
        {
            Sequence < beans::GetDirectPropertyTolerantResult > aResults(xTolPropSet->getDirectPropertyValuesTolerant(rApiNames));
            sal_Int32 nResultCount(aResults.getLength());
            if (nResultCount > 0)
            {
                const beans::GetDirectPropertyTolerantResult *pResults = aResults.getConstArray();
                FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin());
                XMLPropertyState aNewProperty( -1 );
                while (nResultCount > 0 && aPropIter != aPropInfos.end())
                {
                    if (pResults->Name == aPropIter->GetApiName())
                    {
                        aNewProperty.mnIndex = -1;
                        aNewProperty.maValue = pResults->Value;

                        for (auto const& index : aPropIter->GetIndexes())
                        {
                            aNewProperty.mnIndex = index;
                            aPropStates.AddPropertyState( aNewProperty );
                        }
                        ++pResults;
                        --nResultCount;
                    }
                    ++aPropIter;
                }
            }
        }
        else
        {
            const Sequence < beans::GetPropertyTolerantResult > aResults(xTolPropSet->getPropertyValuesTolerant(rApiNames));
            OSL_ENSURE( rApiNames.getLength() == aResults.getLength(), "wrong implemented XTolerantMultiPropertySet" );
            FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin());
            XMLPropertyState aNewProperty( -1 );
            OSL_ENSURE( aPropInfos.size() == static_cast<sal_uInt32>(aResults.getLength()), "wrong implemented XTolerantMultiPropertySet??" );
            forconst auto& rResult : aResults )
            {
                if ((rResult.Result == beans::TolerantPropertySetResultType::SUCCESS) &&
                    ((rResult.State == PropertyState_DIRECT_VALUE) || (rResult.State == PropertyState_DEFAULT_VALUE)))
                {
                    aNewProperty.mnIndex = -1;
                    aNewProperty.maValue = rResult.Value;

                    for (auto const& index : aPropIter->GetIndexes())
                    {
                        aNewProperty.mnIndex = index;
                        aPropStates.AddPropertyState( aNewProperty );
                    }
                }
                ++aPropIter;
            }
        }
    }
    else
    {
        Sequence < PropertyState > aStates;
        const PropertyState *pStates = nullptr;
        Reference< XPropertyState > xPropState( rPropSet, UNO_QUERY );
        if( xPropState.is() )
        {
            aStates = xPropState->getPropertyStates( rApiNames );
            pStates = aStates.getConstArray();
        }

        Reference < XMultiPropertySet > xMultiPropSet( rPropSet, UNO_QUERY );
        if( xMultiPropSet.is() && !bDefault )
        {
            Sequence < Any > aValues;
            if( pStates )
            {
                // step 1: get value count
                sal_uInt32 nValueCount = 0;

                for (size_t i = 0; i < aPropInfos.size(); ++i, ++pStates)
                {
                    if( *pStates == PropertyState_DIRECT_VALUE )
                        nValueCount++;
                }

                if( nValueCount )
                {
                    // step 2: collect property names
                    Sequence < OUString > aAPINames( nValueCount );
                    OUString *pAPINames = aAPINames.getArray();

                    ::std::vector< FilterPropertyInfoList_Impl::iterator > aPropIters;
                    aPropIters.reserve( nValueCount );

                    FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
                    OSL_ENSURE(aItr != aPropInfos.end(),"Invalid iterator!");

                    pStates = aStates.getConstArray();
                    sal_uInt32 i = 0;
                    while( i < nValueCount )
                    {
                        if( *pStates == PropertyState_DIRECT_VALUE )
                        {
                            *pAPINames++ = aItr->GetApiName();
                            aPropIters.push_back( aItr );
                            ++i;
                        }
                        ++aItr;
                        ++pStates;
                    }

                    aValues = xMultiPropSet->getPropertyValues( aAPINames );
                    const Any *pValues = aValues.getConstArray();

                    ::std::vector< FilterPropertyInfoList_Impl::iterator >::const_iterator
                        pPropIter = aPropIters.begin();

                    XMLPropertyState aNewProperty( -1 );
                    for( i = 0; i < nValueCount; ++i )
                    {
                        aNewProperty.mnIndex = -1;
                        aNewProperty.maValue = *pValues;

                        for (auto const& index : (*pPropIter)->GetIndexes())
                        {
                            aNewProperty.mnIndex = index;
                            aPropStates.AddPropertyState( aNewProperty );
                        }

                        ++pPropIter;
                        ++pValues;
                    }
                }
            }
            else
            {
                aValues = xMultiPropSet->getPropertyValues( rApiNames );
                const Any *pValues = aValues.getConstArray();

                FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
                for (size_t i = 0; i < aPropInfos.size(); ++i)
                {
                    // The value is stored in the PropertySet itself, add to list.
                    XMLPropertyState aNewProperty( -1 );
                    aNewProperty.maValue = *pValues;
                    ++pValues;
                    for (auto const& index : aItr->GetIndexes())
                    {
                        aNewProperty.mnIndex = index;
                        aPropStates.AddPropertyState( aNewProperty );
                    }
                    ++aItr;
                }
            }
        }
        else
        {
            FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin();
            for (size_t i = 0; i < aPropInfos.size(); ++i)
            {
                bool bDirectValue =
                    !pStates || *pStates == PropertyState_DIRECT_VALUE;
                if( bDirectValue || bDefault )
                {
                    // The value is stored in the PropertySet itself, add to list.
                    bool bGotValue = false;
                    XMLPropertyState aNewProperty( -1 );
                    for (auto const& index : aItr->GetIndexes())
                    {
                        if( bDirectValue ||
                            (rPropMapper->GetEntryFlags(index) &
                                            MID_FLAG_DEFAULT_ITEM_EXPORT) != 0 )
                        {
                            try
                            {
                                if( !bGotValue )
                                {
                                    aNewProperty.maValue =
                                        rPropSet->getPropertyValue( aItr->GetApiName() );
                                    bGotValue = true;
                                }
                                aNewProperty.mnIndex = index;
                                aPropStates.AddPropertyState( aNewProperty );
                            }
                            catch( UnknownPropertyException& )
                            {
                                // might be a problem of getImplementationId
                                TOOLS_WARN_EXCEPTION("xmloff.style""unknown property in getPropertyValue" );
                            }

                        }
                    }
                }

                ++aItr;
                if( pStates )
                    ++pStates;
            }
        }
    }
    aPropStates.FillPropertyStateVector(rPropStates);
}

}

struct SvXMLExportPropertyMapper::Impl
{
    typedef std::map<css::uno::Reference<css::beans::XPropertySetInfo>, std::unique_ptr<FilterPropertiesInfo_Impl>> CacheType;
    CacheType maCache;

    rtl::Reference<SvXMLExportPropertyMapper> mxNextMapper;
    rtl::Reference<XMLPropertySetMapper> mxPropMapper;

    OUString maStyleName;
};

// ctor/dtor , class SvXMLExportPropertyMapper

SvXMLExportPropertyMapper::SvXMLExportPropertyMapper(
        const rtl::Reference< XMLPropertySetMapper >& rMapper ) :
    mpImpl(new Impl)
{
    mpImpl->mxPropMapper = rMapper;
}

SvXMLExportPropertyMapper::~SvXMLExportPropertyMapper()
{
}

void SvXMLExportPropertyMapper::ChainExportMapper(
        const rtl::Reference< SvXMLExportPropertyMapper>& rMapper )
{
    // add map entries from rMapper to current map
    mpImpl->mxPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() );
    // rMapper uses the same map as 'this'
    rMapper->mpImpl->mxPropMapper = mpImpl->mxPropMapper;

    // set rMapper as last mapper in current chain
    rtl::Reference< SvXMLExportPropertyMapper > xNext = mpImpl->mxNextMapper;
    if( xNext.is())
    {
        while (xNext->mpImpl->mxNextMapper.is())
            xNext = xNext->mpImpl->mxNextMapper;
        xNext->mpImpl->mxNextMapper = rMapper;
    }
    else
        mpImpl->mxNextMapper = rMapper;

    // if rMapper was already chained, correct
    // map pointer of successors
    xNext = rMapper;

    while (xNext->mpImpl->mxNextMapper.is())
    {
        xNext = xNext->mpImpl->mxNextMapper;
        xNext->mpImpl->mxPropMapper = mpImpl->mxPropMapper;
    }
}

std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter(
    SvXMLExport const& rExport,
    const uno::Reference<beans::XPropertySet>& rPropSet, bool bEnableFoFontFamily ) const
{
    return Filter_(rExport, rPropSet, false, bEnableFoFontFamily);
}

std::vector<XMLPropertyState> SvXMLExportPropertyMapper::FilterDefaults(
    SvXMLExport const& rExport,
    const uno::Reference<beans::XPropertySet>& rPropSet ) const
{
    return Filter_(rExport, rPropSet, truefalse/*bEnableFoFontFamily*/);
}

std::vector<XMLPropertyState> SvXMLExportPropertyMapper::Filter_(
    SvXMLExport const& rExport,
    const Reference<XPropertySet>& xPropSet, bool bDefault, bool bEnableFoFontFamily ) const
{
    std::vector< XMLPropertyState > aPropStateArray;

    // Retrieve XPropertySetInfo and XPropertyState
    Reference< XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() );
    if( !xInfo.is() )
        return aPropStateArray;

    sal_Int32 nProps = mpImpl->mxPropMapper->GetEntryCount();

    FilterPropertiesInfo_Impl *pFilterInfo = nullptr;

    Impl::CacheType::iterator aIter = mpImpl->maCache.find(xInfo);
    if (aIter != mpImpl->maCache.end())
        pFilterInfo = (*aIter).second.get();

    bool bDelInfo = false;
    if( !pFilterInfo )
    {
        assert(GetODFDefaultVersion() != SvtSaveOptions::ODFVER_UNKNOWN);
        const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(rExport.getSaneDefaultVersion());
        pFilterInfo = new FilterPropertiesInfo_Impl;
        for( sal_Int32 i=0; i < nProps; i++ )
        {
            // Are we allowed to ask for the property? (MID_FLAG_NO_PROP..)
            // Does the PropertySet contain name of mpEntries-array ?
            const OUString& rAPIName = mpImpl->mxPropMapper->GetEntryAPIName( i );
            const sal_Int32 nFlags = mpImpl->mxPropMapper->GetEntryFlags( i );
            if( (0 == (nFlags & MID_FLAG_NO_PROPERTY_EXPORT)) &&
                ( (0 != (nFlags & MID_FLAG_MUST_EXIST)) ||
                  xInfo->hasPropertyByName( rAPIName ) ) )
            {
                const SvtSaveOptions::ODFSaneDefaultVersion nEarliestODFVersionForExport(
                        mpImpl->mxPropMapper->GetEarliestODFVersionForExport(i));
                // note: only standard ODF versions are allowed here,
                // only exception is the unknown future
                assert((nEarliestODFVersionForExport & SvtSaveOptions::ODFSVER_EXTENDED) == 0
                    || nEarliestODFVersionForExport == SvtSaveOptions::ODFSVER_FUTURE_EXTENDED);
                static_assert(SvtSaveOptions::ODFSVER_LATEST_EXTENDED < SvtSaveOptions::ODFSVER_FUTURE_EXTENDED);
                /// standard ODF namespaces for elements and attributes
                static sal_uInt16 s_OdfNs[] = {
                    XML_NAMESPACE_OFFICE,
                    XML_NAMESPACE_STYLE,
                    XML_NAMESPACE_TEXT,
                    XML_NAMESPACE_TABLE,
                    XML_NAMESPACE_DRAW,
                    XML_NAMESPACE_FO,
                    XML_NAMESPACE_XLINK,
                    XML_NAMESPACE_DC,
                    XML_NAMESPACE_META,
                    XML_NAMESPACE_NUMBER,
                    XML_NAMESPACE_PRESENTATION,
                    XML_NAMESPACE_SVG,
                    XML_NAMESPACE_CHART,
                    XML_NAMESPACE_DR3D,
                    XML_NAMESPACE_MATH,
                    XML_NAMESPACE_FORM,
                    XML_NAMESPACE_SCRIPT,
                    XML_NAMESPACE_CONFIG,
                    XML_NAMESPACE_DB,
                    XML_NAMESPACE_XFORMS,
                    XML_NAMESPACE_SMIL,
                    XML_NAMESPACE_ANIMATION,
                    XML_NAMESPACE_XML,
                    XML_NAMESPACE_XHTML,
                    XML_NAMESPACE_GRDDL,
                };
                static bool s_Assert(false);
                if (!s_Assert)
                {
                    assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs)));
                    s_Assert = true;
                }
                //static_assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs)));
                auto const ns(mpImpl->mxPropMapper->GetEntryNameSpace(i));
                auto const iter(std::lower_bound(std::begin(s_OdfNs), std::end(s_OdfNs),
                            ns));
                bool const isExtension(iter == std::end(s_OdfNs) || *iter != ns
                        // FIXME: very special hack to suppress style:hyperlink
                        || (ns == XML_NAMESPACE_STYLE
                            && mpImpl->mxPropMapper->GetEntryXMLName(i) == GetXMLToken(XML_HYPERLINK)));
                if (isExtension
                    ? ((nCurrentVersion & SvtSaveOptions::ODFSVER_EXTENDED)
                        // if it's in standard ODF, don't export extension
                        && (nCurrentVersion < nEarliestODFVersionForExport))
                    : (nEarliestODFVersionForExport <= nCurrentVersion))
                {
                    pFilterInfo->AddProperty(rAPIName, i);
                }
            }
        }

        // Check whether the property set info is destroyed if it is assigned to
        // a weak reference only; If it is destroyed, then every instance of
        // getPropertySetInfo returns a new object; such property set infos must
        // not be cached:
        WeakReference < XPropertySetInfo > xWeakInfo( xInfo );
        xInfo.clear();
        xInfo = xWeakInfo;
        if( xInfo.is() )
        {
            mpImpl->maCache.emplace(xInfo, std::unique_ptr<FilterPropertiesInfo_Impl>(pFilterInfo));
        }
        else
            bDelInfo = true;
    }

    if( pFilterInfo->GetPropertyCount() )
    {
        try
        {
            pFilterInfo->FillPropertyStateArray(
                aPropStateArray, xPropSet, mpImpl->mxPropMapper, bDefault);
        }
        catch( UnknownPropertyException& )
        {
            // might be a problem of getImplementationId
            TOOLS_WARN_EXCEPTION("xmloff.style""unknown property in getPropertyStates" );
        }
    }

    // Call context-filter
    if( !aPropStateArray.empty() )
        ContextFilter(bEnableFoFontFamily, aPropStateArray, xPropSet);

    // Have to do if we change from a vector to a list or something like that

    if( bDelInfo )
        delete pFilterInfo;

    return aPropStateArray;
}

void SvXMLExportPropertyMapper::ContextFilter(
        bool bEnableFoFontFamily,
        std::vector< XMLPropertyState >& rProperties,
        const Reference< XPropertySet >& rPropSet ) const
{
    // Derived class could implement this.
    if (mpImpl->mxNextMapper.is())
        mpImpl->mxNextMapper->ContextFilter(bEnableFoFontFamily, rProperties, rPropSet);
}

// Compares two Sequences of XMLPropertyState:
//  1.Number of elements equal ?
//  2.Index of each element equal ? (So I know whether the propertynames are the same)
//  3.Value of each element equal ?
bool SvXMLExportPropertyMapper::Equals(
        const std::vector< XMLPropertyState >& aProperties1,
        const std::vector< XMLPropertyState >& aProperties2 ) const
{
    if (aProperties1.size() < aProperties2.size())
        return true;
    if (aProperties1.size() > aProperties2.size())
        return false;

    sal_uInt32 nCount = aProperties1.size();

    for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex)
    {
        const XMLPropertyState& rProp1 = aProperties1[ nIndex ];
        const XMLPropertyState& rProp2 = aProperties2[ nIndex ];

        // Compare index. If equal, compare value
        if( rProp1.mnIndex < rProp2.mnIndex )
            return true;
        if( rProp1.mnIndex > rProp2.mnIndex )
            return false;

        if( rProp1.mnIndex != -1 )
        {
            // Now compare values
            if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) &
                  XML_TYPE_BUILDIN_CMP ) != 0 )
            {
                // simple type ( binary compare )
                if ( rProp1.maValue != rProp2.maValue)
                    return false;
            }
            else
            {
                // complex type ( ask for compare-function )
                if (!mpImpl->mxPropMapper->GetPropertyHandler(
                            rProp1.mnIndex )->equals( rProp1.maValue,
                                                      rProp2.maValue ))
                    return false;
            }
        }
    }

    return true;
}

// Compares two Sequences of XMLPropertyState:
//  1.Number of elements equal ?
//  2.Index of each element equal ? (So I know whether the propertynames are the same)
//  3.Value of each element equal ?
bool SvXMLExportPropertyMapper::LessPartial(
        const std::vector< XMLPropertyState >& aProperties1,
        const std::vector< XMLPropertyState >& aProperties2 ) const
{
    if (aProperties1.size() < aProperties2.size())
        return true;
    if (aProperties1.size() > aProperties2.size())
        return false;

    sal_uInt32 nCount = aProperties1.size();

    for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex)
    {
        const XMLPropertyState& rProp1 = aProperties1[ nIndex ];
        const XMLPropertyState& rProp2 = aProperties2[ nIndex ];

        // Compare index. If equal, compare value
        if( rProp1.mnIndex < rProp2.mnIndex )
            return true;
        if( rProp1.mnIndex > rProp2.mnIndex )
            return false;

        if( rProp1.mnIndex != -1 )
        {
            // Now compare values
            if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) &
                  XML_TYPE_BUILDIN_CMP ) != 0 )
            {
                // simple type ( binary compare )
                if ( comphelper::anyLess(rProp1.maValue, rProp2.maValue) )
                    return true;
                if ( comphelper::anyLess(rProp2.maValue, rProp1.maValue ) )
                    return false;
            }
        }
    }

    return false;
}

/** fills the given attribute list with the items in the given set
void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
        const ::std::vector< XMLPropertyState >& rProperties,
        const SvXMLUnitConverter& rUnitConverter,
        const SvXMLNamespaceMap& rNamespaceMap,
        sal_uInt16 nFlags ) const
{
    _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
                nFlags, 0, -1, -1 );
}

void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList,
        const ::std::vector< XMLPropertyState >& rProperties,
        const SvXMLUnitConverter& rUnitConverter,
        const SvXMLNamespaceMap& rNamespaceMap,
        sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
        sal_uInt16 nFlags ) const
{
    _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap,
                nFlags, 0, nPropMapStartIdx, nPropMapEndIdx );
}
*/


void SvXMLExportPropertyMapper::exportXML(
        SvXMLExport& rExport,
        const ::std::vector< XMLPropertyState >& rProperties,
        SvXmlExportFlags nFlags,
        bool bUseExtensionNamespaceForGraphicProperties) const
{
    exportXML(rExport, rProperties, -1, -1,  nFlags, bUseExtensionNamespaceForGraphicProperties);
}


void SvXMLExportPropertyMapper::exportXML(
        SvXMLExport& rExport,
        const ::std::vector< XMLPropertyState >& rProperties,
        sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx,
        SvXmlExportFlags nFlags, bool bUseExtensionNamespaceForGraphicProperties) const
{
    sal_uInt16 nPropTypeFlags = 0;
    for( sal_uInt16 i=0; i<MAX_PROP_TYPES; ++i )
    {
        sal_uInt16 nPropType = aPropTokens[i].nType;
        if( 0==i || (nPropTypeFlags & (1 << nPropType)) != 0 )
        {
            sal_uInt16 nNamespace = XML_NAMESPACE_STYLE;
            if (bUseExtensionNamespaceForGraphicProperties &&
                aPropTokens[i].eToken == xmloff::token::XML_GRAPHIC_PROPERTIES)
            {
                nNamespace = XML_NAMESPACE_LO_EXT;
                if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
                {
                    continue// don't write for ODF <= 1.2
                }
            }

            std::vector<sal_uInt16> aIndexArray;

            _exportXML( nPropType, nPropTypeFlags,
                        rExport.GetAttrList(), rProperties,
                        rExport.GetMM100UnitConverter(),
                        rExport.GetNamespaceMap(),
                        &aIndexArray,
                        nPropMapStartIdx, nPropMapEndIdx );

            if( rExport.GetAttrList().getLength() > 0 ||
                !aIndexArray.empty() )
            {
                SvXMLElementExport aElem( rExport, nNamespace,
                                  aPropTokens[i].eToken,
                                  bool(nFlags & SvXmlExportFlags::IGN_WS),
                                  false );

                exportElementItems( rExport, rProperties, nFlags, aIndexArray );
            }
        }
    }
}

/** this method is called for every item that has the
    MID_FLAG_SPECIAL_ITEM_EXPORT flag set */

void SvXMLExportPropertyMapper::handleSpecialItem(
        comphelper::AttributeList& rAttrList,
        const XMLPropertyState& rProperty,
        const SvXMLUnitConverter& rUnitConverter,
        const SvXMLNamespaceMap& rNamespaceMap,
        const ::std::vector< XMLPropertyState > *pProperties,
        sal_uInt32 nIdx ) const
{
    OSL_ENSURE(mpImpl->mxNextMapper.is(), "special item not handled in xml export");
    if (mpImpl->mxNextMapper.is())
        mpImpl->mxNextMapper->handleSpecialItem(
            rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx);
}

/** this method is called for every item that has the
    MID_FLAG_ELEMENT_EXPORT flag set */

void SvXMLExportPropertyMapper::handleElementItem(
        SvXMLExport& rExport,
        const XMLPropertyState& rProperty,
        SvXmlExportFlags nFlags,
        const ::std::vector< XMLPropertyState > *pProperties,
        sal_uInt32 nIdx ) const
{
    OSL_ENSURE(mpImpl->mxNextMapper.is(), "element item not handled in xml export");
    if (mpImpl->mxNextMapper.is())
        mpImpl->mxNextMapper->handleElementItem(rExport, rProperty, nFlags, pProperties, nIdx);
}

// protected methods

/** fills the given attribute list with the items in the given set */
void SvXMLExportPropertyMapper::_exportXML(
        sal_uInt16 nPropType, sal_uInt16& rPropTypeFlags,
        comphelper::AttributeList& rAttrList,
        const ::std::vector< XMLPropertyState >& rProperties,
        const SvXMLUnitConverter& rUnitConverter,
        const SvXMLNamespaceMap& rNamespaceMap,
        std::vector<sal_uInt16>* pIndexArray,
        sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx ) const
{
    const sal_uInt32 nCount = rProperties.size();
    sal_uInt32 nIndex = 0;

    if( -1 == nPropMapStartIdx )
        nPropMapStartIdx = 0;
    if( -1 == nPropMapEndIdx )
        nPropMapEndIdx = mpImpl->mxPropMapper->GetEntryCount();

    while( nIndex < nCount )
    {
        sal_Int32 nPropMapIdx = rProperties[nIndex].mnIndex;
        if( nPropMapIdx >= nPropMapStartIdx &&
            nPropMapIdx < nPropMapEndIdx  )// valid entry?
        {
            sal_uInt32 nEFlags = mpImpl->mxPropMapper->GetEntryFlags(nPropMapIdx);
            sal_uInt16 nEPType = GET_PROP_TYPE(nEFlags);
            OSL_ENSURE(nEPType >= (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT),
                       "no prop type specified");
            rPropTypeFlags |= (1 << nEPType);
            if( nEPType == nPropType )
            {
                // we have a valid map entry here, so let's use it...
                if( ( nEFlags & MID_FLAG_ELEMENT_ITEM_EXPORT ) != 0 )
                {
                    // element items do not add any properties,
                    // we export it later
                    if( pIndexArray )
                    {
                        pIndexArray->push_back( static_cast<sal_uInt16>(nIndex) );
                    }
                }
                else
                {
                    _exportXML( rAttrList, rProperties[nIndex], rUnitConverter,
                                rNamespaceMap, &rProperties, nIndex );
                }
            }
        }

        nIndex++;
    }
}

namespace
{
// -1 = Attribute needs extended namespace, but current ODF version is strict.
// 1 = Attribute needs extended namespace and current ODF version allows it.
// 0 = Attribute does not need extended namespace
sal_Int8 CheckExtendedNamespace(std::u16string_view sXMLAttributeName, std::u16string_view sValue,
                                const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion)
{
    if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE)
        && (IsXMLToken(sValue, XML_BT_LR) || IsXMLToken(sValue, XML_TB_RL90)))
        return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1;
    else if (IsXMLToken(sXMLAttributeName, XML_VERTICAL_REL)
             && (IsXMLToken(sValue, XML_PAGE_CONTENT_BOTTOM)
                 || IsXMLToken(sValue, XML_PAGE_CONTENT_TOP)))
        return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1;
    // don't export end zones when they have the default no-limit value
    else if (IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_ALWAYS)
        || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_COLUMN)
        || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_PAGE)
        || IsXMLToken(sXMLAttributeName, XML_HYPHENATION_ZONE_SPREAD))
        return IsXMLToken(sValue, XML_NO_LIMIT) ? -1 : 1;
    else if (IsXMLToken(sXMLAttributeName, XML_WORD_SPACING)
        || IsXMLToken(sXMLAttributeName, XML_WORD_SPACING_MINIMUM)
        || IsXMLToken(sXMLAttributeName, XML_WORD_SPACING_MAXIMUM))
    {
        static constexpr OUString s100PercentCompare( u"100%"_ustr );
        size_t nBegin = sValue.find( s100PercentCompare );
        return nBegin != std::u16string_view::npos ? -1 : 1;
    }
    return 0;
}
}

void SvXMLExportPropertyMapper::_exportXML(
        comphelper::AttributeList& rAttrList,
        const XMLPropertyState& rProperty,
        const SvXMLUnitConverter& rUnitConverter,
        const SvXMLNamespaceMap& rNamespaceMap,
        const ::std::vector< XMLPropertyState > *pProperties,
        sal_uInt32 nIdx ) const
{
    if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_SPECIAL_ITEM_EXPORT) != 0)
    {
        uno::Reference< container::XNameContainer > xAttrContainer;
        if( (rProperty.maValue >>= xAttrContainer) && xAttrContainer.is() )
        {
            std::unique_ptr<SvXMLNamespaceMap> pNewNamespaceMap;
            const SvXMLNamespaceMap *pNamespaceMap = &rNamespaceMap;

            const uno::Sequence< OUString > aAttribNames( xAttrContainer->getElementNames() );

            xml::AttributeData aData;
            forconst auto& rAttribName : aAttribNames )
            {
                xAttrContainer->getByName( rAttribName ) >>= aData;
                OUString sAttribName( rAttribName );

                // extract namespace prefix from attribute name if it exists
                OUString sPrefix;
                const sal_Int32 nColonPos =
                    rAttribName.indexOf( ':' );
                if( nColonPos != -1 )
                    sPrefix = rAttribName.copy( 0, nColonPos );

                if( !sPrefix.isEmpty() )
                {
                    OUString sNamespace( aData.Namespace );

                    // if the prefix isn't defined yet or has another meaning,
                    // we have to redefine it now.
                    sal_uInt16 nKey = pNamespaceMap->GetKeyByPrefix( sPrefix );
                    if( USHRT_MAX == nKey || pNamespaceMap->GetNameByKey( nKey ) != sNamespace )
                    {
                        bool bAddNamespace = false;
                        if( USHRT_MAX == nKey )
                        {
                            // The prefix is unused, so it is sufficient
                            // to add it to the namespace map.
                            bAddNamespace = true;
                        }
                        else
                        {
                            // check if there is a prefix registered for the
                            // namespace URI
                            nKey = pNamespaceMap->GetKeyByName( sNamespace );
                            if( XML_NAMESPACE_UNKNOWN == nKey )
                            {
                                // There is no prefix for the namespace, so
                                // we have to generate one and have to add it.
                                sal_Int32 n=0;
                                OUString sOrigPrefix( sPrefix );
                                do
                                {
                                    sPrefix = sOrigPrefix + OUString::number( ++n );
                                    nKey = pNamespaceMap->GetKeyByPrefix( sPrefix );
                                }
                                while( nKey != USHRT_MAX );

                                bAddNamespace = true;
                            }
                            else
                            {
                                // If there is a prefix for the namespace,
                                // we reuse that.
                                sPrefix = pNamespaceMap->GetPrefixByKey( nKey );
                            }
                            // In any case, the attribute name has to be adapted.
                            sAttribName = sPrefix + ":" + rAttribName.subView(nColonPos+1);
                        }

                        if( bAddNamespace )
                        {
                            if( !pNewNamespaceMap )
                            {
                                pNewNamespaceMap.reset(new SvXMLNamespaceMap( rNamespaceMap ));
                                pNamespaceMap = pNewNamespaceMap.get();
                            }
                            pNewNamespaceMap->Add( sPrefix, sNamespace );
                            OUString sAttr = GetXMLToken(XML_XMLNS) + ":" + sPrefix;
                            rAttrList.AddAttribute( sAttr, sNamespace );
                        }
                    }
                }
                OUString sOldValue( rAttrList.getValueByName( sAttribName ) );
                OSL_ENSURE( sOldValue.isEmpty(), "alien attribute exists already" );
                OSL_ENSURE(aData.Type == GetXMLToken(XML_CDATA), "different type to our default type which should be written out");
                if( sOldValue.isEmpty() )
                    rAttrList.AddAttribute( sAttribName, aData.Value );
            }
        }
        else
        {
            handleSpecialItem( rAttrList, rProperty, rUnitConverter,
                               rNamespaceMap, pProperties, nIdx );
        }
    }
    else if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_ELEMENT_ITEM_EXPORT ) == 0)
    {
        OUString aValue;
        OUString sName = rNamespaceMap.GetQNameByKey(
            mpImpl->mxPropMapper->GetEntryNameSpace(rProperty.mnIndex),
            mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex));

        bool bRemove = false;
        if ((mpImpl->mxPropMapper->GetEntryFlags( rProperty.mnIndex ) & MID_FLAG_MERGE_ATTRIBUTE) != 0)
        {
            aValue = rAttrList.getValueByName( sName );
            bRemove = true;
        }

        if (mpImpl->mxPropMapper->exportXML(aValue, rProperty, rUnitConverter))
        {
            if( bRemove )
                rAttrList.RemoveAttribute( sName );

            // We don't seem to have a generic mechanism to write an attribute in the extension
            // namespace in case of certain attribute values only, so do this manually.
            sal_Int8 nExtendedStatus
                = CheckExtendedNamespace(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex),
                                         aValue, rUnitConverter.getSaneDefaultVersion());
            if (nExtendedStatus == -1)
                return;
            if (nExtendedStatus == 1)
                sName = rNamespaceMap.GetQNameByKey(
                    XML_NAMESPACE_LO_EXT, mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex));
            rAttrList.AddAttribute( sName, aValue );
        }
    }
}

void SvXMLExportPropertyMapper::exportElementItems(
        SvXMLExport& rExport,
        const ::std::vector< XMLPropertyState >& rProperties,
        SvXmlExportFlags nFlags,
        const std::vector<sal_uInt16>& rIndexArray ) const
{
    bool bItemsExported = false;
    for (const sal_uInt16 nElement : rIndexArray)
    {
        OSL_ENSURE( 0 != (mpImpl->mxPropMapper->GetEntryFlags(
                rProperties[nElement].mnIndex ) & MID_FLAG_ELEMENT_ITEM_EXPORT),
                "wrong mid flag!" );

        rExport.IgnorableWhitespace();
        handleElementItem( rExport, rProperties[nElement],
                           nFlags, &rProperties, nElement );
        bItemsExported = true;
    }

    if( bItemsExported )
        rExport.IgnorableWhitespace();
}

const rtl::Reference<XMLPropertySetMapper>& SvXMLExportPropertyMapper::getPropertySetMapper() const
{
    return mpImpl->mxPropMapper;
}

void SvXMLExportPropertyMapper::SetStyleName( const OUString& rStyleName )
{
    mpImpl->maStyleName = rStyleName;
}

const OUString& SvXMLExportPropertyMapper::GetStyleName() const
{
    return mpImpl->maStyleName;
}

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

Messung V0.5
C=94 H=95 G=94

¤ Dauer der Verarbeitung: 0.5 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.