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

    #include <tools/diagnose_ex.h>
    #include <sal/log.hxx>
    #include <com/sun/star/beans/XPropertySetInfo.hpp>
    #include <tools/urlobj.hxx>
    #include <vcl/graph.hxx>
    #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
    #include <xmloff/nmspmap.hxx>
    #include <xmloff/xmluconv.hxx>
    #include <xmloff/xmlnmspe.hxx>
    #include <xmloff/xmltoken.hxx>
    #include <xmloff/XMLFontStylesContext.hxx>
    #include <xmloff/xmlictxt.hxx>
    #include <xmloff/xmlimp.hxx>
    #include <xmloff/xmlnumfi.hxx>
    #include <XMLEventImportHelper.hxx>
    #include <XMLStarBasicContextFactory.hxx>
    #include <XMLScriptContextFactory.hxx>
    #include <StyleMap.hxx>
    #include <xmloff/ProgressBarHelper.hxx>
    #include <xmloff/xmlerror.hxx>
    #include <com/sun/star/lang/XMultiServiceFactory.hpp>
    #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
    #include <com/sun/star/io/XOutputStream.hpp>
    #include <com/sun/star/util/MeasureUnit.hpp>
    #include <com/sun/star/document/XBinaryStreamResolver.hpp>
    #include <com/sun/star/document/XStorageBasedDocument.hpp>
    #include <com/sun/star/document/XGraphicStorageHandler.hpp>
    #include <com/sun/star/graphic/GraphicProvider.hpp>
    #include <com/sun/star/xml/sax/XLocator.hpp>
    #include <com/sun/star/xml/sax/FastParser.hpp>
    #include <com/sun/star/packages/zip/ZipIOException.hpp>
    #include <comphelper/fileformat.h>
    #include <comphelper/namecontainer.hxx>
    #include <comphelper/servicehelper.hxx>
    #include <cppuhelper/implbase.hxx>
    #include <cppuhelper/supportsservice.hxx>
    #include <comphelper/extract.hxx>
    #include <comphelper/documentconstants.hxx>
    #include <comphelper/storagehelper.hxx>
    #include <unotools/fontcvt.hxx>
    #include <o3tl/make_unique.hxx>
    #include <xmloff/fasttokenhandler.hxx>
    #include <vcl/GraphicExternalLink.hxx>

    #include <com/sun/star/rdf/XMetadatable.hpp>
    #include <com/sun/star/rdf/XRepositorySupplier.hpp>
    #include <RDFaImportHelper.hxx>

    using ::com::sun::star::beans::XPropertySetInfo;

    using namespace ::com::sun::star;
    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::util;
    using namespace ::com::sun::star::io;
    using namespace ::com::sun::star::container;
    using namespace ::com::sun::star::document;
    using namespace ::xmloff::token;

    css::uno::Reference< css::xml::sax::XFastTokenHandler > SvXMLImport::xTokenHandler( new FastTokenHandler() );
    std::unordered_map< sal_Int32, std::pair< OUString, OUString > > SvXMLImport::aNamespaceMap;
    std::unordered_map< OUString, OUString, OUStringHash > SvXMLImport::aNamespaceURIPrefixMap;
    const OUString SvXMLImport::aDefaultNamespace = OUString("");
    const OUString SvXMLImport::aNamespaceSeparator = OUString(":");
    bool SvXMLImport::bIsNSMapsInitialized = false;

    class SvXMLImportEventListener : public cppu::WeakImplHelper< css::lang::XEventListener >
    {
    private:
        SvXMLImport*    pImport;

    public:
        explicit SvXMLImportEventListener(SvXMLImport* pImport);

                                // XEventListener
        virtual void SAL_CALL disposing(const lang::EventObject& rEventObject) override;
    };

    SvXMLImportEventListener::SvXMLImportEventListener(SvXMLImport* pTempImport)
        : pImport(pTempImport)
    {
    }

    // XEventListener
    void SAL_CALL SvXMLImportEventListener::disposing( const lang::EventObject& )
    {
        if (pImport)
        {
            pImport->DisposingModel();
            pImport = nullptr;
        }
    }

    namespace
    {

    OUString
    getBuildIdsProperty(uno::Reference<beans::XPropertySet> const& xImportInfo)
    {
        if (xImportInfo.is())
        {
            try
            {
                Reference< XPropertySetInfo > const xSetInfo(
                        xImportInfo->getPropertySetInfo());
                if (xSetInfo.is() && xSetInfo->hasPropertyByName("BuildId"))
                {
                    OUString aBuildId;
                    xImportInfo->getPropertyValue("BuildId") >>= aBuildId;
                    return aBuildId;
                }
            }
            catch (Exception const&)
            {
                DBG_UNHANDLED_EXCEPTION("xmloff.core", "exception getting BuildId");
            }
        }
        return OUString();
    }

    class DocumentInfo
    {
    private:
        sal_uInt16 mnGeneratorVersion;

    public:
        explicit DocumentInfo( const SvXMLImport& rImport )
            : mnGeneratorVersion( SvXMLImport::ProductVersionUnknown )
        {
            OUString const buildIds(
                    getBuildIdsProperty(rImport.getImportInfo()));
            if (!buildIds.isEmpty())
            {
                sal_Int32 const ix = buildIds.indexOf(';');
                if (-1 != ix)
                {
                    OUString const loVersion(buildIds.copy(ix + 1));
                    if (!loVersion.isEmpty())
                    {
                        if ('3' == loVersion[0])
                        {
                            mnGeneratorVersion = SvXMLImport::LO_3x;
                        }
                        else if ('4' == loVersion[0])
                        {
                            if (loVersion.getLength() > 1
                                && (loVersion[1] == '0' || loVersion[1] == '1'))
                            {
                                mnGeneratorVersion = SvXMLImport::LO_41x; // 4.0/4.1
                            }
                            else if (loVersion.getLength() > 1 && '2' == loVersion[1])
                            {
                                mnGeneratorVersion = SvXMLImport::LO_42x; // 4.2
                            }
                            else if (loVersion.getLength() > 1 && '3' == loVersion[1])
                            {
                                mnGeneratorVersion = SvXMLImport::LO_43x; // 4.3
                            }
                            else if (loVersion.getLength() > 1 && '4' == loVersion[1])
                            {
                                mnGeneratorVersion = SvXMLImport::LO_44x; // 4.4
                            }
                        }
                        else if ('5' == loVersion[0])
                        {
                            mnGeneratorVersion = SvXMLImport::LO_5x;
                        }
                        else if ('6' == loVersion[0])
                        {
                            mnGeneratorVersion = SvXMLImport::LO_6x;
                        }
                        else
                        {
                            SAL_INFO("xmloff.core", "unknown LO version: " << loVersion);
                        }
                        return; // ignore buildIds
                    }
                }
            }
            sal_Int32 nUPD, nBuild;
            if ( rImport.getBuildIds( nUPD, nBuild ) )
            {
                if ( nUPD >= 640 && nUPD <= 645 )
                {
                    mnGeneratorVersion = SvXMLImport::OOo_1x;
                }
                else if ( nUPD == 680 )
                {
                    mnGeneratorVersion = SvXMLImport::OOo_2x;
                }
                else if ( nUPD == 300 && nBuild <= 9379 )
                {
                    mnGeneratorVersion = SvXMLImport::OOo_30x;
                }
                else if ( nUPD == 310 )
                {
                    mnGeneratorVersion = SvXMLImport::OOo_31x;
                }
                else if ( nUPD == 320 )
                {
                    mnGeneratorVersion = SvXMLImport::OOo_32x;
                }
                else if ( nUPD == 330 )
                {
                    mnGeneratorVersion = SvXMLImport::OOo_33x;
                }
                else if ( nUPD == 340 )
                {
                    mnGeneratorVersion = SvXMLImport::OOo_34x;
                }
                else if (nUPD == 400 || nUPD == 401)
                {
                    mnGeneratorVersion = SvXMLImport::AOO_40x;
                }
                else if (nUPD >= 410)
                {
                    // effectively this means "latest", see use
                    // in XMLGraphicsDefaultStyle::SetDefaults()!
                    mnGeneratorVersion = SvXMLImport::AOO_4x;
                }
            }
        }

        sal_uInt16 getGeneratorVersion() const
        {
            return mnGeneratorVersion;
        }
    };

    }

    class SvXMLImport_Impl
    {
    public:
        FontToSubsFontConverter hBatsFontConv;
        FontToSubsFontConverter hMathFontConv;

        bool mbOwnGraphicResolver;
        bool mbOwnEmbeddedResolver;
        INetURLObject aBaseURL;
        INetURLObject aDocBase;

        /// name of stream in package, e.g., "content.xml"
        OUString mStreamName;

        OUString aODFVersion;

        bool mbIsOOoXML;

        // Boolean, indicating that position attributes
        // of shapes are given in horizontal left-to-right layout. This is the case
        // for the OpenOffice.org file format. (#i28749#)
        bool mbShapePositionInHoriL2R;
        bool mbTextDocInOOoFileFormat;

        const uno::Reference< uno::XComponentContext > mxComponentContext;
        OUString implementationName;

        uno::Reference< embed::XStorage > mxSourceStorage;

        std::unique_ptr< xmloff::RDFaImportHelper > mpRDFaHelper;

        std::unique_ptr< DocumentInfo > mpDocumentInfo;

        SvXMLImport_Impl( const uno::Reference< uno::XComponentContext >& rxContext,
                          OUString const & theImplementationName)
            : hBatsFontConv( nullptr )
            , hMathFontConv( nullptr )
            , mbOwnGraphicResolver( false )
            , mbOwnEmbeddedResolver( false )
            , mbIsOOoXML(false)
            // Convert drawing object positions from OOo file format to OASIS (#i28749#)
            , mbShapePositionInHoriL2R( false )
            , mbTextDocInOOoFileFormat( false )
            , mxComponentContext( rxContext )
            , implementationName(theImplementationName)
            , mpRDFaHelper() // lazy
            , mpDocumentInfo() // lazy
        {
            SAL_WARN_IF(!mxComponentContext.is(), "xmloff.core", "SvXMLImport: no ComponentContext");
            if (!mxComponentContext.is()) throw uno::RuntimeException();
        }

        sal_uInt16 getGeneratorVersion( const SvXMLImport& rImport )
        {
            if ( !mpDocumentInfo.get() )
            {
                mpDocumentInfo.reset( new DocumentInfo( rImport ) );
            }

            return mpDocumentInfo->getGeneratorVersion();
        }

        ::comphelper::UnoInterfaceToUniqueIdentifierMapper maInterfaceToIdentifierMapper;
    };

    SvXMLImportContext *SvXMLImport::CreateDocumentContext(sal_uInt16 const nPrefix,
                                             const OUString& rLocalName,
                                             const uno::Reference< xml::sax::XAttributeList >& )
    {
        return new SvXMLImportContext( *this, nPrefix, rLocalName );
    }

    SvXMLImportContext *SvXMLImport::CreateFastContext( sal_Int32 /*Element*/,
            const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ )
    {
        return new SvXMLImportContext( *this );
    }

    void SvXMLImport::InitCtor_()
    {
        if( mnImportFlags != SvXMLImportFlags::NONE )
        {
            // implicit "xml" namespace prefix
            mpNamespaceMap->Add( GetXMLToken(XML_XML), GetXMLToken(XML_N_XML), XML_NAMESPACE_XML );
            mpNamespaceMap->Add( "_office", GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE );
            mpNamespaceMap->Add( "_office_ooo", GetXMLToken(XML_N_OFFICE_EXT), XML_NAMESPACE_OFFICE_EXT );
            mpNamespaceMap->Add( "_ooo", GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO );
            mpNamespaceMap->Add( "_style", GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE );
            mpNamespaceMap->Add( "_text", GetXMLToken(XML_N_TEXT), XML_NAMESPACE_TEXT );
            mpNamespaceMap->Add( "_table", GetXMLToken(XML_N_TABLE), XML_NAMESPACE_TABLE );
            mpNamespaceMap->Add( "_table_ooo", GetXMLToken(XML_N_TABLE_EXT), XML_NAMESPACE_TABLE_EXT );
            mpNamespaceMap->Add( "_draw", GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW );
            mpNamespaceMap->Add( "_draw_ooo", GetXMLToken(XML_N_DRAW_EXT), XML_NAMESPACE_DRAW_EXT );
            mpNamespaceMap->Add( "_dr3d", GetXMLToken(XML_N_DR3D), XML_NAMESPACE_DR3D );
            mpNamespaceMap->Add( "_fo", GetXMLToken(XML_N_FO_COMPAT), XML_NAMESPACE_FO );
            mpNamespaceMap->Add( "_xlink", GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK );
            mpNamespaceMap->Add( "_dc", GetXMLToken(XML_N_DC), XML_NAMESPACE_DC );
            mpNamespaceMap->Add( "_dom", GetXMLToken(XML_N_DOM), XML_NAMESPACE_DOM );
            mpNamespaceMap->Add( "_meta", GetXMLToken(XML_N_META), XML_NAMESPACE_META );
            mpNamespaceMap->Add( "_number", GetXMLToken(XML_N_NUMBER), XML_NAMESPACE_NUMBER );
            mpNamespaceMap->Add( "_svg", GetXMLToken(XML_N_SVG_COMPAT), XML_NAMESPACE_SVG );
            mpNamespaceMap->Add( "_chart", GetXMLToken(XML_N_CHART), XML_NAMESPACE_CHART );
            mpNamespaceMap->Add( "_math", GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH );
            mpNamespaceMap->Add( "_form", GetXMLToken(XML_N_FORM), XML_NAMESPACE_FORM );
            mpNamespaceMap->Add( "_script", GetXMLToken(XML_N_SCRIPT), XML_NAMESPACE_SCRIPT );
            mpNamespaceMap->Add( "_config", GetXMLToken(XML_N_CONFIG), XML_NAMESPACE_CONFIG );
            mpNamespaceMap->Add( "_xforms", GetXMLToken(XML_N_XFORMS_1_0), XML_NAMESPACE_XFORMS );
            mpNamespaceMap->Add( "_formx", GetXMLToken( XML_N_FORMX ), XML_NAMESPACE_FORMX );
            mpNamespaceMap->Add( "_xsd", GetXMLToken(XML_N_XSD), XML_NAMESPACE_XSD );
            mpNamespaceMap->Add( "_xsi", GetXMLToken(XML_N_XSI), XML_NAMESPACE_XFORMS );
            mpNamespaceMap->Add( "_ooow", GetXMLToken(XML_N_OOOW), XML_NAMESPACE_OOOW );
            mpNamespaceMap->Add( "_oooc", GetXMLToken(XML_N_OOOC), XML_NAMESPACE_OOOC );
            mpNamespaceMap->Add( "_field", GetXMLToken(XML_N_FIELD), XML_NAMESPACE_FIELD );
            mpNamespaceMap->Add( "_of", GetXMLToken(XML_N_OF), XML_NAMESPACE_OF );
            mpNamespaceMap->Add( "_xhtml", GetXMLToken(XML_N_XHTML), XML_NAMESPACE_XHTML );
            mpNamespaceMap->Add( "_css3text", GetXMLToken(XML_N_CSS3TEXT), XML_NAMESPACE_CSS3TEXT );

            mpNamespaceMap->Add( "_calc_libo", GetXMLToken(XML_N_CALC_EXT), XML_NAMESPACE_CALC_EXT);
            mpNamespaceMap->Add( "_office_libo",
                                 GetXMLToken(XML_N_LO_EXT), XML_NAMESPACE_LO_EXT);
        }

        msPackageProtocol = "vnd.sun.star.Package:";

        if (mxNumberFormatsSupplier.is())
            mpNumImport = o3tl::make_unique<SvXMLNumFmtHelper>(mxNumberFormatsSupplier, GetComponentContext());

        if (mxModel.is() && !mxEventListener.is())
        {
            mxEventListener.set(new SvXMLImportEventListener(this));
            mxModel->addEventListener(mxEventListener);
        }
    }

    SvXMLImport::SvXMLImport(
        const css::uno::Reference< css::uno::XComponentContext >& xContext,
        OUString const & implementationName, SvXMLImportFlags nImportFlags )
    :   mpImpl( new SvXMLImport_Impl(xContext, implementationName) ),
        mpNamespaceMap( new SvXMLNamespaceMap ),

        mpUnitConv( new SvXMLUnitConverter( xContext,
                    util::MeasureUnit::MM_100TH, util::MeasureUnit::MM_100TH) ),

        mnImportFlags( nImportFlags ),
        mnErrorFlags(SvXMLErrorFlags::NO),
        isFastContext( false ),
        maNamespaceHandler( new SvXMLImportFastNamespaceHandler() ),
        mbIsFormsSupported( true ),
        mbIsTableShapeSupported( false )
    {
        SAL_WARN_IF( !xContext.is(), "xmloff.core", "got no service manager" );
        InitCtor_();
        mxParser = xml::sax::FastParser::create( xContext );
        setNamespaceHandler( maNamespaceHandler.get() );
        setTokenHandler( xTokenHandler  );
        if ( !bIsNSMapsInitialized )
        {
            initializeNamespaceMaps();
            bIsNSMapsInitialized = true;
        }
        registerNamespaces();
    }

    void SvXMLImport::cleanup() throw ()
    {
        if (mxEventListener.is() && mxModel.is())
            mxModel->removeEventListener(mxEventListener);
        // clear context stacks first in case of parse error because the context
        // class dtors are full of application logic
        while (!maFastContexts.empty())
        {
            if (SvXMLStylesContext* pStylesContext = dynamic_cast<SvXMLStylesContext*>(maFastContexts.top().get()))
                pStylesContext->Clear();
            maFastContexts.pop();
        }
        while (!maContexts.empty())
        {
            if (SvXMLStylesContext* pStylesContext = dynamic_cast<SvXMLStylesContext*>(maContexts.top().get()))
                pStylesContext->Clear();
            maContexts.pop();
        }
        DisposingModel();
    }

    SvXMLImport::~SvXMLImport() throw ()
    {
        cleanup();
    }

    namespace
    {
        class theSvXMLImportUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSvXMLImportUnoTunnelId> {};
    }

    // XUnoTunnel
    sal_Int64 SAL_CALL SvXMLImport::getSomething( const uno::Sequence< sal_Int8 >& rId )
    {
        if( rId.getLength() == 16 &&
            0 == memcmp( theSvXMLImportUnoTunnelId::get().getSeq().getConstArray(),
                         rId.getConstArray(), 16 ) )
        {
            return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_uIntPtr>(this));
        }
        return 0;
    }

    namespace
    {
        class setFastDocumentHandlerGuard
        {
        private:
            css::uno::Reference<css::xml::sax::XFastParser> mxParser;
        public:
            setFastDocumentHandlerGuard(const css::uno::Reference<css::xml::sax::XFastParser>& Parser,
                                        const css::uno::Reference<css::xml::sax::XFastDocumentHandler>& Handler)
                : mxParser(Parser)
            {
                mxParser->setFastDocumentHandler(Handler);
            }
            //guarantee restoration of null document handler
            ~setFastDocumentHandlerGuard()
            {
                mxParser->setFastDocumentHandler(nullptr);
            }
        };
    }

    // XFastParser
    void SAL_CALL SvXMLImport::parseStream( const xml::sax::InputSource& aInputSource )
    {
        setFastDocumentHandlerGuard aDocumentHandlerGuard(mxParser, mxFastDocumentHandler.is() ? mxFastDocumentHandler : this);
        mxParser->parseStream(aInputSource);
    }

    void SAL_CALL SvXMLImport::setFastDocumentHandler( const uno::Reference< xml::sax::XFastDocumentHandler >& Handler )
    {
        mxFastDocumentHandler = Handler;
    }

    void SAL_CALL SvXMLImport::setTokenHandler( const uno::Reference< xml::sax::XFastTokenHandler >& Handler )
    {
        mxParser->setTokenHandler( Handler );
    }

    void SAL_CALL SvXMLImport::registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken )
    {
        mxParser->registerNamespace( NamespaceURL, NamespaceToken );
    }

    OUString SAL_CALL SvXMLImport::getNamespaceURL( const OUString& rPrefix )
    {
        return mxParser->getNamespaceURL( rPrefix );
    }

    void SAL_CALL SvXMLImport::setErrorHandler( const uno::Reference< xml::sax::XErrorHandler >& Handler )
    {
        mxParser->setErrorHandler( Handler );
    }

    void SAL_CALL SvXMLImport::setEntityResolver( const uno::Reference< xml::sax::XEntityResolver >& Resolver )
    {
        mxParser->setEntityResolver( Resolver );
    }

    void SAL_CALL SvXMLImport::setLocale( const lang::Locale& rLocale )
    {
        mxParser->setLocale( rLocale );
    }

    void SAL_CALL SvXMLImport::setNamespaceHandler( const uno::Reference< xml::sax::XFastNamespaceHandler >& Handler)
    {
        mxParser->setNamespaceHandler( Handler );
    }

    void SAL_CALL SvXMLImport::startDocument()
    {
        SAL_INFO( "xmloff.core", "{ SvXMLImport::startDocument" );
        if (!mxGraphicStorageHandler.is() || !mxEmbeddedResolver.is())
        {
            Reference< lang::XMultiServiceFactory > xFactory( mxModel,  UNO_QUERY );
            if( xFactory.is() )
            {
                try
                {
                    if (!mxGraphicStorageHandler.is())
                    {
                        // #99870# Import... instead of Export...
                        mxGraphicStorageHandler.set(
                            xFactory->createInstance("com.sun.star.document.ImportGraphicStorageHandler"),
                            UNO_QUERY);
                        mpImpl->mbOwnGraphicResolver = mxGraphicStorageHandler.is();
                    }

                    if( !mxEmbeddedResolver.is() )
                    {
                        // #99870# Import... instead of Export...
                        mxEmbeddedResolver.set(
                            xFactory->createInstance("com.sun.star.document.ImportEmbeddedObjectResolver"),
                            UNO_QUERY);
                        mpImpl->mbOwnEmbeddedResolver = mxEmbeddedResolver.is();
                    }
                }
                catch( css::uno::Exception& )
                {
                }
            }
        }
    }

    void SAL_CALL SvXMLImport::endDocument()
    {
        SAL_INFO( "xmloff.core", "} SvXMLImport::endDocument" );
        //  #i9518# All the stuff that accesses the document has to be done here, not in the dtor,
        //  because the SvXMLImport dtor might not be called until after the document has been closed.

        GetTextImport()->MapCrossRefHeadingFieldsHorribly();

        if (mpImpl->mpRDFaHelper.get())
        {
            const uno::Reference<rdf::XRepositorySupplier> xRS(mxModel,
                uno::UNO_QUERY);
            if (xRS.is())
            {
                mpImpl->mpRDFaHelper->InsertRDFa( xRS );
            }
        }

        mpNumImport.reset();
        if (mxImportInfo.is())
        {
            uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxImportInfo->getPropertySetInfo();
            if (xPropertySetInfo.is())
            {
                if (bool(mpProgressBarHelper))
                {
                    OUString sProgressMax(XML_PROGRESSMAX);
                    OUString sProgressCurrent(XML_PROGRESSCURRENT);
                    OUString sRepeat(XML_PROGRESSREPEAT);
                    if (xPropertySetInfo->hasPropertyByName(sProgressMax) &&
                        xPropertySetInfo->hasPropertyByName(sProgressCurrent))
                    {
                        sal_Int32 nProgressMax(mpProgressBarHelper->GetReference());
                        sal_Int32 nProgressCurrent(mpProgressBarHelper->GetValue());
                        mxImportInfo->setPropertyValue(sProgressMax, uno::Any(nProgressMax));
                        mxImportInfo->setPropertyValue(sProgressCurrent, uno::Any(nProgressCurrent));
                    }
                    if (xPropertySetInfo->hasPropertyByName(sRepeat))
                        mxImportInfo->setPropertyValue(sRepeat, css::uno::makeAny(mpProgressBarHelper->GetRepeat()));
                    // pProgressBarHelper is deleted in dtor
                }
                OUString sNumberStyles(XML_NUMBERSTYLES);
                if (mxNumberStyles.is() && xPropertySetInfo->hasPropertyByName(sNumberStyles))
                {
                    mxImportInfo->setPropertyValue(sNumberStyles, Any(mxNumberStyles));
                }
            }
        }

        if( mxFontDecls.is() )
            static_cast<SvXMLStylesContext *>(mxFontDecls.get())->Clear();
        if( mxStyles.is() )
            static_cast<SvXMLStylesContext *>(mxStyles.get())->Clear();
        if( mxAutoStyles.is() )
            static_cast<SvXMLStylesContext *>(mxAutoStyles.get())->Clear();
        if( mxMasterStyles.is() )
            static_cast<SvXMLStylesContext *>(mxMasterStyles.get())->Clear();

        // possible form-layer related knittings which can only be done when
        // the whole document exists
        if ( mxFormImport.is() )
            mxFormImport->documentDone();

        //  The shape import helper does the z-order sorting in the dtor,
        //  so it must be deleted here, too.
        mxShapeImport = nullptr;

        if( mpImpl->mbOwnGraphicResolver )
        {
            Reference<lang::XComponent> xComp(mxGraphicStorageHandler, UNO_QUERY);
            xComp->dispose();
        }

        if( mpImpl->mbOwnEmbeddedResolver )
        {
            Reference< lang::XComponent > xComp( mxEmbeddedResolver, UNO_QUERY );
            xComp->dispose();
        }
        mpStyleMap.clear();

        if ( bool( mpXMLErrors ) )
        {
            mpXMLErrors->ThrowErrorAsSAXException( XMLERROR_FLAG_SEVERE );
        }
    }

    std::unique_ptr<SvXMLNamespaceMap> SvXMLImport::processNSAttributes(
            const uno::Reference< xml::sax::XAttributeList >& xAttrList)
    {
        std::unique_ptr<SvXMLNamespaceMap> pRewindMap;
        sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
        for( sal_Int16 i=0; i < nAttrCount; i++ )
        {
            const OUString& rAttrName = xAttrList->getNameByIndex( i );
            if ( rAttrName == "office:version" )
            {
                mpImpl->aODFVersion = xAttrList->getValueByIndex( i );

                // the ODF version in content.xml and manifest.xml must be the same starting from ODF1.2
                if ( mpImpl->mStreamName == "content.xml" && !IsODFVersionConsistent( mpImpl->aODFVersion ) )
                {
                    throw xml::sax::SAXException("Inconsistent ODF versions in content.xml and manifest.xml!",
                            uno::Reference< uno::XInterface >(),
                            uno::makeAny(
                                packages::zip::ZipIOException("Inconsistent ODF versions in content.xml and manifest.xml!" ) ) );
                }
            }
            else if( ( rAttrName.getLength() >= 5 ) &&
                ( rAttrName.startsWith( GetXMLToken(XML_XMLNS) ) ) &&
                ( rAttrName.getLength() == 5 || ':' == rAttrName[5] ) )
            {
                if( !pRewindMap )
                {
                    pRewindMap = std::move(mpNamespaceMap);
                    mpNamespaceMap.reset(new SvXMLNamespaceMap(*pRewindMap));
                }
                const OUString& rAttrValue = xAttrList->getValueByIndex( i );

                OUString aPrefix( ( rAttrName.getLength() == 5 )
                                     ? OUString()
                                     : rAttrName.copy( 6 ) );
                // Add namespace, but only if it is known.
                sal_uInt16 nKey = mpNamespaceMap->AddIfKnown( aPrefix, rAttrValue );
                // If namespace is unknown, try to match a name with similar
                // TC Id an version
                if( XML_NAMESPACE_UNKNOWN == nKey  )
                {
                    OUString aTestName( rAttrValue );
                    if( SvXMLNamespaceMap::NormalizeURI( aTestName ) )
                        nKey = mpNamespaceMap->AddIfKnown( aPrefix, aTestName );
                }
                // If that namespace is not known, too, add it as unknown
                if( XML_NAMESPACE_UNKNOWN == nKey  )
                    mpNamespaceMap->Add( aPrefix, rAttrValue );

            }
        }
        return pRewindMap;
    }

    void SAL_CALL SvXMLImport::startElement( const OUString& rName,
                                             const uno::Reference< xml::sax::XAttributeList >& xAttrList )
    {
        //    SAL_INFO("svg", "startElement " << rName);
        // Process namespace attributes. This must happen before creating the
        // context, because namespace declaration apply to the element name itself.
        std::unique_ptr<SvXMLNamespaceMap> pRewindMap(processNSAttributes(xAttrList));

        // Get element's namespace and local name.
        OUString aLocalName;
        sal_uInt16 nPrefix =
            mpNamespaceMap->GetKeyByAttrName( rName, &aLocalName );

        // If there are contexts already, call a CreateChildContext at the topmost
        // context. Otherwise, create a default context.
        SvXMLImportContextRef xContext;
        if(!maContexts.empty())
        {
            xContext = maContexts.top()->CreateChildContext(nPrefix, aLocalName, xAttrList);
            SAL_WARN_IF( !xContext.is() || (xContext->GetPrefix() != nPrefix), "xmloff.core",
                    "SvXMLImport::startElement: created context has wrong prefix" );
        }
        else
        {
            xContext.set(CreateDocumentContext(nPrefix, aLocalName, xAttrList));
            if( (nPrefix & XML_NAMESPACE_UNKNOWN_FLAG) != 0 &&
                dynamic_cast< const SvXMLImportContext*>(xContext.get()) !=  nullptr )
            {
                Reference<xml::sax::XLocator> xDummyLocator;
                Sequence < OUString > aParams { rName };

                SetError( XMLERROR_FLAG_SEVERE|XMLERROR_UNKNOWN_ROOT,
                          aParams, "Root element unknown", xDummyLocator );
            }
        }

        SAL_WARN_IF( !xContext.is(), "xmloff.core", "SvXMLImport::startElement: missing context" );
        if( !xContext.is() )
            xContext.set(new SvXMLImportContext( *this, nPrefix, aLocalName ));

        // Remember old namespace map.
        if( pRewindMap )
            xContext->PutRewindMap(std::move(pRewindMap));

        // Call a startElement at the new context.
        xContext->StartElement( xAttrList );

        // Push context on stack.
        maContexts.push(xContext);
    }

    void SAL_CALL SvXMLImport::endElement( const OUString&
    #ifdef DBG_UTIL
    rName
    #endif
    )
    {
        if (maContexts.empty())
        {
            SAL_WARN("xmloff.core", "SvXMLImport::endElement: no context left");
            return;
        }

        std::unique_ptr<SvXMLNamespaceMap> pRewindMap;

        {
            // Get topmost context and remove it from the stack.
            SvXMLImportContextRef xContext = maContexts.top();
            maContexts.pop();

    #ifdef DBG_UTIL
            // Non product only: check if endElement call matches startELement call.
            OUString aLocalName;
            sal_uInt16 nPrefix =
                mpNamespaceMap->GetKeyByAttrName( rName, &aLocalName );
            SAL_WARN_IF( xContext->GetPrefix() != nPrefix,  "xmloff.core", "SvXMLImport::endElement: popped context has wrong prefix" );
            SAL_WARN_IF( xContext->GetLocalName() != aLocalName, "xmloff.core", "SvXMLImport::endElement: popped context has wrong lname" );
    #endif

            // Call a EndElement at the current context.
            xContext->EndElement();
            // Get a namespace map to rewind.
            pRewindMap = xContext->TakeRewindMap();
            // note: delete xContext *before* rewinding namespace map!
        }

        // Rewind a namespace map.
        if (pRewindMap)
        {
            mpNamespaceMap.reset();
            mpNamespaceMap = std::move(pRewindMap);
        }
    }

    void SAL_CALL SvXMLImport::characters( const OUString& rChars )
    {
        if ( !maFastContexts.empty() )
        {
            maFastContexts.top()->characters( rChars );
        }
        else if( !maContexts.empty() )
        {
            maContexts.top()->Characters( rChars );
        }
    }

    void SvXMLImport::Characters( const OUString& rChars )
    {
        if( !maContexts.empty() )
        {
            maContexts.top()->Characters( rChars );
        }
    }

    void SAL_CALL SvXMLImport::ignorableWhitespace( const OUString& )
    {
    }

    void SAL_CALL SvXMLImport::processingInstruction( const OUString&,
                                           const OUString& )
    {
    }

    void SAL_CALL SvXMLImport::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& rLocator )
    {
        mxLocator = rLocator;
    }

    // XFastContextHandler
    void SAL_CALL SvXMLImport::startFastElement (sal_Int32 Element,
        const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
    {
        if ( Attribs.is() )
        {
            sax_fastparser::FastAttributeList *pAttribList =
                sax_fastparser::FastAttributeList::castToFastAttributeList( Attribs );
            auto &aIter( pAttribList->find( XML_ELEMENT( OFFICE, XML_VERSION ) ) );
            if( aIter != pAttribList->end() )
            {
                mpImpl->aODFVersion = aIter.toString();

                // the ODF version in content.xml and manifest.xml must be the same starting from ODF1.2
                if ( mpImpl->mStreamName == "content.xml" && !IsODFVersionConsistent( mpImpl->aODFVersion ) )
                {
                    throw xml::sax::SAXException("Inconsistent ODF versions in content.xml and manifest.xml!",
                            uno::Reference< uno::XInterface >(),
                            uno::makeAny(
                                packages::zip::ZipIOException("Inconsistent ODF versions in content.xml and manifest.xml!" ) ) );
                }
            }
        }

        //Namespace handling is unnecessary. It is done by the fastparser itself.
        uno::Reference<XFastContextHandler> xContext;
        if (!maFastContexts.empty())
        {
            uno::Reference<XFastContextHandler> pHandler = maFastContexts.top();
            xContext = pHandler->createFastChildContext( Element, Attribs );
        }
        else
            xContext.set( CreateFastContext( Element, Attribs ) );

        if ( !xContext.is() )
            xContext.set( new SvXMLImportContext( *this ) );

        isFastContext = true;

        // Call a startElement at the new context.
        xContext->startFastElement( Element, Attribs );

        if ( isFastContext )
        {
            if ( maNamespaceAttrList.is() )
                maNamespaceAttrList->Clear();
            else
                maNamespaceAttrList = new comphelper::AttributeList;

            maNamespaceHandler->addNSDeclAttributes( maNamespaceAttrList );
            std::unique_ptr<SvXMLNamespaceMap> pRewindMap(
                    processNSAttributes( maNamespaceAttrList.get() ));
            assert( dynamic_cast<SvXMLImportContext*>( xContext.get() ) != nullptr );
            SvXMLImportContext *pContext = static_cast<SvXMLImportContext*>( xContext.get() );
            if (pRewindMap)
                pContext->PutRewindMap(std::move(pRewindMap));
            maContexts.push(pContext);
        }

        // Push context on stack.
        maFastContexts.push(xContext);
    }

    void SAL_CALL SvXMLImport::startUnknownElement (const OUString & rPrefix, const OUString & rLocalName,
        const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
    {
        uno::Reference<XFastContextHandler> xContext;
        if (!maFastContexts.empty())
        {
            uno::Reference<XFastContextHandler> pHandler = maFastContexts.top();
            xContext = pHandler->createUnknownChildContext( rPrefix, rLocalName, Attribs );
        }
        else
            xContext.set( CreateFastContext( -1, Attribs ) );

        if ( !xContext.is() )
            xContext.set( new SvXMLImportContext( *this ) );

        xContext->startUnknownElement( rPrefix, rLocalName, Attribs );
        maFastContexts.push(xContext);
    }

    void SAL_CALL SvXMLImport::endFastElement (sal_Int32 Element)
    {
        if (!maFastContexts.empty())
        {
            uno::Reference<XFastContextHandler> xContext = maFastContexts.top();
            maFastContexts.pop();
            isFastContext = true;
            xContext->endFastElement( Element );
            if (isFastContext)
                maContexts.pop();

            xContext = nullptr;
        }
    }

    void SAL_CALL SvXMLImport::endUnknownElement (const OUString & rPrefix, const OUString & rLocalName)
    {
        if (!maFastContexts.empty())
        {
            uno::Reference<XFastContextHandler> xContext = maFastContexts.top();
            maFastContexts.pop();
            xContext->endUnknownElement( rPrefix, rLocalName );
            xContext = nullptr;
        }
    }

    uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
        SvXMLImport::createFastChildContext (sal_Int32,
        const uno::Reference< xml::sax::XFastAttributeList > &)
    {
        return this;
    }

    uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
        SvXMLImport::createUnknownChildContext (const OUString &, const OUString &,
        const uno::Reference< xml::sax::XFastAttributeList > &)
    {
        return this;
    }

    // XExtendedDocumentHandler
    void SAL_CALL SvXMLImport::startCDATA()
    {
    }

    void SAL_CALL SvXMLImport::endCDATA()
    {
    }

    void SAL_CALL SvXMLImport::comment( const OUString& )
    {
    }

    void SAL_CALL SvXMLImport::allowLineBreak()
    {
    }

    void SAL_CALL SvXMLImport::unknown( const OUString& )
    {
    }

    void SvXMLImport::SetStatistics(const uno::Sequence< beans::NamedValue> &)
    {
        GetProgressBarHelper()->SetRepeat(false);
        GetProgressBarHelper()->SetReference(0);
    }

    // XImporter
    void SAL_CALL SvXMLImport::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc )
    {
        mxModel.set( xDoc, UNO_QUERY );
        if( !mxModel.is() )
            throw lang::IllegalArgumentException();

        try
        {
            uno::Reference<document::XStorageBasedDocument> const xSBDoc(mxModel, uno::UNO_QUERY);
            uno::Reference<embed::XStorage> const xStor(xSBDoc.is() ? xSBDoc->getDocumentStorage()
                                                                    : nullptr);
            if (xStor.is())
            {
                mpImpl->mbIsOOoXML =
                    ::comphelper::OStorageHelper::GetXStorageFormat(xStor)
                       < SOFFICE_FILEFORMAT_8;
            }
        }
        catch (uno::Exception const&)
        {
            DBG_UNHANDLED_EXCEPTION("xmloff.core");
        }
        if (!mxEventListener.is())
        {
            mxEventListener.set(new SvXMLImportEventListener(this));
            mxModel->addEventListener(mxEventListener);
        }

        SAL_WARN_IF( bool(mpNumImport), "xmloff.core", "number format import already exists." );
        mpNumImport.reset();
    }

    // XFilter
    sal_Bool SAL_CALL SvXMLImport::filter( const uno::Sequence< beans::PropertyValue >& )
    {
        return false;
    }

    void SAL_CALL SvXMLImport::cancel(  )
    {
    }

    // XInitialize
    void SAL_CALL SvXMLImport::initialize( const uno::Sequence< uno::Any >& aArguments )
    {
        const sal_Int32 nAnyCount = aArguments.getLength();
        const uno::Any* pAny = aArguments.getConstArray();

        for( sal_Int32 nIndex = 0; nIndex < nAnyCount; nIndex++, pAny++ )
        {
            Reference<XInterface> xValue;
            *pAny >>= xValue;

            uno::Reference<task::XStatusIndicator> xTmpStatusIndicator(
                xValue, UNO_QUERY );
            if( xTmpStatusIndicator.is() )
                mxStatusIndicator = xTmpStatusIndicator;

            uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler(xValue, UNO_QUERY);
            if (xGraphicStorageHandler.is())
                mxGraphicStorageHandler = xGraphicStorageHandler;

            uno::Reference<document::XEmbeddedObjectResolver> xTmpObjectResolver(
                xValue, UNO_QUERY );
            if( xTmpObjectResolver.is() )
                mxEmbeddedResolver = xTmpObjectResolver;

            uno::Reference<beans::XPropertySet> xTmpPropSet( xValue, UNO_QUERY );
            if( xTmpPropSet.is() )
            {
                mxImportInfo = xTmpPropSet;
                uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxImportInfo->getPropertySetInfo();
                if (xPropertySetInfo.is())
                {
                    OUString sPropName(XML_NUMBERSTYLES);
                    if (xPropertySetInfo->hasPropertyByName(sPropName))
                    {
                        uno::Any aAny = mxImportInfo->getPropertyValue(sPropName);
                        aAny >>= mxNumberStyles;
                    }

                    sPropName = "PrivateData";
                    if (xPropertySetInfo->hasPropertyByName(sPropName))
                    {
                        Reference < XInterface > xIfc;
                        uno::Any aAny = mxImportInfo->getPropertyValue(sPropName);
                        aAny >>= xIfc;

                        StyleMap *pSMap = StyleMap::getImplementation( xIfc );
                        if( pSMap )
                        {
                            mpStyleMap = pSMap;
                        }
                    }
                    OUString sBaseURI;
                    sPropName = "BaseURI";
                    if (xPropertySetInfo->hasPropertyByName(sPropName))
                    {
                        uno::Any aAny = mxImportInfo->getPropertyValue(sPropName);
                        aAny >>= sBaseURI;
                        mpImpl->aBaseURL.SetURL( sBaseURI );
                        mpImpl->aDocBase.SetURL( sBaseURI );
                    }
                    OUString sRelPath;
                    sPropName = "StreamRelPath";
                    if( xPropertySetInfo->hasPropertyByName(sPropName) )
                    {
                        uno::Any aAny = mxImportInfo->getPropertyValue(sPropName);
                        aAny >>= sRelPath;
                    }
                    OUString sName;
                    sPropName = "StreamName";
                    if( xPropertySetInfo->hasPropertyByName(sPropName) )
                    {
                        uno::Any aAny = mxImportInfo->getPropertyValue(sPropName);
                        aAny >>= sName;
                    }
                    if( !sBaseURI.isEmpty() && !sName.isEmpty() )
                    {
                        if( !sRelPath.isEmpty() )
                            mpImpl->aBaseURL.insertName( sRelPath );
                        mpImpl->aBaseURL.insertName( sName );
                    }
                    mpImpl->mStreamName = sName; // Note: may be empty (XSLT)
                    // Retrieve property <ShapePositionInHoriL2R> (#i28749#)
                    sPropName = "ShapePositionInHoriL2R";
                    if( xPropertySetInfo->hasPropertyByName(sPropName) )
                    {
                        uno::Any aAny = mxImportInfo->getPropertyValue(sPropName);
                        aAny >>= mpImpl->mbShapePositionInHoriL2R;
                    }
                    sPropName = "TextDocInOOoFileFormat";
                    if( xPropertySetInfo->hasPropertyByName(sPropName) )
                    {
                        uno::Any aAny = mxImportInfo->getPropertyValue(sPropName);
                        aAny >>= mpImpl->mbTextDocInOOoFileFormat;
                    }

                    sPropName = "SourceStorage";
                    if( xPropertySetInfo->hasPropertyByName(sPropName) )
                        mxImportInfo->getPropertyValue(sPropName) >>= mpImpl->mxSourceStorage;
                }
            }
        }

        uno::Reference<lang::XInitialization> const xInit(mxParser, uno::UNO_QUERY_THROW);
        uno::Sequence<uno::Any> args(1);
        args[0] <<= OUString("IgnoreMissingNSDecl");
        xInit->initialize( args );
    }

    // XServiceInfo
    OUString SAL_CALL SvXMLImport::getImplementationName()
    {
        return mpImpl->implementationName;
    }

    sal_Bool SAL_CALL SvXMLImport::supportsService( const OUString& rServiceName )
    {
        return cppu::supportsService(this, rServiceName);
    }

    uno::Sequence< OUString > SAL_CALL SvXMLImport::getSupportedServiceNames(  )
    {
        uno::Sequence<OUString> aSeq(2);
        aSeq[0] = "com.sun.star.document.ImportFilter";
        aSeq[1] = "com.sun.star.xml.XMLImportFilter";
        return aSeq;
    }

    XMLTextImportHelper* SvXMLImport::CreateTextImport()
    {
        return new XMLTextImportHelper( mxModel, *this );
    }

    XMLShapeImportHelper* SvXMLImport::CreateShapeImport()
    {
        return new XMLShapeImportHelper( *this, mxModel );
    }

    SchXMLImportHelper* SvXMLImport::CreateChartImport()
    {
        return new SchXMLImportHelper();
    }

    ::xmloff::OFormLayerXMLImport* SvXMLImport::CreateFormImport()
    {
        return new ::xmloff::OFormLayerXMLImport(*this);
    }

    // Get or create fill/line/lineend-style-helper

    const Reference< container::XNameContainer > & SvXMLImport::GetGradientHelper()
    {
        if( !mxGradientHelper.is() )
        {
            if( mxModel.is() )
            {
                Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY);
                if( xServiceFact.is() )
                {
                    try
                    {
                        mxGradientHelper.set( xServiceFact->createInstance(
                            "com.sun.star.drawing.GradientTable" ), UNO_QUERY);
                    }
                    catch( lang::ServiceNotRegisteredException& )
                    {}
                }
            }
        }

        return mxGradientHelper;
    }

    const Reference< container::XNameContainer > & SvXMLImport::GetHatchHelper()
    {
        if( !mxHatchHelper.is() )
        {
            if( mxModel.is() )
            {
                Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY);
                if( xServiceFact.is() )
                {
                    try
                    {
                        mxHatchHelper.set( xServiceFact->createInstance(
                            "com.sun.star.drawing.HatchTable" ), UNO_QUERY);
                    }
                    catch( lang::ServiceNotRegisteredException& )
                    {}
                }
            }
        }

        return mxHatchHelper;
    }

    const Reference< container::XNameContainer > & SvXMLImport::GetBitmapHelper()
    {
        if( !mxBitmapHelper.is() )
        {
            if( mxModel.is() )
            {
                Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY);
                if( xServiceFact.is() )
                {
                    try
                    {
                        mxBitmapHelper.set( xServiceFact->createInstance(
                            "com.sun.star.drawing.BitmapTable" ), UNO_QUERY);
                    }
                    catch( lang::ServiceNotRegisteredException& )
                    {}
                }
            }
        }

        return mxBitmapHelper;
    }

    const Reference< container::XNameContainer > & SvXMLImport::GetTransGradientHelper()
    {
        if( !mxTransGradientHelper.is() )
        {
            if( mxModel.is() )
            {
                Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY);
                if( xServiceFact.is() )
                {
                    try
                    {
                        mxTransGradientHelper.set( xServiceFact->createInstance(
                            "com.sun.star.drawing.TransparencyGradientTable" ), UNO_QUERY);
                    }
                    catch( lang::ServiceNotRegisteredException& )
                    {}
                }
            }
        }

        return mxTransGradientHelper;
    }

    const Reference< container::XNameContainer > & SvXMLImport::GetMarkerHelper()
    {
        if( !mxMarkerHelper.is() )
        {
            if( mxModel.is() )
            {
                Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY);
                if( xServiceFact.is() )
                {
                    try
                    {
                        mxMarkerHelper.set( xServiceFact->createInstance( "com.sun.star.drawing.MarkerTable" ), UNO_QUERY);
                    }
                    catch( lang::ServiceNotRegisteredException& )
                    {}
                }
            }
        }

        return mxMarkerHelper;
    }

    const Reference< container::XNameContainer > & SvXMLImport::GetDashHelper()
    {
        if( !mxDashHelper.is() )
        {
            if( mxModel.is() )
            {
                Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY);
                if( xServiceFact.is() )
                {
                    try
                    {
                        mxDashHelper.set( xServiceFact->createInstance( "com.sun.star.drawing.DashTable" ), UNO_QUERY);
                    }
                    catch( lang::ServiceNotRegisteredException& )
                    {}
                }
            }
        }

        return mxDashHelper;
    }

    bool SvXMLImport::IsPackageURL( const OUString& rURL ) const
    {

        // if, and only if, only parts are imported, then we're in a package
        const SvXMLImportFlags nTest = SvXMLImportFlags::META|SvXMLImportFlags::STYLES|SvXMLImportFlags::CONTENT|SvXMLImportFlags::SETTINGS;
        if( (mnImportFlags & nTest) == nTest )
            return false;

        // TODO: from this point extract to own static function

        // Some quick tests: Some may rely on the package structure!
        sal_Int32 nLen = rURL.getLength();
        if( nLen > 0 && '/' == rURL[0] )
            // RFC2396 net_path or abs_path
            return false;
        else if( nLen > 1 && '.' == rURL[0] )
        {
            if( '.' == rURL[1] )
                // ../: We are never going up one level, so we know
                // it's not an external URI
                return false;
            else if( '/' == rURL[1] )
                // we are remaining on a level, so it's an package URI
                return true;
        }

        // Now check for a RFC2396 schema
        sal_Int32 nPos = 1;
        while( nPos < nLen )
        {
            switch( rURL[nPos] )
            {
            case '/':
                // a relative path segment
                return true;
            case ':':
                // a schema
                return false;
            default:
                break;
                // we don't care about any other characters
            }
            ++nPos;
        }

        return true;
    }

    uno::Reference<graphic::XGraphic> SvXMLImport::loadGraphicByURL(OUString const & rURL)
    {
        uno::Reference<graphic::XGraphic> xGraphic;

        if (mxGraphicStorageHandler.is())
        {
            if (IsPackageURL(rURL))
            {
                xGraphic = mxGraphicStorageHandler->loadGraphic(rURL);
            }
            else
            {
                OUString const & rAbsoluteURL = GetAbsoluteReference(rURL);
                GraphicExternalLink aExternalLink(rAbsoluteURL);
                Graphic aGraphic(aExternalLink);
                xGraphic = aGraphic.GetXGraphic();
            }
        }

        return xGraphic;
    }

    uno::Reference<graphic::XGraphic> SvXMLImport::loadGraphicFromBase64(uno::Reference<io::XOutputStream> const & rxOutputStream)
    {
        uno::Reference<graphic::XGraphic> xGraphic;

        if (mxGraphicStorageHandler.is())
        {
            xGraphic = mxGraphicStorageHandler->loadGraphicFromOutputStream(rxOutputStream);
        }

        return xGraphic;
    }

    Reference< XOutputStream > SvXMLImport::GetStreamForGraphicObjectURLFromBase64()
    {
        Reference< XOutputStream > xOStm;
        Reference< document::XBinaryStreamResolver > xStmResolver(mxGraphicStorageHandler, UNO_QUERY);

        if( xStmResolver.is() )
            xOStm = xStmResolver->createOutputStream();

        return xOStm;
    }

    OUString SvXMLImport::ResolveEmbeddedObjectURL(
                                        const OUString& rURL,
                                        const OUString& rClassId )
    {
        OUString sRet;

        if( IsPackageURL( rURL ) )
        {
            if ( mxEmbeddedResolver.is() )
            {
                OUString sURL( rURL );
                if( !rClassId.isEmpty() )
                {
                    sURL += "!" + rClassId;
                }
                sRet = mxEmbeddedResolver->resolveEmbeddedObjectURL( sURL );
            }
        }
        else
            sRet = GetAbsoluteReference( rURL );

        return sRet;
    }

    Reference< embed::XStorage > const & SvXMLImport::GetSourceStorage()
    {
        return mpImpl->mxSourceStorage;
    }

    Reference < XOutputStream >
            SvXMLImport::GetStreamForEmbeddedObjectURLFromBase64()
    {
        Reference < XOutputStream > xOLEStream;

        if( mxEmbeddedResolver.is() )
        {
            Reference< XNameAccess > xNA( mxEmbeddedResolver, UNO_QUERY );
            if( xNA.is() )
            {
                Any aAny = xNA->getByName( "Obj12345678" );
                aAny >>= xOLEStream;
            }
        }

        return xOLEStream;
    }

    OUString SvXMLImport::ResolveEmbeddedObjectURLFromBase64()
    {
        OUString sRet;

        if( mxEmbeddedResolver.is() )
        {
            sRet = mxEmbeddedResolver->resolveEmbeddedObjectURL( "Obj12345678" );
        }

        return sRet;
    }

    void SvXMLImport::AddStyleDisplayName( sal_uInt16 nFamily,
                                           const OUString& rName,
                                           const OUString& rDisplayName )
    {
        if( !mpStyleMap.is() )
        {
            mpStyleMap = new StyleMap;
            if( mxImportInfo.is() )
            {
                OUString sPrivateData( "PrivateData" );
                Reference< beans::XPropertySetInfo > xPropertySetInfo =
                    mxImportInfo->getPropertySetInfo();
                if( xPropertySetInfo.is() &&
                    xPropertySetInfo->hasPropertyByName(sPrivateData) )
                {
                    Reference < XInterface > xIfc(
                            static_cast< XUnoTunnel *>( mpStyleMap.get() ) );
                    mxImportInfo->setPropertyValue( sPrivateData, Any(xIfc) );
                }
            }
        }

        StyleMap::key_type aKey( nFamily, rName );
        StyleMap::value_type aValue( aKey, rDisplayName );
        ::std::pair<StyleMap::iterator,bool> aRes( mpStyleMap->insert( aValue ) );
        SAL_WARN_IF( !aRes.second,
                     "xmloff.core",
           "duplicate style name of family " << nFamily << ": \"" << rName << "\"");

    }

    OUString SvXMLImport::GetStyleDisplayName( sal_uInt16 nFamily,
                                               const OUString& rName ) const
    {
        OUString sName( rName );
        if( mpStyleMap.is() && !rName.isEmpty() )
        {
            StyleMap::key_type aKey( nFamily, rName );
            StyleMap::const_iterator aIter = mpStyleMap->find( aKey );
            if( aIter != mpStyleMap->end() )
                sName = (*aIter).second;
        }
        return sName;
    }

    void SvXMLImport::SetViewSettings(const css::uno::Sequence<css::beans::PropertyValue>&)
    {
    }

    void SvXMLImport::SetConfigurationSettings(const css::uno::Sequence<css::beans::PropertyValue>&)
    {
    }

    void SvXMLImport::SetDocumentSpecificSettings(const OUString&, const uno::Sequence<beans::PropertyValue>&)
    {
    }

    ProgressBarHelper*  SvXMLImport::GetProgressBarHelper()
    {
        if (!mpProgressBarHelper)
        {
            mpProgressBarHelper = o3tl::make_unique<ProgressBarHelper>(mxStatusIndicator, false);

            if (mxImportInfo.is())
            {
                uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxImportInfo->getPropertySetInfo();
                if (xPropertySetInfo.is())
                {
                    OUString sProgressRange(XML_PROGRESSRANGE);
                    OUString sProgressMax(XML_PROGRESSMAX);
                    OUString sProgressCurrent(XML_PROGRESSCURRENT);
                    OUString sRepeat(XML_PROGRESSREPEAT);
                    if (xPropertySetInfo->hasPropertyByName(sProgressMax) &&
                        xPropertySetInfo->hasPropertyByName(sProgressCurrent) &&
                        xPropertySetInfo->hasPropertyByName(sProgressRange))
                    {
                        uno::Any aAny;
                        sal_Int32 nProgressMax(0);
                        sal_Int32 nProgressCurrent(0);
                        sal_Int32 nProgressRange(0);
                        aAny = mxImportInfo->getPropertyValue(sProgressRange);
                        if (aAny >>= nProgressRange)
                            mpProgressBarHelper->SetRange(nProgressRange);
                        aAny = mxImportInfo->getPropertyValue(sProgressMax);
                        if (aAny >>= nProgressMax)
                            mpProgressBarHelper->SetReference(nProgressMax);
                        aAny = mxImportInfo->getPropertyValue(sProgressCurrent);
                        if (aAny >>= nProgressCurrent)
                            mpProgressBarHelper->SetValue(nProgressCurrent);
                    }
                    if (xPropertySetInfo->hasPropertyByName(sRepeat))
                    {
                        uno::Any aAny = mxImportInfo->getPropertyValue(sRepeat);
                        if (aAny.getValueType() == cppu::UnoType<bool>::get())
                            mpProgressBarHelper->SetRepeat(::cppu::any2bool(aAny));
                        else {
                            SAL_WARN( "xmloff.core", "why is it no boolean?" );
                        }
                    }
                }
            }
        }
        return mpProgressBarHelper.get();
    }

    void SvXMLImport::AddNumberStyle(sal_Int32 nKey, const OUString& rName)
    {
        if (!mxNumberStyles.is())
            mxNumberStyles.set( comphelper::NameContainer_createInstance( ::cppu::UnoType<sal_Int32>::get()) );
        if (mxNumberStyles.is())
        {
            try
            {
                mxNumberStyles->insertByName(rName, Any(nKey));
            }
            catch ( uno::Exception& )
            {
                DBG_UNHANDLED_EXCEPTION( "xmloff.core", "Numberformat could not be inserted");
            }
        }
        else {
            SAL_WARN( "xmloff.core", "not possible to create NameContainer");
        }
    }

    XMLEventImportHelper& SvXMLImport::GetEventImport()
    {
        if (!mpEventImportHelper)
        {
            // construct event helper and register StarBasic handler and standard
            // event tables
            mpEventImportHelper = o3tl::make_unique<XMLEventImportHelper>();
            const OUString& sStarBasic(GetXMLToken(XML_STARBASIC));
            mpEventImportHelper->RegisterFactory(sStarBasic,
                                                new XMLStarBasicContextFactory());
            const OUString& sScript(GetXMLToken(XML_SCRIPT));
            mpEventImportHelper->RegisterFactory(sScript,
                                                new XMLScriptContextFactory());
            mpEventImportHelper->AddTranslationTable(aStandardEventTable);

            // register StarBasic event handler with capitalized spelling
            mpEventImportHelper->RegisterFactory("StarBasic",
                                                new XMLStarBasicContextFactory());
        }

        return *mpEventImportHelper;
    }

    void SvXMLImport::SetFontDecls( XMLFontStylesContext *pFontDecls )
    {
        if (mxFontDecls.is())
            static_cast<SvXMLStylesContext*>(mxFontDecls.get())->Clear();
        mxFontDecls = pFontDecls;
    }

    void SvXMLImport::SetStyles( SvXMLStylesContext *pStyles )
    {
        if (mxStyles.is())
            static_cast<SvXMLStylesContext*>(mxStyles.get())->Clear();
        mxStyles = pStyles;
    }

    void SvXMLImport::SetAutoStyles( SvXMLStylesContext *pAutoStyles )
    {
        if (pAutoStyles && mxNumberStyles.is() && (mnImportFlags & SvXMLImportFlags::CONTENT) )
        {
            uno::Reference<xml::sax::XAttributeList> xAttrList;
            uno::Sequence< OUString > aNames = mxNumberStyles->getElementNames();
            sal_uInt32 nCount(aNames.getLength());
            if (nCount)
            {
                const OUString* pNames = aNames.getConstArray();
                if ( pNames )
                {
                    SvXMLStyleContext* pContext;
                    uno::Any aAny;
                    sal_Int32 nKey(0);
                    for (sal_uInt32 i = 0; i < nCount; i++, pNames++)
                    {
                        aAny = mxNumberStyles->getByName(*pNames);
                        if (aAny >>= nKey)
                        {
                            pContext = new SvXMLNumFormatContext( *this, XML_NAMESPACE_NUMBER,
                                        *pNames, xAttrList, nKey, *pAutoStyles );
                            pAutoStyles->AddStyle(*pContext);
                        }
                    }
                }
            }
        }
        if (mxAutoStyles.is())
            static_cast<SvXMLStylesContext*>(mxAutoStyles.get())->Clear();
        mxAutoStyles = pAutoStyles;
        GetTextImport()->SetAutoStyles( pAutoStyles );
        GetShapeImport()->SetAutoStylesContext( pAutoStyles );
        GetChartImport()->SetAutoStylesContext( pAutoStyles );
        GetFormImport()->setAutoStyleContext( pAutoStyles );
    }

    void SvXMLImport::SetMasterStyles( SvXMLStylesContext *pMasterStyles )
    {
        if (mxMasterStyles.is())
            static_cast<SvXMLStylesContext*>(mxMasterStyles.get())->Clear();
        mxMasterStyles = pMasterStyles;
    }

    XMLFontStylesContext *SvXMLImport::GetFontDecls()
    {
        return static_cast<XMLFontStylesContext *>(mxFontDecls.get());
    }

    SvXMLStylesContext *SvXMLImport::GetStyles()
    {
        return static_cast<SvXMLStylesContext *>(mxStyles.get());
    }

    SvXMLStylesContext *SvXMLImport::GetAutoStyles()
    {
        return static_cast<SvXMLStylesContext *>(mxAutoStyles.get());
    }

    const XMLFontStylesContext *SvXMLImport::GetFontDecls() const
    {
        return static_cast<const XMLFontStylesContext *>(mxFontDecls.get());
    }

    const SvXMLStylesContext *SvXMLImport::GetStyles() const
    {
        return static_cast<const SvXMLStylesContext *>(mxStyles.get());
    }

    const SvXMLStylesContext *SvXMLImport::GetAutoStyles() const
    {
        return static_cast<const SvXMLStylesContext *>(mxAutoStyles.get());
    }

    OUString SvXMLImport::GetAbsoluteReference(const OUString& rValue) const
    {
        if( rValue.isEmpty() || rValue[0] == '#' )
            return rValue;

        INetURLObject aAbsURL;
        if( mpImpl->aBaseURL.GetNewAbsURL( rValue, &aAbsURL ) )
            return aAbsURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
        else
            return rValue;
    }

    bool SvXMLImport::IsODFVersionConsistent( const OUString& aODFVersion )
    {
        // the check returns sal_False only if the storage version could be retrieved
        bool bResult = true;

        if ( !aODFVersion.isEmpty() && aODFVersion.compareTo( ODFVER_012_TEXT ) >= 0 )
        {
            // check the consistency only for the ODF1.2 and later ( according to content.xml )
            // manifest.xml might have no version, it should be checked here and the correct version should be set
            try
            {
                uno::Reference< document::XStorageBasedDocument > xDoc( mxModel, uno::UNO_QUERY_THROW );
                uno::Reference< embed::XStorage > xStor = xDoc->getDocumentStorage();
                uno::Reference< beans::XPropertySet > xStorProps( xStor, uno::UNO_QUERY_THROW );

                // the check should be done only for OASIS format
                if (!IsOOoXML())
                {
                    bool bRepairPackage = false;
                    try
                    {
                        xStorProps->getPropertyValue( "RepairPackage" )
                            >>= bRepairPackage;
                    } catch ( uno::Exception& )
                    {}

                    // check only if not in Repair mode
                    if ( !bRepairPackage )
                    {
                        OUString aStorVersion;
                        xStorProps->getPropertyValue( "Version" )
                            >>= aStorVersion;

                        // if the storage version is set in manifest.xml, it must be the same as in content.xml
                        // if not, set it explicitly to be used further ( it will work even for readonly storage )
                        // This workaround is not nice, but I see no other way to handle it, since there are
                        // ODF1.2 documents without version in manifest.xml
                        if ( !aStorVersion.isEmpty() )
                            bResult = aODFVersion == aStorVersion;
                        else
                            xStorProps->setPropertyValue( "Version",
                                                          uno::makeAny( aODFVersion ) );

                        if ( bResult )
                        {
                            bool bInconsistent = false;
                            xStorProps->getPropertyValue( "IsInconsistent" )
                                >>= bInconsistent;
                            bResult = !bInconsistent;
                        }
                    }
                }
            }
            catch( uno::Exception& )
            {}
        }

        return bResult;
    }

    void SvXMLImport::CreateNumberFormatsSupplier_()
    {
        SAL_WARN_IF( mxNumberFormatsSupplier.is(), "xmloff.core", "number formats supplier already exists!" );
        if(mxModel.is())
            mxNumberFormatsSupplier =
                uno::Reference< util::XNumberFormatsSupplier> (mxModel, uno::UNO_QUERY);
    }

    void SvXMLImport::CreateDataStylesImport_()
    {
        SAL_WARN_IF( bool(mpNumImport), "xmloff.core", "data styles import already exists!" );
        uno::Reference<util::XNumberFormatsSupplier> xNum =
            GetNumberFormatsSupplier();
        if ( xNum.is() )
            mpNumImport = o3tl::make_unique<SvXMLNumFmtHelper>(xNum, GetComponentContext() );
    }

    sal_Unicode SvXMLImport::ConvStarBatsCharToStarSymbol( sal_Unicode c )
    {
        sal_Unicode cNew = c;
        if( !mpImpl->hBatsFontConv )
        {
            mpImpl->hBatsFontConv = CreateFontToSubsFontConverter( "StarBats",
                     FontToSubsFontFlags::IMPORT );
            SAL_WARN_IF( !mpImpl->hBatsFontConv, "xmloff.core", "Got no symbol font converter" );
        }
        if( mpImpl->hBatsFontConv )
        {
            cNew = ConvertFontToSubsFontChar( mpImpl->hBatsFontConv, c );
        }

        return cNew;
    }

    sal_Unicode SvXMLImport::ConvStarMathCharToStarSymbol( sal_Unicode c )
    {
        sal_Unicode cNew = c;
        if( !mpImpl->hMathFontConv )
        {
            mpImpl->hMathFontConv = CreateFontToSubsFontConverter( "StarMath",
                     FontToSubsFontFlags::IMPORT );
            SAL_WARN_IF( !mpImpl->hMathFontConv, "xmloff.core", "Got no symbol font converter" );
        }
        if( mpImpl->hMathFontConv )
        {
            cNew = ConvertFontToSubsFontChar( mpImpl->hMathFontConv, c );
        }

        return cNew;
    }

    void SvXMLImport::SetError(
        sal_Int32 nId,
        const Sequence<OUString>& rMsgParams,
        const OUString& rExceptionMessage,
        const Reference<xml::sax::XLocator>& rLocator )
    {
        // maintain error flags
        if ( ( nId & XMLERROR_FLAG_ERROR ) != 0 )
            mnErrorFlags |= SvXMLErrorFlags::ERROR_OCCURRED;
        if ( ( nId & XMLERROR_FLAG_WARNING ) != 0 )
            mnErrorFlags |= SvXMLErrorFlags::WARNING_OCCURRED;
        if ( ( nId & XMLERROR_FLAG_SEVERE ) != 0 )
            mnErrorFlags |= SvXMLErrorFlags::DO_NOTHING;

        // create error list on demand
        if ( !mpXMLErrors )
            mpXMLErrors = o3tl::make_unique<XMLErrors>();

        // save error information
        // use document locator (if none supplied)
        mpXMLErrors->AddRecord( nId, rMsgParams, rExceptionMessage,
                               rLocator.is() ? rLocator : mxLocator );
    }

    void SvXMLImport::SetError(
        sal_Int32 nId,
        const Sequence<OUString>& rMsgParams)
    {
        SetError( nId, rMsgParams, "", nullptr );
    }

    void SvXMLImport::SetError(
        sal_Int32 nId)
    {
        Sequence<OUString> aSeq(0);
        SetError( nId, aSeq );
    }

    void SvXMLImport::SetError(
        sal_Int32 nId,
        const OUString& rMsg1)
    {
        Sequence<OUString> aSeq { rMsg1 };
        SetError( nId, aSeq );
    }

    void SvXMLImport::SetError(
        sal_Int32 nId,
        const OUString& rMsg1,
        const OUString& rMsg2)
    {
        Sequence<OUString> aSeq(2);
        OUString* pSeq = aSeq.getArray();
        pSeq[0] = rMsg1;
        pSeq[1] = rMsg2;
        SetError( nId, aSeq );
    }

    void SvXMLImport::DisposingModel()
    {
        if( mxFontDecls.is() )
            static_cast<SvXMLStylesContext *>(mxFontDecls.get())->Clear();
        if( mxStyles.is() )
            static_cast<SvXMLStylesContext *>(mxStyles.get())->Clear();
        if( mxAutoStyles.is() )
            static_cast<SvXMLStylesContext *>(mxAutoStyles.get())->Clear();
        if( mxMasterStyles.is() )
            static_cast<SvXMLStylesContext *>(mxMasterStyles.get())->Clear();

        mxModel.set(nullptr);
        mxEventListener.set(nullptr);
    }

    ::comphelper::UnoInterfaceToUniqueIdentifierMapper& SvXMLImport::getInterfaceToIdentifierMapper()
    {
        return mpImpl->maInterfaceToIdentifierMapper;
    }

    uno::Reference< uno::XComponentContext > const &
    SvXMLImport::GetComponentContext() const
    {
        return mpImpl->mxComponentContext;
    }

    OUString SvXMLImport::GetBaseURL() const
    {
        return mpImpl->aBaseURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
    }

    OUString SvXMLImport::GetDocumentBase() const
    {
        return mpImpl->aDocBase.GetMainURL( INetURLObject::DecodeMechanism::NONE );
    }

    // Convert drawing object positions from OOo file format to OASIS (#i28749#)
    bool SvXMLImport::IsShapePositionInHoriL2R() const
    {
        return mpImpl->mbShapePositionInHoriL2R;
    }

    bool SvXMLImport::IsTextDocInOOoFileFormat() const
    {
        return mpImpl->mbTextDocInOOoFileFormat;
    }

    void SvXMLImport::initXForms()
    {
        // dummy method; to be implemented by derived classes supporting XForms
    }

    bool SvXMLImport::getBuildIds( sal_Int32& rUPD, sal_Int32& rBuild ) const
    {
        bool bRet = false;
        OUString const aBuildId(getBuildIdsProperty(mxImportInfo));
        if (!aBuildId.isEmpty())
        {
            sal_Int32 nIndex = aBuildId.indexOf('$');
            if (nIndex != -1)
            {
                rUPD = aBuildId.copy( 0, nIndex ).toInt32();
                sal_Int32 nIndexEnd = aBuildId.indexOf(';', nIndex);
                rBuild = (nIndexEnd == -1)
                    ? aBuildId.copy(nIndex + 1).toInt32()
                    : aBuildId.copy(nIndex + 1, nIndexEnd - nIndex - 1).toInt32();
                bRet = true;
            }
        }
        return bRet;
    }

    sal_uInt16 SvXMLImport::getGeneratorVersion() const
    {
        // --> ORW
        return mpImpl->getGeneratorVersion( *this );
        // <--
    }

    bool SvXMLImport::isGeneratorVersionOlderThan(
            sal_uInt16 const nOOoVersion, sal_uInt16 const nLOVersion)
    {
        assert( (nLOVersion  & LO_flag));
        assert(!(nOOoVersion & LO_flag));
        const sal_uInt16 nGeneratorVersion(getGeneratorVersion());
        return (nGeneratorVersion & LO_flag)
            ?   nGeneratorVersion < nLOVersion
            :   nGeneratorVersion < nOOoVersion;
    }

    OUString const & SvXMLImport::GetODFVersion() const
    {
        return mpImpl->aODFVersion;
    }

    bool SvXMLImport::IsOOoXML() const
    {
        return mpImpl->mbIsOOoXML;
    }

    // xml:id for RDF metadata
    void SvXMLImport::SetXmlId(uno::Reference<uno::XInterface> const & i_xIfc,
        OUString const & i_rXmlId)
    {
        if (!i_rXmlId.isEmpty()) {
            try {
                const uno::Reference<rdf::XMetadatable> xMeta(i_xIfc,
                    uno::UNO_QUERY);
    //FIXME: not yet
                if (xMeta.is()) {
                    const beans::StringPair mdref( mpImpl->mStreamName, i_rXmlId );
                    try {
                        xMeta->setMetadataReference(mdref);
                    } catch (lang::IllegalArgumentException &) {
                        // probably duplicate; ignore
                        SAL_INFO("xmloff.core", "SvXMLImport::SetXmlId: cannot set xml:id");
                    }
                }
            } catch (uno::Exception &) {
                SAL_WARN("xmloff.core","SvXMLImport::SetXmlId: exception?");
            }
        }
    }

    ::xmloff::RDFaImportHelper &
    SvXMLImport::GetRDFaImportHelper()
    {
        if (!mpImpl->mpRDFaHelper.get())
        {
            mpImpl->mpRDFaHelper.reset( new ::xmloff::RDFaImportHelper(*this) );
        }
        return *mpImpl->mpRDFaHelper;
    }

    void
    SvXMLImport::AddRDFa(const uno::Reference<rdf::XMetadatable>& i_xObject,
        OUString const & i_rAbout,
        OUString const & i_rProperty,
        OUString const & i_rContent,
        OUString const & i_rDatatype)
    {
        // N.B.: we only get called if i_xObject had xhtml:about attribute
        // (an empty attribute value is valid)
        ::xmloff::RDFaImportHelper & rRDFaHelper( GetRDFaImportHelper() );
        rRDFaHelper.ParseAndAddRDFa(i_xObject,
            i_rAbout, i_rProperty, i_rContent, i_rDatatype);
    }

    bool SvXMLImport::embeddedFontAlreadyProcessed( const OUString& url )
    {
        if( embeddedFontUrlsKnown.count( url ) != 0 )
            return true;
        embeddedFontUrlsKnown.insert( url );
        return false;
    }

    const OUString SvXMLImport::getNameFromToken( sal_Int32 nToken )
    {
        uno::Sequence< sal_Int8 > aSeq = xTokenHandler->getUTF8Identifier( nToken & TOKEN_MASK );
        return OUString( reinterpret_cast< const char* >(
                        aSeq.getConstArray() ), aSeq.getLength(), RTL_TEXTENCODING_UTF8 );
    }

    const OUString SvXMLImport::getNamespacePrefixFromToken(sal_Int32 nToken, const SvXMLNamespaceMap* pMap)
    {
        sal_Int32 nNamespaceToken = ( nToken & NMSP_MASK ) >> NMSP_SHIFT;
        auto aIter( aNamespaceMap.find( nNamespaceToken ) );
        if( aIter != aNamespaceMap.end() )
        {
            if (pMap)
            {
                OUString sRet = pMap->GetPrefixByKey(pMap->GetKeyByName((*aIter).second.second));
                if (!sRet.isEmpty())
                    return sRet;
            }
            return (*aIter).second.first;
        }
        else
            return OUString();
    }

    const OUString SvXMLImport::getNamespaceURIFromToken( sal_Int32 nToken )
    {
        sal_Int32 nNamespaceToken = ( nToken & NMSP_MASK ) >> NMSP_SHIFT;
        auto aIter( aNamespaceMap.find( nNamespaceToken ) );
        if( aIter != aNamespaceMap.end() )
            return (*aIter).second.second;
        else
            return OUString();
    }

    const OUString SvXMLImport::getNamespacePrefixFromURI( const OUString& rURI )
    {
        auto aIter( aNamespaceURIPrefixMap.find(rURI) );
        if( aIter != aNamespaceURIPrefixMap.end() )
            return (*aIter).second;
        else
            return OUString();
    }

    void SvXMLImport::initializeNamespaceMaps()
    {
        auto mapTokenToNamespace = [&]( sal_Int32 nToken, sal_Int32 nPrefix, sal_Int32 nNamespace )
        {
            if ( nToken >= 0 )
            {
                const OUString& sNamespace = GetXMLToken( static_cast<XMLTokenEnum>( nNamespace ) );
                const OUString& sPrefix = GetXMLToken( static_cast<XMLTokenEnum>( nPrefix ) );
                aNamespaceMap[ nToken + 1 ] = std::make_pair( sPrefix, sNamespace );
                aNamespaceURIPrefixMap.emplace( sNamespace, sPrefix );
            }
        };

        mapTokenToNamespace( XML_NAMESPACE_OFFICE,           XML_NP_OFFICE,        XML_N_OFFICE           );
        mapTokenToNamespace( XML_OLD_NAMESPACE_OFFICE,       XML_NP_OFFICE,        XML_N_OFFICE_OLD       );
        mapTokenToNamespace( XML_NAMESPACE_OFFICE_OOO,       XML_NP_OFFICE,        XML_N_OFFICE_OOO       );
        mapTokenToNamespace( XML_NAMESPACE_STYLE,            XML_NP_STYLE,         XML_N_STYLE            );
        mapTokenToNamespace( XML_OLD_NAMESPACE_STYLE,        XML_NP_STYLE,         XML_N_STYLE_OLD        );
        mapTokenToNamespace( XML_NAMESPACE_STYLE_OOO,        XML_NP_STYLE,         XML_N_STYLE_OOO        );
        mapTokenToNamespace( XML_NAMESPACE_TEXT,             XML_NP_TEXT,          XML_N_TEXT             );
        mapTokenToNamespace( XML_OLD_NAMESPACE_TEXT,         XML_NP_TEXT,          XML_N_TEXT_OLD         );
        mapTokenToNamespace( XML_NAMESPACE_TEXT_OOO,         XML_NP_TEXT,          XML_N_TEXT_OOO         );
        mapTokenToNamespace( XML_NAMESPACE_TABLE,            XML_NP_TABLE,         XML_N_TABLE            );
        mapTokenToNamespace( XML_OLD_NAMESPACE_TABLE,        XML_NP_TABLE,         XML_N_TABLE_OLD        );
        mapTokenToNamespace( XML_NAMESPACE_TABLE_OOO,        XML_NP_TABLE,         XML_N_TABLE_OOO        );
        mapTokenToNamespace( XML_NAMESPACE_DRAW,             XML_NP_DRAW,          XML_N_DRAW             );
        mapTokenToNamespace( XML_OLD_NAMESPACE_DRAW,         XML_NP_DRAW,          XML_N_DRAW_OLD         );
        mapTokenToNamespace( XML_NAMESPACE_DRAW_OOO,         XML_NP_DRAW,          XML_N_DRAW_OOO         );
        mapTokenToNamespace( XML_NAMESPACE_FO,               XML_NP_FO,            XML_N_FO               );
        mapTokenToNamespace( XML_OLD_NAMESPACE_FO,           XML_NP_FO,            XML_N_FO_OLD           );
        mapTokenToNamespace( XML_NAMESPACE_FO_COMPAT,        XML_NP_FO,            XML_N_FO_COMPAT        );
        mapTokenToNamespace( XML_NAMESPACE_XLINK,            XML_NP_XLINK,         XML_N_XLINK            );
        mapTokenToNamespace( XML_OLD_NAMESPACE_XLINK,        XML_NP_XLINK,         XML_N_XLINK_OLD        );
        mapTokenToNamespace( XML_NAMESPACE_DC,               XML_NP_DC,            XML_N_DC               );
        mapTokenToNamespace( XML_NAMESPACE_META,             XML_NP_META,          XML_N_META             );
        mapTokenToNamespace( XML_OLD_NAMESPACE_META,         XML_NP_META,          XML_N_META_OLD         );
        mapTokenToNamespace( XML_NAMESPACE_META_OOO,         XML_NP_META,          XML_N_META_OOO         );
        mapTokenToNamespace( XML_NAMESPACE_NUMBER,           XML_NP_NUMBER,        XML_N_NUMBER           );
        mapTokenToNamespace( XML_OLD_NAMESPACE_NUMBER,       XML_NP_NUMBER,        XML_N_NUMBER_OLD       );
        mapTokenToNamespace( XML_NAMESPACE_NUMBER_OOO,       XML_NP_NUMBER,        XML_N_NUMBER_OOO       );
        mapTokenToNamespace( XML_NAMESPACE_PRESENTATION,     XML_NP_PRESENTATION,  XML_N_PRESENTATION     );
        mapTokenToNamespace( XML_OLD_NAMESPACE_PRESENTATION, XML_NP_PRESENTATION,  XML_N_PRESENTATION_OLD );
        mapTokenToNamespace( XML_NAMESPACE_PRESENTATION_OOO, XML_NP_PRESENTATION,  XML_N_PRESENTATION_OOO );
        mapTokenToNamespace( XML_NAMESPACE_SVG,              XML_NP_SVG,           XML_N_SVG              );
        mapTokenToNamespace( XML_NAMESPACE_SVG_COMPAT,       XML_NP_SVG,           XML_N_SVG_COMPAT       );
        mapTokenToNamespace( XML_NAMESPACE_CHART,            XML_NP_CHART,         XML_N_CHART            );
        mapTokenToNamespace( XML_OLD_NAMESPACE_CHART,        XML_NP_CHART,         XML_N_CHART_OLD        );
        mapTokenToNamespace( XML_NAMESPACE_CHART_OOO,        XML_NP_CHART,         XML_N_CHART_OOO        );
        mapTokenToNamespace( XML_NAMESPACE_DR3D,             XML_NP_DR3D,          XML_N_DR3D             );
        mapTokenToNamespace( XML_NAMESPACE_DR3D_OOO,         XML_NP_DR3D,          XML_N_DR3D_OOO         );
        mapTokenToNamespace( XML_NAMESPACE_MATH,             XML_NP_MATH,          XML_N_MATH             );
        mapTokenToNamespace( XML_NAMESPACE_VERSIONS_LIST,    XML_NP_VERSIONS_LIST, XML_N_VERSIONS_LIST    );
        mapTokenToNamespace( XML_NAMESPACE_FORM,             XML_NP_FORM,          XML_N_FORM             );
        mapTokenToNamespace( XML_NAMESPACE_FORM_OOO,         XML_NP_FORM,          XML_N_FORM_OOO         );
        mapTokenToNamespace( XML_NAMESPACE_SCRIPT,           XML_NP_SCRIPT,        XML_N_SCRIPT           );
        mapTokenToNamespace( XML_NAMESPACE_SCRIPT_OOO,       XML_NP_SCRIPT,        XML_N_SCRIPT_OOO       );
        mapTokenToNamespace( XML_NAMESPACE_BLOCKLIST,        XML_NP_BLOCK_LIST,    XML_N_BLOCK_LIST       );
        mapTokenToNamespace( XML_NAMESPACE_CONFIG,           XML_NP_CONFIG,        XML_N_CONFIG           );
        mapTokenToNamespace( XML_NAMESPACE_CONFIG_OOO,       XML_NP_CONFIG,        XML_N_CONFIG_OOO       );
        mapTokenToNamespace( XML_NAMESPACE_OOO,              XML_NP_OOO,           XML_N_OOO              );
        mapTokenToNamespace( XML_NAMESPACE_OOOW,             XML_NP_OOOW,          XML_N_OOOW             );
        mapTokenToNamespace( XML_NAMESPACE_OOOC,             XML_NP_OOOC,          XML_N_OOOC             );
        mapTokenToNamespace( XML_NAMESPACE_DOM,              XML_NP_DOM,           XML_N_DOM              );
        mapTokenToNamespace( XML_NAMESPACE_DB,               XML_NP_DB,            XML_N_DB               );
        mapTokenToNamespace( XML_NAMESPACE_DB_OASIS,         XML_NP_DB,            XML_N_DB_OASIS         );
        mapTokenToNamespace( XML_NAMESPACE_DLG,              XML_NP_DLG,           XML_N_DLG              );
        mapTokenToNamespace( XML_NAMESPACE_XFORMS,           XML_NP_XFORMS_1_0,    XML_N_XFORMS_1_0       );
        mapTokenToNamespace( XML_NAMESPACE_XSD,              XML_NP_XSD,           XML_N_XSD              );
        mapTokenToNamespace( XML_NAMESPACE_XSI,              XML_NP_XSI,           XML_N_XSI              );
        mapTokenToNamespace( XML_NAMESPACE_SMIL,             XML_NP_SMIL,          XML_N_SMIL             );
        mapTokenToNamespace( XML_OLD_NAMESPACE_SMIL,         XML_NP_SMIL,          XML_N_SMIL_OLD         );
        mapTokenToNamespace( XML_NAMESPACE_SMIL_COMPAT,      XML_NP_SMIL,          XML_N_SMIL_COMPAT      );
        mapTokenToNamespace( XML_NAMESPACE_ANIMATION,        XML_NP_ANIMATION,     XML_N_ANIMATION        );
        mapTokenToNamespace( XML_NAMESPACE_REPORT,           XML_NP_RPT,           XML_N_RPT              );
        mapTokenToNamespace( XML_NAMESPACE_REPORT_OASIS,     XML_NP_RPT,           XML_N_RPT_OASIS        );
        mapTokenToNamespace( XML_NAMESPACE_OF,               XML_NP_OF,            XML_N_OF               );
        mapTokenToNamespace( XML_NAMESPACE_XHTML,            XML_NP_XHTML,         XML_N_XHTML            );
        mapTokenToNamespace( XML_NAMESPACE_GRDDL,            XML_NP_GRDDL,         XML_N_GRDDL            );
        mapTokenToNamespace( XML_NAMESPACE_OFFICE_EXT,       XML_NP_OFFICE_EXT,    XML_N_OFFICE_EXT       );
        mapTokenToNamespace( XML_NAMESPACE_TABLE_EXT,        XML_NP_TABLE_EXT,     XML_N_TABLE_EXT        );
        mapTokenToNamespace( XML_NAMESPACE_CHART_EXT,        XML_NP_CHART_EXT,     XML_N_CHART_EXT        );
        mapTokenToNamespace( XML_NAMESPACE_DRAW_EXT,         XML_NP_DRAW_EXT,      XML_N_DRAW_EXT         );
        mapTokenToNamespace( XML_NAMESPACE_CALC_EXT,         XML_NP_CALC_EXT,      XML_N_CALC_EXT         );
        mapTokenToNamespace( XML_NAMESPACE_LO_EXT,           XML_NP_LO_EXT,        XML_N_LO_EXT           );
        mapTokenToNamespace( XML_NAMESPACE_CSS3TEXT,         XML_NP_CSS3TEXT,      XML_N_CSS3TEXT         );
        mapTokenToNamespace( XML_NAMESPACE_FIELD,            XML_NP_FIELD,         XML_N_FIELD            );
        mapTokenToNamespace( XML_NAMESPACE_FORMX,            XML_NP_FORMX,         XML_N_FORMX            );
    }

    void SvXMLImport::registerNamespaces()
    {
        for( auto const &aNamespaceEntry : aNamespaceMap )
        {
            // aNamespaceMap = { Token : ( NamespacePrefix, NamespaceURI ) }
            registerNamespace( aNamespaceEntry.second.second, aNamespaceEntry.first << NMSP_SHIFT );
        }
    }

    SvXMLImportFastNamespaceHandler::SvXMLImportFastNamespaceHandler()
    {
    }

    void SvXMLImportFastNamespaceHandler::addNSDeclAttributes( rtl::Reference < comphelper::AttributeList > const & rAttrList )
    {
        for(const auto& aNamespaceDefine : m_aNamespaceDefines)
        {
            OUString& rPrefix = aNamespaceDefine.get()->m_aPrefix;
            OUString& rNamespaceURI = aNamespaceDefine.get()->m_aNamespaceURI;
            OUString sDecl;
            if ( rPrefix.isEmpty() )
                sDecl = "xmlns";
            else
                sDecl = "xmlns:" + rPrefix;
            rAttrList->AddAttribute( sDecl, "CDATA", rNamespaceURI );
        }
        m_aNamespaceDefines.clear();
    }

    void SvXMLImportFastNamespaceHandler::registerNamespace( const OUString& rNamespacePrefix, const OUString& rNamespaceURI )
    {
        // Elements with default namespace parsed by FastParser have namespace prefix.
        // A default namespace needs to be registered with the prefix, to maintain the compatibility.
        if ( rNamespacePrefix.isEmpty() )
            m_aNamespaceDefines.push_back( o3tl::make_unique<NamespaceDefine>(
                                        SvXMLImport::getNamespacePrefixFromURI( rNamespaceURI ), rNamespaceURI) );

        m_aNamespaceDefines.push_back( o3tl::make_unique<NamespaceDefine>(
                                        rNamespacePrefix, rNamespaceURI) );
    }

    OUString SvXMLImportFastNamespaceHandler::getNamespaceURI( const OUString&/* rNamespacePrefix */ )
    {
        return OUString();
    }

    SvXMLLegacyToFastDocHandler::SvXMLLegacyToFastDocHandler( const rtl::Reference< SvXMLImport > & rImport )
    :   mrImport( rImport ),
        mxFastAttributes( new sax_fastparser::FastAttributeList( SvXMLImport::xTokenHandler.get(),
            dynamic_cast< sax_fastparser::FastTokenHandlerBase *>( SvXMLImport::xTokenHandler.get() ) ) )
    {
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc )
    {
        mrImport->setTargetDocument( xDoc );
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::startDocument()
    {
        mrImport->startDocument();
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::endDocument()
    {
        mrImport->endDocument();
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::startElement( const OUString& rName,
                            const uno::Reference< xml::sax::XAttributeList >& xAttrList )
    {
        mrImport->processNSAttributes(xAttrList);
        OUString aLocalName;
        sal_uInt16 nPrefix = mrImport->mpNamespaceMap->GetKeyByAttrName( rName, &aLocalName );
        Sequence< sal_Int8 > aLocalNameSeq( reinterpret_cast<sal_Int8 const *>(
                                        OUStringToOString( aLocalName, RTL_TEXTENCODING_UTF8 ).getStr()), aLocalName.getLength() );
        sal_Int32 mnElement = NAMESPACE_TOKEN( nPrefix ) | SvXMLImport::xTokenHandler->getTokenFromUTF8( aLocalNameSeq );
        mxFastAttributes->clear();

        sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
        for( sal_Int16 i=0; i < nAttrCount; i++ )
        {
            OUString aLocalAttrName;
            OUString aNamespace;
            const OUString& rAttrName = xAttrList->getNameByIndex( i );
            const OUString& rAttrValue = xAttrList->getValueByIndex( i );
            sal_uInt16 const nAttrPrefix(mrImport->mpNamespaceMap->GetKeyByAttrName(
                    rAttrName, nullptr, &aLocalAttrName, &aNamespace));
            if( XML_NAMESPACE_XMLNS != nAttrPrefix )
            {
                Sequence< sal_Int8 > aAttrSeq( reinterpret_cast<sal_Int8 const *>(
                                        OUStringToOString( aLocalAttrName, RTL_TEXTENCODING_UTF8 ).getStr()), aLocalAttrName.getLength() );
                auto const nToken(SvXMLImport::xTokenHandler->getTokenFromUTF8(aAttrSeq));
                if (nToken == xmloff::XML_TOKEN_INVALID)
                {
                    mxFastAttributes->addUnknown(aNamespace,
                        OUStringToOString(rAttrName, RTL_TEXTENCODING_UTF8),
                        OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8));
                }
                else
                {
                    sal_Int32 const nAttr = NAMESPACE_TOKEN(nAttrPrefix) | nToken;
                    mxFastAttributes->add(nAttr, OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8).getStr());
                }
            }
        }
        mrImport->startFastElement( mnElement, mxFastAttributes.get() );
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::endElement( const OUString& rName )
    {
        OUString aLocalName;
        sal_uInt16 nPrefix = mrImport->mpNamespaceMap->GetKeyByAttrName( rName, &aLocalName );
        Sequence< sal_Int8 > aLocalNameSeq( reinterpret_cast<sal_Int8 const *>(
                                        OUStringToOString( aLocalName, RTL_TEXTENCODING_UTF8 ).getStr()), aLocalName.getLength() );
        sal_Int32 mnElement = NAMESPACE_TOKEN( nPrefix ) | SvXMLImport::xTokenHandler->getTokenFromUTF8( aLocalNameSeq );
        mrImport->endFastElement( mnElement );
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::characters( const OUString& aChars )
    {
        mrImport->characters( aChars );
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::ignorableWhitespace( const OUString& aWhitespaces )
    {
        mrImport->ignorableWhitespace( aWhitespaces );
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::processingInstruction( const OUString& aTarget,
                                                                      const OUString& aData)
    {
        mrImport->processingInstruction( aTarget, aData );
    }

    void SAL_CALL SvXMLLegacyToFastDocHandler::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& rLocator )
    {
        mrImport->setDocumentLocator( rLocator );
    }

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

↑ V547 Expression 'pNames' is always true.