/* -*- 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 <xmloff/unointerfacetouniqueidentifiermapper.hxx>
 
#include <string_view>
 
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/text/XTextCursor.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/text/ControlCharacter.hpp>
#include <com/sun/star/text/XTextRangeCompare.hpp>
#include <com/sun/star/drawing/XShapes.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/rdf/XMetadatable.hpp>
 
#include <sax/tools/converter.hxx>
 
#include <xmloff/prstylei.hxx>
#include <xmloff/xmlictxt.hxx>
#include <xmloff/xmlimp.hxx>
#include <xmloff/xmltoken.hxx>
#include <xmloff/xmlnamespace.hxx>
#include <xmloff/txtimp.hxx>
#include "txtparai.hxx"
#include <txtfldi.hxx>
#include "XMLFootnoteImportContext.hxx"
#include "XMLTextMarkImportContext.hxx"
#include "XMLTextFrameContext.hxx"
#include <xmloff/XMLCharContext.hxx>
#include "XMLTextFrameHyperlinkContext.hxx"
#include <xmloff/XMLEventsImportContext.hxx>
#include "XMLChangeImportContext.hxx"
#include <txtlists.hxx>
 
#include "txtparaimphint.hxx"
#include "xmllinebreakcontext.hxx"
#include "xmlcontentcontrolcontext.hxx"
 
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::text;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::beans;
using namespace ::xmloff::token;
using ::com::sun::star::container::XEnumerationAccess;
using ::com::sun::star::container::XEnumeration;
 
void XMLHints_Impl::push_back(std::unique_ptr<XMLIndexMarkHint_Impl> pHint)
{
    m_IndexHintsById.emplace(pHint->GetID(), pHint.get());
    m_Hints.push_back(std::move(pHint));
}
void XMLHints_Impl::push_back(std::unique_ptr<XMLHint_Impl> pHint)
{
    m_Hints.push_back(std::move(pHint));
}
 
XMLCharContext::XMLCharContext(
        SvXMLImport& rImport,
        const Reference< xml::sax::XFastAttributeList > & xAttrList,
        sal_Unicode c,
        bool bCount ) :
    SvXMLImportContext( rImport )
    ,m_nControl(0)
    ,m_nCount(1)
    ,m_c(c)
{
    if( !bCount )
        return;
 
    for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
    {
        if( aIter.getToken() == XML_ELEMENT(TEXT, XML_C) )
        {
            sal_Int32 nTmp = aIter.toInt32();
            if( nTmp > 0 )
            {
                if( nTmp > SAL_MAX_UINT16 )
                    m_nCount = SAL_MAX_UINT16;
                else
                    m_nCount = static_cast<sal_uInt16>(nTmp);
            }
        }
        else
            XMLOFF_WARN_UNKNOWN("xmloff", aIter);
    }
}
 
XMLCharContext::XMLCharContext(
        SvXMLImport& rImp,
        sal_Int16 nControl ) :
    SvXMLImportContext( rImp )
    ,m_nControl(nControl)
    ,m_nCount(0)
    ,m_c(0)
{
}
 
XMLCharContext::~XMLCharContext()
{
}
void XMLCharContext::endFastElement(sal_Int32 )
{
    if ( !m_nCount )
        InsertControlCharacter( m_nControl );
    else
    {
        if( 1U == m_nCount )
        {
            OUString sBuff( &m_c, 1 );
            InsertString(sBuff);
        }
        else
        {
            OUStringBuffer sBuff(static_cast<int>(m_nCount));
            while( m_nCount-- )
                sBuff.append( &m_c, 1 );
 
            InsertString(sBuff.makeStringAndClear() );
        }
    }
}
void XMLCharContext::InsertControlCharacter(sal_Int16   _nControl)
{
    GetImport().GetTextImport()->InsertControlCharacter( _nControl );
}
void XMLCharContext::InsertString(const OUString& _sString)
{
    GetImport().GetTextImport()->InsertString( _sString );
}
 
namespace {
 
/** import start of reference (<text:reference-start>) */
class XMLStartReferenceContext_Impl : public SvXMLImportContext
{
public:
 
    // Do everything in constructor. Well ...
    XMLStartReferenceContext_Impl (
        SvXMLImport& rImport,
        XMLHints_Impl& rHints,
        const Reference<xml::sax::XFastAttributeList> & xAttrList);
 
    static bool FindName(
        const Reference<xml::sax::XFastAttributeList> & xAttrList,
        OUString& rName);
};
 
}
 
XMLStartReferenceContext_Impl::XMLStartReferenceContext_Impl(
    SvXMLImport& rImport,
    XMLHints_Impl& rHints,
    const Reference<xml::sax::XFastAttributeList> & xAttrList) :
        SvXMLImportContext(rImport)
{
    OUString sName;
 
    if (FindName(xAttrList, sName))
    {
        std::unique_ptr<XMLHint_Impl> pHint(new XMLReferenceHint_Impl(
            sName, rImport.GetTextImport()->GetCursor()->getStart()));
 
        // degenerates to point reference, if no end is found!
        pHint->SetEnd(rImport.GetTextImport()->GetCursor()->getStart() );
 
        rHints.push_back(std::move(pHint));
    }
}
 
bool XMLStartReferenceContext_Impl::FindName(
    const Reference<xml::sax::XFastAttributeList> & xAttrList,
    OUString& rName)
{
    bool bNameOK( false );
 
    // find name attribute first
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
    {
        if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_NAME) )
        {
            rName = aIter.toString();
            bNameOK = true;
            break;
        }
    }
 
    return bNameOK;
}
 
namespace {
 
/** import end of reference (<text:reference-end>) */
class XMLEndReferenceContext_Impl : public SvXMLImportContext
{
public:
 
    // Do everything in constructor. Well ...
    XMLEndReferenceContext_Impl(
        SvXMLImport& rImport,
        const XMLHints_Impl& rHints,
        const Reference<xml::sax::XFastAttributeList> & xAttrList);
};
 
}
 
XMLEndReferenceContext_Impl::XMLEndReferenceContext_Impl(
    SvXMLImport& rImport,
    const XMLHints_Impl& rHints,
    const Reference<xml::sax::XFastAttributeList> & xAttrList) :
        SvXMLImportContext(rImport)
{
    OUString sName;
 
    // borrow from XMLStartReferenceContext_Impl
    if (!XMLStartReferenceContext_Impl::FindName(xAttrList, sName))
        return;
 
    // search for reference start
    for (const auto& rHintPtr : rHints.GetHints())
    {
        XMLHint_Impl *const pHint = rHintPtr.get();
        if ( pHint->IsReference() &&
             sName == static_cast<XMLReferenceHint_Impl *>(pHint)->GetRefName() )
        {
            // set end and stop searching
            pHint->SetEnd(GetImport().GetTextImport()->
                                 GetCursor()->getStart() );
            break;
        }
    }
    // else: no start (in this paragraph) -> ignore
}
 
namespace {
 
class XMLImpHyperlinkContext_Impl : public SvXMLImportContext
{
    XMLHints_Impl&  m_rHints;
    XMLHyperlinkHint_Impl   *mpHint;
 
    bool&       mrbIgnoreLeadingSpace;
 
public:
 
 
    XMLImpHyperlinkContext_Impl(
            SvXMLImport& rImport,
            sal_Int32 nElement,
            const Reference< xml::sax::XFastAttributeList > & xAttrList,
            XMLHints_Impl& rHints,
            bool& rIgnLeadSpace );
 
    virtual ~XMLImpHyperlinkContext_Impl() override;
 
    virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
        sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
 
    virtual void SAL_CALL characters( const OUString& rChars ) override;
};
 
}
 
XMLImpHyperlinkContext_Impl::XMLImpHyperlinkContext_Impl(
    SvXMLImport& rImport,
    sal_Int32 /*nElement*/,
    const Reference< xml::sax::XFastAttributeList > & xAttrList,
    XMLHints_Impl& rHints,
    bool& rIgnLeadSpace )
    : SvXMLImportContext( rImport )
    , m_rHints( rHints )
    , mpHint( new XMLHyperlinkHint_Impl( GetImport().GetTextImport()->GetCursorAsRange()->getStart() ) )
    , mrbIgnoreLeadingSpace( rIgnLeadSpace )
{
    OUString sShow;
 
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
    {
        OUString sValue = aIter.toString();
        switch (aIter.getToken())
        {
        case XML_ELEMENT(XLINK, XML_HREF):
            mpHint->SetHRef( GetImport().GetAbsoluteReference( sValue ) );
            break;
        case XML_ELEMENT(OFFICE, XML_NAME):
            mpHint->SetName( sValue );
            break;
        case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME):
            mpHint->SetTargetFrameName( sValue );
            break;
        case XML_ELEMENT(XLINK, XML_SHOW):
            sShow = sValue;
            break;
        case XML_ELEMENT(TEXT, XML_STYLE_NAME):
            mpHint->SetStyleName( sValue );
            break;
        case XML_ELEMENT(TEXT, XML_VISITED_STYLE_NAME):
            mpHint->SetVisitedStyleName( sValue );
            break;
        case XML_ELEMENT(XLINK, XML_TYPE):
            // don't show warning for this
            break;
        default:
            XMLOFF_WARN_UNKNOWN("xmloff", aIter);
        }
    }
 
    if( !sShow.isEmpty() && mpHint->GetTargetFrameName().isEmpty() )
    {
        if( IsXMLToken( sShow, XML_NEW ) )
            mpHint->SetTargetFrameName(
                    u"_blank"_ustr );
        else if( IsXMLToken( sShow, XML_REPLACE ) )
            mpHint->SetTargetFrameName(
                    u"_self"_ustr );
    }
 
    if ( mpHint->GetHRef().isEmpty() )
    {
        // hyperlink without a URL is not imported.
        delete mpHint;
        mpHint = nullptr;
    }
    else
    {
        m_rHints.push_back(std::unique_ptr<XMLHyperlinkHint_Impl>(mpHint));
    }
}
 
