diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2020-10-19 17:53:51 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2020-10-20 00:41:26 +0200 |
commit | 326c8d06070a4a41a666db919702f7c423dc7a18 (patch) | |
tree | 6f7d669c5f5cf40cb94c003c6fdbcb7512ba2337 | |
parent | c4cec8647faf130111d67302e75998ddff4c0792 (diff) |
sw reqif-xhtml export, embedded objects: handle non-package Ole10Native stream
Commit 1392fd6a7eaf9f507639096984c2a0108f254795 (sw reqif-xhtml export,
embedded objects: handle Ole10Native stream, 2020-04-30) added support
for handling an OLE1 stream which contains something other than OLE2
data.
However, that assumed a fixed class name ("Package") and a matching
class id. Fix this, similar to how the import side was fixed with commit
247b247dadc8f0133a8eb94f1423a29315cf998a (sw reqif-xhtml import,
embedded objects: handle non-package Ole10Native stream, 2020-10-16).
Change-Id: If2ec9434c802e23e395cf2a6eaf63ad5b1db9c1c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104531
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
-rw-r--r-- | sw/qa/extras/htmlexport/htmlexport.cxx | 247 | ||||
-rw-r--r-- | sw/source/filter/html/htmlreqifreader.cxx | 17 |
2 files changed, 147 insertions, 117 deletions
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index 8ba6b7e4d160..c96c1c8215b1 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -49,6 +49,78 @@ #include <docsh.hxx> #include <unotxdoc.hxx> +namespace +{ +/// Test RTF parser that just extracts a single OLE2 object from a file. +class TestReqIfRtfReader : public SvRTFParser +{ +public: + TestReqIfRtfReader(SvStream& rStream); + void NextToken(int nToken) override; + bool WriteObjectData(SvStream& rOLE); + +private: + bool m_bInObjData = false; + OStringBuffer m_aHex; +}; + +TestReqIfRtfReader::TestReqIfRtfReader(SvStream& rStream) + : SvRTFParser(rStream) +{ +} + +void TestReqIfRtfReader::NextToken(int nToken) +{ + switch (nToken) + { + case '}': + m_bInObjData = false; + break; + case RTF_TEXTTOKEN: + if (m_bInObjData) + m_aHex.append(OUStringToOString(aToken, RTL_TEXTENCODING_ASCII_US)); + break; + case RTF_OBJDATA: + m_bInObjData = true; + break; + } +} + +bool TestReqIfRtfReader::WriteObjectData(SvStream& rOLE) +{ + OString aObjdata = m_aHex.makeStringAndClear(); + + SvMemoryStream aStream; + int b = 0; + int count = 2; + + // Feed the destination text to a stream. + for (int i = 0; i < aObjdata.getLength(); ++i) + { + char ch = aObjdata[i]; + if (ch != 0x0d && ch != 0x0a) + { + b = b << 4; + sal_Int8 parsed = msfilter::rtfutil::AsHex(ch); + if (parsed == -1) + return false; + b += parsed; + count--; + if (!count) + { + aStream.WriteChar(b); + count = 2; + b = 0; + } + } + } + + aStream.Seek(0); + rOLE.WriteStream(aStream); + return true; +} +} + class HtmlExportTest : public SwModelTestBase, public HtmlTestTools { private: @@ -141,8 +213,39 @@ private: /// HTML export of the sw doc model tests. class SwHtmlDomExportTest : public SwModelTestBase, public HtmlTestTools { +public: + /// Get the .ole path, assuming maTempFile is an XHTML export result. + OUString GetOlePath(); + /// Parse the ole1 data out of an RTF fragment URL. + void ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryStream& rOle1); }; +OUString SwHtmlDomExportTest::GetOlePath() +{ + SvMemoryStream aStream; + HtmlExportTest::wrapFragment(maTempFile, aStream); + xmlDocUniquePtr pDoc = parseXmlStream(&aStream); + CPPUNIT_ASSERT(pDoc); + OUString aOlePath = getXPath( + pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object", "data"); + OUString aOleSuffix(".ole"); + CPPUNIT_ASSERT(aOlePath.endsWith(aOleSuffix)); + INetURLObject aUrl(maTempFile.GetURL()); + aUrl.setBase(aOlePath.copy(0, aOlePath.getLength() - aOleSuffix.getLength())); + aUrl.setExtension("ole"); + return aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE); +} + +void SwHtmlDomExportTest::ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryStream& rOle1) +{ + SvMemoryStream aRtf; + HtmlExportTest::wrapRtfFragment(rRtfUrl, aRtf); + tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf)); + CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error); + CPPUNIT_ASSERT(xReader->WriteObjectData(rOle1)); + CPPUNIT_ASSERT(rOle1.Tell()); +} + char const DATA_DIRECTORY[] = "/sw/qa/extras/htmlexport/data/"; DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testFdo81276, "fdo81276.html") @@ -921,78 +1024,6 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifParagraphAlignment) assertXPathNoAttribute(pDoc, "//reqif-xhtml:p", "align"); } -namespace -{ -/// Test RTF parser that just extracts a single OLE2 object from a file. -class TestReqIfRtfReader : public SvRTFParser -{ -public: - TestReqIfRtfReader(SvStream& rStream); - void NextToken(int nToken) override; - bool WriteObjectData(SvStream& rOLE); - -private: - bool m_bInObjData = false; - OStringBuffer m_aHex; -}; - -TestReqIfRtfReader::TestReqIfRtfReader(SvStream& rStream) - : SvRTFParser(rStream) -{ -} - -void TestReqIfRtfReader::NextToken(int nToken) -{ - switch (nToken) - { - case '}': - m_bInObjData = false; - break; - case RTF_TEXTTOKEN: - if (m_bInObjData) - m_aHex.append(OUStringToOString(aToken, RTL_TEXTENCODING_ASCII_US)); - break; - case RTF_OBJDATA: - m_bInObjData = true; - break; - } -} - -bool TestReqIfRtfReader::WriteObjectData(SvStream& rOLE) -{ - OString aObjdata = m_aHex.makeStringAndClear(); - - SvMemoryStream aStream; - int b = 0; - int count = 2; - - // Feed the destination text to a stream. - for (int i = 0; i < aObjdata.getLength(); ++i) - { - char ch = aObjdata[i]; - if (ch != 0x0d && ch != 0x0a) - { - b = b << 4; - sal_Int8 parsed = msfilter::rtfutil::AsHex(ch); - if (parsed == -1) - return false; - b += parsed; - count--; - if (!count) - { - aStream.WriteChar(b); - count = 2; - b = 0; - } - } - } - - aStream.Seek(0); - rOLE.WriteStream(aStream); - return true; -} -} - CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PDF) { // Save to reqif-xhtml. @@ -1005,29 +1036,9 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PDF) comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")), }; xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties); - - // Get the .ole path. - SvMemoryStream aStream; - HtmlExportTest::wrapFragment(maTempFile, aStream); - xmlDocUniquePtr pDoc = parseXmlStream(&aStream); - CPPUNIT_ASSERT(pDoc); - OUString aOlePath = getXPath( - pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object", "data"); - OUString aOleSuffix(".ole"); - CPPUNIT_ASSERT(aOlePath.endsWith(aOleSuffix)); - INetURLObject aUrl(maTempFile.GetURL()); - aUrl.setBase(aOlePath.copy(0, aOlePath.getLength() - aOleSuffix.getLength())); - aUrl.setExtension("ole"); - OUString aRtfUrl = aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE); - - // Parse the ole1 data out of that. - SvMemoryStream aRtf; - HtmlExportTest::wrapRtfFragment(aRtfUrl, aRtf); - tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf)); - CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error); + OUString aRtfUrl = GetOlePath(); SvMemoryStream aOle1; - CPPUNIT_ASSERT(xReader->WriteObjectData(aOle1)); - CPPUNIT_ASSERT(aOle1.Tell()); + ParseOle1FromRtfUrl(aRtfUrl, aOle1); // Check the content of the ole1 data. // Skip ObjectHeader, see [MS-OLEDS] 2.2.4. @@ -1116,6 +1127,30 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1Paint) // i.e. the "Package" clsid was used on the OLE2 storage unconditionally, even for an mspaint // case, which has its own clsid. CPPUNIT_ASSERT_EQUAL(aExpected.GetHexName(), aActual.GetHexName()); + + aStoreProperties = { + comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")), + comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")), + }; + xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties); + OUString aRtfUrl = GetOlePath(); + SvMemoryStream aOle1; + ParseOle1FromRtfUrl(aRtfUrl, aOle1); + + // Check the content of the ole1 data. + // Skip ObjectHeader, see [MS-OLEDS] 2.2.4. + aOle1.Seek(0); + sal_uInt32 nData; + aOle1.ReadUInt32(nData); // OLEVersion + aOle1.ReadUInt32(nData); // FormatID + aOle1.ReadUInt32(nData); // ClassName + CPPUNIT_ASSERT(nData); + OString aClassName = read_uInt8s_ToOString(aOle1, nData - 1); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: PBrush + // - Actual : Package + // i.e. a hardcoded class name was written. + CPPUNIT_ASSERT_EQUAL(OString("PBrush"), aClassName); } CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testMultiParaListItem) @@ -1205,29 +1240,9 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PresDataNoOle2) comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")), }; xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties); - - // Get the .ole path. - SvMemoryStream aStream; - HtmlExportTest::wrapFragment(maTempFile, aStream); - xmlDocUniquePtr pDoc = parseXmlStream(&aStream); - CPPUNIT_ASSERT(pDoc); - OUString aOlePath = getXPath( - pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p/reqif-xhtml:object", "data"); - OUString aOleSuffix(".ole"); - CPPUNIT_ASSERT(aOlePath.endsWith(aOleSuffix)); - INetURLObject aUrl(maTempFile.GetURL()); - aUrl.setBase(aOlePath.copy(0, aOlePath.getLength() - aOleSuffix.getLength())); - aUrl.setExtension("ole"); - OUString aRtfUrl = aUrl.GetMainURL(INetURLObject::DecodeMechanism::NONE); - - // Parse the ole1 data out of the RTF fragment. - SvMemoryStream aRtf; - HtmlExportTest::wrapRtfFragment(aRtfUrl, aRtf); - tools::SvRef<TestReqIfRtfReader> xReader(new TestReqIfRtfReader(aRtf)); - CPPUNIT_ASSERT(xReader->CallParser() != SvParserState::Error); + OUString aRtfUrl = GetOlePath(); SvMemoryStream aOle1; - CPPUNIT_ASSERT(xReader->WriteObjectData(aOle1)); - CPPUNIT_ASSERT(aOle1.Tell()); + ParseOle1FromRtfUrl(aRtfUrl, aOle1); // Check the content of the ole1 data. // Skip ObjectHeader, see [MS-OLEDS] 2.2.4. diff --git a/sw/source/filter/html/htmlreqifreader.cxx b/sw/source/filter/html/htmlreqifreader.cxx index 2e20e84f06b8..e7b4dece4a41 100644 --- a/sw/source/filter/html/htmlreqifreader.cxx +++ b/sw/source/filter/html/htmlreqifreader.cxx @@ -20,6 +20,7 @@ #include <filter/msfilter/msdffimp.hxx> #include <vcl/cvtgrf.hxx> #include <ndole.hxx> +#include <sal/log.hxx> namespace { @@ -155,7 +156,21 @@ OString InsertOLE1HeaderFromOle10NativeStream(const tools::SvRef<SotStorage>& xS sal_uInt32 nOle1Size = 0; xOle1Stream->ReadUInt32(nOle1Size); - OString aClassName("Package"); + OString aClassName; + if (xStorage->GetClassName() == SvGlobalName(0x0003000A, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46)) + { + aClassName = "PBrush"; + } + else + { + if (xStorage->GetClassName() + != SvGlobalName(0x0003000C, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46)) + { + SAL_WARN("sw.html", "InsertOLE1HeaderFromOle10NativeStream: unexpected class id: " + << xStorage->GetClassName().GetHexName()); + } + aClassName = "Package"; + } // Write ObjectHeader, see [MS-OLEDS] 2.2.4. rOle1.Seek(0); |