/* -*- 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 <com/sun/star/embed/XStorage.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/xml/sax/InputSource.hpp>
#include <com/sun/star/xml/sax/Parser.hpp>
#include <com/sun/star/xml/sax/SAXParseException.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/document/NamedPropertyValues.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/packages/zip/ZipIOException.hpp>
#include <com/sun/star/packages/WrongPasswordException.hpp>
#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
#include <com/sun/star/task/XStatusIndicator.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <o3tl/any.hxx>
#include <vcl/errinf.hxx>
#include <sfx2/docfile.hxx>
#include <svtools/sfxecode.hxx>
#include <svl/stritem.hxx>
#include <svx/dialmgr.hxx>
#include <svx/strings.hrc>
#include <svx/xmlgrhlp.hxx>
#include <svx/xmleohlp.hxx>
#include <comphelper/fileformat.h>
#include <comphelper/genericpropertyset.hxx>
#include <comphelper/propertysetinfo.hxx>
#include <sal/log.hxx>
#include <sfx2/frame.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <swerror.h>
#include <fltini.hxx>
#include <drawdoc.hxx>
#include <doc.hxx>
#include <docfunc.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentMarkAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <DocumentRedlineManager.hxx>
#include <docary.hxx>
#include <docsh.hxx>
#include <unotextrange.hxx>
#include <SwXMLSectionList.hxx>
 
#include <SwStyleNameMapper.hxx>
#include <poolfmt.hxx>
#include <numrule.hxx>
#include <paratr.hxx>
#include <fmtrowsplt.hxx>
 
#include <svx/svdpage.hxx>
#include <svx/svditer.hxx>
#include <svx/svdoole2.hxx>
#include <svx/svdograf.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/sfxsids.hrc>
#include <istyleaccess.hxx>
 
#include <sfx2/DocumentMetadataAccess.hxx>
#include <comphelper/diagnose_ex.hxx>
 
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::text;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::document;
using namespace ::com::sun::star::lang;
 
static void lcl_EnsureValidPam( SwPaM& rPam )
{
    if( rPam.GetPointContentNode() != nullptr )
    {
        // set proper point content
        if( rPam.GetPointContentNode() != rPam.GetPoint()->GetContentNode() )
        {
            rPam.GetPoint()->nContent.Assign( rPam.GetPointContentNode(), 0 );
        }
        // else: point was already valid
 
        // if mark is invalid, we delete it
        if( ( rPam.GetMarkContentNode() == nullptr ) ||
            ( rPam.GetMarkContentNode() != rPam.GetMark()->GetContentNode() ) )
        {
            rPam.DeleteMark();
        }
    }
    else
    {
        // point is not valid, so move it into the first content
        rPam.DeleteMark();
        rPam.GetPoint()->Assign(
            *rPam.GetDoc().GetNodes().GetEndOfContent().StartOfSectionNode() );
        rPam.GetPoint()->Adjust(SwNodeOffset(+1));
        rPam.Move( fnMoveForward, GoInContent ); // go into content
    }
}
 
XMLReader::XMLReader()
{
}
 
SwReaderType XMLReader::GetReaderType()
{
    return SwReaderType::Storage;
}
 
namespace
{
 
/// read a component (file + filter version)
ErrCodeMsg ReadThroughComponent(
    uno::Reference<io::XInputStream> const & xInputStream,
    uno::Reference<XComponent> const & xModelComponent,
    const OUString& rStreamName,
    uno::Reference<uno::XComponentContext> const & rxContext,
    const char* pFilterName,
    const Sequence<Any>& rFilterArguments,
    const OUString& rName,
    bool bMustBeSuccessful,
    bool bEncrypted )
{
    OSL_ENSURE(xInputStream.is(), "input stream missing");
    OSL_ENSURE(xModelComponent.is(), "document missing");
    OSL_ENSURE(rxContext.is(), "factory missing");
    OSL_ENSURE(nullptr != pFilterName,"I need a service name for the component!");
 
    // prepare ParserInputSource
    xml::sax::InputSource aParserInput;
    aParserInput.sSystemId = rName;
    aParserInput.aInputStream = xInputStream;
 
    // get filter
    const OUString aFilterName(OUString::createFromAscii(pFilterName));
    uno::Reference< XInterface > xFilter =
        rxContext->getServiceManager()->createInstanceWithArgumentsAndContext(aFilterName, rFilterArguments, rxContext);
    SAL_WARN_IF(!xFilter.is(), "sw.filter", "Can't instantiate filter component: " << aFilterName);
    if( !xFilter.is() )
        return ERR_SWG_READ_ERROR;
    // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler
    uno::Reference< xml::sax::XFastParser > xFastParser(xFilter, UNO_QUERY);
    uno::Reference< xml::sax::XDocumentHandler > xDocumentHandler;
    if (!xFastParser)
        xDocumentHandler.set(xFilter, UNO_QUERY);
    if (!xDocumentHandler && !xFastParser)
    {
        SAL_WARN("sd", "service does not implement XFastParser or XDocumentHandler");
        assert(false);
        return ERR_SWG_READ_ERROR;
    }
 
    // connect model and filter
    uno::Reference < XImporter > xImporter( xFilter, UNO_QUERY );
    xImporter->setTargetDocument( xModelComponent );
 
    // finally, parse the stream
    try
    {
        if (xFastParser)
            xFastParser->parseStream( aParserInput );
        else
        {
            uno::Reference< xml::sax::XParser > xParser = xml::sax::Parser::create(rxContext);
            // connect parser and filter
            xParser->setDocumentHandler( xDocumentHandler );
            xParser->parseStream( aParserInput );
        }
    }
    catch( xml::sax::SAXParseException& r)
    {
        css::uno::Any ex( cppu::getCaughtException() );
        // sax parser sends wrapped exceptions,
        // try to find the original one
        xml::sax::SAXException aSaxEx = *static_cast<xml::sax::SAXException*>(&r);
        bool bTryChild = true;
 
        while( bTryChild )
        {
            xml::sax::SAXException aTmp;
            if ( aSaxEx.WrappedException >>= aTmp )
                aSaxEx = std::move(aTmp);
            else
                bTryChild = false;
        }
 
        packages::zip::ZipIOException aBrokenPackage;
        if ( aSaxEx.WrappedException >>= aBrokenPackage )
            return ERRCODE_IO_BROKENPACKAGE;
 
        if( bEncrypted )
            return ERRCODE_SFX_WRONGPASSWORD;
 
        SAL_WARN( "sw", "SAX parse exception caught while importing: " << exceptionToString(ex) );
 
        const OUString sErr( OUString::number( r.LineNumber )
            + ","
            + OUString::number( r.ColumnNumber ) );
 
        if( !rStreamName.isEmpty() )
        {
            return ErrCodeMsg(
                            (bMustBeSuccessful ? ERR_FORMAT_FILE_ROWCOL
                                                    : WARN_FORMAT_FILE_ROWCOL),
                            rStreamName, sErr,
                            DialogMask::ButtonsOk | DialogMask::MessageError );
        }
        else
        {
            OSL_ENSURE( bMustBeSuccessful, "Warnings are not supported" );
            return ErrCodeMsg( ERR_FORMAT_ROWCOL, sErr,
                             DialogMask::ButtonsOk | DialogMask::MessageError );
        }
    }
    catch(const xml::sax::SAXException& r)
    {
        css::uno::Any ex( cppu::getCaughtException() );
        packages::zip::ZipIOException aBrokenPackage;
        if ( r.WrappedException >>= aBrokenPackage )
            return ERRCODE_IO_BROKENPACKAGE;
 
        if( bEncrypted )
            return ERRCODE_SFX_WRONGPASSWORD;
 
        SAL_WARN( "sw", "uno exception caught while importing: " << exceptionToString(ex) );
        return ERR_SWG_READ_ERROR;
    }
    catch(const packages::zip::ZipIOException&)
    {
        TOOLS_WARN_EXCEPTION( "sw", "uno exception caught while importing" );
        return ERRCODE_IO_BROKENPACKAGE;
    }
    catch(const io::IOException&)
    {
        TOOLS_WARN_EXCEPTION( "sw", "uno exception caught while importing" );
        return ERR_SWG_READ_ERROR;
    }
    catch(const uno::Exception&)
    {
        TOOLS_WARN_EXCEPTION( "sw", "uno exception caught while importing" );
        return ERR_SWG_READ_ERROR;
    }
 
    // success!
    return ERRCODE_NONE;
}
 
// read a component (storage version)
ErrCodeMsg ReadThroughComponent(
    uno::Reference<embed::XStorage> const & xStorage,
    uno::Reference<XComponent> const & xModelComponent,
    const char* pStreamName,
    uno::Reference<uno::XComponentContext> const & rxContext,
    const char* pFilterName,
    const Sequence<Any>& rFilterArguments,
    const OUString& rName,
    bool bMustBeSuccessful)
{
    OSL_ENSURE(xStorage.is(), "Need storage!");
    OSL_ENSURE(nullptr != pStreamName, "Please, please, give me a name!");
 
    // open stream (and set parser input)
    OUString sStreamName = OUString::createFromAscii(pStreamName);
    bool bContainsStream = false;
    try
    {
        bContainsStream = xStorage->isStreamElement(sStreamName);
    }
    catch( container::NoSuchElementException& )
    {
    }
 
    if (!bContainsStream )
    {
        // stream name not found! return immediately with OK signal
        return ERRCODE_NONE;
    }
 
    // set Base URL
    uno::Reference< beans::XPropertySet > xInfoSet;
    if( rFilterArguments.hasElements() )
        rFilterArguments.getConstArray()[0] >>= xInfoSet;
    OSL_ENSURE( xInfoSet.is(), "missing property set" );
    if( xInfoSet.is() )
    {
        xInfoSet->setPropertyValue( u"StreamName"_ustr, Any( sStreamName ) );
    }
 
    try
    {
        // get input stream
        uno::Reference <io::XStream> xStream = xStorage->openStreamElement( sStreamName, embed::ElementModes::READ );
        uno::Reference <beans::XPropertySet > xProps( xStream, uno::UNO_QUERY );
 
        Any aAny = xProps->getPropertyValue(u"Encrypted"_ustr);
 
        std::optional<const bool> b = o3tl::tryAccess<bool>(aAny);
        bool bEncrypted = b.has_value() && *b;
 
        uno::Reference <io::XInputStream> xInputStream = xStream->getInputStream();
 
        // read from the stream
        return ReadThroughComponent(
            xInputStream, xModelComponent, sStreamName, rxContext,
            pFilterName, rFilterArguments,
            rName, bMustBeSuccessful, bEncrypted );
    }
    catch ( packages::WrongPasswordException& )
    {
        return ERRCODE_SFX_WRONGPASSWORD;
    }
    catch( packages::zip::ZipIOException& )
    {
        return ERRCODE_IO_BROKENPACKAGE;
    }
    catch ( uno::Exception& )
    {
        OSL_FAIL( "Error on import" );
        // TODO/LATER: error handling
    }
 
    return ERR_SWG_READ_ERROR;
}
 
}
 
// #i44177#
static void lcl_AdjustOutlineStylesForOOo(SwDoc& _rDoc)
{
    // array containing the names of the default outline styles ('Heading 1',
    // 'Heading 2', ..., 'Heading 10')
    OUString aDefOutlStyleNames[ MAXLEVEL ];
    {
        OUString sStyleName;
        for ( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
        {
            sStyleName =
                SwStyleNameMapper::GetProgName( RES_POOLCOLL_HEADLINE1 + i,
                                                sStyleName );
            aDefOutlStyleNames[i] = sStyleName;
        }
    }
 
    // array indicating, which outline level already has a style assigned.
    bool aOutlineLevelAssigned[ MAXLEVEL ];
    // array of the default outline styles, which are created for the document.
    SwTextFormatColl* aCreatedDefaultOutlineStyles[ MAXLEVEL ];
 
    {
        for ( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
        {
            aOutlineLevelAssigned[ i ] = false;
            aCreatedDefaultOutlineStyles[ i ] = nullptr;
        }
    }
 
    // determine, which outline level has already a style assigned and
    // which of the default outline styles is created.
    const SwTextFormatColls& rColls = *(_rDoc.GetTextFormatColls());
    for ( size_t n = 1; n < rColls.size(); ++n )
    {
        SwTextFormatColl* pColl = rColls[ n ];
        if ( pColl->IsAssignedToListLevelOfOutlineStyle() )
        {
            aOutlineLevelAssigned[ pColl->GetAssignedOutlineStyleLevel() ] = true;
        }
 
        for ( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
        {
            if ( aCreatedDefaultOutlineStyles[ i ] == nullptr &&
                 pColl->GetName() == aDefOutlStyleNames[i] )
            {
                aCreatedDefaultOutlineStyles[ i ] = pColl;
                break;
            }
        }
    }
 
    // assign already created default outline style to outline level, which
    // doesn't have a style assigned to it.
    const SwNumRule* pOutlineRule = _rDoc.GetOutlineNumRule();
    for ( sal_uInt8 i = 0; i < MAXLEVEL; ++i )
    {
        // #i73361#
        // Do not change assignment of already created default outline style
        // to a certain outline level.
        if ( !aOutlineLevelAssigned[ i ] &&
             aCreatedDefaultOutlineStyles[ i ] != nullptr &&
             ! aCreatedDefaultOutlineStyles[ i ]->IsAssignedToListLevelOfOutlineStyle() )
        {
            // apply outline level at created default outline style
            aCreatedDefaultOutlineStyles[ i ]->AssignToListLevelOfOutlineStyle(i);
 
            // apply outline numbering rule, if none is set.
            const SwNumRuleItem& rItem =
                aCreatedDefaultOutlineStyles[ i ]->GetFormatAttr( RES_PARATR_NUMRULE, false );
            if ( rItem.GetValue().isEmpty() )
            {
                SwNumRuleItem aItem( pOutlineRule->GetName() );
                aCreatedDefaultOutlineStyles[ i ]->SetFormatAttr( aItem );
            }
        }
    }
}
 
static void lcl_ConvertSdrOle2ObjsToSdrGrafObjs(SwDoc& _rDoc)
{
    if ( !(_rDoc.getIDocumentDrawModelAccess().GetDrawModel() &&
         _rDoc.getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 )) )
        return;
 
    const SdrPage& rSdrPage( *(_rDoc.getIDocumentDrawModelAccess().GetDrawModel()->GetPage( 0 )) );
 
    // iterate recursive with group objects over all shapes on the draw page
    SdrObjListIter aIter( &rSdrPage );
    while( aIter.IsMore() )
    {
        SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( aIter.Next() );
        if( pOle2Obj )
        {
            // found an ole2 shape
            SdrObjList* pObjList = pOle2Obj->getParentSdrObjListFromSdrObject();
 
            // get its graphic
            Graphic aGraphic;
            pOle2Obj->Connect();
            const Graphic* pGraphic = pOle2Obj->GetGraphic();
            if( pGraphic )
                aGraphic = *pGraphic;
            pOle2Obj->Disconnect();
 
            // create new graphic shape with the ole graphic and shape size
            rtl::Reference<SdrGrafObj> pGraphicObj = new SdrGrafObj(
                pOle2Obj->getSdrModelFromSdrObject(),
                aGraphic,
                pOle2Obj->GetCurrentBoundRect());
 
            // apply layer of ole2 shape at graphic shape
            pGraphicObj->SetLayer( pOle2Obj->GetLayer() );
 
            // replace ole2 shape with the new graphic object and delete the ol2 shape
            pObjList->ReplaceObject( pGraphicObj.get(), pOle2Obj->GetOrdNum() );
        }
    }
}
 
ErrCodeMsg XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, const OUString & rName )
{
    // needed for relative URLs, but in clipboard copy/paste there may be none
    // and also there is the SwXMLTextBlocks special case
    SAL_INFO_IF(rBaseURL.isEmpty(), "sw.filter", "sw::XMLReader: no base URL");
 
    // Get service factory
    const uno::Reference< uno::XComponentContext >& xContext =
            comphelper::getProcessComponentContext();
 
    uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
    rtl::Reference<SvXMLGraphicHelper> xGraphicHelper;
    uno::Reference< document::XEmbeddedObjectResolver > xObjectResolver;
    rtl::Reference<SvXMLEmbeddedObjectHelper> xObjectHelper;
 
    // get the input stream (storage or stream)
    uno::Reference<embed::XStorage> xStorage;
    if( m_pMedium )
        xStorage = m_pMedium->GetStorage();
    else
        xStorage = m_xStorage;
 
    if( !xStorage.is() )
        return ERR_SWG_READ_ERROR;
 
    xGraphicHelper = SvXMLGraphicHelper::Create( xStorage,
                                                 SvXMLGraphicHelperMode::Read );
    xGraphicStorageHandler = xGraphicHelper.get();
    SfxObjectShell *pPersist = rDoc.GetPersist();
    if( pPersist )
    {
        xObjectHelper = SvXMLEmbeddedObjectHelper::Create(
                                        xStorage, *pPersist,
                                        SvXMLEmbeddedObjectHelperMode::Read );
        xObjectResolver = xObjectHelper.get();
    }
 
    // Get the docshell, the model, and finally the model's component
    SwDocShell *pDocSh = rDoc.GetDocShell();
    OSL_ENSURE( pDocSh, "XMLReader::Read: got no doc shell" );
    if( !pDocSh )
        return ERR_SWG_READ_ERROR;
    uno::Reference< lang::XComponent > xModelComp = pDocSh->GetModel();
    OSL_ENSURE( xModelComp.is(),
            "XMLReader::Read: got no model" );
    if( !xModelComp.is() )
        return ERR_SWG_READ_ERROR;
 
    // create and prepare the XPropertySet that gets passed through
    // the components, and the XStatusIndicator that shows progress to
    // the user.
 
    // create XPropertySet with three properties for status indicator
    static comphelper::PropertyMapEntry const aInfoMap[] =
    {
        { u"ProgressRange"_ustr, 0,
              ::cppu::UnoType<sal_Int32>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0},
        { u"ProgressMax"_ustr, 0,
              ::cppu::UnoType<sal_Int32>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0},
        { u"ProgressCurrent"_ustr, 0,
              ::cppu::UnoType<sal_Int32>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0},
        { u"NumberStyles"_ustr, 0,
              cppu::UnoType<container::XNameContainer>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0},
        { u"RecordChanges"_ustr, 0,
              cppu::UnoType<bool>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"ShowChanges"_ustr, 0,
              cppu::UnoType<bool>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"RedlineProtectionKey"_ustr, 0,
              cppu::UnoType<Sequence<sal_Int8>>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"PrivateData"_ustr, 0,
              cppu::UnoType<XInterface>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"BaseURI"_ustr, 0,
              ::cppu::UnoType<OUString>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"StreamRelPath"_ustr, 0,
              ::cppu::UnoType<OUString>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"StreamName"_ustr, 0,
              ::cppu::UnoType<OUString>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        // properties for insert modes
        { u"StyleInsertModeFamilies"_ustr, 0,
              cppu::UnoType<Sequence<OUString>>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"StyleInsertModeOverwrite"_ustr, 0,
              cppu::UnoType<bool>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"TextInsertModeRange"_ustr, 0,
              cppu::UnoType<text::XTextRange>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0},
        { u"AutoTextMode"_ustr, 0,
              cppu::UnoType<bool>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"OrganizerMode"_ustr, 0,
              cppu::UnoType<bool>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
 
        // #i28749# - Add property, which indicates, if the
        // shape position attributes are given in horizontal left-to-right layout.
        // This is the case for the OpenOffice.org file format.
        { u"ShapePositionInHoriL2R"_ustr, 0,
              cppu::UnoType<bool>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
 
        { u"BuildId"_ustr, 0,
              ::cppu::UnoType<OUString>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
 
        // Add property, which indicates, if a text document in OpenOffice.org
        // file format is read.
        // Note: Text documents read via the binary filter are also finally
        //       read using the OpenOffice.org file format. Thus, e.g. for text
        //       documents in StarOffice 5.2 binary file format this property
        //       will be true.
        { u"TextDocInOOoFileFormat"_ustr, 0,
              cppu::UnoType<bool>::get(),
              beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"SourceStorage"_ustr, 0, cppu::UnoType<embed::XStorage>::get(),
          css::beans::PropertyAttribute::MAYBEVOID, 0 },
        { u"IsInPaste"_ustr, 0, cppu::UnoType<bool>::get(),
          beans::PropertyAttribute::MAYBEVOID, 0 },
    };
    uno::Reference< beans::XPropertySet > xInfoSet(
                comphelper::GenericPropertySet_CreateInstance(
                            new comphelper::PropertySetInfo( aInfoMap ) ) );
 
    // get BuildId from parent container if available
    uno::Reference< container::XChild > xChild( xModelComp, uno::UNO_QUERY );
    if( xChild.is() )
    {
        uno::Reference< beans::XPropertySet > xParentSet( xChild->getParent(), uno::UNO_QUERY );
        if( xParentSet.is() )
        {
            uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xParentSet->getPropertySetInfo() );
            static constexpr OUString sPropName(u"BuildId"_ustr );
            if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(sPropName) )
            {
                xInfoSet->setPropertyValue( sPropName, xParentSet->getPropertyValue(sPropName) );
            }
        }
    }
 
    // try to get an XStatusIndicator from the Medium
    uno::Reference<task::XStatusIndicator> xStatusIndicator;
 
    if (pDocSh->GetMedium())
    {
        const SfxUnoAnyItem* pItem =
            pDocSh->GetMedium()->GetItemSet().GetItem(SID_PROGRESS_STATUSBAR_CONTROL);
        if (pItem)
        {
            pItem->GetValue() >>= xStatusIndicator;
        }
    }
 
    // set progress range and start status indicator
    sal_Int32 nProgressRange(1000000);
    if (xStatusIndicator.is())
    {
        xStatusIndicator->start(SvxResId(RID_SVXSTR_DOC_LOAD), nProgressRange);
    }
    uno::Any aProgRange;
    aProgRange <<= nProgressRange;
    xInfoSet->setPropertyValue(u"ProgressRange"_ustr, aProgRange);
 
    Reference< container::XNameAccess > xLateInitSettings( document::NamedPropertyValues::create(xContext), UNO_QUERY_THROW );
    beans::NamedValue aLateInitSettings( u"LateInitSettings"_ustr, Any( xLateInitSettings ) );
 
    xInfoSet->setPropertyValue( u"SourceStorage"_ustr, Any( xStorage ) );
 
    xInfoSet->setPropertyValue(u"IsInPaste"_ustr, Any(IsInPaste()));
 
    // prepare filter arguments, WARNING: the order is important!
    Sequence<Any> aFilterArgs{  Any(xInfoSet),
                                Any(xStatusIndicator),
                                Any(xGraphicStorageHandler),
                                Any(xObjectResolver),
                                Any(aLateInitSettings) };
 
    Sequence<Any> aEmptyArgs{   Any(xInfoSet),
                                Any(xStatusIndicator) };
 
    // prepare for special modes
    if( m_aOption.IsFormatsOnly() )
    {
        sal_Int32 nCount =
            (m_aOption.IsFrameFormats() ? 1 : 0) +
            (m_aOption.IsPageDescs() ? 1 : 0) +
            (m_aOption.IsTextFormats() ? 2 : 0) +
            (m_aOption.IsNumRules() ? 1 : 0);
 
        Sequence< OUString> aFamiliesSeq( nCount );
        OUString *pSeq = aFamiliesSeq.getArray();
        if( m_aOption.IsFrameFormats() )
            // SfxStyleFamily::Frame;
            *pSeq++ = "FrameStyles";
        if( m_aOption.IsPageDescs() )
            // SfxStyleFamily::Page;
            *pSeq++ = "PageStyles";
        if( m_aOption.IsTextFormats() )
        {
            // (SfxStyleFamily::Char|SfxStyleFamily::Para);
            *pSeq++ = "CharacterStyles";
            *pSeq++ = "ParagraphStyles";
        }
        if( m_aOption.IsNumRules() )
            // SfxStyleFamily::Pseudo;
            *pSeq++ = "NumberingStyles";
 
        xInfoSet->setPropertyValue( u"StyleInsertModeFamilies"_ustr,
                                    Any(aFamiliesSeq) );
 
        xInfoSet->setPropertyValue( u"StyleInsertModeOverwrite"_ustr, Any(!m_aOption.IsMerge()) );
    }
    else if( m_bInsertMode )
    {
        const rtl::Reference<SwXTextRange> xInsertTextRange =
            SwXTextRange::CreateXTextRange(rDoc, *rPaM.GetPoint(), nullptr);
        xInfoSet->setPropertyValue( u"TextInsertModeRange"_ustr,
                                    Any(uno::Reference<text::XTextRange>(xInsertTextRange)) );
    }
    else
    {
        rPaM.GetBound().nContent.Assign(nullptr, 0);
        rPaM.GetBound(false).nContent.Assign(nullptr, 0);
    }
 
    if( IsBlockMode() )
    {
        xInfoSet->setPropertyValue( u"AutoTextMode"_ustr, Any(true) );
    }
    if( IsOrganizerMode() )
    {
        xInfoSet->setPropertyValue( u"OrganizerMode"_ustr, Any(true) );
    }
 
    // Set base URI
    // there is ambiguity which medium should be used here
    // for now the own medium has a preference
    SfxMedium* pMedDescrMedium = m_pMedium ? m_pMedium : pDocSh->GetMedium();
    OSL_ENSURE( pMedDescrMedium, "There is no medium to get MediaDescriptor from!" );
 
    xInfoSet->setPropertyValue( u"BaseURI"_ustr, Any( rBaseURL ) );
 
    // TODO/LATER: separate links from usual embedded objects
    OUString StreamPath;
    if( SfxObjectCreateMode::EMBEDDED == rDoc.GetDocShell()->GetCreateMode() )
    {
        if (pMedDescrMedium)
        {
            const SfxStringItem* pDocHierarchItem =
                pMedDescrMedium->GetItemSet().GetItem(SID_DOC_HIERARCHICALNAME);
            if ( pDocHierarchItem )
                StreamPath = pDocHierarchItem->GetValue();
        }
        else
        {
            StreamPath = "dummyObjectName";
        }
 
        if( !StreamPath.isEmpty() )
        {
            xInfoSet->setPropertyValue( u"StreamRelPath"_ustr, Any( StreamPath ) );
        }
    }
 
    rtl::Reference<SwDoc> aHoldRef(&rDoc); // prevent deletion
    ErrCodeMsg nRet = ERRCODE_NONE;
 
    // save redline mode into import info property set
    static constexpr OUString sShowChanges(u"ShowChanges"_ustr);
    static constexpr OUString sRecordChanges(u"RecordChanges"_ustr);
    static constexpr OUString sRedlineProtectionKey(u"RedlineProtectionKey"_ustr);
    xInfoSet->setPropertyValue( sShowChanges,
        Any(IDocumentRedlineAccess::IsShowChanges(rDoc.getIDocumentRedlineAccess().GetRedlineFlags())) );
    xInfoSet->setPropertyValue( sRecordChanges,
        Any(IDocumentRedlineAccess::IsRedlineOn(rDoc.getIDocumentRedlineAccess().GetRedlineFlags())) );
    xInfoSet->setPropertyValue( sRedlineProtectionKey,
        Any(rDoc.getIDocumentRedlineAccess().GetRedlinePassword()) );
 
    // force redline mode to "none"
    rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( RedlineFlags::NONE );
 
    const bool bOASIS = ( SotStorage::GetVersion( xStorage ) > SOFFICE_FILEFORMAT_60 );
    // #i28749# - set property <ShapePositionInHoriL2R>
    {
        const bool bShapePositionInHoriL2R = !bOASIS;
        xInfoSet->setPropertyValue(
                u"ShapePositionInHoriL2R"_ustr,
                Any( bShapePositionInHoriL2R ) );
    }
    {
        const bool bTextDocInOOoFileFormat = !bOASIS;
        xInfoSet->setPropertyValue(
                u"TextDocInOOoFileFormat"_ustr,
                Any( bTextDocInOOoFileFormat ) );
    }
 
    ErrCode nWarnRDF = ERRCODE_NONE;
    if ( !(IsOrganizerMode() || IsBlockMode() || m_aOption.IsFormatsOnly() ||
           m_bInsertMode) )
    {
        // RDF metadata - must be read before styles/content
        // N.B.: embedded documents have their own manifest.rdf!
        try
        {
            const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(xModelComp,
                uno::UNO_QUERY_THROW);
            const uno::Reference<frame::XModel> xModel(xModelComp,
                uno::UNO_QUERY_THROW);
            const uno::Reference<rdf::XURI> xBaseURI( ::sfx2::createBaseURI(
                xContext, xModel, rBaseURL, StreamPath) );
            const uno::Reference<task::XInteractionHandler> xHandler(
                pDocSh->GetMedium()->GetInteractionHandler() );
            xDMA->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
        }
        catch (const lang::WrappedTargetException & e)
        {
            ucb::InteractiveAugmentedIOException iaioe;
            if (e.TargetException >>= iaioe)
            {
                // import error that was not ignored by InteractionHandler!
                nWarnRDF = ERR_SWG_READ_ERROR;
            }
            else
            {
                nWarnRDF = WARN_SWG_FEATURES_LOST; // uhh... something wrong?
            }
        }
        catch (uno::Exception &)
        {
            nWarnRDF = WARN_SWG_FEATURES_LOST; // uhh... something went wrong?
        }
    }
 
    // read storage streams
 
    // #i103539#: always read meta.xml for generator
    ErrCodeMsg const nWarn = ReadThroughComponent(
        xStorage, xModelComp, "meta.xml", xContext,
        (bOASIS ? "com.sun.star.comp.Writer.XMLOasisMetaImporter"
                : "com.sun.star.comp.Writer.XMLMetaImporter"),
        aEmptyArgs, rName, false );
 
    ErrCodeMsg nWarn2 = ERRCODE_NONE;
    if( !(IsOrganizerMode() || IsBlockMode() || m_aOption.IsFormatsOnly() ||
          m_bInsertMode) )
    {
        nWarn2 = ReadThroughComponent(
            xStorage, xModelComp, "settings.xml", xContext,
            (bOASIS ? "com.sun.star.comp.Writer.XMLOasisSettingsImporter"
                    : "com.sun.star.comp.Writer.XMLSettingsImporter"),
            aFilterArgs, rName, false );
    }
 
    nRet = ReadThroughComponent(
        xStorage, xModelComp, "styles.xml", xContext,
        (bOASIS ? "com.sun.star.comp.Writer.XMLOasisStylesImporter"
                : "com.sun.star.comp.Writer.XMLStylesImporter"),
        aFilterArgs, rName, true );
 
    if( !nRet && !(IsOrganizerMode() || m_aOption.IsFormatsOnly()) )
        nRet = ReadThroughComponent(
           xStorage, xModelComp, "content.xml", xContext,
            (bOASIS ? "com.sun.star.comp.Writer.XMLOasisContentImporter"
                    : "com.sun.star.comp.Writer.XMLContentImporter"),
           aFilterArgs, rName, true );
 
    if( !IsOrganizerMode() && !IsBlockMode() && !m_bInsertMode &&
          !m_aOption.IsFormatsOnly() &&
            // sw_redlinehide: disable layout cache for now
          *o3tl::doAccess<bool>(xInfoSet->getPropertyValue(sShowChanges)) &&
            // sw_fieldmarkhide: also disable if there is a fieldmark
          rDoc.getIDocumentMarkAccess()->getFieldmarksCount() == 0)
    {
        try
        {
            uno::Reference < io::XStream > xStm = xStorage->openStreamElement( u"layout-cache"_ustr, embed::ElementModes::READ );
            std::unique_ptr<SvStream> pStrm2 = utl::UcbStreamHelper::CreateStream( xStm );
            if( !pStrm2->GetError() )
                rDoc.ReadLayoutCache( *pStrm2 );
        }
        catch (const uno::Exception&)
        {
        }
    }
 
    // Notify math objects
    if( m_bInsertMode )
        rDoc.PrtOLENotify( false );
    else if ( rDoc.IsOLEPrtNotifyPending() )
        rDoc.PrtOLENotify( true );
 
    if (!nRet)
    {
        if (nWarn)
            nRet = nWarn;
        else if (nWarn2)
            nRet = std::move(nWarn2);
        else
            nRet = nWarnRDF;
    }
 
    ::svx::DropUnusedNamedItems(xModelComp);
 
    m_aOption.ResetAllFormatsOnly();
 
    // redline password
    Any aAny = xInfoSet->getPropertyValue( sRedlineProtectionKey );
    Sequence<sal_Int8> aKey;
    aAny >>= aKey;
    rDoc.getIDocumentRedlineAccess().SetRedlinePassword( aKey );
 
    // restore redline mode from import info property set
    RedlineFlags nRedlineFlags = RedlineFlags::ShowInsert;
    aAny = xInfoSet->getPropertyValue( sShowChanges );
    if ( *o3tl::doAccess<bool>(aAny) )
        nRedlineFlags |= RedlineFlags::ShowDelete;
    aAny = xInfoSet->getPropertyValue( sRecordChanges );
    if ( *o3tl::doAccess<bool>(aAny) || aKey.hasElements() )
        nRedlineFlags |= RedlineFlags::On;
 
    // ... restore redline mode
    // (First set bogus mode to make sure the mode in getIDocumentRedlineAccess().SetRedlineFlags()
    //  is different from its previous mode.)
    rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( ~nRedlineFlags );
    // must set flags to show delete so that CompressRedlines works
    rDoc.getIDocumentRedlineAccess().SetRedlineFlags(nRedlineFlags|RedlineFlags::ShowDelete);
    // tdf#83260 ensure that the first call of CompressRedlines after loading
    // the document is a no-op by calling it now
    rDoc.getIDocumentRedlineAccess().CompressRedlines();
    // can't set it on the layout or view shell because it doesn't exist yet
    rDoc.GetDocumentRedlineManager().SetHideRedlines(!(nRedlineFlags & RedlineFlags::ShowDelete));
 
    lcl_EnsureValidPam( rPaM ); // move Pam into valid content
 
    if( xGraphicHelper )
        xGraphicHelper->dispose();
    xGraphicHelper.clear();
    xGraphicStorageHandler = nullptr;
    if( xObjectHelper )
        xObjectHelper->dispose();
    xObjectHelper.clear();
    xObjectResolver = nullptr;
    aHoldRef.clear();
 
    if ( !bOASIS )
    {
        // #i44177# - assure that for documents in OpenOffice.org
        // file format the relation between outline numbering rule and styles is
        // filled-up accordingly.
        // Note: The OpenOffice.org file format, which has no content that applies
        //       a certain style, which is related to the outline numbering rule,
        //       has lost the information, that this certain style is related to
        //       the outline numbering rule.
        // #i70748# - only for templates
        if ( m_pMedium && m_pMedium->GetFilter() &&
             m_pMedium->GetFilter()->IsOwnTemplateFormat() )
        {
            lcl_AdjustOutlineStylesForOOo( rDoc );
        }
        // Fix #i58251#: Unfortunately is the static default different to SO7 behaviour,
        // so we have to set a dynamic default after importing SO7
        rDoc.SetDefault(SwFormatRowSplit(false));
    }
 
    rDoc.PropagateOutlineRule();
 
    // #i62875#
    if ( rDoc.getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE) && !docfunc::ExistsDrawObjs( rDoc ) )
    {
        rDoc.getIDocumentSettingAccess().set(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE, false);
    }
 
    // Convert all instances of <SdrOle2Obj> into <SdrGrafObj>, because the
    // Writer doesn't support such objects.
    lcl_ConvertSdrOle2ObjsToSdrGrafObjs( rDoc );
 
    // set BuildId on XModel for later OLE object loading
    if( xInfoSet.is() )
    {
        uno::Reference< beans::XPropertySet > xModelSet( xModelComp, uno::UNO_QUERY );
        if( xModelSet.is() )
        {
            uno::Reference< beans::XPropertySetInfo > xModelSetInfo( xModelSet->getPropertySetInfo() );
            static constexpr OUString sName(u"BuildId"_ustr );
            if( xModelSetInfo.is() && xModelSetInfo->hasPropertyByName(sName) )
            {
                xModelSet->setPropertyValue( sName, xInfoSet->getPropertyValue(sName) );
            }
        }
    }
 
    // tdf#115815 restore annotation ranges stored in temporary bookmarks
    rDoc.getIDocumentMarkAccess()->restoreAnnotationMarks();
 
    if (xStatusIndicator.is())
    {
        xStatusIndicator->end();
    }
 
    rDoc.GetIStyleAccess().clearCaches(); // Clear Automatic-Style-Caches(shared_pointer!)
    return nRet;
}
 
    // read the sections of the document, which is equal to the medium.
    // returns the count of it
size_t XMLReader::GetSectionList( SfxMedium& rMedium,
                                  std::vector<OUString>& rStrings) const
{
    const uno::Reference< uno::XComponentContext >& xContext =
            comphelper::getProcessComponentContext();
    uno::Reference < embed::XStorage > xStg2;
    if( ( xStg2 = rMedium.GetStorage() ).is() )
    {
        try
        {
            xml::sax::InputSource aParserInput;
            static constexpr OUString sDocName( u"content.xml"_ustr );
            aParserInput.sSystemId = sDocName;
 
            uno::Reference < io::XStream > xStm = xStg2->openStreamElement( sDocName, embed::ElementModes::READ );
            aParserInput.aInputStream = xStm->getInputStream();
 
            // get filter
            rtl::Reference< SwXMLSectionList > xImport = new SwXMLSectionList( xContext, rStrings );
 
            // parse
            xImport->parseStream( aParserInput );
        }
        catch( xml::sax::SAXParseException&  )
        {
            TOOLS_WARN_EXCEPTION("sw", "");
            // re throw ?
        }
        catch( xml::sax::SAXException&  )
        {
            TOOLS_WARN_EXCEPTION("sw", "");
            // re throw ?
        }
        catch( io::IOException& )
        {
            TOOLS_WARN_EXCEPTION("sw", "");
            // re throw ?
        }
        catch( packages::WrongPasswordException& )
        {
            // re throw ?
        }
    }
    return rStrings.size();
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

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

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

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

V519 The 'aAny' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 885, 890.