XMLImpHyperlinkContext_Impl::~XMLImpHyperlinkContext_Impl()
{
    if (mpHint)
        mpHint->SetEnd( GetImport().GetTextImport()
                            ->GetCursorAsRange()->getStart() );
}
 
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpHyperlinkContext_Impl::createFastChildContext(
    sal_Int32 nElement,
    const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
{
    if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) )
    {
        XMLEventsImportContext* pCtxt = new XMLEventsImportContext(GetImport());
        if (mpHint)
            mpHint->SetEventsContext(pCtxt);
        return pCtxt;
    }
    else
    {
        return XMLImpSpanContext_Impl::CreateSpanContext(
            GetImport(), nElement, xAttrList,
            m_rHints, mrbIgnoreLeadingSpace );
    }
}
 
void XMLImpHyperlinkContext_Impl::characters( const OUString& rChars )
{
    GetImport().GetTextImport()->InsertString( rChars, mrbIgnoreLeadingSpace );
}
 
namespace {
 
class XMLImpRubyBaseContext_Impl : public SvXMLImportContext
{
    XMLHints_Impl&  m_rHints;
 
    bool&       rIgnoreLeadingSpace;
 
public:
 
 
    XMLImpRubyBaseContext_Impl(
            SvXMLImport& rImport,
            sal_Int32 nElement,
            const Reference< xml::sax::XFastAttributeList > & xAttrList,
            XMLHints_Impl& rHints,
            bool& rIgnLeadSpace );
 
    virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
        sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
 
    virtual void SAL_CALL characters( const OUString& rChars ) override;
};
 
}
 
XMLImpRubyBaseContext_Impl::XMLImpRubyBaseContext_Impl(
        SvXMLImport& rImport,
        sal_Int32 /*nElement*/,
        const Reference< xml::sax::XFastAttributeList > &,
        XMLHints_Impl& rHints,
        bool& rIgnLeadSpace )
    : SvXMLImportContext( rImport )
    , m_rHints( rHints )
    , rIgnoreLeadingSpace( rIgnLeadSpace )
{
}
 
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpRubyBaseContext_Impl::createFastChildContext(
    sal_Int32 nElement,
    const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
{
    return XMLImpSpanContext_Impl::CreateSpanContext( GetImport(), nElement, xAttrList,
                               m_rHints, rIgnoreLeadingSpace );
}
 
void XMLImpRubyBaseContext_Impl::characters( const OUString& rChars )
{
    GetImport().GetTextImport()->InsertString( rChars, rIgnoreLeadingSpace );
}
 
namespace {
 
class XMLImpRubyContext_Impl : public SvXMLImportContext
{
    XMLHints_Impl&  m_rHints;
 
    bool&       rIgnoreLeadingSpace;
 
    Reference < XTextRange > m_xStart;
    OUString        m_sStyleName;
    OUString        m_sTextStyleName;
    OUString        m_sText;
 
public:
 
 
    XMLImpRubyContext_Impl(
            SvXMLImport& rImport,
            sal_Int32 nElement,
            const Reference< xml::sax::XFastAttributeList > & xAttrList,
            XMLHints_Impl& rHints,
            bool& rIgnLeadSpace );
 
    virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
 
    virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
        sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
 
    void SetTextStyleName( const OUString& s ) { m_sTextStyleName = s; }
    void AppendText( std::u16string_view s ) { m_sText += s; }
};
 
class XMLImpRubyTextContext_Impl : public SvXMLImportContext
{
    XMLImpRubyContext_Impl & m_rRubyContext;
 
public:
 
 
    XMLImpRubyTextContext_Impl(
            SvXMLImport& rImport,
            sal_Int32 nElement,
            const Reference< xml::sax::XFastAttributeList > & xAttrList,
            XMLImpRubyContext_Impl & rParent );
 
    virtual void SAL_CALL characters( const OUString& rChars ) override;
};
 
}
 
XMLImpRubyTextContext_Impl::XMLImpRubyTextContext_Impl(
        SvXMLImport& rImport,
        sal_Int32 /*nElement*/,
        const Reference< xml::sax::XFastAttributeList > & xAttrList,
        XMLImpRubyContext_Impl & rParent )
    : SvXMLImportContext( rImport )
    , m_rRubyContext( rParent )
{
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
    {
        if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) )
        {
            m_rRubyContext.SetTextStyleName( aIter.toString() );
            break;
        }
    }
}
 
void XMLImpRubyTextContext_Impl::characters( const OUString& rChars )
{
    m_rRubyContext.AppendText( rChars );
}
 
 
XMLImpRubyContext_Impl::XMLImpRubyContext_Impl(
        SvXMLImport& rImport,
        sal_Int32 /*nElement*/,
        const Reference< xml::sax::XFastAttributeList > & xAttrList,
        XMLHints_Impl& rHints,
        bool& rIgnLeadSpace )
    : SvXMLImportContext( rImport )
    , m_rHints( rHints )
    , rIgnoreLeadingSpace( rIgnLeadSpace )
    , m_xStart( GetImport().GetTextImport()->GetCursorAsRange()->getStart() )
{
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
    {
        if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) )
        {
            m_sStyleName = aIter.toString();
            break;
        }
    }
}
 
void XMLImpRubyContext_Impl::endFastElement(sal_Int32 )
{
    const rtl::Reference < XMLTextImportHelper > xTextImport(
        GetImport().GetTextImport());
    const Reference < XTextCursor > xAttrCursor(
        xTextImport->GetText()->createTextCursorByRange( m_xStart ));
    if (!xAttrCursor.is())
    {
        SAL_WARN("xmloff.text", "cannot insert ruby");
        return;
    }
    xAttrCursor->gotoRange(xTextImport->GetCursorAsRange()->getStart(),
            true);
    xTextImport->SetRuby( GetImport(), xAttrCursor,
         m_sStyleName, m_sTextStyleName, m_sText );
}
 
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpRubyContext_Impl::createFastChildContext(
    sal_Int32 nElement,
    const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
{
    if( nElement == XML_ELEMENT(TEXT, XML_RUBY_BASE) )
        return new XMLImpRubyBaseContext_Impl( GetImport(), nElement,
                                                   xAttrList,
                                                   m_rHints,
                                                   rIgnoreLeadingSpace );
    else if( nElement == XML_ELEMENT(TEXT, XML_RUBY_TEXT) )
        return new XMLImpRubyTextContext_Impl( GetImport(), nElement,
                                                       xAttrList,
                                                       *this );
    else
        XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
 
    return nullptr;
}
 
namespace {
 
/** for text:meta and text:meta-field
 */
class XMLMetaImportContextBase : public SvXMLImportContext
{
    XMLHints_Impl&    m_rHints;
 
    bool& m_rIgnoreLeadingSpace;
 
    /// start position
    Reference<XTextRange> m_xStart;
 
protected:
    OUString m_XmlId;
 
public:
 
    XMLMetaImportContextBase(
        SvXMLImport& i_rImport,
        const sal_Int32 nElement,
        XMLHints_Impl& i_rHints,
        bool & i_rIgnoreLeadingSpace );
 
    virtual void SAL_CALL startFastElement(
            sal_Int32 nElement,
            const Reference<xml::sax::XFastAttributeList> & i_xAttrList) override;
 
    virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
 
    virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
        sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
 
    virtual void SAL_CALL characters( const OUString& i_rChars ) override;
 
    virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter);
 
    virtual void InsertMeta(const Reference<XTextRange> & i_xInsertionRange)
        = 0;
};
 
}
 
