From 41aa970b3120837ca9cadb12997a53ad322145a4 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Wed, 27 Aug 2014 15:24:37 +0200 Subject: DOCX import: fix handling of embedded DOCX files The problem was that SwXTextEmbeddedObject::getEmbeddedObject() returned an empty reference for those embedded objects, so the HTML filter couldn't extract their content when it wanted to do so. It turns out the reason for this was that the DOCX importer only handled the replacement image + raw native data for the object. Fix this by creating the embedded object with the correct CLSID and import the raw data into the empty embedded document model. This is similar to what is done for XLSX-in-PPTX in oox::drawingml::ShapeExport::WriteOLE2Shape(), just for the import part. Change-Id: Ieb1dcb1774d2d4da00117e3a35160053066c78aa --- writerfilter/source/dmapper/DomainMapper_Impl.cxx | 12 +++- writerfilter/source/dmapper/OLEHandler.cxx | 69 ++++++++++++++++++++++- writerfilter/source/dmapper/OLEHandler.hxx | 16 +++++- 3 files changed, 93 insertions(+), 4 deletions(-) (limited to 'writerfilter') diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 0428c8752520..cbb502454c45 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -1319,8 +1319,13 @@ void DomainMapper_Impl::appendOLE( const OUString& rStreamName, OLEHandlerPtr pO uno::Reference< text::XTextContent > xOLE( m_xTextFactory->createInstance(sEmbeddedService), uno::UNO_QUERY_THROW ); uno::Reference< beans::XPropertySet > xOLEProperties(xOLE, uno::UNO_QUERY_THROW); - xOLEProperties->setPropertyValue(PropertyNameSupplier::GetPropertyNameSupplier().GetName( PROP_STREAM_NAME ), - uno::makeAny( rStreamName )); + OUString aCLSID = pOLEHandler->getCLSID(); + if (aCLSID.isEmpty()) + xOLEProperties->setPropertyValue(PropertyNameSupplier::GetPropertyNameSupplier().GetName( PROP_STREAM_NAME ), + uno::makeAny( rStreamName )); + else + xOLEProperties->setPropertyValue("CLSID", uno::makeAny(OUString(aCLSID))); + awt::Size aSize = pOLEHandler->getSize(); if( !aSize.Width ) aSize.Width = 1000; @@ -1362,6 +1367,9 @@ void DomainMapper_Impl::appendOLE( const OUString& rStreamName, OLEHandlerPtr pO appendTextContent( xOLE, uno::Sequence< beans::PropertyValue >() ); + if (!aCLSID.isEmpty()) + pOLEHandler->importStream(m_xComponentContext, GetTextDocument(), xOLE); + } catch( const uno::Exception& ) { diff --git a/writerfilter/source/dmapper/OLEHandler.cxx b/writerfilter/source/dmapper/OLEHandler.cxx index a0840057d285..a743ceb8afd7 100644 --- a/writerfilter/source/dmapper/OLEHandler.cxx +++ b/writerfilter/source/dmapper/OLEHandler.cxx @@ -24,9 +24,13 @@ #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include @@ -34,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -177,7 +182,7 @@ void OLEHandler::lcl_sprm(Sprm & rSprm) } -void OLEHandler::saveInteropProperties(uno::Reference const& xTextDocument, const OUString& sObjectName) +void OLEHandler::saveInteropProperties(uno::Reference const& xTextDocument, const OUString& sObjectName, const OUString& sOldObjectName) { const OUString sGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG; const OUString sEmbeddingsPropName = "EmbeddedObjects"; @@ -206,6 +211,17 @@ void OLEHandler::saveInteropProperties(uno::Reference const // save ProgID of current object sal_Int32 length = objectsList.getLength(); + + // If we got an "old name", erase that first. + if (!sOldObjectName.isEmpty()) + { + comphelper::SequenceAsHashMap aMap(objectsList); + comphelper::SequenceAsHashMap::iterator it = aMap.find(sOldObjectName); + if (it != aMap.end()) + aMap.erase(it); + objectsList = aMap.getAsConstPropertyValueList(); + } + objectsList.realloc( length + 1 ); objectsList[length].Name = sObjectName; objectsList[length].Value = uno::Any( aGrabBagAttribute ); @@ -224,6 +240,56 @@ void OLEHandler::saveInteropProperties(uno::Reference const xDocProps->setPropertyValue( sGrabBagPropName, uno::Any( aGrabBag ) ); } +void OLEHandler::importStream(uno::Reference xComponentContext, uno::Reference xTextDocument, uno::Reference xOLE) +{ + OUString aFilterService, aFilterName; + if (m_sProgId == "Word.Document.12") + { + aFilterService = "com.sun.star.comp.Writer.WriterFilter"; + aFilterName = "writer_MS_Word_2007"; + } + + if (!m_xInputStream.is() || aFilterService.isEmpty()) + return; + + // Create the filter service. + uno::Reference xInterface = xComponentContext->getServiceManager()->createInstanceWithContext(aFilterService, xComponentContext); + + // Initialize it. + uno::Sequence aArgs(1); + aArgs[0].Name = "Type"; + aArgs[0].Value <<= OUString(aFilterName); + uno::Sequence aAnySeq(1); + aAnySeq[0] <<= aArgs; + uno::Reference xInitialization(xInterface, uno::UNO_QUERY); + xInitialization->initialize(aAnySeq); + + // Set target document. + uno::Reference xImporter(xInterface, uno::UNO_QUERY); + uno::Reference xSupplier(xOLE, uno::UNO_QUERY); + uno::Reference xEmbeddedObject(xSupplier->getEmbeddedObject(), uno::UNO_QUERY); + xImporter->setTargetDocument( xEmbeddedObject ); + + // Import the input stream. + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["InputStream"] <<= m_xInputStream; + uno::Reference xFilter(xInterface, uno::UNO_QUERY); + xFilter->filter(aMediaDescriptor.getAsConstPropertyValueList()); + + // Now that the data is imported, update the (typically) changed stream name. + uno::Reference xPropertySet(xOLE, uno::UNO_QUERY); + saveInteropProperties(xTextDocument, xPropertySet->getPropertyValue("StreamName").get(), m_aURL); +} + +OUString OLEHandler::getCLSID() +{ + OUString aRet; + + if (m_sProgId == "Word.Document.12") + aRet = "8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6"; + + return aRet; +} OUString OLEHandler::copyOLEOStream( uno::Reference const& xTextDocument) @@ -267,6 +333,7 @@ OUString OLEHandler::copyOLEOStream( } uno::Reference< lang::XComponent > xComp( xEmbeddedResolver, uno::UNO_QUERY_THROW ); xComp->dispose(); + m_aURL = aURL; } catch( const uno::Exception& ) { diff --git a/writerfilter/source/dmapper/OLEHandler.hxx b/writerfilter/source/dmapper/OLEHandler.hxx index 2c9695528375..64677bb560a0 100644 --- a/writerfilter/source/dmapper/OLEHandler.hxx +++ b/writerfilter/source/dmapper/OLEHandler.hxx @@ -34,8 +34,12 @@ namespace com{ namespace sun{ namespace star{ class XInputStream; } namespace text{ + class XTextContent; class XTextDocument; } + namespace uno { + class XComponentContext; + } }}} namespace writerfilter { namespace dmapper @@ -51,6 +55,8 @@ class OLEHandler : public LoggedProperties OUString m_sDrawAspect; OUString m_sObjectId; OUString m_sr_id; + /// The stream URL right after the import of the raw data. + OUString m_aURL; sal_Int32 m_nDxaOrig; sal_Int32 m_nDyaOrig; @@ -72,7 +78,7 @@ class OLEHandler : public LoggedProperties // Interoperability virtual void saveInteropProperties( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextDocument > const& xTextDocument, - const OUString& sObjectName ); + const OUString& sObjectName, const OUString& sOldObjectName = OUString() ); public: OLEHandler(DomainMapper& rDomainMapper); @@ -82,6 +88,14 @@ public: inline bool isOLEObject( ) { return m_xInputStream.is( ); }; + /// In case of a valid CLSID, import the native data to the previously created empty OLE object. + void importStream(css::uno::Reference xComponentContext, + css::uno::Reference xTextDocument, + css::uno::Reference xOLE); + + /// Get the CLSID of the OLE object, in case we can find one based on m_sProgId. + OUString getCLSID(); + OUString copyOLEOStream( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextDocument > const & xTextDocument ); ::com::sun::star::awt::Size getSize() const { return m_aShapeSize;} -- cgit v1.2.3