fdo#68724: sw: fix crash on Insert->File with Hybrid PDF

This is an unfortunate combination of 2 special cases:
- the Hybrid PDF has its own XFilter implementation to extract the
  embedded ODF document
- Writer needs to create a SwReader with SwPaM for Insert

Since the PDF XFilter uses a special service in sfx2 to implement
the import, handling this requires a new method in SfxObjectShell
that calls back into Writer to create the properly setup SwReader.

Change-Id: Ie85f3bfa322bfe883c479e1cb198a8bf0cbbac23
diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx
index fac2625..de041fbf 100644
--- a/include/sfx2/objsh.hxx
+++ b/include/sfx2/objsh.hxx
@@ -116,6 +116,9 @@ namespace com { namespace sun { namespace star {
    namespace lang {
        class XComponent;
    }
    namespace text {
        class XTextRange;
    }
} } }

typedef sal_uInt32 SfxObjectShellFlags;
@@ -348,7 +351,12 @@ public:
                                    sal_Bool bForceNonModified = sal_False );
    sal_Bool                    SaveCompletedChildren( sal_Bool bSuccess );

    virtual sal_Bool            ImportFrom( SfxMedium &rMedium, bool bInsert );
    /** a very special case to insert at a position in Writer from UNO,
        via OwnSubFilterService */
    virtual bool                InsertGeneratedStream(SfxMedium& rMedium,
            css::uno::Reference<css::text::XTextRange> const& xInsertPosition);
    virtual bool                ImportFrom( SfxMedium &rMedium,
            css::uno::Reference<css::text::XTextRange> const& xInsertPosition);
    sal_Bool                    ExportTo( SfxMedium &rMedium );

    // xmlsec05, check with SFX team
diff --git a/sd/source/ui/docshell/docshel4.cxx b/sd/source/ui/docshell/docshel4.cxx
index 04fcf2a..eeae100 100644
--- a/sd/source/ui/docshell/docshel4.cxx
+++ b/sd/source/ui/docshell/docshel4.cxx
@@ -375,9 +375,10 @@ sal_Bool DrawDocShell::LoadFrom( SfxMedium& rMedium )
/**
 * load from 3rd party format
 */