XMLMetaImportContextBase::XMLMetaImportContextBase(
        SvXMLImport& i_rImport,
        const sal_Int32 /*i_nElement*/,
        XMLHints_Impl& i_rHints,
        bool & i_rIgnoreLeadingSpace )
    : SvXMLImportContext( i_rImport )
    , m_rHints( i_rHints )
    , m_rIgnoreLeadingSpace( i_rIgnoreLeadingSpace )
    , m_xStart( GetImport().GetTextImport()->GetCursorAsRange()->getStart() )
{
}
 
void XMLMetaImportContextBase::startFastElement(
        sal_Int32 /*nElement*/,
        const Reference<xml::sax::XFastAttributeList> & xAttrList)
{
    for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
        ProcessAttribute(aIter);
}
 
void XMLMetaImportContextBase::endFastElement(sal_Int32 )
{
    SAL_WARN_IF(!m_xStart.is(), "xmloff.text", "no mxStart?");
    if (!m_xStart.is()) return;
 
    const Reference<XTextRange> xEndRange(
        GetImport().GetTextImport()->GetCursorAsRange()->getStart() );
 
    // create range for insertion
    const Reference<XTextCursor> xInsertionCursor(
        GetImport().GetTextImport()->GetText()->createTextCursorByRange(
            xEndRange) );
    xInsertionCursor->gotoRange(m_xStart, true);
 
    InsertMeta(xInsertionCursor);
}
 
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLMetaImportContextBase::createFastChildContext(
    sal_Int32 nElement,
    const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
{
    return XMLImpSpanContext_Impl::CreateSpanContext( GetImport(), nElement,
        xAttrList, m_rHints, m_rIgnoreLeadingSpace );
}
 
void XMLMetaImportContextBase::characters( const OUString& i_rChars )
{
    GetImport().GetTextImport()->InsertString(i_rChars, m_rIgnoreLeadingSpace);
}
 
void XMLMetaImportContextBase::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter)
{
    if ( aIter.getToken() == XML_ELEMENT(XML, XML_ID) )
        m_XmlId = aIter.toString();
    else
        XMLOFF_WARN_UNKNOWN("xmloff", aIter);
}
 
namespace {
 
/** text:meta */
class XMLMetaImportContext : public XMLMetaImportContextBase
{
    // RDFa
    bool m_bHaveAbout;
    OUString m_sAbout;
    OUString m_sProperty;
    OUString m_sContent;
    OUString m_sDatatype;
 
public:
 
    XMLMetaImportContext(
        SvXMLImport& i_rImport,
        sal_Int32 nElement,
        XMLHints_Impl& i_rHints,
        bool & i_rIgnoreLeadingSpace );
 
    virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override;
 
    virtual void InsertMeta(const Reference<XTextRange> & i_xInsertionRange) override;
};
 
}
 
XMLMetaImportContext::XMLMetaImportContext(
        SvXMLImport& i_rImport,
        sal_Int32 nElement,
        XMLHints_Impl& i_rHints,
        bool & i_rIgnoreLeadingSpace )
    : XMLMetaImportContextBase( i_rImport, nElement,
            i_rHints, i_rIgnoreLeadingSpace )
    , m_bHaveAbout(false)
{
}
 
void XMLMetaImportContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter)
{
    switch (aIter.getToken())
    {
        // RDFa
        case XML_ELEMENT(XHTML, XML_ABOUT):
            m_sAbout = aIter.toString();
            m_bHaveAbout = true;
            break;
        case XML_ELEMENT(XHTML, XML_PROPERTY):
            m_sProperty = aIter.toString();
            break;
        case XML_ELEMENT(XHTML, XML_CONTENT):
            m_sContent = aIter.toString();
            break;
        case XML_ELEMENT(XHTML, XML_DATATYPE):
            m_sDatatype = aIter.toString();
            break;
        default:
            XMLMetaImportContextBase::ProcessAttribute(aIter);
    }
}
 
void XMLMetaImportContext::InsertMeta(
    const Reference<XTextRange> & i_xInsertionRange)
{
    SAL_WARN_IF(m_bHaveAbout == m_sProperty.isEmpty(), "xmloff.text", "XMLMetaImportContext::InsertMeta: invalid RDFa?");
    if (!m_XmlId.isEmpty() || (m_bHaveAbout && !m_sProperty.isEmpty()))
    {
        // insert mark
        const uno::Reference<rdf::XMetadatable> xMeta(
            XMLTextMarkImportContext::CreateAndInsertMark(
                GetImport(),
                u"com.sun.star.text.InContentMetadata"_ustr,
                OUString(),
                i_xInsertionRange, m_XmlId),
            uno::UNO_QUERY);
        SAL_WARN_IF(!xMeta.is(), "xmloff.text", "cannot insert Meta?");
 
        if (xMeta.is() && m_bHaveAbout)
        {
            GetImport().AddRDFa(xMeta,
                m_sAbout, m_sProperty, m_sContent, m_sDatatype);
        }
    }
    else
    {
        SAL_INFO("xmloff.text", "invalid <text:meta>: no xml:id, no valid RDFa");
    }
}
 
namespace {
 
/** text:meta-field */
class XMLMetaFieldImportContext : public XMLMetaImportContextBase
{
    OUString m_DataStyleName;
 
public:
 
    XMLMetaFieldImportContext(
        SvXMLImport& i_rImport,
        sal_Int32 nElement,
        XMLHints_Impl& i_rHints,
        bool & i_rIgnoreLeadingSpace );
 
    virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override;
 
    virtual void InsertMeta(const Reference<XTextRange> & i_xInsertionRange) override;
};
 
}
 
XMLMetaFieldImportContext::XMLMetaFieldImportContext(
        SvXMLImport& i_rImport,
        sal_Int32 nElement,
        XMLHints_Impl& i_rHints,
        bool & i_rIgnoreLeadingSpace )
    : XMLMetaImportContextBase( i_rImport, nElement,
            i_rHints, i_rIgnoreLeadingSpace )
{
}
 
void XMLMetaFieldImportContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter)
{
    switch (aIter.getToken())
    {
        case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME):
            m_DataStyleName = aIter.toString();
            break;
        default:
            XMLMetaImportContextBase::ProcessAttribute(aIter);
    }
}
 
void XMLMetaFieldImportContext::InsertMeta(
    const Reference<XTextRange> & i_xInsertionRange)
{
    if (!m_XmlId.isEmpty()) // valid?
    {
        // insert mark
        const Reference<XPropertySet> xPropertySet(
            XMLTextMarkImportContext::CreateAndInsertMark(
                GetImport(),
                u"com.sun.star.text.textfield.MetadataField"_ustr,
                OUString(),
                i_xInsertionRange, m_XmlId),
            UNO_QUERY);
        SAL_WARN_IF(!xPropertySet.is(), "xmloff.text", "cannot insert MetaField?");
        if (!xPropertySet.is()) return;
 
        if (!m_DataStyleName.isEmpty())
        {
            bool isDefaultLanguage(true);
 
            const sal_Int32 nKey( GetImport().GetTextImport()->GetDataStyleKey(
                                   m_DataStyleName, & isDefaultLanguage) );
 
            if (-1 != nKey)
            {
                OUString sPropertyIsFixedLanguage(u"IsFixedLanguage"_ustr);
                xPropertySet->setPropertyValue(u"NumberFormat"_ustr, Any(nKey));
                if ( xPropertySet->getPropertySetInfo()->
                        hasPropertyByName( sPropertyIsFixedLanguage ) )
                {
                    xPropertySet->setPropertyValue( sPropertyIsFixedLanguage,
                        Any(!isDefaultLanguage) );
                }
            }
        }
    }
    else
    {
        SAL_INFO("xmloff.text", "invalid <text:meta-field>: no xml:id");
    }
}
 
namespace {
 
/**
 * Process index marks.
 *
 * All *-mark-end index marks should instantiate *this* class (because
 * it doesn't process attributes other than ID), while the *-mark and
 * *-mark-start classes should instantiate the appropriate subclasses.
 */
class XMLIndexMarkImportContext_Impl : public SvXMLImportContext
{
    XMLHints_Impl& m_rHints;
    OUString sID;
 
public:
 
    XMLIndexMarkImportContext_Impl(
        SvXMLImport& rImport,
        XMLHints_Impl& rHints);
 
    void SAL_CALL startFastElement(sal_Int32 nElement, const Reference<xml::sax::XFastAttributeList> & xAttrList) override;
 
protected:
 
    /// process all attributes
    void ProcessAttributes(sal_Int32 nElement, const Reference<xml::sax::XFastAttributeList> & xAttrList,
                           Reference<beans::XPropertySet>& rPropSet);
 
    /**
     * All marks can be created immediately. Since we don't care about
     * the element content, ProcessAttribute should set the properties
     * immediately.
     *
     * This method tolerates an empty PropertySet; subclasses however
     * are not expected to.
     */
    virtual void ProcessAttribute(sal_Int32 nElement,
                                  const sax_fastparser::FastAttributeList::FastAttributeIter & aIter,
                                  Reference<beans::XPropertySet>& rPropSet);
 
