From 78428d963eb742eae5c35010640d673aa94f7cf6 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Thu, 25 May 2017 12:54:41 +0200 Subject: [PATCH] webservices: Add support for reading attributes in binary mode. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/webservices/reader.c | 141 ++++++++++++++++++++++++++++++++ dlls/webservices/tests/reader.c | 69 ++++++++++++++++ 2 files changed, 210 insertions(+) diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index 39f02020878..a5e3efc5bd3 100644 --- a/dlls/webservices/reader.c +++ b/dlls/webservices/reader.c @@ -1221,6 +1221,11 @@ error: return hr; } +static inline BOOL is_text_type( unsigned char type ) +{ + return (type >= RECORD_ZERO_TEXT && type <= RECORD_QNAME_DICTIONARY_TEXT_WITH_ENDELEMENT); +} + static HRESULT read_int31( struct reader *reader, ULONG *len ) { unsigned char byte; @@ -1258,6 +1263,42 @@ static HRESULT read_string( struct reader *reader, WS_XML_STRING **str ) return hr; } +static HRESULT read_attribute_value_bin( struct reader *reader, WS_XML_ATTRIBUTE *attr ) +{ + WS_XML_UTF8_TEXT *utf8 = NULL; + unsigned char type; + HRESULT hr; + ULONG len; + + if ((hr = read_byte( reader, &type )) != S_OK) return hr; + if (!is_text_type( type )) return WS_E_INVALID_FORMAT; + + switch (type) + { + case RECORD_CHARS8_TEXT: + { + unsigned char len8; + if ((hr = read_byte( reader, &len8 )) != S_OK) return hr; + len = len8; + break; + } + default: + ERR( "unhandled record type %02x\n", type ); + return WS_E_NOT_SUPPORTED; + } + + if (!(utf8 = alloc_utf8_text( NULL, len ))) return E_OUTOFMEMORY; + if (!len) utf8->value.bytes = (BYTE *)(utf8 + 1); /* quirk */ + if ((hr = read_bytes( reader, utf8->value.bytes, len )) != S_OK) + { + heap_free( utf8 ); + return hr; + } + + attr->value = &utf8->text; + return S_OK; +} + static HRESULT read_attribute_text( struct reader *reader, WS_XML_ATTRIBUTE **ret ) { static const WS_XML_STRING xmlns = {5, (BYTE *)"xmlns"}; @@ -1314,6 +1355,83 @@ error: return hr; } +static inline BOOL is_attribute_type( unsigned char type ) +{ + return (type >= RECORD_SHORT_ATTRIBUTE && type <= RECORD_PREFIX_ATTRIBUTE_Z); +} + +static HRESULT read_attribute_bin( struct reader *reader, WS_XML_ATTRIBUTE **ret ) +{ + WS_XML_ATTRIBUTE *attr; + unsigned char type = 0; + HRESULT hr; + + if ((hr = read_byte( reader, &type )) != S_OK) return hr; + if (!is_attribute_type( type )) return WS_E_INVALID_FORMAT; + if (!(attr = heap_alloc_zero( sizeof(*attr) ))) return E_OUTOFMEMORY; + + if (type >= RECORD_PREFIX_ATTRIBUTE_A && type <= RECORD_PREFIX_ATTRIBUTE_Z) + { + unsigned char ch = type - RECORD_PREFIX_ATTRIBUTE_A + 'a'; + if (!(attr->prefix = alloc_xml_string( &ch, 1 ))) + { + hr = E_OUTOFMEMORY; + goto error; + } + if ((hr = read_string( reader, &attr->localName )) != S_OK) goto error; + if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error; + } + else + { + switch (type) + { + case RECORD_SHORT_ATTRIBUTE: + if (!(attr->prefix = alloc_xml_string( NULL, 0 ))) + { + hr = E_OUTOFMEMORY; + goto error; + } + if ((hr = read_string( reader, &attr->localName )) != S_OK) goto error; + if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error; + break; + + case RECORD_ATTRIBUTE: + if ((hr = read_string( reader, &attr->prefix )) != S_OK) goto error; + if ((hr = read_string( reader, &attr->localName )) != S_OK) goto error; + if ((hr = read_attribute_value_bin( reader, attr )) != S_OK) goto error; + break; + + case RECORD_SHORT_XMLNS_ATTRIBUTE: + if (!(attr->prefix = alloc_xml_string( NULL, 0 ))) + { + hr = E_OUTOFMEMORY; + goto error; + } + if ((hr = read_string( reader, &attr->ns )) != S_OK) goto error; + attr->isXmlNs = 1; + break; + + case RECORD_XMLNS_ATTRIBUTE: + if ((hr = read_string( reader, &attr->prefix )) != S_OK) goto error; + if ((hr = read_string( reader, &attr->ns )) != S_OK) goto error; + if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error; + attr->isXmlNs = 1; + break; + + default: + ERR( "unhandled record type %02x\n", type ); + return WS_E_NOT_SUPPORTED; + } + } + + *ret = attr; + return S_OK; + +error: + free_attribute( attr ); + return hr; +} + static inline struct node *find_parent( struct reader *reader ) { if (node_type( reader->current ) == WS_XML_NODE_TYPE_END_ELEMENT) @@ -1438,6 +1556,28 @@ static inline BOOL is_element_type( unsigned char type ) return (type >= RECORD_SHORT_ELEMENT && type <= RECORD_PREFIX_ELEMENT_Z); } +static HRESULT read_attributes_bin( struct reader *reader, WS_XML_ELEMENT_NODE *elem ) +{ + WS_XML_ATTRIBUTE *attr; + unsigned char type; + HRESULT hr; + + reader->current_attr = 0; + for (;;) + { + if ((hr = read_peek( reader, &type )) != S_OK) return hr; + if (!is_attribute_type( type )) break; + if ((hr = read_attribute_bin( reader, &attr )) != S_OK) return hr; + if ((hr = append_attribute( elem, attr )) != S_OK) + { + free_attribute( attr ); + return hr; + } + reader->current_attr++; + } + return S_OK; +} + static HRESULT read_element_bin( struct reader *reader ) { struct node *node = NULL, *parent; @@ -1491,6 +1631,7 @@ static HRESULT read_element_bin( struct reader *reader ) goto error; } + if ((hr = read_attributes_bin( reader, elem )) != S_OK) goto error; if ((hr = set_namespaces( reader, elem )) != S_OK) goto error; read_insert_node( reader, parent, node ); diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c index 34fe2da5649..41cbadcde6b 100644 --- a/dlls/webservices/tests/reader.c +++ b/dlls/webservices/tests/reader.c @@ -4510,8 +4510,13 @@ static void test_binary_encoding(void) { 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}; const WS_XML_NODE *node; const WS_XML_ELEMENT_NODE *elem; + const WS_XML_ATTRIBUTE *attr; WS_XML_READER *reader; HRESULT hr; @@ -4543,6 +4548,70 @@ static void test_binary_encoding(void) ok( hr == S_OK, "got %08x\n", hr ); ok( node->nodeType == WS_XML_NODE_TYPE_END_ELEMENT, "got %u\n", node->nodeType ); + /* single character prefix element */ + hr = set_input_bin( reader, res2, sizeof(res2) ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsReadNode( reader, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsGetReaderNode( reader, &node, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( node->nodeType == WS_XML_NODE_TYPE_ELEMENT, "got %u\n", node->nodeType ); + elem = (const WS_XML_ELEMENT_NODE *)node; + ok( elem->prefix->length == 1, "got %u\n", elem->prefix->length ); + ok( !memcmp( elem->prefix->bytes, "p", 1 ), "wrong prefix\n" ); + ok( elem->localName->length == 1, "got %u\n", elem->localName->length ); + ok( !memcmp( elem->localName->bytes, "t", 1 ), "wrong name\n" ); + ok( elem->ns->length == 2, "got %u\n", elem->ns->length ); + ok( !memcmp( elem->ns->bytes, "ns", 2 ), "wrong namespace\n" ); + ok( elem->attributeCount == 1, "got %u\n", elem->attributeCount ); + ok( !elem->isEmpty, "empty\n" ); + attr = elem->attributes[0]; + ok( !attr->singleQuote, "single quote\n" ); + ok( attr->isXmlNs, "not xmlns\n" ); + ok( attr->prefix->length == 1, "got %u\n", attr->prefix->length ); + ok( !memcmp( attr->prefix->bytes, "p", 1 ), "wrong prefix\n" ); + ok( attr->ns->length == 2, "got %u\n", attr->ns->length ); + ok( !memcmp( attr->ns->bytes, "ns", 2 ), "wrong namespace\n" ); + + hr = WsReadNode( reader, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsGetReaderNode( reader, &node, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( node->nodeType == WS_XML_NODE_TYPE_END_ELEMENT, "got %u\n", node->nodeType ); + + /* element */ + hr = set_input_bin( reader, res3, sizeof(res3) ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsReadNode( reader, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsGetReaderNode( reader, &node, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( node->nodeType == WS_XML_NODE_TYPE_ELEMENT, "got %u\n", node->nodeType ); + elem = (const WS_XML_ELEMENT_NODE *)node; + ok( elem->prefix->length == 2, "got %u\n", elem->prefix->length ); + ok( !memcmp( elem->prefix->bytes, "p2", 2 ), "wrong prefix\n" ); + ok( elem->localName->length == 1, "got %u\n", elem->localName->length ); + ok( !memcmp( elem->localName->bytes, "t", 1 ), "wrong name\n" ); + ok( elem->ns->length == 2, "got %u\n", elem->ns->length ); + ok( !memcmp( elem->ns->bytes, "ns", 2 ), "wrong namespace\n" ); + ok( elem->attributeCount == 1, "got %u\n", elem->attributeCount ); + ok( !elem->isEmpty, "empty\n" ); + attr = elem->attributes[0]; + ok( !attr->singleQuote, "single quote\n" ); + ok( attr->isXmlNs, "not xmlns\n" ); + ok( attr->prefix->length == 2, "got %u\n", attr->prefix->length ); + ok( !memcmp( attr->prefix->bytes, "p2", 2 ), "wrong prefix\n" ); + ok( attr->ns->length == 2, "got %u\n", attr->ns->length ); + ok( !memcmp( attr->ns->bytes, "ns", 2 ), "wrong namespace\n" ); + + hr = WsReadNode( reader, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsGetReaderNode( reader, &node, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( node->nodeType == WS_XML_NODE_TYPE_END_ELEMENT, "got %u\n", node->nodeType ); + WsFreeReader( reader ); }