[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