    static void GetServiceName(OUString& sServiceName,
                               sal_Int32 nElement);
 
    bool CreateMark(Reference<beans::XPropertySet>& rPropSet,
                        const OUString& rServiceName);
};
 
}
 
XMLIndexMarkImportContext_Impl::XMLIndexMarkImportContext_Impl(
    SvXMLImport& rImport,
    XMLHints_Impl& rHints)
    : SvXMLImportContext(rImport)
    , m_rHints(rHints)
{
}
 
void XMLIndexMarkImportContext_Impl::startFastElement(
    sal_Int32 nElement,
    const Reference<xml::sax::XFastAttributeList> & xAttrList)
{
    // get Cursor position (needed for all cases)
    Reference<XTextRange> xPos(
        GetImport().GetTextImport()->GetCursor()->getStart());
    Reference<beans::XPropertySet> xMark;
 
    switch (nElement)
    {
        case XML_ELEMENT(TEXT, XML_TOC_MARK):
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK):
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK):
        {
            // single mark: create mark and insert
            OUString sService;
            GetServiceName(sService, nElement);
            if (CreateMark(xMark, sService))
            {
                ProcessAttributes(nElement, xAttrList, xMark);
                m_rHints.push_back(
                    std::make_unique<XMLIndexMarkHint_Impl>(xMark, xPos));
            }
            // else: can't create mark -> ignore
            break;
        }
 
        case XML_ELEMENT(TEXT, XML_TOC_MARK_START):
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START):
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START):
        {
            // start: create mark and insert (if ID is found)
            OUString sService;
            GetServiceName(sService, nElement);
            if (CreateMark(xMark, sService))
            {
                ProcessAttributes(nElement, xAttrList, xMark);
                if (!sID.isEmpty())
                {
                    // process only if we find an ID
                    m_rHints.push_back(
                        std::make_unique<XMLIndexMarkHint_Impl>(xMark, xPos, sID));
                }
                // else: no ID -> we'll never find the end -> ignore
            }
            // else: can't create mark -> ignore
            break;
        }
 
        case XML_ELEMENT(TEXT, XML_TOC_MARK_END):
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END):
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END):
        {
            // end: search for ID and set end of mark
 
            // call process attributes with empty XPropertySet:
            ProcessAttributes(nElement, xAttrList, xMark);
            if (!sID.isEmpty())
            {
                // if we have an ID, find the hint and set the end position
                XMLIndexMarkHint_Impl *const pHint = m_rHints.GetIndexHintById(sID);
                if (pHint)
                    // set end and stop searching
                    pHint->SetEnd(xPos);
            }
            // else: no ID -> ignore
            break;
        }
 
        default:
            SAL_WARN("xmloff.text", "unknown index mark type!");
            break;
    }
}
 
void XMLIndexMarkImportContext_Impl::ProcessAttributes(
    sal_Int32 nElement,
    const Reference<xml::sax::XFastAttributeList> & xAttrList,
    Reference<beans::XPropertySet>& rPropSet)
{
    // process attributes
    for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
    {
        ProcessAttribute(nElement, aIter, rPropSet);
    }
}
 
void XMLIndexMarkImportContext_Impl::ProcessAttribute(
    sal_Int32 nElement,
    const sax_fastparser::FastAttributeList::FastAttributeIter & aIter,
    Reference<beans::XPropertySet>& rPropSet)
{
    // we only know ID + string-value attribute;
    // (former: marks, latter: -start + -end-marks)
    // the remainder is handled in sub-classes
    switch (nElement)
    {
        case XML_ELEMENT(TEXT, XML_TOC_MARK):
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK):
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK):
            if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_STRING_VALUE) )
            {
                rPropSet->setPropertyValue(u"AlternativeText"_ustr, uno::Any(aIter.toString()));
            }
            // else: ignore!
            break;
 
        case XML_ELEMENT(TEXT, XML_TOC_MARK_START):
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START):
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START):
        case XML_ELEMENT(TEXT, XML_TOC_MARK_END):
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END):
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END):
            if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_ID) )
            {
                sID = aIter.toString();
            }
            // else: ignore
            break;
 
        default:
            XMLOFF_WARN_UNKNOWN("xmloff", aIter);
            break;
    }
}
 
 
void XMLIndexMarkImportContext_Impl::GetServiceName(
    OUString& sServiceName,
    sal_Int32 nElement)
{
    switch (nElement)
    {
        case XML_ELEMENT(TEXT, XML_TOC_MARK):
        case XML_ELEMENT(TEXT, XML_TOC_MARK_START):
        case XML_ELEMENT(TEXT, XML_TOC_MARK_END):
        {
            sServiceName = "com.sun.star.text.ContentIndexMark";
            break;
        }
 
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK):
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START):
        case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END):
        {
            sServiceName = "com.sun.star.text.UserIndexMark";
            break;
        }
 
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK):
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START):
        case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END):
        {
            sServiceName = "com.sun.star.text.DocumentIndexMark";
            break;
        }
 
        default:
        {
            XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
            sServiceName.clear();
            break;
        }
    }
}
 
bool XMLIndexMarkImportContext_Impl::CreateMark(
    Reference<beans::XPropertySet>& rPropSet,
    const OUString& rServiceName)
{
    Reference<lang::XMultiServiceFactory>
        xFactory(GetImport().GetModel(), UNO_QUERY);
 
    if( xFactory.is() )
    {
        Reference<beans::XPropertySet> xPropSet( xFactory->createInstance(rServiceName), UNO_QUERY );
        if (xPropSet.is())
            rPropSet = std::move(xPropSet);
        return true;
    }
 
    return false;
}
 
namespace {
 
class XMLTOCMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl
{
public:
 
    XMLTOCMarkImportContext_Impl(
        SvXMLImport& rImport,
        XMLHints_Impl& rHints);
 
protected:
 
    /** process outline level */
    virtual void ProcessAttribute(sal_Int32 nElement,
                                  const sax_fastparser::FastAttributeList::FastAttributeIter & aIter,
                                  Reference<beans::XPropertySet>& rPropSet) override;
};
 
}
 
XMLTOCMarkImportContext_Impl::XMLTOCMarkImportContext_Impl(
    SvXMLImport& rImport, XMLHints_Impl& rHints) :
        XMLIndexMarkImportContext_Impl(rImport, rHints)
{
}
 
void XMLTOCMarkImportContext_Impl::ProcessAttribute(
    sal_Int32 nElement,
    const sax_fastparser::FastAttributeList::FastAttributeIter & aIter,
    Reference<beans::XPropertySet>& rPropSet)
{
    SAL_WARN_IF(!rPropSet.is(), "xmloff.text", "need PropertySet");
 
    switch (aIter.getToken())
    {
        case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL):
        {
            // outline level: set Level property
            sal_Int32 nTmp;
            if (::sax::Converter::convertNumber( nTmp, aIter.toView() )
                && nTmp >= 1
                && nTmp < GetImport().GetTextImport()->
                                GetChapterNumbering()->getCount() )
            {
                rPropSet->setPropertyValue(u"Level"_ustr, uno::Any(static_cast<sal_Int16>(nTmp - 1)));
            }
            // else: value out of range -> ignore
            break;
        }
        default:
            // else: delegate to superclass
            XMLIndexMarkImportContext_Impl::ProcessAttribute(
                nElement, aIter, rPropSet);
    }
}
 
namespace {
 
class XMLUserIndexMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl
{
public:
 
    XMLUserIndexMarkImportContext_Impl(
        SvXMLImport& rImport,
        XMLHints_Impl& rHints);
 
protected:
 
    /** process index name */
    virtual void ProcessAttribute(sal_Int32 nElement,
                                  const sax_fastparser::FastAttributeList::FastAttributeIter & aIter,
                                  Reference<beans::XPropertySet>& rPropSet) override;
};
 
}
 
XMLUserIndexMarkImportContext_Impl::XMLUserIndexMarkImportContext_Impl(
    SvXMLImport& rImport, XMLHints_Impl& rHints) :
        XMLIndexMarkImportContext_Impl(rImport, rHints)
{
}
 
void XMLUserIndexMarkImportContext_Impl::ProcessAttribute(
    sal_Int32 nElement,
    const sax_fastparser::FastAttributeList::FastAttributeIter & aIter,
    Reference<beans::XPropertySet>& rPropSet)
{
    switch (aIter.getToken())
    {
        case XML_ELEMENT(TEXT, XML_INDEX_NAME):
            rPropSet->setPropertyValue(u"UserIndexName"_ustr, uno::Any(aIter.toString()));
            break;
        case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL):
        {
            // outline level: set Level property
            sal_Int32 nTmp;
            if (::sax::Converter::convertNumber(
                nTmp, aIter.toView(), 0,
               GetImport().GetTextImport()->GetChapterNumbering()->getCount()))
            {
                rPropSet->setPropertyValue(u"Level"_ustr, uno::Any(static_cast<sal_Int16>(nTmp - 1)));
            }
            // else: value out of range -> ignore
            break;
        }
        default:
            // else: unknown text property: delegate to super class
            XMLIndexMarkImportContext_Impl::ProcessAttribute(
                nElement, aIter, rPropSet);
    }
}
 
