include/svtools/HtmlWriter.hxx | 4 +++ svtools/qa/unit/testHtmlWriter.cxx | 38 +++++++++++++++++++++++++++++++++++ svtools/source/svhtml/HtmlWriter.cxx | 30 +++++++++++++++++++++++---- 3 files changed, 67 insertions(+), 5 deletions(-)
New commits: commit c4c7d967588b2efbb60f89d80d911c87277a347b Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Jun 24 16:07:15 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jun 27 15:04:37 2022 +0200 sw HTML export: fix missing escaping for image links Hyperlink URLs on images are currently written to the HTML output as-is, without any any encoding. Image links are written using HtmlWriter from svtools, which has the advantage of not building the markup manually (similar to sax_fastparser::FastSerializerHelper for XML), but that doesn't do any escaping. Some other parts of the HTML export build the export markup manually, but use HTMLOutFuncs::Out_String() to encode problematic content. Fix the problem by using HTMLOutFuncs::Out_String() in HtmlWriter for attribute values: it seems reasonable to assume that users of HtmlWriter would pass in unencoded strings, similar to how the sax serializer works. This could lead to double-encoding in case some user of HtmlWriter::attribute() would encode its attribute value already, but inspecting existing calls, none of the clients seem to do that at the moment. (cherry picked from commit 167a5ce786b0561028ad42ea3fc92e55d14484a4) Change-Id: I5439e829b1b837cb9c51292b118f0b47e84197db diff --git a/svtools/qa/unit/testHtmlWriter.cxx b/svtools/qa/unit/testHtmlWriter.cxx index 70045ba8a50b..9328347f6ff4 100644 --- a/svtools/qa/unit/testHtmlWriter.cxx +++ b/svtools/qa/unit/testHtmlWriter.cxx @@ -200,6 +200,27 @@ CPPUNIT_TEST_FIXTURE(Test, testExactElementEnd) CPPUNIT_ASSERT_EQUAL(OString("<start><a/><b/></start>"), aString); } +CPPUNIT_TEST_FIXTURE(Test, testAttributeValueEncode) +{ + // Given a HTML writer: + SvMemoryStream aStream; + HtmlWriter aHtml(aStream); + aHtml.prettyPrint(false); + + // When writing an attribute with a value that needs encoding: + aHtml.start("element"); + aHtml.attribute("attribute", "a&b"); + aHtml.end(); + + // Then make sure that the encoding is performed: + OString aString = extractFromStream(aStream); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: <element attribute="a&b"/> + // - Actual : <element attribute="a&b"/> + // i.e. attribute value was not encoded in HTML, but it was in e.g. XML. + CPPUNIT_ASSERT_EQUAL(OString("<element attribute=\"a&b\"/>"), aString); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/svhtml/HtmlWriter.cxx b/svtools/source/svhtml/HtmlWriter.cxx index 875da0a724ca..9010564d986f 100644 --- a/svtools/source/svhtml/HtmlWriter.cxx +++ b/svtools/source/svhtml/HtmlWriter.cxx @@ -11,6 +11,7 @@ #include <svtools/HtmlWriter.hxx> #include <tools/stream.hxx> #include <sal/log.hxx> +#include <svtools/htmlout.hxx> HtmlWriter::HtmlWriter(SvStream& rStream, const OString& rNamespace) : mrStream(rStream), @@ -127,7 +128,7 @@ void HtmlWriter::writeAttribute(SvStream& rStream, const OString& aAttribute, co rStream.WriteOString(aAttribute); rStream.WriteChar('='); rStream.WriteChar('"'); - rStream.WriteOString(aValue); + HTMLOutFuncs::Out_String(rStream, OStringToOUString(aValue, RTL_TEXTENCODING_UTF8), RTL_TEXTENCODING_UTF8); rStream.WriteChar('"'); } commit 12248c17f2ec0e61a85b1b2fc1715ffb2868eba9 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon May 31 21:14:41 2021 +0900 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Jun 27 14:29:07 2022 +0200 HtmlWriter: add end tag checking and helper for attribute writing Added an input variable to end to enter the name of which variable is ending. This is to check that the expected end tag is actually written. Added writeAttribute, which is independent from HtmlWriter and just writes the HTML attribute format to the stream. (cherry picked from commit 685c8db519b022f879cf575ec763d00de98906a3) Conflicts: include/svtools/HtmlWriter.hxx svtools/source/svhtml/HtmlWriter.cxx Change-Id: Ib00a4a37354cd1cb1781ba729ed4046a966e1eb1 diff --git a/include/svtools/HtmlWriter.hxx b/include/svtools/HtmlWriter.hxx index 49f2aa6c02f2..007668b6018f 100644 --- a/include/svtools/HtmlWriter.hxx +++ b/include/svtools/HtmlWriter.hxx @@ -39,10 +39,14 @@ public: void start(const OString& aElement); + bool end(const OString& aElement); void end(); void flushStack(); + static void writeAttribute(SvStream& rStream, const OString& aAttribute, sal_Int32 aValue); + static void writeAttribute(SvStream& rStream, const OString& aAttribute, const OString& aValue); + void attribute(const OString& aAttribute, const char* aValue); void attribute(const OString& aAttribute, sal_Int32 aValue); void attribute(const OString& aAttribute, const OString& aValue); diff --git a/svtools/qa/unit/testHtmlWriter.cxx b/svtools/qa/unit/testHtmlWriter.cxx index 773da64c4891..70045ba8a50b 100644 --- a/svtools/qa/unit/testHtmlWriter.cxx +++ b/svtools/qa/unit/testHtmlWriter.cxx @@ -183,6 +183,23 @@ CPPUNIT_TEST_FIXTURE(Test, testCharacters) CPPUNIT_ASSERT_EQUAL(OString("<abc>hello</abc>"), aString); } +CPPUNIT_TEST_FIXTURE(Test, testExactElementEnd) +{ + SvMemoryStream aStream; + + HtmlWriter aHtml(aStream); + aHtml.prettyPrint(false); + aHtml.start("start"); + aHtml.start("a"); + CPPUNIT_ASSERT(aHtml.end("a")); + aHtml.start("b"); + CPPUNIT_ASSERT(!aHtml.end("c")); + CPPUNIT_ASSERT(aHtml.end("start")); + + OString aString = extractFromStream(aStream); + CPPUNIT_ASSERT_EQUAL(OString("<start><a/><b/></start>"), aString); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svtools/source/svhtml/HtmlWriter.cxx b/svtools/source/svhtml/HtmlWriter.cxx index 7414b40b15b5..875da0a724ca 100644 --- a/svtools/source/svhtml/HtmlWriter.cxx +++ b/svtools/source/svhtml/HtmlWriter.cxx @@ -10,6 +10,7 @@ #include <svtools/HtmlWriter.hxx> #include <tools/stream.hxx> +#include <sal/log.hxx> HtmlWriter::HtmlWriter(SvStream& rStream, const OString& rNamespace) : mrStream(rStream), @@ -80,6 +81,14 @@ void HtmlWriter::flushStack() } } +bool HtmlWriter::end(const OString& aElement) +{ + bool bExpected = maElementStack.back() == aElement; + SAL_WARN_IF(!bExpected, "svtools", "HtmlWriter: end element mismatch - '" << aElement << "' expected '" << maElementStack.back() << "'"); + end(); + return bExpected; +} + void HtmlWriter::end() { if (mbElementOpen && !mbCharactersWritten) @@ -108,16 +117,26 @@ void HtmlWriter::end() mbCharactersWritten = false; } +void HtmlWriter::writeAttribute(SvStream& rStream, const OString& aAttribute, sal_Int32 aValue) +{ + writeAttribute(rStream, aAttribute, OString::number(aValue)); +} + +void HtmlWriter::writeAttribute(SvStream& rStream, const OString& aAttribute, const OString& aValue) +{ + rStream.WriteOString(aAttribute); + rStream.WriteChar('='); + rStream.WriteChar('"'); + rStream.WriteOString(aValue); + rStream.WriteChar('"'); +} + void HtmlWriter::attribute(const OString &aAttribute, const OString& aValue) { if (mbElementOpen && !aAttribute.isEmpty() && !aValue.isEmpty()) { mrStream.WriteChar(' '); - mrStream.WriteOString(aAttribute); - mrStream.WriteChar('='); - mrStream.WriteChar('"'); - mrStream.WriteOString(aValue); - mrStream.WriteChar('"'); + writeAttribute(mrStream, aAttribute, aValue); } }