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