namespace {
 
class XMLAlphaIndexMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl
{
public:
 
    XMLAlphaIndexMarkImportContext_Impl(
        SvXMLImport& rImport,
        XMLHints_Impl& rHints);
 
protected:
 
    /** process primary + secondary keys */
    virtual void ProcessAttribute(sal_Int32 nElement,
                                  const sax_fastparser::FastAttributeList::FastAttributeIter & aIter,
                                  Reference<beans::XPropertySet>& rPropSet) override;
};
 
}
 
XMLAlphaIndexMarkImportContext_Impl::XMLAlphaIndexMarkImportContext_Impl(
    SvXMLImport& rImport, XMLHints_Impl& rHints) :
        XMLIndexMarkImportContext_Impl(rImport, rHints)
{
}
 
void XMLAlphaIndexMarkImportContext_Impl::ProcessAttribute(
    sal_Int32 nElement,
    const sax_fastparser::FastAttributeList::FastAttributeIter & aIter,
    Reference<beans::XPropertySet>& rPropSet)
{
    switch (aIter.getToken())
    {
        case XML_ELEMENT(TEXT, XML_KEY1):
            rPropSet->setPropertyValue(u"PrimaryKey"_ustr, uno::Any(aIter.toString()));
            break;
        case XML_ELEMENT(TEXT, XML_KEY2):
            rPropSet->setPropertyValue(u"SecondaryKey"_ustr, uno::Any(aIter.toString()));
            break;
        case XML_ELEMENT(TEXT, XML_KEY1_PHONETIC):
            rPropSet->setPropertyValue(u"PrimaryKeyReading"_ustr, uno::Any(aIter.toString()));
            break;
        case XML_ELEMENT(TEXT, XML_KEY2_PHONETIC):
            rPropSet->setPropertyValue(u"SecondaryKeyReading"_ustr, uno::Any(aIter.toString()));
            break;
        case XML_ELEMENT(TEXT, XML_STRING_VALUE_PHONETIC):
            rPropSet->setPropertyValue(u"TextReading"_ustr, uno::Any(aIter.toString()));
            break;
        case XML_ELEMENT(TEXT, XML_MAIN_ENTRY):
        {
            bool bMainEntry = false;
            bool bTmp(false);
 
            if (::sax::Converter::convertBool(bTmp, aIter.toView()))
                bMainEntry = bTmp;
 
            rPropSet->setPropertyValue(u"IsMainEntry"_ustr, uno::Any(bMainEntry));
            break;
        }
        default:
            XMLIndexMarkImportContext_Impl::ProcessAttribute(
                nElement, aIter, rPropSet);
    }
}
 
 
XMLImpSpanContext_Impl::XMLImpSpanContext_Impl(
        SvXMLImport& rImport,
        sal_Int32 /*nElement*/,
        const Reference< xml::sax::XFastAttributeList > & xAttrList,
        XMLHints_Impl& rHints,
        bool& rIgnLeadSpace,
        sal_uInt8 nSFConvFlags)
:   SvXMLImportContext( rImport )
,   m_rHints( rHints )
,   pHint( nullptr  )
,   rIgnoreLeadingSpace( rIgnLeadSpace )
,   nStarFontsConvFlags( nSFConvFlags & (CONV_FROM_STAR_BATS|CONV_FROM_STAR_MATH) )
{
    OUString aStyleName;
 
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
    {
        if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) )
        {
            aStyleName = aIter.toString();
            break;
        }
    }
 
    if( !aStyleName.isEmpty() )
    {
        pHint = new XMLStyleHint_Impl( aStyleName,
                  GetImport().GetTextImport()->GetCursorAsRange()->getStart() );
        m_rHints.push_back(std::unique_ptr<XMLStyleHint_Impl>(pHint));
    }
}
 
