summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-10-19 17:53:51 +0200
committerMiklos Vajna <vmiklos@collabora.com>2020-10-20 10:32:39 +0200
commite79d02c89448b954ecb96a3e390d244f0353dabf (patch)
tree795374d7f7f404a6e984c80e957409ea82687e96
parent3a2b9e680bd074b680d7896de5011337c3af53bd (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). (cherry picked from commit 326c8d06070a4a41a666db919702f7c423dc7a18) Change-Id: If2ec9434c802e23e395cf2a6eaf63ad5b1db9c1c
-rw-r--r--sw/qa/extras/htmlexport/htmlexport.cxx247
-rw-r--r--sw/source/filter/html/htmlreqifreader.cxx17
2 files changed, 147 insertions, 117 deletions
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 25ef00eaa93b..e2a7e5eb6a60 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -39,6 +39,78 @@
#include <sot/storage.hxx>
#include <svl/eitem.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:
@@ -131,8 +203,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")
@@ -904,78 +1007,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.
@@ -988,29 +1019,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.
@@ -1099,6 +1110,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)
@@ -1188,29 +1223,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 26119adfed46..938d71efd5c5 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(tools::SvRef<SotStorage>& xStorage
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);