[1/8] webservices: Escape XML special characters where needed.

Hans Leidekker hans at codeweavers.com
Wed Sep 28 05:37:59 CDT 2016


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/tests/writer.c | 175 ++++++++++++++++++++++++++++++++++------
 dlls/webservices/writer.c       |  67 +++++++++++++--
 2 files changed, 213 insertions(+), 29 deletions(-)

diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c
index 80b9f43..326aed2 100644
--- a/dlls/webservices/tests/writer.c
+++ b/dlls/webservices/tests/writer.c
@@ -441,7 +441,7 @@ static void test_WsWriteStartAttribute(void)
     HRESULT hr;
     WS_XML_WRITER *writer;
     WS_XML_STRING prefix = {1, (BYTE *)"p"}, localname = {3, (BYTE *)"str"}, ns = {2, (BYTE *)"ns"};
-    WS_XML_UTF8_TEXT text;
+    WS_XML_UTF8_TEXT text = {{WS_XML_TEXT_TYPE_UTF8}};
 
     hr = WsCreateWriter( NULL, 0, &writer, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -462,10 +462,8 @@ static void test_WsWriteStartAttribute(void)
     ok( hr == S_OK, "got %08x\n", hr );
     check_output( writer, "", __LINE__ );
 
-    text.text.textType = WS_XML_TEXT_TYPE_UTF8;
     text.value.length  = 1;
     text.value.bytes   = (BYTE *)"0";
-    text.value.dictionary = NULL;
     hr = WsWriteText( writer, &text.text, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
     check_output( writer, "", __LINE__ );
@@ -1103,7 +1101,7 @@ static void test_WsWriteStartCData(void)
     HRESULT hr;
     WS_XML_WRITER *writer;
     WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
-    WS_XML_UTF8_TEXT text;
+    WS_XML_UTF8_TEXT text = {{WS_XML_TEXT_TYPE_UTF8}};
 
     hr = WsCreateWriter( NULL, 0, &writer, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -1128,10 +1126,8 @@ static void test_WsWriteStartCData(void)
     ok( hr == S_OK, "got %08x\n", hr );
     check_output( writer, "<t><![CDATA[", __LINE__ );
 
-    text.text.textType = WS_XML_TEXT_TYPE_UTF8;
     text.value.bytes = (BYTE *)"<data>";
     text.value.length = 6;
-    text.value.dictionary = NULL;
     hr = WsWriteText( writer, &text.text, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
     check_output( writer, "<t><![CDATA[<data>", __LINE__ );
@@ -1790,12 +1786,12 @@ static void test_WsWriteNode(void)
     WS_XML_STRING localname = {1, (BYTE *)"t"}, localname2 = {4, (BYTE *)"attr"}, ns = {0, NULL};
     WS_XML_WRITER *writer;
     WS_XML_BUFFER *buffer;
-    WS_XML_UTF8_TEXT utf8;
+    WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
     WS_XML_ATTRIBUTE attr, *attrs[1];
     WS_XML_ELEMENT_NODE elem;
-    WS_XML_COMMENT_NODE comment;
+    WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
     WS_XML_NODE node;
-    WS_XML_TEXT_NODE text;
+    WS_XML_TEXT_NODE text = {{WS_XML_NODE_TYPE_TEXT}};
     WS_HEAP *heap;
     HRESULT hr;
 
@@ -1817,10 +1813,8 @@ static void test_WsWriteNode(void)
     hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
 
-    utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
     utf8.value.bytes   = (BYTE *)"value";
     utf8.value.length  = sizeof("value") - 1;
-    utf8.value.dictionary = NULL;
 
     attr.singleQuote = TRUE;
     attr.isXmlNs     = FALSE;
@@ -1837,14 +1831,12 @@ static void test_WsWriteNode(void)
     elem.attributeCount = 1;
     elem.attributes     = attrs;
     elem.isEmpty        = FALSE;
-    hr = WsWriteNode( writer, (const WS_XML_NODE *)&elem, NULL );
+    hr = WsWriteNode( writer, &elem.node, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
 
-    comment.node.nodeType = WS_XML_NODE_TYPE_COMMENT;
     comment.value.bytes   = (BYTE *)"comment";
     comment.value.length  = sizeof("comment") - 1;
-    comment.value.dictionary = NULL;
-    hr = WsWriteNode( writer, (const WS_XML_NODE *)&comment, NULL );
+    hr = WsWriteNode( writer, &comment.node, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
 
     node.nodeType = WS_XML_NODE_TYPE_EOF;
@@ -1861,10 +1853,8 @@ static void test_WsWriteNode(void)
 
     utf8.value.bytes   = (BYTE *)"cdata";
     utf8.value.length  = sizeof("cdata") - 1;
-    utf8.value.dictionary = NULL;
-    text.node.nodeType = WS_XML_NODE_TYPE_TEXT;
     text.text          = &utf8.text;
-    hr = WsWriteNode( writer, (const WS_XML_NODE *)&text, NULL );
+    hr = WsWriteNode( writer, &text.node, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
 
     node.nodeType = WS_XML_NODE_TYPE_END_CDATA;
@@ -1873,8 +1863,7 @@ static void test_WsWriteNode(void)
 
     utf8.value.bytes   = (BYTE *)"text";
     utf8.value.length  = sizeof("text") - 1;
-    utf8.value.dictionary = NULL;
-    hr = WsWriteNode( writer, (const WS_XML_NODE *)&text, NULL );
+    hr = WsWriteNode( writer, &text.node, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
 
     node.nodeType = WS_XML_NODE_TYPE_END_ELEMENT;
@@ -2205,7 +2194,7 @@ static void test_WsWriteText(void)
 {
     HRESULT hr;
     WS_XML_WRITER *writer;
-    WS_XML_UTF8_TEXT utf8;
+    WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
 
     hr = WsCreateWriter( NULL, 0, &writer, NULL );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -2213,12 +2202,10 @@ static void test_WsWriteText(void)
     hr = set_output( writer );
     ok( hr == S_OK, "got %08x\n", hr );
 
-    utf8.text.textType = WS_XML_TEXT_TYPE_UTF8;
     utf8.value.bytes  = (BYTE *)"test";
     utf8.value.length = 4;
-    utf8.value.dictionary = NULL;
     hr = WsWriteText( writer, &utf8.text, NULL );
-    todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
+    ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
 
     WsFreeWriter( writer );
 }
@@ -2309,6 +2296,145 @@ static void test_WsWriteArray(void)
     WsFreeWriter( writer );
 }
 
+static void test_escapes(void)
+{
+    WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL};
+    WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
+    WS_XML_WRITER *writer;
+    struct test
+    {
+        const char *text;
+        const char *result;
+        BOOL        single;
+    };
+    static const struct test tests_elem[] =
+    {
+        { "<",  "<t><</t>" },
+        { ">",  "<t>></t>" },
+        { "\"", "<t>\"</t>" },
+        { "&",  "<t>&</t>" },
+        { "&&",  "<t>&&</t>" },
+        { "'",  "<t>'</t>" },
+    };
+    static const struct test tests_attr[] =
+    {
+        { "<",  "<t t=\"<\"/>" },
+        { ">",  "<t t=\">\"/>" },
+        { "\"", "<t t=\""\"/>" },
+        { "&", "<t t=\"&\"/>" },
+        { "'", "<t t=\"'\"/>" },
+        { "\"", "<t t='\"'/>", TRUE },
+        { "'", "<t t='''/>", TRUE },
+    };
+    static const struct test tests_cdata[] =
+    {
+        { "<",  "<t><![CDATA[<]]></t>" },
+        { ">",  "<t><![CDATA[>]]></t>" },
+        { "\"", "<t><![CDATA[\"]]></t>" },
+        { "&",  "<t><![CDATA[&]]></t>" },
+        { "[",  "<t><![CDATA[[]]></t>" },
+        { "]",  "<t><![CDATA[]]]></t>" },
+        { "'",  "<t><![CDATA[']]></t>" },
+    };
+    static const struct test tests_comment[] =
+    {
+        { "<",  "<t><!--<--></t>" },
+        { ">",  "<t><!-->--></t>" },
+        { "\"", "<t><!--\"--></t>" },
+        { "&",  "<t><!--&--></t>" },
+        { "'",  "<t><!--'--></t>" },
+    };
+    HRESULT hr;
+    ULONG i;
+
+    hr = WsCreateWriter( NULL, 0, &writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    for (i = 0; i < sizeof(tests_elem)/sizeof(tests_elem[0]); i++)
+    {
+        hr = set_output( writer );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        utf8.value.bytes  = (BYTE *)tests_elem[i].text;
+        utf8.value.length = strlen( tests_elem[i].text );
+        hr = WsWriteText( writer, &utf8.text, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsWriteEndElement( writer, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        check_output( writer, tests_elem[i].result, __LINE__ );
+    }
+
+    for (i = 0; i < sizeof(tests_attr)/sizeof(tests_attr[0]); i++)
+    {
+        hr = set_output( writer );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, tests_attr[i].single, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        utf8.value.bytes  = (BYTE *)tests_attr[i].text;
+        utf8.value.length = strlen( tests_attr[i].text );
+        hr = WsWriteText( writer, &utf8.text, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsWriteEndAttribute( writer, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsWriteEndElement( writer, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        check_output( writer, tests_attr[i].result, __LINE__ );
+    }
+
+    for (i = 0; i < sizeof(tests_cdata)/sizeof(tests_cdata[0]); i++)
+    {
+        hr = set_output( writer );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsWriteStartCData( writer, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        utf8.value.bytes  = (BYTE *)tests_cdata[i].text;
+        utf8.value.length = strlen( tests_cdata[i].text );
+        hr = WsWriteText( writer, &utf8.text, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsWriteEndCData( writer, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsWriteEndElement( writer, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        check_output( writer, tests_cdata[i].result, __LINE__ );
+    }
+
+    for (i = 0; i < sizeof(tests_comment)/sizeof(tests_comment[0]); i++)
+    {
+        WS_XML_COMMENT_NODE comment = {{WS_XML_NODE_TYPE_COMMENT}};
+
+        hr = set_output( writer );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        comment.value.bytes  = (BYTE *)tests_comment[i].text;
+        comment.value.length = strlen( tests_comment[i].text );
+        hr = WsWriteNode( writer, &comment.node, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsWriteEndElement( writer, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+        check_output( writer, tests_comment[i].result, __LINE__ );
+    }
+
+    WsFreeWriter( writer );
+}
+
 START_TEST(writer)
 {
     test_WsCreateWriter();
@@ -2338,4 +2464,5 @@ START_TEST(writer)
     test_field_flags();
     test_WsWriteText();
     test_WsWriteArray();
+    test_escapes();
 }
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index 3665613..2f74f75 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -425,6 +425,45 @@ static inline void write_bytes( struct writer *writer, const BYTE *bytes, ULONG
     writer->write_pos += len;
 }
 
+struct escape
+{
+    char        ch;
+    const char *entity;
+    ULONG       len;
+};
+static const struct escape escape_lt = { '<', "<", 4 };
+static const struct escape escape_gt = { '>', ">", 4 };
+static const struct escape escape_amp = { '&', "&", 5 };
+static const struct escape escape_apos = { '\'', "'", 6 };
+static const struct escape escape_quot = { '"', """, 6 };
+
+static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULONG len,
+                                   const struct escape **escapes, ULONG nb_escapes )
+{
+    ULONG i, j, size;
+    const BYTE *ptr;
+    HRESULT hr;
+
+    for (i = 0; i < len; i++)
+    {
+        ptr = &bytes[i];
+        size = 1;
+        for (j = 0; j < nb_escapes; j++)
+        {
+            if (bytes[i] == escapes[j]->ch)
+            {
+                ptr = (const BYTE *)escapes[j]->entity;
+                size = escapes[j]->len;
+                break;
+            }
+        }
+        if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
+        write_bytes( writer, ptr, size );
+    }
+
+    return S_OK;
+}
+
 static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
 {
     WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)attr->value;
@@ -452,10 +491,17 @@ static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
     write_bytes( writer, attr->localName->bytes, attr->localName->length );
     write_char( writer, '=' );
     write_char( writer, quote );
-    if (text) write_bytes( writer, text->value.bytes, text->value.length );
+    if (text)
+    {
+        const struct escape *escapes[3];
+        escapes[0] = attr->singleQuote ? &escape_apos : &escape_quot;
+        escapes[1] = &escape_lt;
+        escapes[2] = &escape_amp;
+        hr = write_bytes_escape( writer, text->value.bytes, text->value.length, escapes, 3 );
+    }
     write_char( writer, quote );
 
-    return S_OK;
+    return hr;
 }
 
 static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
@@ -1285,9 +1331,20 @@ static HRESULT write_text( struct writer *writer )
     const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
     HRESULT hr;
 
-    if ((hr = write_grow_buffer( writer, utf8->value.length )) != S_OK) return hr;
-    write_bytes( writer, utf8->value.bytes, utf8->value.length );
-    return S_OK;
+    if (!writer->current->parent) return WS_E_INVALID_FORMAT;
+    if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_ELEMENT)
+    {
+        const struct escape *escapes[3] = { &escape_lt, &escape_gt, &escape_amp };
+        return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
+    }
+    else if (node_type( writer->current->parent ) == WS_XML_NODE_TYPE_CDATA)
+    {
+        if ((hr = write_grow_buffer( writer, utf8->value.length )) != S_OK) return hr;
+        write_bytes( writer, utf8->value.bytes, utf8->value.length );
+        return S_OK;
+    }
+
+    return WS_E_INVALID_FORMAT;
 }
 
 static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
-- 
2.1.4




More information about the wine-patches mailing list