void XMLImpSpanContext_Impl::endFastElement(sal_Int32 )
{
    if (!pHint)
        return;
 
    Reference<XTextRange> xCrsrRange(GetImport().GetTextImport()->GetCursorAsRange());
    if (!xCrsrRange.is())
        return; // Robust (defective file)
 
    pHint->SetEnd(xCrsrRange->getStart());
}
 
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpSpanContext_Impl::CreateSpanContext(
        SvXMLImport& rImport,
        sal_Int32 nElement,
        const Reference< xml::sax::XFastAttributeList > & xAttrList,
        XMLHints_Impl& rHints,
        bool& rIgnoreLeadingSpace,
        sal_uInt8 nStarFontsConvFlags
     )
{
    SvXMLImportContext *pContext = nullptr;
 
    switch( nElement )
    {
    case XML_ELEMENT(TEXT, XML_SPAN):
        pContext = new XMLImpSpanContext_Impl( rImport, nElement,
                                               xAttrList,
                                               rHints,
                                               rIgnoreLeadingSpace
                                               ,nStarFontsConvFlags
                                             );
        break;
 
    case XML_ELEMENT(TEXT, XML_TAB):
        pContext = new XMLCharContext( rImport, xAttrList,
                                               0x0009, false );
        rIgnoreLeadingSpace = false;
        break;
 
    case XML_ELEMENT(TEXT, XML_LINE_BREAK):
        if (xAttrList->hasAttribute(XML_ELEMENT(LO_EXT, XML_CLEAR)))
        {
            pContext = new SvXMLLineBreakContext(rImport, *rImport.GetTextImport());
        }
        else
        {
            pContext = new XMLCharContext(rImport, ControlCharacter::LINE_BREAK);
        }
        rIgnoreLeadingSpace = false;
        break;
 
    case XML_ELEMENT(TEXT, XML_S):
        pContext = new XMLCharContext( rImport, xAttrList, 0x0020, true );
        rIgnoreLeadingSpace = false;
        break;
 
    case XML_ELEMENT(TEXT, XML_A):
    {
        // test for HyperLinkURL property. If present, insert link as
        // text property (StarWriter), else try to insert as text
        // field (StarCalc, StarDraw, ...)
        Reference< beans::XPropertySet > xPropSet( rImport.GetTextImport()->GetCursor(), UNO_QUERY );
 
        if ( xPropSet->getPropertySetInfo()->hasPropertyByName( u"HyperLinkURL"_ustr ) )
        {
            pContext = new XMLImpHyperlinkContext_Impl(
                    rImport,
                    nElement,
                    xAttrList,
                    rHints,
                    rIgnoreLeadingSpace );
        }
        else
        {
            pContext = new XMLUrlFieldImportContext(rImport, *rImport.GetTextImport());
            //whitespace handling like other fields
            rIgnoreLeadingSpace = false;
 
        }
        break;
    }
 
    case XML_ELEMENT(TEXT, XML_RUBY):
        pContext = new XMLImpRubyContext_Impl( rImport, nElement,
                                               xAttrList,
                                               rHints,
                                               rIgnoreLeadingSpace );
        break;
 
    case XML_ELEMENT(TEXT, XML_NOTE):
        if (rImport.GetTextImport()->IsInFrame())
        {
            // we must not insert footnotes into text frames
            pContext = new SvXMLImportContext( rImport );
        }
        else
        {
            pContext = new XMLFootnoteImportContext(rImport, *rImport.GetTextImport());
        }
        rIgnoreLeadingSpace = false;
        break;
 
    case XML_ELEMENT(TEXT, XML_REFERENCE_MARK):
    case XML_ELEMENT(TEXT, XML_BOOKMARK):
    case XML_ELEMENT(TEXT, XML_BOOKMARK_START):
    case XML_ELEMENT(TEXT, XML_BOOKMARK_END):
        pContext = new XMLTextMarkImportContext(rImport, *rImport.GetTextImport(),
                                                rHints.GetCrossRefHeadingBookmark());
        break;
 
    case XML_ELEMENT(FIELD, XML_FIELDMARK):
    case XML_ELEMENT(FIELD, XML_FIELDMARK_START):
    case XML_ELEMENT(FIELD, XML_FIELDMARK_SEPARATOR):
    case XML_ELEMENT(FIELD, XML_FIELDMARK_END):
        pContext = new XMLTextMarkImportContext(rImport, *rImport.GetTextImport(),
                                                rHints.GetCrossRefHeadingBookmark());
        break;
 
    case XML_ELEMENT(TEXT, XML_REFERENCE_MARK_START):
        pContext = new XMLStartReferenceContext_Impl( rImport,
                                                      rHints, xAttrList );
        break;
 
    case XML_ELEMENT(TEXT, XML_REFERENCE_MARK_END):
        pContext = new XMLEndReferenceContext_Impl( rImport,
                                                    rHints, xAttrList );
        break;
 
    case XML_ELEMENT(DRAW, XML_FRAME):
        {
            Reference < XTextRange > xAnchorPos =
                rImport.GetTextImport()->GetCursor()->getStart();
            XMLTextFrameContext *pTextFrameContext =
                            new XMLTextFrameContext(rImport,
                                         xAttrList,
                                         TextContentAnchorType_AS_CHARACTER );
            // Remove check for text content. (#i33242#)
            // Check for text content is done on the processing of the hint
            if( TextContentAnchorType_AT_CHARACTER ==
                                            pTextFrameContext->GetAnchorType() )
            {
                rHints.push_back(std::make_unique<XMLTextFrameHint_Impl>(
                                    pTextFrameContext, xAnchorPos));
            }
            pContext = pTextFrameContext;
            rIgnoreLeadingSpace = false;
        }
        break;
    case XML_ELEMENT(DRAW, XML_A):
        {
            Reference < XTextRange > xAnchorPos(rImport.GetTextImport()->GetCursor()->getStart());
            pContext =
                new XMLTextFrameHyperlinkContext( rImport, nElement,
                                        xAttrList,
                                        TextContentAnchorType_AS_CHARACTER );
            rHints.push_back(
                std::make_unique<XMLTextFrameHint_Impl>(pContext, xAnchorPos));
        }
        break;
 
    case XML_ELEMENT(TEXT, XML_TOC_MARK):
    case XML_ELEMENT(TEXT, XML_TOC_MARK_START):
        pContext = new XMLTOCMarkImportContext_Impl(
            rImport, rHints);
        break;
 
    case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK):
    case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START):
        pContext = new XMLUserIndexMarkImportContext_Impl(
            rImport, rHints);
        break;
 
    case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK):
    case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START):
        pContext = new XMLAlphaIndexMarkImportContext_Impl(
            rImport, rHints);
        break;
 
    case XML_ELEMENT(TEXT, XML_TOC_MARK_END):
    case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END):
    case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END):
        pContext = new XMLIndexMarkImportContext_Impl(
            rImport, rHints);
        break;
 
    case XML_ELEMENT(TEXT, XML_CHANGE_START):
    case XML_ELEMENT(TEXT, XML_CHANGE_END):
    case XML_ELEMENT(TEXT, XML_CHANGE):
        pContext = new XMLChangeImportContext(
            rImport,
            ((nElement == XML_ELEMENT(TEXT, XML_CHANGE_END))
                ? XMLChangeImportContext::Element::END
                : (nElement == XML_ELEMENT(TEXT, XML_CHANGE_START))
                    ? XMLChangeImportContext::Element::START
                    : XMLChangeImportContext::Element::POINT),
            false);
        break;
 
    case  XML_ELEMENT(TEXT, XML_META):
        pContext = new XMLMetaImportContext(rImport, nElement,
            rHints, rIgnoreLeadingSpace );
        break;
 
    case XML_ELEMENT(TEXT, XML_META_FIELD):
        pContext = new XMLMetaFieldImportContext(rImport, nElement,
            rHints, rIgnoreLeadingSpace );
        break;
 
    case XML_ELEMENT(LO_EXT, XML_CONTENT_CONTROL):
        pContext = new XMLContentControlContext(rImport, nElement, rHints, rIgnoreLeadingSpace);
        break;
 
    default:
        // none of the above? then it's probably  a text field!
        pContext = XMLTextFieldImportContext::CreateTextFieldImportContext(
            rImport, *rImport.GetTextImport(), nElement);
        // #108784# import draw elements (except control shapes in headers)
        if( pContext == nullptr &&
            !( rImport.GetTextImport()->IsInHeaderFooter() &&
               nElement == XML_ELEMENT(DRAW, XML_CONTROL ) ) )
        {
            Reference < XShapes > xShapes;
            SvXMLShapeContext* pShapeContext = XMLShapeImportHelper::CreateGroupChildContext(
                rImport, nElement, xAttrList, xShapes );
            pContext = pShapeContext;
            // OD 2004-04-20 #i26791# - keep shape in a text frame hint to
            // adjust its anchor position, if it's at-character anchored
            Reference < XTextRange > xAnchorPos =
                rImport.GetTextImport()->GetCursor()->getStart();
            rHints.push_back(
                std::make_unique<XMLDrawHint_Impl>(pShapeContext, xAnchorPos));
        }
        // Behind fields, shapes and any unknown content blanks aren't ignored
        rIgnoreLeadingSpace = false;
    }
 
    if (!pContext)
        XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
    return pContext;
}
 
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpSpanContext_Impl::createFastChildContext(
    sal_Int32 nElement,
    const uno::Reference< xml::sax::XFastAttributeList>& xAttrList )
{
    return CreateSpanContext( GetImport(), nElement, xAttrList,
                               m_rHints, rIgnoreLeadingSpace
                               ,nStarFontsConvFlags
                             );
}
 
void XMLImpSpanContext_Impl::characters( const OUString& rChars )
{
    OUString sStyleName;
    if( pHint )
        sStyleName = pHint->GetStyleName();
    OUString sChars =
        GetImport().GetTextImport()->ConvertStarFonts( rChars, sStyleName,
                                                       nStarFontsConvFlags,
                                                       false, GetImport() );
    GetImport().GetTextImport()->InsertString( sChars, rIgnoreLeadingSpace );
}
 
 
XMLParaContext::XMLParaContext(
        SvXMLImport& rImport,
        sal_Int32 nElement,
        const Reference< xml::sax::XFastAttributeList > & xAttrList ) :
    SvXMLImportContext( rImport ),
    xStart( rImport.GetTextImport()->GetCursorAsRange()->getStart() ),
    m_bHaveAbout(false),
    nOutlineLevel( (nElement & TOKEN_MASK) == XML_H ? 1 : -1 ),
    // Lost outline numbering in master document (#i73509#)
    mbOutlineLevelAttrFound( false ),
    mbOutlineContentVisible(true),
    bIgnoreLeadingSpace( true ),
    bHeading( (nElement & TOKEN_MASK) == XML_H ),
    bIsListHeader( false ),
    bIsRestart (false),
    nStartValue(0),
    nStarFontsConvFlags( 0 )
{
    bool bHaveXmlId( false );
    OUString aCondStyleName;
 
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
    {
        switch( aIter.getToken() )
        {
        case XML_ELEMENT(XML, XML_ID):
            m_sXmlId = aIter.toString();
            bHaveXmlId = true;
            break;
        case XML_ELEMENT(XHTML, XML_ABOUT):
            m_sAbout = aIter.toString();
            m_bHaveAbout = true;
            break;
        case XML_ELEMENT(XHTML, XML_PROPERTY):
            m_sProperty = aIter.toString();
            break;
        case XML_ELEMENT(XHTML, XML_CONTENT):
            m_sContent = aIter.toString();
            break;
        case XML_ELEMENT(XHTML, XML_DATATYPE):
            m_sDatatype = aIter.toString();
            break;
        case XML_ELEMENT(TEXT, XML_ID):
            if (!bHaveXmlId) { m_sXmlId = aIter.toString(); }
            break;
        case XML_ELEMENT(TEXT, XML_STYLE_NAME):
            sStyleName = aIter.toString();
            break;
        case XML_ELEMENT(TEXT, XML_COND_STYLE_NAME):
            aCondStyleName = aIter.toString();
            break;
        case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL):
            {
                sal_Int32 nTmp = aIter.toInt32();
                if( nTmp > 0 )
                {
                    if( nTmp > 127 )
                        nTmp = 127;
                    nOutlineLevel = static_cast<sal_Int8>(nTmp);
                }
                // Lost outline numbering in master document (#i73509#)
                mbOutlineLevelAttrFound = true;
            }
            break;
        case XML_ELEMENT(LO_EXT, XML_OUTLINE_CONTENT_VISIBLE):
            {
                bool bBool(false);
                if (::sax::Converter::convertBool(bBool, aIter.toView()))
                    mbOutlineContentVisible = bBool;
            }
            break;
        case XML_ELEMENT(TEXT, XML_IS_LIST_HEADER):
            {
                bool bBool(false);
                if (::sax::Converter::convertBool(bBool, aIter.toView()))
                    bIsListHeader = bBool;
            }
            break;
        case XML_ELEMENT(TEXT, XML_RESTART_NUMBERING):
            {
                bool bBool(false);
                if (::sax::Converter::convertBool(bBool, aIter.toView()))
                    bIsRestart = bBool;
            }
            break;
        case XML_ELEMENT(TEXT, XML_START_VALUE):
            {
                nStartValue = sal::static_int_cast< sal_Int16 >(aIter.toInt32());
            }
            break;
        case XML_ELEMENT(LO_EXT, XML_MARKER_STYLE_NAME):
            if (auto pStyle = rImport.GetTextImport()->FindAutoCharStyle(aIter.toString()))
                m_aMarkerStyleName = pStyle->GetAutoName();
            break;
        default:
            XMLOFF_WARN_UNKNOWN("xmloff", aIter);
        }
    }
 
    if( !aCondStyleName.isEmpty() )
        sStyleName = aCondStyleName;
}
 
