[6/6] webservices: Add support for writing attributes and text in binary mode.
Hans Leidekker
hans at codeweavers.com
Tue May 23 05:03:54 CDT 2017
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/webservices/tests/writer.c | 100 ++++++++++++--
dlls/webservices/writer.c | 284 +++++++++++++++++++++++++++++-----------
2 files changed, 302 insertions(+), 82 deletions(-)
diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c
index 7ee0325985..3e8dad4e3e 100644
--- a/dlls/webservices/tests/writer.c
+++ b/dlls/webservices/tests/writer.c
@@ -3420,17 +3420,46 @@ static void test_WsWriteCharsUtf8(void)
WsFreeWriter( writer );
}
+static void check_output_bin( WS_XML_WRITER *writer, const char *expected, int len, unsigned int line )
+{
+ WS_BYTES bytes;
+ ULONG size = sizeof(bytes);
+ HRESULT hr;
+
+ memset( &bytes, 0, sizeof(bytes) );
+ hr = WsGetWriterProperty( writer, WS_XML_WRITER_PROPERTY_BYTES, &bytes, size, NULL );
+ ok( hr == S_OK, "%u: got %08x\n", line, hr );
+ ok( bytes.length == len, "%u: got %u expected %u\n", line, bytes.length, len );
+ if (bytes.length != len) return;
+ ok( !memcmp( bytes.bytes, expected, bytes.length ), "%u: got %s expected %s\n", line,
+ debugstr_bytes(bytes.bytes, bytes.length), debugstr_bytes((const BYTE *)expected, len) );
+}
+
static void test_binary_encoding(void)
{
- static const char res[] = {0x40,0x01,'t',0x01,0};
- static const char res2[] = {0x6d,0x01,'t',0x09,0x01,'p',0x02,'n','s',0x01,0};
- static const char res3[] = {0x41,0x02,'p','2',0x01,'t',0x09,0x02,'p','2',0x02,'n','s',0x01,0};
+ static const char res[] =
+ {0x40,0x01,'t',0x01};
+ static const char res2[] =
+ {0x6d,0x01,'t',0x09,0x01,'p',0x02,'n','s',0x01};
+ static const char res3[] =
+ {0x41,0x02,'p','2',0x01,'t',0x09,0x02,'p','2',0x02,'n','s',0x01};
+ static const char res4[] =
+ {0x41,0x02,'p','2',0x01,'t',0x09,0x02,'p','2',0x02,'n','s',0x99,0x04,'t','e','s','t'};
+ static const char res100[] =
+ {0x40,0x01,'t',0x04,0x01,'t',0x98,0x00,0x01};
+ static const char res101[] =
+ {0x40,0x01,'t',0x35,0x01,'t',0x98,0x00,0x09,0x01,'p',0x02,'n','s',0x01};
+ static const char res102[] =
+ {0x40,0x01,'t',0x05,0x02,'p','2',0x01,'t',0x98,0x00,0x09,0x02,'p','2',0x02,'n','s',0x01};
+ static const char res103[] =
+ {0x40,0x01,'t',0x05,0x02,'p','2',0x01,'t',0x98,0x04,'t','e','s','t',0x09,0x02,'p','2',0x02,'n','s',0x01};
WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
static const char prefix[] = "p", prefix2[] = "p2";
- static const char localname[] = "t", empty[] = "", ns[] = "ns";
+ static const char localname[] = "t", ns[] = "ns";
const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
- WS_XML_STRING str, str2, str3;
+ WS_XML_STRING str, str2, str3, localname2 = {1, (BYTE *)"t"}, empty = {0, NULL};
+ WS_XML_UTF8_TEXT utf8 = {{WS_XML_TEXT_TYPE_UTF8}};
WS_XML_WRITER *writer;
HRESULT hr;
ULONG i;
@@ -3439,13 +3468,32 @@ static void test_binary_encoding(void)
const char *prefix;
const char *localname;
const char *ns;
+ const char *text;
const char *result;
+ int len_result;
}
elem_tests[] =
{
- { NULL, localname, empty, res }, /* short element */
- { prefix, localname, ns, res2 }, /* one character prefix element */
- { prefix2, localname, ns, res3 }, /* element */
+ { NULL, localname, "", NULL, res, sizeof(res) }, /* short element */
+ { prefix, localname, ns, NULL, res2, sizeof(res2) }, /* one character prefix element */
+ { prefix2, localname, ns, NULL, res3, sizeof(res3) }, /* element */
+ { prefix2, localname, ns, "test", res4, sizeof(res4) }, /* element with text */
+ };
+ static const struct
+ {
+ const char *prefix;
+ const char *localname;
+ const char *ns;
+ const char *value;
+ const char *result;
+ int len_result;
+ }
+ attr_tests[] =
+ {
+ { NULL, localname, "", NULL, res100, sizeof(res100) }, /* short attribute */
+ { prefix, localname, ns, NULL, res101, sizeof(res101) }, /* one character prefix attribute */
+ { prefix2, localname, ns, NULL, res102, sizeof(res102) }, /* attribute */
+ { prefix2, localname, ns, "test", res103, sizeof(res103) }, /* attribute with value */
};
hr = WsCreateWriter( NULL, 0, &writer, NULL );
@@ -3462,9 +3510,43 @@ static void test_binary_encoding(void)
hr = WsWriteStartElement( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
+ if (elem_tests[i].text)
+ {
+ utf8.value.length = strlen( elem_tests[i].text );
+ utf8.value.bytes = (BYTE *)elem_tests[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 );
+ if (hr == S_OK) check_output_bin( writer, elem_tests[i].result, elem_tests[i].len_result, __LINE__ );
+ }
+
+ for (i = 0; i < sizeof(attr_tests)/sizeof(attr_tests[0]); i++)
+ {
+ hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
+ ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+ prefix_ptr = init_xmlstring( attr_tests[i].prefix, &str );
+ localname_ptr = init_xmlstring( attr_tests[i].localname, &str2 );
+ ns_ptr = init_xmlstring( elem_tests[i].ns, &str3 );
+
+ hr = WsWriteStartElement( writer, NULL, &localname2, &empty, NULL );
+ ok( hr == S_OK, "%u: got %08x\n", i, hr );
+ hr = WsWriteStartAttribute( writer, prefix_ptr, localname_ptr, ns_ptr, FALSE, NULL );
+ ok( hr == S_OK, "%u: got %08x\n", i, hr );
+ if (attr_tests[i].value)
+ {
+ utf8.value.length = strlen( attr_tests[i].value );
+ utf8.value.bytes = (BYTE *)attr_tests[i].value;
+ hr = WsWriteText( writer, &utf8.text, NULL );
+ ok( hr == S_OK, "%u: got %08x\n", i, hr );
+ }
+ hr = WsWriteEndAttribute( writer, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteEndElement( writer, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
- if (hr == S_OK) check_output( writer, elem_tests[i].result, __LINE__ );
+ if (hr == S_OK) check_output_bin( writer, attr_tests[i].result, attr_tests[i].len_result, __LINE__ );
}
WsFreeWriter( writer );
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index e1b8c9e4a3..adf110dae6 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -525,9 +525,19 @@ static HRESULT write_bytes_escape( struct writer *writer, const BYTE *bytes, ULO
return S_OK;
}
-static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
+static HRESULT write_attribute_value_text( struct writer *writer, const WS_XML_TEXT *text, BOOL single )
+{
+ WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
+ const struct escape *escapes[3];
+
+ escapes[0] = single ? &escape_apos : &escape_quot;
+ escapes[1] = &escape_lt;
+ escapes[2] = &escape_amp;
+ return write_bytes_escape( writer, utf8->value.bytes, utf8->value.length, escapes, 3 );
+}
+
+static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
{
- WS_XML_UTF8_TEXT *text = (WS_XML_UTF8_TEXT *)attr->value;
unsigned char quote = attr->singleQuote ? '\'' : '"';
const WS_XML_STRING *prefix = NULL;
ULONG size;
@@ -539,7 +549,6 @@ static HRESULT write_attribute( struct writer *writer, WS_XML_ATTRIBUTE *attr )
size = attr->localName->length + 4 /* ' =""' */;
if (prefix && prefix->length) size += prefix->length + 1 /* ':' */;
- if (text) size += text->value.length;
if ((hr = write_grow_buffer( writer, size )) != S_OK) return hr;
write_char( writer, ' ' );
@@ -551,19 +560,156 @@ 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)
- {
- 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 );
- }
+ if (attr->value) hr = write_attribute_value_text( writer, attr->value, attr->singleQuote );
write_char( writer, quote );
return hr;
}
+static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr )
+{
+ if (!attr->prefix || !attr->prefix->length) return RECORD_SHORT_ATTRIBUTE;
+ if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
+ {
+ return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
+ }
+ return RECORD_ATTRIBUTE;
+};
+
+static HRESULT write_int31( struct writer *writer, ULONG len )
+{
+ HRESULT hr;
+
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ if (len < 0x80)
+ {
+ write_char( writer, len );
+ return S_OK;
+ }
+ write_char( writer, (len & 0x7f) | 0x80 );
+
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ if ((len >>= 7) < 0x80)
+ {
+ write_char( writer, len );
+ return S_OK;
+ }
+ write_char( writer, (len & 0x7f) | 0x80 );
+
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ if ((len >>= 7) < 0x80)
+ {
+ write_char( writer, len );
+ return S_OK;
+ }
+ write_char( writer, (len & 0x7f) | 0x80 );
+
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ if ((len >>= 7) < 0x80)
+ {
+ write_char( writer, len );
+ return S_OK;
+ }
+ write_char( writer, (len & 0x7f) | 0x80 );
+
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ if ((len >>= 7) < 0x08)
+ {
+ write_char( writer, len );
+ return S_OK;
+ }
+ return WS_E_INVALID_FORMAT;
+}
+
+static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
+{
+ HRESULT hr;
+ if ((hr = write_int31( writer, len )) != S_OK) return hr;
+ if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
+ write_bytes( writer, bytes, len );
+ return S_OK;
+}
+
+static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL attr )
+{
+ const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
+ if (!utf8 || utf8->value.length <= 0xff) return attr ? RECORD_CHARS8_TEXT : RECORD_CHARS8_TEXT_WITH_ENDELEMENT;
+ return 0;
+};
+
+static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TEXT *text )
+{
+ WS_XML_UTF8_TEXT *utf8 = (WS_XML_UTF8_TEXT *)text;
+ enum record_type type = get_text_record_type( text, TRUE );
+ HRESULT hr;
+
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ write_char( writer, type );
+
+ switch (type)
+ {
+ case RECORD_CHARS8_TEXT:
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ if (!utf8 || !utf8->value.length) write_char( writer, 0 );
+ else
+ {
+ write_char( writer, utf8->value.length );
+ 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;
+
+ default:
+ ERR( "unhandled record type %u\n", type );
+ return WS_E_NOT_SUPPORTED;
+ }
+}
+
+static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
+{
+ enum record_type type = get_attr_record_type( attr );
+ HRESULT hr;
+
+ if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
+ write_char( writer, type );
+
+ if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z)
+ {
+ if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
+ return write_attribute_value_bin( writer, attr->value );
+ }
+
+ switch (type)
+ {
+ case RECORD_SHORT_ATTRIBUTE:
+ if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
+ break;
+
+ case RECORD_ATTRIBUTE:
+ if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
+ if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
+ break;
+
+ default:
+ ERR( "unhandled record type %u\n", type );
+ return WS_E_NOT_SUPPORTED;
+ }
+
+ return write_attribute_value_bin( writer, attr->value );
+}
+
+static HRESULT write_attribute( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
+{
+ switch (writer->output_enc)
+ {
+ case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_attribute_text( writer, attr );
+ case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_attribute_bin( writer, attr );
+ default:
+ ERR( "unhandled encoding %u\n", writer->output_enc );
+ return WS_E_NOT_SUPPORTED;
+ }
+}
+
static inline BOOL is_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
{
return (WsXmlStringEquals( writer->current_ns, ns, NULL ) == S_OK);
@@ -647,60 +793,6 @@ static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr )
return RECORD_XMLNS_ATTRIBUTE;
};
-static HRESULT write_int31( struct writer *writer, ULONG len )
-{
- HRESULT hr;
-
- if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
- if (len < 0x80)
- {
- write_char( writer, len );
- return S_OK;
- }
- write_char( writer, (len & 0x7f) | 0x80 );
-
- if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
- if ((len >>= 7) < 0x80)
- {
- write_char( writer, len );
- return S_OK;
- }
- write_char( writer, (len & 0x7f) | 0x80 );
-
- if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
- if ((len >>= 7) < 0x80)
- {
- write_char( writer, len );
- return S_OK;
- }
- write_char( writer, (len & 0x7f) | 0x80 );
-
- if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
- if ((len >>= 7) < 0x80)
- {
- write_char( writer, len );
- return S_OK;
- }
- write_char( writer, (len & 0x7f) | 0x80 );
-
- if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
- if ((len >>= 7) < 0x08)
- {
- write_char( writer, len );
- return S_OK;
- }
- return WS_E_INVALID_FORMAT;
-}
-
-static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len )
-{
- HRESULT hr;
- if ((hr = write_int31( writer, len )) != S_OK) return hr;
- if ((hr = write_grow_buffer( writer, len )) != S_OK) return hr;
- write_bytes( writer, bytes, len );
- return S_OK;
-}
-
static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
{
enum record_type type = get_xmlns_record_type( attr );
@@ -1003,6 +1095,7 @@ static HRESULT write_endelement_text( struct writer *writer, const WS_XML_ELEMEN
static HRESULT write_endelement_bin( struct writer *writer )
{
HRESULT hr;
+ if (node_type( writer->current ) == WS_XML_NODE_TYPE_TEXT) return S_OK;
if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
write_char( writer, RECORD_ENDELEMENT );
return S_OK;
@@ -1138,7 +1231,7 @@ static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *
if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY;
- if (!prefix && ns->length > 0) prefix = elem->prefix;
+ if (!prefix && ns->length) prefix = elem->prefix;
attr->singleQuote = !!single;
if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
@@ -1859,13 +1952,11 @@ static HRESULT write_add_text_node( struct writer *writer, const WS_XML_TEXT *va
return S_OK;
}
-static HRESULT write_text( struct writer *writer, ULONG offset )
+static HRESULT write_text_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
{
- const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)writer->current;
- const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text->text;
+ const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
HRESULT hr;
- 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 };
@@ -1881,8 +1972,55 @@ static HRESULT write_text( struct writer *writer, ULONG offset )
return WS_E_INVALID_FORMAT;
}
+static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
+{
+ const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
+ enum record_type type = get_text_record_type( text, FALSE );
+ HRESULT hr;
+
+ if (offset)
+ {
+ FIXME( "no support for appending text in binary mode\n" );
+ return WS_E_NOT_SUPPORTED;
+ }
+
+ switch (type)
+ {
+ case RECORD_CHARS8_TEXT_WITH_ENDELEMENT:
+ if ((hr = write_grow_buffer( writer, 2 )) != S_OK) return hr;
+ write_char( writer, type );
+ if (!utf8 || !utf8->value.length) write_char( writer, 0 );
+ else
+ {
+ write_char( writer, utf8->value.length );
+ 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;
+
+ default:
+ FIXME( "unhandled record type %u\n", type );
+ return WS_E_NOT_SUPPORTED;
+ }
+}
+
+static HRESULT write_text( struct writer *writer, const WS_XML_TEXT *text, ULONG offset )
+{
+ if (!writer->current->parent) return WS_E_INVALID_FORMAT;
+
+ switch (writer->output_enc)
+ {
+ case WS_XML_WRITER_ENCODING_TYPE_TEXT: return write_text_text( writer, text, offset );
+ case WS_XML_WRITER_ENCODING_TYPE_BINARY: return write_text_bin( writer, text, offset );
+ default:
+ ERR( "unhandled encoding %u\n", writer->output_enc );
+ return WS_E_NOT_SUPPORTED;
+ }
+}
+
static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
{
+ WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
ULONG offset;
HRESULT hr;
@@ -1891,10 +2029,10 @@ static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
{
offset = 0;
if ((hr = write_add_text_node( writer, text )) != S_OK) return hr;
+ node = (WS_XML_TEXT_NODE *)writer->current;
}
else
{
- WS_XML_TEXT_NODE *node = (WS_XML_TEXT_NODE *)writer->current;
WS_XML_UTF8_TEXT *new, *old = (WS_XML_UTF8_TEXT *)node->text;
offset = old->value.length;
@@ -1903,7 +2041,7 @@ static HRESULT write_text_node( struct writer *writer, const WS_XML_TEXT *text )
node->text = &new->text;
}
- if ((hr = write_text( writer, offset )) != S_OK) return hr;
+ if ((hr = write_text( writer, node->text, offset )) != S_OK) return hr;
writer->state = WRITER_STATE_TEXT;
return S_OK;
@@ -3539,7 +3677,7 @@ static HRESULT write_tree_node( struct writer *writer )
case WS_XML_NODE_TYPE_TEXT:
if (writer->state == WRITER_STATE_STARTELEMENT && (hr = write_endstartelement( writer )) != S_OK)
return hr;
- if ((hr = write_text( writer, 0 )) != S_OK) return hr;
+ if ((hr = write_text( writer, ((const WS_XML_TEXT_NODE *)writer->current)->text, 0 )) != S_OK) return hr;
writer->state = WRITER_STATE_TEXT;
return S_OK;
--
2.11.0
More information about the wine-patches
mailing list