webservices: Keep track of prefix bindings.
Hans Leidekker
hans at codeweavers.com
Wed Mar 9 07:16:32 CST 2016
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/webservices/reader.c | 137 ++++++++++++++++++++++++++++++---
dlls/webservices/tests/reader.c | 128 +++++++++++++++++++++++++++++-
dlls/webservices/webservices_private.h | 5 ++
3 files changed, 256 insertions(+), 14 deletions(-)
diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index 72e75c3..37e8bdb 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -396,6 +396,12 @@ enum reader_state
READER_STATE_EOF
};
+struct prefix
+{
+ WS_XML_STRING str;
+ WS_XML_STRING ns;
+};
+
struct reader
{
ULONG read_size;
@@ -405,6 +411,9 @@ struct reader
struct node *root;
struct node *current;
ULONG current_attr;
+ struct prefix *prefixes;
+ ULONG nb_prefixes;
+ ULONG nb_prefixes_allocated;
WS_XML_READER_INPUT_TYPE input_type;
const unsigned char *input_data;
ULONG input_size;
@@ -422,6 +431,13 @@ static struct reader *alloc_reader(void)
for (i = 0; i < count; i++) size += reader_props[i].size;
if (!(ret = heap_alloc_zero( size ))) return NULL;
+ if (!(ret->prefixes = heap_alloc_zero( sizeof(*ret->prefixes) )))
+ {
+ heap_free( ret );
+ return NULL;
+ }
+ ret->nb_prefixes = ret->nb_prefixes_allocated = 1;
+
ptr = (char *)&ret->prop[count];
for (i = 0; i < count; i++)
{
@@ -433,6 +449,74 @@ static struct reader *alloc_reader(void)
return ret;
}
+static void clear_prefixes( struct prefix *prefixes, ULONG count )
+{
+ ULONG i;
+ for (i = 0; i < count; i++)
+ {
+ heap_free( prefixes[i].str.bytes );
+ prefixes[i].str.bytes = NULL;
+ prefixes[i].str.length = 0;
+
+ heap_free( prefixes[i].ns.bytes );
+ prefixes[i].ns.bytes = NULL;
+ prefixes[i].ns.length = 0;
+ }
+}
+
+static HRESULT set_prefix( struct prefix *prefix, const WS_XML_STRING *str, const WS_XML_STRING *ns )
+{
+ if (str)
+ {
+ heap_free( prefix->str.bytes );
+ if (!(prefix->str.bytes = heap_alloc( str->length ))) return E_OUTOFMEMORY;
+ memcpy( prefix->str.bytes, str->bytes, str->length );
+ prefix->str.length = str->length;
+ }
+
+ heap_free( prefix->ns.bytes );
+ if (!(prefix->ns.bytes = heap_alloc( ns->length ))) return E_OUTOFMEMORY;
+ memcpy( prefix->ns.bytes, ns->bytes, ns->length );
+ prefix->ns.length = ns->length;
+
+ return S_OK;
+}
+
+static HRESULT bind_prefix( struct reader *reader, const WS_XML_STRING *prefix, const WS_XML_STRING *ns )
+{
+ ULONG i;
+ HRESULT hr;
+
+ for (i = 0; i < reader->nb_prefixes; i++)
+ {
+ if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK)
+ return set_prefix( &reader->prefixes[i], NULL, ns );
+ }
+ if (i >= reader->nb_prefixes_allocated)
+ {
+ ULONG new_size = reader->nb_prefixes_allocated * sizeof(*reader->prefixes) * 2;
+ struct prefix *tmp = heap_realloc_zero( reader->prefixes, new_size );
+ if (!tmp) return E_OUTOFMEMORY;
+ reader->prefixes = tmp;
+ reader->nb_prefixes_allocated *= 2;
+ }
+
+ if ((hr = set_prefix( &reader->prefixes[i], prefix, ns )) != S_OK) return hr;
+ reader->nb_prefixes++;
+ return S_OK;
+}
+
+static const WS_XML_STRING *get_namespace( struct reader *reader, const WS_XML_STRING *prefix )
+{
+ ULONG i;
+ for (i = 0; i < reader->nb_prefixes; i++)
+ {
+ if (WsXmlStringEquals( prefix, &reader->prefixes[i].str, NULL ) == S_OK)
+ return &reader->prefixes[i].ns;
+ }
+ return NULL;
+}
+
static HRESULT set_reader_prop( struct reader *reader, WS_XML_READER_PROPERTY_ID id, const void *value, ULONG size )
{
if (id >= reader->prop_count || size != reader_props[id].size || reader_props[id].readonly)
@@ -487,6 +571,8 @@ static HRESULT read_init_state( struct reader *reader )
destroy_nodes( reader->root );
reader->root = NULL;
+ clear_prefixes( reader->prefixes, reader->nb_prefixes );
+ reader->nb_prefixes = 1;
if (!(node = alloc_node( WS_XML_NODE_TYPE_EOF ))) return E_OUTOFMEMORY;
read_insert_eof( reader, node );
reader->state = READER_STATE_INITIAL;
@@ -548,6 +634,8 @@ void WINAPI WsFreeReader( WS_XML_READER *handle )
if (!reader) return;
destroy_nodes( reader->root );
+ clear_prefixes( reader->prefixes, reader->nb_prefixes );
+ heap_free( reader->prefixes );
heap_free( reader );
}
@@ -947,8 +1035,19 @@ static HRESULT read_attribute( struct reader *reader, WS_XML_ATTRIBUTE **ret )
hr = E_OUTOFMEMORY;
if (WsXmlStringEquals( prefix, &xmlns, NULL ) == S_OK)
{
+ heap_free( prefix );
attr->isXmlNs = 1;
- if (!(attr->prefix = alloc_xml_string( localname->bytes, localname->length ))) goto error;
+ if (!(attr->prefix = alloc_xml_string( localname->bytes, localname->length )))
+ {
+ heap_free( localname );
+ goto error;
+ }
+ attr->localName = localname;
+ }
+ else if (!prefix->length && WsXmlStringEquals( localname, &xmlns, NULL ) == S_OK)
+ {
+ attr->isXmlNs = 1;
+ attr->prefix = prefix;
attr->localName = localname;
}
else
@@ -982,15 +1081,12 @@ static HRESULT read_attribute( struct reader *reader, WS_XML_ATTRIBUTE **ret )
if (attr->isXmlNs)
{
if (!(attr->ns = alloc_xml_string( start, len ))) goto error;
+ if ((hr = bind_prefix( reader, attr->prefix, attr->ns )) != S_OK) goto error;
if (!(text = alloc_utf8_text( NULL, 0 ))) goto error;
- attr->value = &text->text;
- }
- else
- {
- if (!(attr->ns = alloc_xml_string( NULL, 0 ))) goto error;
- if (!(text = alloc_utf8_text( start, len ))) goto error;
- attr->value = &text->text;
}
+ else if (!(text = alloc_utf8_text( start, len ))) goto error;
+
+ attr->value = &text->text;
attr->singleQuote = (quote == '\'');
*ret = attr;
@@ -1037,6 +1133,26 @@ static struct node *read_find_parent( struct reader *reader, const WS_XML_STRING
return NULL;
}
+static HRESULT set_namespaces( struct reader *reader, WS_XML_ELEMENT_NODE *elem )
+{
+ static const WS_XML_STRING xml = {3, (BYTE *)"xml"};
+ const WS_XML_STRING *ns;
+ ULONG i;
+
+ if (!(ns = get_namespace( reader, elem->prefix ))) return WS_E_INVALID_FORMAT;
+ if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
+ if (!elem->ns->length) elem->ns->bytes = (BYTE *)(elem->ns + 1); /* quirk */
+
+ for (i = 0; i < elem->attributeCount; i++)
+ {
+ WS_XML_ATTRIBUTE *attr = elem->attributes[i];
+ if (attr->isXmlNs || WsXmlStringEquals( attr->prefix, &xml, NULL ) == S_OK) continue;
+ if (!(ns = get_namespace( reader, attr->prefix ))) return WS_E_INVALID_FORMAT;
+ if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
+ }
+ return S_OK;
+}
+
static HRESULT read_element( struct reader *reader )
{
unsigned int len = 0, ch, skip;
@@ -1072,11 +1188,7 @@ static HRESULT read_element( struct reader *reader )
hr = E_OUTOFMEMORY;
if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) goto error;
elem = (WS_XML_ELEMENT_NODE *)node;
-
if ((hr = parse_name( start, len, &elem->prefix, &elem->localName )) != S_OK) goto error;
- hr = E_OUTOFMEMORY;
- if (!(elem->ns = alloc_xml_string( NULL, 0 ))) goto error;
- elem->ns->bytes = (BYTE *)(elem->ns + 1);
reader->current_attr = 0;
for (;;)
@@ -1091,6 +1203,7 @@ static HRESULT read_element( struct reader *reader )
}
reader->current_attr++;
}
+ if ((hr = set_namespaces( reader, elem )) != S_OK) goto error;
read_insert_node( reader, parent, node );
reader->state = READER_STATE_STARTELEMENT;
diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c
index 68668c5..38675db 100644
--- a/dlls/webservices/tests/reader.c
+++ b/dlls/webservices/tests/reader.c
@@ -2220,7 +2220,7 @@ static void test_WsGetNamespaceFromPrefix(void)
ok( !memcmp( ns->bytes, "ns", 2 ), "wrong data\n" );
}
- prepare_namespace_test( reader, "<t xmlns:prefix='ns'>>/t>" );
+ prepare_namespace_test( reader, "<t xmlns:prefix='ns'></t>" );
ns = NULL;
hr = WsGetNamespaceFromPrefix( reader, &prefix, TRUE, &ns, NULL );
ok( hr == S_OK, "got %08x\n", hr );
@@ -2244,6 +2244,12 @@ static void test_WsGetNamespaceFromPrefix(void)
WS_XML_UTF8_TEXT *text;
ok( elem->node.nodeType == WS_XML_NODE_TYPE_ELEMENT, "got %u\n", elem->node.nodeType );
+ ok( elem->prefix != NULL, "prefix not set\n" );
+ ok( !elem->prefix->length, "got %u\n", elem->prefix->length );
+ ok( elem->prefix->bytes == NULL, "bytes not set\n" );
+ ok( elem->ns != NULL, "ns not set\n" );
+ ok( !elem->ns->length, "got %u\n", elem->ns->length );
+ ok( elem->ns->bytes != NULL, "bytes not set\n" );
ok( elem->attributeCount == 1, "got %u\n", elem->attributeCount );
ok( elem->attributes != NULL, "attributes not set\n" );
@@ -2259,7 +2265,7 @@ static void test_WsGetNamespaceFromPrefix(void)
ok( !memcmp( attr->localName->bytes, "prefix", 6 ), "wrong data\n" );
ok( attr->ns != NULL, "ns not set\n" );
ok( attr->ns->length == 2, "got %u\n", attr->ns->length );
- ok( attr->ns->bytes != NULL, "bytes set\n" );
+ ok( attr->ns->bytes != NULL, "bytes not set\n" );
ok( !memcmp( attr->ns->bytes, "ns", 2 ), "wrong data\n" );
ok( attr->value != NULL, "value not set\n" );
@@ -2319,6 +2325,124 @@ static void test_WsGetNamespaceFromPrefix(void)
ok( hr == S_FALSE, "got %08x\n", hr );
ok( ns == NULL, "ns not set\n" );
+ hr = set_input( reader, "<t prefix:attr='' xmlns:prefix='ns'></t>", sizeof("<t prefix:attr='' xmlns:prefix='ns'></t>") - 1 );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsGetReaderNode( reader, &node, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ if (node)
+ {
+ WS_XML_ELEMENT_NODE *elem = (WS_XML_ELEMENT_NODE *)node;
+ WS_XML_ATTRIBUTE *attr;
+
+ ok( elem->node.nodeType == WS_XML_NODE_TYPE_ELEMENT, "got %u\n", elem->node.nodeType );
+ ok( elem->attributeCount == 2, "got %u\n", elem->attributeCount );
+ ok( elem->attributes != NULL, "attributes not set\n" );
+
+ attr = elem->attributes[0];
+ ok( attr->singleQuote, "singleQuote not set\n" );
+ ok( !attr->isXmlNs, "isXmlNs is set\n" );
+ ok( attr->prefix != NULL, "prefix not set\n" );
+ ok( attr->prefix->length == 6, "got %u\n", attr->prefix->length );
+ ok( attr->prefix->bytes != NULL, "bytes not set\n" );
+ ok( !memcmp( attr->prefix->bytes, "prefix", 6 ), "wrong data\n" );
+ ok( attr->localName != NULL, "localName not set\n" );
+ ok( attr->localName->length == 4, "got %u\n", attr->localName->length );
+ ok( !memcmp( attr->localName->bytes, "attr", 4 ), "wrong data\n" );
+ ok( attr->ns != NULL, "ns not set\n" );
+ ok( attr->ns->length == 2, "got %u\n", attr->ns->length );
+ ok( attr->ns->bytes != NULL, "bytes not set\n" );
+ ok( !memcmp( attr->ns->bytes, "ns", 2 ), "wrong data\n" );
+ }
+
+ hr = set_input( reader, "<t xmlns:p='ns'><u xmlns:p='ns2'/></t>", sizeof("<t xmlns:p='ns'><u xmlns:p='ns2'/></t>") - 1 );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadStartElement( reader, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ hr = set_input( reader, "<t xmlns:p='ns'><p:u p:a=''/></t>", sizeof("<t xmlns:p='ns'><p:u p:a=''/></t>") - 1 );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadStartElement( reader, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsGetReaderNode( reader, &node, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ if (node)
+ {
+ WS_XML_ELEMENT_NODE *elem = (WS_XML_ELEMENT_NODE *)node;
+ WS_XML_ATTRIBUTE *attr;
+
+ ok( elem->node.nodeType == WS_XML_NODE_TYPE_ELEMENT, "got %u\n", elem->node.nodeType );
+ ok( elem->attributeCount == 1, "got %u\n", elem->attributeCount );
+ ok( elem->attributes != NULL, "attributes not set\n" );
+
+ attr = elem->attributes[0];
+ ok( attr->prefix != NULL, "prefix not set\n" );
+ ok( attr->prefix->length == 1, "got %u\n", attr->prefix->length );
+ ok( attr->prefix->bytes != NULL, "bytes set\n" );
+ ok( !memcmp( attr->prefix->bytes, "p", 1 ), "wrong data\n" );
+ ok( attr->localName != NULL, "localName not set\n" );
+ ok( attr->localName->length == 1, "got %u\n", attr->localName->length );
+ ok( !memcmp( attr->localName->bytes, "a", 1 ), "wrong data\n" );
+ ok( attr->ns != NULL, "ns not set\n" );
+ ok( attr->ns->length == 2, "got %u\n", attr->ns->length );
+ ok( attr->ns->bytes != NULL, "bytes not set\n" );
+ ok( !memcmp( attr->ns->bytes, "ns", 2 ), "wrong data\n" );
+ }
+
+ hr = set_input( reader, "<t xmlns='ns'></t>", sizeof("<t xmlns='ns'></t>") - 1 );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsGetReaderNode( reader, &node, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+ if (node)
+ {
+ WS_XML_ELEMENT_NODE *elem = (WS_XML_ELEMENT_NODE *)node;
+ WS_XML_ATTRIBUTE *attr;
+
+ ok( elem->node.nodeType == WS_XML_NODE_TYPE_ELEMENT, "got %u\n", elem->node.nodeType );
+ ok( elem->prefix != NULL, "prefix not set\n" );
+ ok( !elem->prefix->length, "got %u\n", elem->prefix->length );
+ ok( elem->prefix->bytes == NULL, "bytes not set\n" );
+ ok( elem->ns != NULL, "ns not set\n" );
+ ok( elem->ns->length == 2, "got %u\n", elem->ns->length );
+ ok( elem->ns->bytes != NULL, "bytes not set\n" );
+ ok( !memcmp( elem->ns->bytes, "ns", 2 ), "wrong data\n" );
+
+ attr = elem->attributes[0];
+ ok( attr->isXmlNs, "isXmlNs is not set\n" );
+ ok( attr->prefix != NULL, "prefix not set\n" );
+ ok( !attr->prefix->length, "got %u\n", attr->prefix->length );
+ ok( attr->prefix->bytes == NULL, "bytes set\n" );
+ ok( attr->localName != NULL, "localName not set\n" );
+ ok( attr->localName->length == 5, "got %u\n", attr->localName->length );
+ ok( !memcmp( attr->localName->bytes, "xmlns", 5 ), "wrong data\n" );
+ ok( attr->ns != NULL, "ns not set\n" );
+ ok( attr->ns->length == 2, "got %u\n", attr->ns->length );
+ ok( attr->ns->bytes != NULL, "bytes not set\n" );
+ ok( !memcmp( attr->ns->bytes, "ns", 2 ), "wrong data\n" );
+ }
+
+ hr = set_input( reader, "<t xmlns:p='ns' xmlns:p='ns2'></t>", sizeof("<t xmlns:p='ns' xmlns:p='ns2'></t>") - 1 );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
+ todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
+
+ hr = set_input( reader, "<t xmlns:p='ns' xmlns:p='ns'></t>", sizeof("<t xmlns:p='ns' xmlns:p='ns'></t>") - 1 );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
+ todo_wine ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
+
+ hr = set_input( reader, "<t xmlns:p='ns' xmlns:P='ns2'></t>", sizeof("<t xmlns:p='ns' xmlns:P='ns2'></t>") - 1 );
+ ok( hr == S_OK, "got %08x\n", hr );
+ hr = WsReadToStartElement( reader, NULL, NULL, NULL, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
WsFreeReader( reader );
}
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index bae2149..780c5c4 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -60,6 +60,11 @@ static inline void *heap_realloc( void *mem, SIZE_T size )
return HeapReAlloc( GetProcessHeap(), 0, mem, size );
}
+static inline void *heap_realloc_zero( void *mem, SIZE_T size )
+{
+ return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size );
+}
+
static inline BOOL heap_free( void *mem )
{
return HeapFree( GetProcessHeap(), 0, mem );
--
2.7.0
More information about the wine-patches
mailing list