void XMLParaContext::endFastElement(sal_Int32 )
{
    rtl::Reference < XMLTextImportHelper > xTxtImport(
        GetImport().GetTextImport());
    Reference<XTextRange> xEnd;
    try
    {
        Reference<XTextRange> const xCrsrRange(xTxtImport->GetCursorAsRange());
        if (!xCrsrRange.is())
            return; // Robust (defective file)
        xEnd = xCrsrRange->getStart();
    }
    catch (uno::Exception const&)
    {
        SAL_INFO("xmloff.text", "XMLParaContext: cursor disposed?");
        return;
    }
 
    // if we have an id set for this paragraph, get a cursor for this
    // paragraph and register it with the given identifier
    // FIXME: this is just temporary, and should be removed when
    // EditEngine paragraphs implement XMetadatable!
    if (!m_sXmlId.isEmpty())
    {
        Reference < XTextCursor > xIdCursor( xTxtImport->GetText()->createTextCursorByRange( xStart ) );
        if( xIdCursor.is() )
        {
            xIdCursor->gotoRange( xEnd, true );
            GetImport().getInterfaceToIdentifierMapper().registerReference(
                m_sXmlId, Reference<XInterface>( xIdCursor, UNO_QUERY ));
        }
    }
 
    // insert a paragraph break
    xTxtImport->InsertControlCharacter( ControlCharacter::APPEND_PARAGRAPH );
 
    // create a cursor that select the whole last paragraph
    Reference < XTextCursor > xAttrCursor;
    try {
        xAttrCursor = xTxtImport->GetText()->createTextCursorByRange( xStart );
        if( !xAttrCursor.is() )
            return; // Robust (defective file)
    } catch (const uno::Exception &) {
        // createTextCursorByRange() likes to throw runtime exception, even
        // though it just means 'we were unable to create the cursor'
        return;
    }
    xAttrCursor->gotoRange( xEnd, true );
 
    // xml:id for RDF metadata
    if (!m_sXmlId.isEmpty() || m_bHaveAbout || !m_sProperty.isEmpty())
    {
        try {
            const uno::Reference<container::XEnumerationAccess> xEA
                (xAttrCursor, uno::UNO_QUERY_THROW);
            const uno::Reference<container::XEnumeration> xEnum(
                xEA->createEnumeration(), uno::UNO_SET_THROW);
            SAL_WARN_IF(!xEnum->hasMoreElements(), "xmloff.text", "xml:id: no paragraph?");
            if (xEnum->hasMoreElements()) {
                uno::Reference<rdf::XMetadatable> xMeta;
                xEnum->nextElement() >>= xMeta;
                SAL_WARN_IF(!xMeta.is(), "xmloff.text", "xml:id: not XMetadatable");
                GetImport().SetXmlId(xMeta, m_sXmlId);
                if (m_bHaveAbout)
                {
                    GetImport().AddRDFa(xMeta,
                        m_sAbout, m_sProperty, m_sContent, m_sDatatype);
                }
                SAL_WARN_IF(xEnum->hasMoreElements(), "xmloff.text", "xml:id: > 1 paragraph?");
            }
        } catch (const uno::Exception &) {
            SAL_INFO("xmloff.text", "XMLParaContext::~XMLParaContext: exception");
        }
    }
 
    OUString const sCellParaStyleName(xTxtImport->GetCellParaStyleDefault());
    if( !sCellParaStyleName.isEmpty() )
    {
        /* Suppress handling of outline and list attributes,
           because of side effects of method <SetStyleAndAttrs(..)> (#i80724#)
        */
        xTxtImport->SetStyleAndAttrs( GetImport(), xAttrCursor,
                                      sCellParaStyleName,
                                      true,
                                      false, -1, // suppress outline handling
                                      false );   // suppress list attributes handling
    }
 
    // #103445# for headings without style name, find the proper style
    if( bHeading && sStyleName.isEmpty() )
        xTxtImport->FindOutlineStyleName( sStyleName, nOutlineLevel );
 
    // set style and hard attributes at the previous paragraph
    // Add parameter <mbOutlineLevelAttrFound> (#i73509#)
    sStyleName = xTxtImport->SetStyleAndAttrs( GetImport(), xAttrCursor,
                                               sStyleName,
                                               true,
                                               mbOutlineLevelAttrFound,
                                               bHeading ? nOutlineLevel : -1,
                                               true,
                                               mbOutlineContentVisible);
 
    if (m_aMarkerStyleName.hasValue())
    {
        if (auto xPropSet = xStart.query<css::beans::XPropertySet>())
        {
            try
            {
                xPropSet->setPropertyValue(u"ListAutoFormat"_ustr, m_aMarkerStyleName);
            }
            catch (const css::beans::UnknownPropertyException&)
            {
                // no problem
            }
        }
    }
 
    // handle list style header
    if (bHeading && (bIsListHeader || bIsRestart))
    {
        Reference<XPropertySet> xPropSet( xAttrCursor, UNO_QUERY );
 
        if (xPropSet.is())
        {
            if (bIsListHeader)
            {
                OUString sNumberingIsNumber
                    (u"NumberingIsNumber"_ustr);
                if(xPropSet->getPropertySetInfo()->
                   hasPropertyByName(sNumberingIsNumber))
                {
                    xPropSet->setPropertyValue
                        (sNumberingIsNumber, Any( false ) );
                }
            }
            if (bIsRestart)
            {
                OUString sParaIsNumberingRestart
                    (u"ParaIsNumberingRestart"_ustr);
                OUString sNumberingStartValue
                    (u"NumberingStartValue"_ustr);
                if (xPropSet->getPropertySetInfo()->
                    hasPropertyByName(sParaIsNumberingRestart))
                {
                    xPropSet->setPropertyValue
                        (sParaIsNumberingRestart, Any(true));
                }
 
                if (xPropSet->getPropertySetInfo()->
                    hasPropertyByName(sNumberingStartValue))
                {
                    xPropSet->setPropertyValue
                        (sNumberingStartValue, Any(nStartValue));
                }
            }
 
        }
    }
 
    if (m_oHints)
    {
        bool bEmptyHints = false;
        if (auto xCompare = xTxtImport->GetText().query<text::XTextRangeCompare>())
        {
            try
            {
                for (const auto& pHint : m_oHints->GetHints())
                {
                    if (xCompare->compareRegionStarts(pHint->GetStart(), pHint->GetEnd()) == 0)
                    {
                        bEmptyHints = true;
                    }
                }
            }
            catch (const uno::Exception&)
            {
                TOOLS_WARN_EXCEPTION("xmloff.text", "");
            }
        }
        bool bSetNoFormatAttr = false;
        uno::Reference<beans::XPropertySet> xCursorProps(xAttrCursor, uno::UNO_QUERY);
        if (bEmptyHints || m_aMarkerStyleName.hasValue())
        {
            // We have at least one empty hint, then make try to ask the cursor to not upgrade our character
            // attributes to paragraph-level formatting, which would lead to incorrect rendering.
            uno::Reference<beans::XPropertySetInfo> xCursorPropsInfo = xCursorProps->getPropertySetInfo();
            bSetNoFormatAttr = xCursorPropsInfo->hasPropertyByName(u"NoFormatAttr"_ustr);
        }
        if (bSetNoFormatAttr)
        {
            xCursorProps->setPropertyValue(u"NoFormatAttr"_ustr, uno::Any(true));
        }
        for (const auto & i : m_oHints->GetHints())
        {
            XMLHint_Impl *const pHint = i.get();
            xAttrCursor->gotoRange( pHint->GetStart(), false );
            xAttrCursor->gotoRange( pHint->GetEnd(), true );
            switch( pHint->GetType() )
            {
            case XMLHintType::XML_HINT_STYLE:
                {
                    const OUString& rStyleName =
                            static_cast<XMLStyleHint_Impl *>(pHint)->GetStyleName();
                    if( !rStyleName.isEmpty() )
                        xTxtImport->SetStyleAndAttrs( GetImport(),
                                                      xAttrCursor, rStyleName,
                                                      false );
                }
                break;
            case XMLHintType::XML_HINT_REFERENCE:
                {
                    const OUString& rRefName =
                            static_cast<XMLReferenceHint_Impl *>(pHint)->GetRefName();
                    if( !rRefName.isEmpty() )
                    {
                        if( !pHint->GetEnd().is() )
                            pHint->SetEnd(xEnd);
 
                        // reference name uses rStyleName member
                        // borrow from XMLTextMarkImportContext
                        XMLTextMarkImportContext::CreateAndInsertMark(
                            GetImport(),
                            u"com.sun.star.text.ReferenceMark"_ustr,
                            rRefName,
                            xAttrCursor);
                    }
                }
                break;
            case XMLHintType::XML_HINT_HYPERLINK:
                {
                    const XMLHyperlinkHint_Impl *pHHint =
                        static_cast<const XMLHyperlinkHint_Impl *>(pHint);
                    xTxtImport->SetHyperlink( GetImport(),
                                              xAttrCursor,
                                              pHHint->GetHRef(),
                                              pHHint->GetName(),
                                              pHHint->GetTargetFrameName(),
                                              pHHint->GetStyleName(),
                                              pHHint->GetVisitedStyleName(),
                                              pHHint->GetEventsContext() );
                }
                break;
            case XMLHintType::XML_HINT_INDEX_MARK:
                {
                    Reference<beans::XPropertySet> xMark(
                        static_cast<const XMLIndexMarkHint_Impl *>(pHint)->GetMark());
                    Reference<XTextContent> xContent(xMark, UNO_QUERY);
                    try
                    {
                        xTxtImport->GetText()->insertTextContent(
                            xAttrCursor, xContent, true );
                    }
                    catch (uno::RuntimeException const&)
                    {
                        TOOLS_INFO_EXCEPTION("xmloff.text", "could not insert index mark, presumably in editengine text");
                    }
                }
                break;
            case XMLHintType::XML_HINT_TEXT_FRAME:
                {
                    const XMLTextFrameHint_Impl *pFHint =
                        static_cast<const XMLTextFrameHint_Impl *>(pHint);
                    // Check for text content (#i33242#)
                    Reference < XTextContent > xTextContent =
                                                    pFHint->GetTextContent();
                    if ( xTextContent.is() )
                    {
                        /* Core impl. of the unification of drawing objects and
                           Writer fly frames (#i26791#)
                        */
                        if ( pFHint->IsBoundAtChar() )
                        {
                            xTextContent->attach( xAttrCursor );
                        }
                    }
                    /* Consider, that hint can also contain a shape -
                       e.g. drawing object of type 'Text'. (#i33242#)
                    */
                    else
                    {
                        Reference < XShape > xShape = pFHint->GetShape();
                        if ( xShape.is() )
                        {
                            // determine anchor type
                            Reference < XPropertySet > xPropSet( xShape, UNO_QUERY );
                            TextContentAnchorType eAnchorType =
                                            TextContentAnchorType_AT_PARAGRAPH;
                            {
                                Any aAny = xPropSet->getPropertyValue( u"AnchorType"_ustr );
                                aAny >>= eAnchorType;
                            }
                            if ( TextContentAnchorType_AT_CHARACTER == eAnchorType )
                            {
                                // set anchor position for at-character anchored objects
                                xPropSet->setPropertyValue(u"TextRange"_ustr, Any(xAttrCursor));
                            }
                        }
                    }
                }
                break;
            /* Core impl. of the unification of drawing objects and
               Writer fly frames (#i26791#)
            */
            case XMLHintType::XML_HINT_DRAW:
                {
                    const XMLDrawHint_Impl *pDHint =
                        static_cast<const XMLDrawHint_Impl*>(pHint);
                    // Improvement: hint directly provides the shape. (#i33242#)
                    const Reference < XShape >& xShape = pDHint->GetShape();
                    if ( xShape.is() )
                    {
                        // determine anchor type
                        Reference < XPropertySet > xPropSet( xShape, UNO_QUERY );
                        TextContentAnchorType eAnchorType = TextContentAnchorType_AT_PARAGRAPH;
                        {
                            Any aAny = xPropSet->getPropertyValue( u"AnchorType"_ustr );
                            aAny >>= eAnchorType;
                        }
                        if ( TextContentAnchorType_AT_CHARACTER == eAnchorType )
                        {
                            // set anchor position for at-character anchored objects
                            xPropSet->setPropertyValue(u"TextRange"_ustr, Any(xAttrCursor));
                        }
                    }
                }
                break;
            default:
                SAL_WARN( "xmloff.text", "What's this" );
                break;
            }
        }
        if (bSetNoFormatAttr)
        {
            xCursorProps->setPropertyValue(u"NoFormatAttr"_ustr, uno::Any(false));
        }
    }
    m_oHints.reset();
}
 
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLParaContext::createFastChildContext(
    sal_Int32 nElement,
    const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
{
    if (!m_oHints)
        m_oHints.emplace();
    return XMLImpSpanContext_Impl::CreateSpanContext(
                                GetImport(), nElement, xAttrList,
                                *m_oHints, bIgnoreLeadingSpace,
                                nStarFontsConvFlags);
}
 
void XMLParaContext::characters( const OUString& rChars )
{
    OUString sChars =
        GetImport().GetTextImport()->ConvertStarFonts( rChars, sStyleName,
                                                       nStarFontsConvFlags,
                                                       true, GetImport() );
    GetImport().GetTextImport()->InsertString( sChars, bIgnoreLeadingSpace );
}
 
 
XMLNumberedParaContext::XMLNumberedParaContext(
        SvXMLImport& i_rImport,
        sal_Int32 /*nElement*/,
        const Reference< xml::sax::XFastAttributeList > & xAttrList ) :
    SvXMLImportContext( i_rImport ),
    m_Level(0),
    m_StartValue(-1)
{
    OUString StyleName;
 
    for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
    {
        switch( aIter.getToken() )
        {
            case XML_ELEMENT(XML, XML_ID):
//FIXME: there is no UNO API for lists
                break;
            case XML_ELEMENT(TEXT, XML_LIST_ID):
                m_ListId = aIter.toString();
                break;
            case XML_ELEMENT(TEXT, XML_LEVEL):
                {
                    sal_Int32 nTmp = aIter.toInt32();
                    if ( nTmp >= 1 && nTmp <= SHRT_MAX ) {
                        m_Level = static_cast<sal_uInt16>(nTmp) - 1;
                    }
                }
                break;
            case XML_ELEMENT(TEXT, XML_STYLE_NAME):
                StyleName = aIter.toString();
                break;
            case XML_ELEMENT(TEXT, XML_CONTINUE_NUMBERING):
                // this attribute is deprecated
//                ContinueNumbering = IsXMLToken(sValue, XML_TRUE);
                break;
            case XML_ELEMENT(TEXT, XML_START_VALUE):
                {
                    sal_Int32 nTmp = aIter.toInt32();
                    if ( nTmp >= 0 && nTmp <= SHRT_MAX ) {
                        m_StartValue = static_cast<sal_Int16>(nTmp);
                    }
                }
                break;
            default:
                XMLOFF_WARN_UNKNOWN("xmloff", aIter);
        }
    }
 
    XMLTextListsHelper& rTextListsHelper(
        i_rImport.GetTextImport()->GetTextListHelper() );
    if (m_ListId.isEmpty())
    {
        SAL_WARN_IF(0 <= i_rImport.GetODFVersion().compareTo(u"1.2"), "xmloff.text", "invalid numbered-paragraph: no list-id (1.2)");
        m_ListId = rTextListsHelper.GetNumberedParagraphListId(m_Level,
            StyleName);
        SAL_WARN_IF(m_ListId.isEmpty(), "xmloff.text", "numbered-paragraph: no ListId");
        if (m_ListId.isEmpty()) {
            return;
        }
    }
    m_xNumRules = rTextListsHelper.EnsureNumberedParagraph( i_rImport,
        m_ListId, m_Level, StyleName);
 
    SAL_WARN_IF(!m_xNumRules.is(), "xmloff.text", "numbered-paragraph: no NumRules");
 
    i_rImport.GetTextImport()->GetTextListHelper().PushListContext( this );
}
 
void XMLNumberedParaContext::endFastElement(sal_Int32 )
{
    if (!m_ListId.isEmpty()) {
        GetImport().GetTextImport()->PopListContext();
    }
}
 
css::uno::Reference< css::xml::sax::XFastContextHandler > XMLNumberedParaContext::createFastChildContext(
    sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
{
    switch (nElement)
    {
        case XML_ELEMENT(TEXT, XML_H):
        case XML_ELEMENT(LO_EXT, XML_H):
        case XML_ELEMENT(TEXT, XML_P):
        case XML_ELEMENT(LO_EXT, XML_P):
            return new XMLParaContext( GetImport(), nElement, xAttrList );
        default:
            XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
    }
 
    return nullptr;
}
 
/* 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 'SetStyleAndAttrs' is required to be utilized.

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

V1037 Two or more case-branches perform the same actions. Check lines: 1402, 1410