diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2020-10-22 17:21:33 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2020-10-27 16:34:44 +0100 |
commit | a613ffd7e353205fb5545e73f84624d0a64460de (patch) | |
tree | 4e75c40966d22d69ef40f1aba9af82dbfe7b94cd | |
parent | ad89e8557e81db6e9eff29cb7a446e734733b268 (diff) |
DOCX import: handle <w:altChunk r:id="..."/>
This refers to a self-contained full DOCX file inside a DOCX file.
(cherry picked from commit 4347d505e7d1c90809dd356334fcdc7936c84f73)
Conflicts:
writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
writerfilter/source/dmapper/DomainMapper_Impl.cxx
writerfilter/source/dmapper/DomainMapper_Impl.hxx
Change-Id: Ic9451833db30231f08ff2e2493da678edbc9a4c6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104885
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r-- | writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx | 21 | ||||
-rw-r--r-- | writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docx | bin | 0 -> 21945 bytes | |||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper.cxx | 12 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 54 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.hxx | 6 |
5 files changed, 90 insertions, 3 deletions
diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx index 00c83c913d96..16d8b1f3b4b0 100644 --- a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx @@ -80,6 +80,27 @@ CPPUNIT_TEST_FIXTURE(Test, testPageBreakFooterTable) // i.e. there was no page break before the last paragraph. CPPUNIT_ASSERT_EQUAL(style::BreakType_PAGE_BEFORE, eType); } + +CPPUNIT_TEST_FIXTURE(Test, testAltChunk) +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "alt-chunk.docx"; + getComponent() = loadFromDesktop(aURL); + uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration(); + uno::Reference<text::XTextRange> xPara; + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("Outer para 1"), xPara->getString()); + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("Outer para 2"), xPara->getString()); + + // Without the accompanying fix in place, this test would have failed with a + // container.NoSuchElementException, as the document had only 2 paragraphs, all the "inner" + // content was lost. + xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(OUString("Inner para 1"), xPara->getString()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docx b/writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docx Binary files differnew file mode 100644 index 000000000000..3348cfd0c04c --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docx diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 6c7af1c34b04..4071a05dafe7 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -160,8 +160,8 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon //import document properties try { - uno::Reference< embed::XStorage > xDocumentStorage = - comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, bRepairStorage ); + m_pImpl->m_xDocumentStorage = comphelper::OStorageHelper::GetStorageOfFormatFromInputStream( + OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, bRepairStorage); uno::Reference< uno::XInterface > xTemp = xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.document.OOXMLDocumentPropertiesImporter", @@ -169,7 +169,8 @@ DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xCon uno::Reference< document::XOOXMLDocumentPropertiesImporter > xImporter( xTemp, uno::UNO_QUERY_THROW ); uno::Reference< document::XDocumentPropertiesSupplier > xPropSupplier( xModel, uno::UNO_QUERY_THROW); - xImporter->importProperties( xDocumentStorage, xPropSupplier->getDocumentProperties() ); + xImporter->importProperties(m_pImpl->m_xDocumentStorage, + xPropSupplier->getDocumentProperties()); } catch( const uno::Exception& ) {} } @@ -1190,6 +1191,11 @@ void DomainMapper::lcl_attribute(Id nName, Value & val) } } break; + case NS_ooxml::LN_CT_AltChunk: + { + m_pImpl->HandleAltChunk(sStringValue); + } + break; default: SAL_WARN("writerfilter", "DomainMapper::lcl_attribute: unhandled token: " << nName); } diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index f2c26fae9672..edb2e348e438 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -73,10 +73,17 @@ #include <com/sun/star/text/XTextColumns.hpp> #include <com/sun/star/awt/CharSet.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/document/XImporter.hpp> +#include <com/sun/star/document/XFilter.hpp> #include <o3tl/temporary.hxx> #include <oox/mathml/import.hxx> #include <rtl/uri.hxx> #include "GraphicHelpers.hxx" +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/streamwrap.hxx> + #include <dmapper/GraphicZOrderHelper.hxx> #include <oox/token/tokens.hxx> @@ -2650,6 +2657,53 @@ void DomainMapper_Impl::ClearPreviousParagraph() m_bFirstParagraphInCell = true; } +void DomainMapper_Impl::HandleAltChunk(const OUString& rStreamName) +{ + try + { + // Create the import filter. + uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory( + comphelper::getProcessServiceFactory()); + uno::Reference<uno::XInterface> xDocxFilter + = xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.WriterFilter"); + + // Set the target document. + uno::Reference<document::XImporter> xImporter(xDocxFilter, uno::UNO_QUERY); + xImporter->setTargetDocument(m_xTextDocument); + + // Set the import parameters. + uno::Reference<embed::XHierarchicalStorageAccess> xStorageAccess(m_xDocumentStorage, + uno::UNO_QUERY); + if (!xStorageAccess.is()) + { + return; + } + // Turn the ZIP stream into a seekable one, as the importer only works with such streams. + uno::Reference<io::XStream> xStream = xStorageAccess->openStreamElementByHierarchicalName( + rStreamName, embed::ElementModes::READ); + std::unique_ptr<SvStream> pStream = utl::UcbStreamHelper::CreateStream(xStream, true); + SvMemoryStream aMemory; + aMemory.WriteStream(*pStream); + uno::Reference<io::XStream> xInputStream = new utl::OStreamWrapper(aMemory); + // Not handling AltChunk during paste for now. + uno::Reference<text::XTextRange> xInsertTextRange = GetCurrentXText()->getEnd(); + uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({ + { "InputStream", uno::Any(xInputStream) }, + { "InsertMode", uno::Any(true) }, + { "TextInsertModeRange", uno::Any(xInsertTextRange) }, + })); + + // Do the actual import. + uno::Reference<document::XFilter> xFilter(xDocxFilter, uno::UNO_QUERY); + xFilter->filter(aDescriptor); + } + catch (const uno::Exception& rException) + { + SAL_WARN("writerfilter", "DomainMapper_Impl::HandleAltChunk: failed to handle alt chunk: " + << rException.Message); + } +} + static sal_Int16 lcl_ParseNumberingType( const OUString& rCommand ) { sal_Int16 nRet = style::NumberingType::PAGE_DESCRIPTOR; diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx index 5d1ed1c4b7cf..588f6f121dfb 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -28,6 +28,7 @@ #include <com/sun/star/style/TabStop.hpp> #include <com/sun/star/container/XNameContainer.hpp> #include <unotools/saveopt.hxx> +#include <com/sun/star/embed/XStorage.hpp> #include <queue> #include <stack> #include <tuple> @@ -1022,6 +1023,11 @@ public: /// start/end node. void ClearPreviousParagraph(); + css::uno::Reference< css::embed::XStorage > m_xDocumentStorage; + + /// Handles <w:altChunk>. + void HandleAltChunk(const OUString& rStreamName); + private: void PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType); // Start a new index section; if needed, finish current paragraph |