summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-10-22 17:21:33 +0200
committerMiklos Vajna <vmiklos@collabora.com>2020-10-27 16:34:44 +0100
commita613ffd7e353205fb5545e73f84624d0a64460de (patch)
tree4e75c40966d22d69ef40f1aba9af82dbfe7b94cd
parentad89e8557e81db6e9eff29cb7a446e734733b268 (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.cxx21
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docxbin0 -> 21945 bytes
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx12
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx54
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.hxx6
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
new file mode 100644
index 000000000000..3348cfd0c04c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docx
Binary files differ
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