sal_Bool DrawDocShell::ImportFrom( SfxMedium &rMedium, bool bInsert )
bool DrawDocShell::ImportFrom(SfxMedium &rMedium,
        uno::Reference<text::XTextRange> const& xInsertPosition)
{
    const sal_Bool bRet=SfxObjectShell::ImportFrom(rMedium, bInsert);
    const sal_Bool bRet = SfxObjectShell::ImportFrom(rMedium, xInsertPosition);

    SfxItemSet* pSet = rMedium.GetItemSet();
    if( pSet )
diff --git a/sd/source/ui/inc/DrawDocShell.hxx b/sd/source/ui/inc/DrawDocShell.hxx
index 5278fc6..d4e46fc 100644
--- a/sd/source/ui/inc/DrawDocShell.hxx
+++ b/sd/source/ui/inc/DrawDocShell.hxx
@@ -76,7 +76,9 @@ public:
    virtual void            Activate( sal_Bool bMDI );
    virtual void            Deactivate( sal_Bool bMDI );
    virtual sal_Bool            InitNew( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage );
    virtual sal_Bool        ImportFrom( SfxMedium &rMedium, bool bInsert=false );
    virtual bool            ImportFrom(SfxMedium &rMedium,
            css::uno::Reference<css::text::XTextRange> const& xInsertPosition)
        SAL_OVERRIDE;
    virtual sal_Bool            ConvertFrom( SfxMedium &rMedium );
    virtual sal_Bool            Save();
    virtual sal_Bool            SaveAsOwnFormat( SfxMedium& rMedium );
diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx
index 125edca..df12f4f 100644
--- a/sfx2/source/doc/objstor.cxx
+++ b/sfx2/source/doc/objstor.cxx
@@ -66,6 +66,7 @@
#include <com/sun/star/io/XTruncate.hpp>
#include <com/sun/star/util/XModifiable.hpp>
#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
#include <com/sun/star/text/XTextRange.hpp>
#include <com/sun/star/xml/crypto/CipherID.hpp>
#include <com/sun/star/xml/crypto/DigestID.hpp>

@@ -548,7 +549,7 @@ sal_Bool SfxObjectShell::DoInitNew( SfxMedium* pMed )

sal_Bool SfxObjectShell::ImportFromGeneratedStream_Impl(
                    const uno::Reference< io::XStream >& xStream,
                    const uno::Sequence< beans::PropertyValue >& aMediaDescr )
                    const uno::Sequence< beans::PropertyValue >& rMediaDescr )
{
    if ( !xStream.is() )
        return sal_False;
@@ -572,22 +573,38 @@ sal_Bool SfxObjectShell::ImportFromGeneratedStream_Impl(
            pMedium->SetStorage_Impl( xStorage );

        SfxAllItemSet aSet( SFX_APP()->GetPool() );
        TransformParameters( SID_OPENDOC, aMediaDescr, aSet );
        TransformParameters( SID_OPENDOC, rMediaDescr, aSet );
        pMedium->GetItemSet()->Put( aSet );
        pMedium->CanDisposeStorage_Impl( sal_False );

        // allow the subfilter to reinit the model
        if ( pImp->m_bIsInit )
            pImp->m_bIsInit = sal_False;

        if ( LoadOwnFormat( *pMedium ) )
        uno::Reference<text::XTextRange> xInsertTextRange;
        for (sal_Int32 i = 0; i < rMediaDescr.getLength(); ++i)
        {
            bHasName = sal_True;
            if ( !IsReadOnly() && IsLoadReadonly() )
                SetReadOnlyUI();
            if (rMediaDescr[i].Name == "TextInsertModeRange")
            {
                rMediaDescr[i].Value >>= xInsertTextRange;
            }
        }

            bResult = sal_True;
            OSL_ENSURE( pImp->m_xDocStorage == xStorage, "Wrong storage is used!\n" );
        if (xInsertTextRange.is())
        {
            bResult = InsertGeneratedStream(*pMedium, xInsertTextRange);
        }
        else
        {

            // allow the subfilter to reinit the model
            if ( pImp->m_bIsInit )
                pImp->m_bIsInit = sal_False;

            if ( LoadOwnFormat( *pMedium ) )
            {
                bHasName = sal_True;
                if ( !IsReadOnly() && IsLoadReadonly() )
                    SetReadOnlyUI();

                bResult = sal_True;
                OSL_ENSURE( pImp->m_xDocStorage == xStorage, "Wrong storage is used!\n" );
            }
        }

        // now the medium can be disconnected from the storage
@@ -748,7 +765,7 @@ sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed )
                {
                    bSetProperty = false;
                }
                bOk = ImportFrom( *pMedium, false );
                bOk = ImportFrom(*pMedium, 0);
                if(bSetProperty)
                {
                    try
@@ -2160,7 +2177,8 @@ sal_Bool SfxObjectShell::ConvertFrom
    return sal_False;
}

sal_Bool SfxObjectShell::ImportFrom( SfxMedium& rMedium, bool bInsert )
bool SfxObjectShell::ImportFrom(SfxMedium& rMedium,
        css::uno::Reference<css::text::XTextRange> const& xInsertPosition)
{
    OUString aFilterName( rMedium.GetFilter()->GetFilterName() );

@@ -2242,10 +2260,13 @@ sal_Bool SfxObjectShell::ImportFrom( SfxMedium& rMedium, bool bInsert )
            aArgs[nEnd-1].Value <<= rMedium.GetBaseURL();
        }

        if ( bInsert ) {
        if (xInsertPosition.is()) {
            aArgs.realloc( ++nEnd );
            aArgs[nEnd-1].Name = "InsertMode";
            aArgs[nEnd-1].Value <<= (sal_Bool) sal_True;
            aArgs.realloc( ++nEnd );
            aArgs[nEnd-1].Name = "TextInsertModeRange";
            aArgs[nEnd-1].Value <<= xInsertPosition;
        }

        // #i119492# During loading, some OLE objects like chart will be set
@@ -3603,6 +3624,15 @@ void SfxObjectShell::UpdateLinks()
bool SfxObjectShell::LoadExternal( SfxMedium& )
{
    // Not implemented. It's an error if the code path ever comes here.
    assert(false);
    return false;
}

bool SfxObjectShell::InsertGeneratedStream(SfxMedium&,
        uno::Reference<text::XTextRange> const&)
{
    // Not implemented. It's an error if the code path ever comes here.
    assert(false);
    return false;
}

diff --git a/sw/inc/docsh.hxx b/sw/inc/docsh.hxx
index 2670603..f8f60bf 100644
--- a/sw/inc/docsh.hxx
+++ b/sw/inc/docsh.hxx
@@ -93,6 +93,9 @@ class SW_DLLPUBLIC SwDocShell: public SfxObjectShell, public SfxListener

    SW_DLLPRIVATE virtual sal_uInt16            PrepareClose( sal_Bool bUI = sal_True, sal_Bool bForBrowsing = sal_False );

    SW_DLLPRIVATE virtual bool     InsertGeneratedStream(SfxMedium& rMedium,
            css::uno::Reference<css::text::XTextRange> const& xInsertPosition)
        SAL_OVERRIDE;

    /// Make DocInfo known to the Doc.
    SW_DLLPRIVATE virtual SfxDocumentInfoDialog* CreateDocumentInfoDialog(
diff --git a/sw/source/ui/app/docsh.cxx b/sw/source/ui/app/docsh.cxx
index e4f9533..e96af96 100644
--- a/sw/source/ui/app/docsh.cxx
+++ b/sw/source/ui/app/docsh.cxx
@@ -106,6 +106,7 @@
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>

#include <unomid.h>
#include <unotextrange.hxx>

#include <sfx2/Metadatable.hxx>
#include <switerator.hxx>
@@ -124,6 +125,22 @@ TYPEINIT2(SwDocShell, SfxObjectShell, SfxListener);

SFX_IMPL_OBJECTFACTORY(SwDocShell, SvGlobalName(SO3_SW_CLASSID), SFXOBJECTSHELL_STD_NORMAL|SFXOBJECTSHELL_HASMENU, "swriter"  )

bool SwDocShell::InsertGeneratedStream(SfxMedium & rMedium,
        uno::Reference<text::XTextRange> const& xInsertPosition)
{
    SwUnoInternalPaM aPam(*GetDoc()); // must have doc since called from SwView
    if (!::sw::XTextRangeToSwPaM(aPam, xInsertPosition))
        return false;
    // similar to SwView::InsertMedium
    SwReader *pReader(0);
    Reader *const pRead = StartConvertFrom(rMedium, &pReader, 0, &aPam);
    if (!pRead)
        return false;
    sal_uLong const nError = pReader->Read(*pRead);
    delete pReader;
    return 0 == nError;
}

// Prepare loading
Reader* SwDocShell::StartConvertFrom(SfxMedium& rMedium, SwReader** ppRdr,
                                    SwCrsrShell *pCrsrShell,
diff --git a/sw/source/ui/uiview/view2.cxx b/sw/source/ui/uiview/view2.cxx
index ecfaa89..06ea67f 100644
--- a/sw/source/ui/uiview/view2.cxx
+++ b/sw/source/ui/uiview/view2.cxx
@@ -131,6 +131,7 @@
#include <fmthdft.hxx>
#include <svx/ofaitem.hxx>
#include <unomid.h>
#include <unotextrange.hxx>
#include <docstat.hxx>
#include <wordcountdialog.hxx>

@@ -2150,7 +2151,11 @@ long SwView::InsertMedium( sal_uInt16 nSlotId, SfxMedium* pMedium, sal_Int16 nVe
                    else
                    {
                        ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
                        nErrno = pDocSh->ImportFrom( *pMedium, true ) ? 0 : ERR_SWG_READ_ERROR;
                        uno::Reference<text::XTextRange> const xInsertPosition(
                            SwXTextRange::CreateXTextRange(*pDoc,
                                *m_pWrtShell->GetCrsr()->GetPoint(), 0));
                        nErrno = pDocSh->ImportFrom(*pMedium, xInsertPosition)
                                    ? 0 : ERR_SWG_READ_ERROR;
                    }

                }