summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-05-04 10:48:07 +0200
committerMiklos Vajna <vmiklos@collabora.com>2020-05-04 16:59:37 +0200
commit2059ea2a92f73cc8ea4bcf9bad833132c8f4c39c (patch)
tree595be6c2aa443368c2c5166f3851baaae0cb2e81
parentba8768e43fe357f2049659b6fc1ef6c13a1c74ef (diff)
sw reqif-xhtml import, embedded objects: handle Ole10Native stream
This is the import side of commit 1392fd6a7eaf9f507639096984c2a0108f254795 (sw reqif-xhtml export, embedded objects: handle Ole10Native stream, 2020-04-30). (cherry picked from commit 800085d4fb0831f2065e86bfd99164cd89998fcd) Conflicts: filter/source/msfilter/rtfutil.cxx sw/CppunitTest_sw_htmlexport.mk Change-Id: Ib98620f06c471a58e75b0e6c0230d37820dbc928
-rw-r--r--filter/source/msfilter/rtfutil.cxx86
-rw-r--r--sw/CppunitTest_sw_htmlexport.mk1
-rw-r--r--sw/qa/extras/htmlexport/htmlexport.cxx31
3 files changed, 114 insertions, 4 deletions
diff --git a/filter/source/msfilter/rtfutil.cxx b/filter/source/msfilter/rtfutil.cxx
index ee7b4c7b74bc..497554163b8d 100644
--- a/filter/source/msfilter/rtfutil.cxx
+++ b/filter/source/msfilter/rtfutil.cxx
@@ -15,6 +15,68 @@
#include <tools/stream.hxx>
#include <unotools/streamwrap.hxx>
#include <vector>
+#include <sot/stg.hxx>
+#include <sot/storage.hxx>
+
+namespace
+{
+/// If rOle1 is native OLE1 data of size nOle1Size, wraps it in an OLE2 container.
+void WrapOle1InOle2(SvStream& rOle1, sal_uInt32 nOle1Size, SvStream& rOle2)
+{
+ tools::SvRef<SotStorage> pStorage = new SotStorage(rOle2);
+ // OLE Package Object
+ SvGlobalName aName(0x0003000C, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46);
+ pStorage->SetClass(aName, SotClipboardFormatId::NONE, "");
+
+ // [MS-OLEDS] 2.3.7 CompObjHeader
+ tools::SvRef<SotStorageStream> pCompObj = pStorage->OpenSotStream("\1CompObj");
+ // Reserved1
+ pCompObj->WriteUInt32(0xfffe0001);
+ // Version
+ pCompObj->WriteUInt32(0x00000a03);
+ // Reserved2
+ pCompObj->WriteUInt32(0xffffffff);
+ pCompObj->WriteUInt32(0x0003000c);
+ pCompObj->WriteUInt32(0x00000000);
+ pCompObj->WriteUInt32(0x000000c0);
+ pCompObj->WriteUInt32(0x46000000);
+ // Rest of CompObjStream
+ // AnsiUserType
+ OString aAnsiUserType("OLE Package");
+ pCompObj->WriteUInt32(aAnsiUserType.getLength() + 1);
+ pCompObj->WriteOString(aAnsiUserType);
+ pCompObj->WriteChar(0);
+ // AnsiClipboardFormat
+ pCompObj->WriteUInt32(0x00000000);
+ // Reserved1
+ OString aReserved1("Package");
+ pCompObj->WriteUInt32(aReserved1.getLength() + 1);
+ pCompObj->WriteOString(aReserved1);
+ pCompObj->WriteChar(0);
+ // UnicodeMarker
+ pCompObj->WriteUInt32(0x71B239F4);
+ // UnicodeUserType
+ pCompObj->WriteUInt32(0x00000000);
+ // UnicodeClipboardFormat
+ pCompObj->WriteUInt32(0x00000000);
+ // Reserved2
+ pCompObj->WriteUInt32(0x00000000);
+ pCompObj->Commit();
+ pCompObj.clear();
+
+ // [MS-OLEDS] 2.3.6 OLENativeStream
+ tools::SvRef<SotStorageStream> pOleNative = pStorage->OpenSotStream("\1Ole10Native");
+ // NativeDataSize
+ pOleNative->WriteUInt32(nOle1Size);
+ pOleNative->WriteStream(rOle1, nOle1Size);
+ pOleNative->Commit();
+ pOleNative.clear();
+
+ pStorage->Commit();
+ pStorage.clear();
+ rOle2.Seek(0);
+}
+}
namespace msfilter
{
@@ -277,10 +339,26 @@ bool ExtractOLE2FromObjdata(const OString& rObjdata, SvStream& rOle2)
if (nData)
{
- // NativeData
- std::vector<char> aBuffer(nData);
- aStream.ReadBytes(aBuffer.data(), aBuffer.size());
- rOle2.WriteBytes(aBuffer.data(), aBuffer.size());
+ sal_uInt64 nPos = aStream.Tell();
+ sal_uInt8 aSignature[8];
+ aStream.ReadBytes(aSignature, SAL_N_ELEMENTS(aSignature));
+ aStream.Seek(nPos);
+ const sal_uInt8 aOle2Signature[8] = { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
+ // Don't use Storage::IsStorageFile() here, that would seek to the start of the stream,
+ // where the magic will always mismatch.
+ if (std::memcmp(aSignature, aOle2Signature, SAL_N_ELEMENTS(aSignature)) == 0)
+ {
+ // NativeData
+ std::vector<char> aBuffer(nData);
+ aStream.ReadBytes(aBuffer.data(), aBuffer.size());
+ rOle2.WriteBytes(aBuffer.data(), aBuffer.size());
+ }
+ else
+ {
+ SvMemoryStream aStorage;
+ WrapOle1InOle2(aStream, nData, aStorage);
+ rOle2.WriteStream(aStorage);
+ }
rOle2.Seek(0);
}
}
diff --git a/sw/CppunitTest_sw_htmlexport.mk b/sw/CppunitTest_sw_htmlexport.mk
index a464e571b27f..0d8cd44f4619 100644
--- a/sw/CppunitTest_sw_htmlexport.mk
+++ b/sw/CppunitTest_sw_htmlexport.mk
@@ -23,6 +23,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_htmlexport, \
msfilter \
sal \
sfx \
+ sot \
svt \
sw \
test \
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 4cc9ea879238..b19a6bf3ad19 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -34,6 +34,7 @@
#include <rtl/strbuf.hxx>
#include <svtools/rtftoken.h>
#include <filter/msfilter/rtfutil.hxx>
+#include <sot/storage.hxx>
class HtmlExportTest : public SwModelTestBase, public HtmlTestTools
{
@@ -1045,6 +1046,36 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PDF)
// i.e. we did not work with the Ole10Native stream, rather created an OLE1 wrapper around the
// OLE1-in-OLE2 data, resulting in additional size.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0x99ed), nData);
+
+ // Now import this back and check the ODT result.
+ mxComponent->dispose();
+ mxComponent.clear();
+ uno::Sequence<beans::PropertyValue> aLoadProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ };
+ mxComponent
+ = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument", aLoadProperties);
+ xStorable.set(mxComponent, uno::UNO_QUERY);
+ utl::TempFile aTempFile;
+ aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("writer8")),
+ };
+ xStorable->storeToURL(aTempFile.GetURL(), aStoreProperties);
+ uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+ = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
+ aTempFile.GetURL());
+ uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName("Object 2"),
+ uno::UNO_QUERY);
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+ tools::SvRef<SotStorage> pStorage = new SotStorage(*pStream);
+ tools::SvRef<SotStorageStream> pOleNative = pStorage->OpenSotStream("\1Ole10Native");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 39409
+ // - Actual : 0
+ // i.e. we didn't handle the case when the ole1 payload was not an ole2 container. Note how the
+ // expected value is the same as nData above + 4 bytes, since this data is length-prefixed.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(39409), pOleNative->GetSize());
}
CPPUNIT_PLUGIN_IMPLEMENT();