[3/6] webservices: Implement WsReadQualifiedName.

Hans Leidekker hans at codeweavers.com
Fri Apr 28 05:12:48 CDT 2017


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/reader.c         | 158 +++++++++++++++++++++++++++++++++++---
 dlls/webservices/tests/reader.c   | 112 +++++++++++++++++++++++++++
 dlls/webservices/webservices.spec |   2 +-
 include/webservices.h             |   2 +
 4 files changed, 262 insertions(+), 12 deletions(-)

diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index 6d15002d00..9b0fd60b3b 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -966,27 +966,45 @@ HRESULT append_attribute( WS_XML_ELEMENT_NODE *elem, WS_XML_ATTRIBUTE *attr )
     return S_OK;
 }
 
-static HRESULT parse_name( const unsigned char *str, unsigned int len,
-                           WS_XML_STRING **prefix, WS_XML_STRING **localname )
+static HRESULT split_name( const unsigned char *str, ULONG len, const unsigned char **prefix,
+                           ULONG *prefix_len, const unsigned char **localname, ULONG *localname_len )
 {
-    const unsigned char *name_ptr = str, *prefix_ptr = NULL;
-    unsigned int i, name_len = len, prefix_len = 0;
+    const unsigned char *ptr = str;
+
+    *prefix = NULL;
+    *prefix_len = 0;
+
+    *localname = str;
+    *localname_len = len;
 
-    for (i = 0; i < len; i++)
+    while (len--)
     {
-        if (str[i] == ':')
+        if (*ptr == ':')
         {
-            prefix_ptr = str;
-            prefix_len = i;
-            name_ptr = &str[i + 1];
-            name_len -= i + 1;
+            if (ptr == str) return WS_E_INVALID_FORMAT;
+            *prefix = str;
+            *prefix_len = ptr - str;
+            *localname = ptr + 1;
+            *localname_len = len;
             break;
         }
+        ptr++;
     }
+    return S_OK;
+}
+
+static HRESULT parse_name( const unsigned char *str, ULONG len, WS_XML_STRING **prefix, WS_XML_STRING **localname )
+{
+    const unsigned char *localname_ptr, *prefix_ptr;
+    ULONG localname_len, prefix_len;
+    HRESULT hr;
+
+    if ((hr = split_name( str, len, &prefix_ptr, &prefix_len,  &localname_ptr, &localname_len )) != S_OK) return hr;
     if (!(*prefix = alloc_xml_string( prefix_ptr, prefix_len ))) return E_OUTOFMEMORY;
-    if (!(*localname = alloc_xml_string( name_ptr, name_len )))
+    if (!(*localname = alloc_xml_string( localname_ptr, localname_len )))
     {
         heap_free( *prefix );
+        *prefix = NULL;
         return E_OUTOFMEMORY;
     }
     return S_OK;
@@ -2116,6 +2134,124 @@ HRESULT WINAPI WsReadEndAttribute( WS_XML_READER *handle, WS_ERROR *error )
     return S_OK;
 }
 
+static HRESULT find_namespace( struct reader *reader, const WS_XML_STRING *prefix, const WS_XML_STRING **ns )
+{
+    const struct node *node;
+    for (node = reader->current->parent; node_type( node ) == WS_XML_NODE_TYPE_ELEMENT; node = node->parent)
+    {
+        const WS_XML_ELEMENT_NODE *elem = &node->hdr;
+        ULONG i;
+        for (i = 0; i < elem->attributeCount; i++)
+        {
+            if (!elem->attributes[i]->isXmlNs) continue;
+            if (WsXmlStringEquals( elem->attributes[i]->prefix, prefix, NULL ) != S_OK) continue;
+            *ns = elem->attributes[i]->ns;
+            return S_OK;
+        }
+    }
+    return WS_E_INVALID_FORMAT;
+}
+
+static HRESULT read_qualified_name( struct reader *reader, WS_HEAP *heap, WS_XML_STRING *prefix_ret,
+                                    WS_XML_STRING *localname_ret, WS_XML_STRING *ns_ret )
+{
+    const WS_XML_TEXT_NODE *node = (const WS_XML_TEXT_NODE *)reader->current;
+    const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)node->text;
+    unsigned char *prefix_bytes, *localname_bytes, *ns_bytes;
+    const unsigned char *ptr = utf8->value.bytes;
+    WS_XML_STRING prefix, localname, empty = {0, NULL};
+    const WS_XML_STRING *ns = ∅
+    ULONG len = utf8->value.length;
+    HRESULT hr;
+
+    while (len && read_isspace( *ptr )) { ptr++; len--; }
+    while (len && read_isspace( ptr[len - 1] )) { len--; }
+    if (!len) return WS_E_INVALID_FORMAT;
+
+    if ((hr = split_name( ptr, len, (const unsigned char **)&prefix.bytes, &prefix.length,
+                          (const unsigned char **)&localname.bytes, &localname.length )) != S_OK) return hr;
+
+    if (!localname.length) return WS_E_INVALID_FORMAT;
+    if (prefix.length && (hr = find_namespace( reader, &prefix, &ns )) != S_OK) return hr;
+
+    if (!(prefix_bytes = ws_alloc( heap, prefix.length ))) return WS_E_QUOTA_EXCEEDED;
+    memcpy( prefix_bytes, prefix.bytes, prefix.length );
+
+    if (!(localname_bytes = ws_alloc( heap, localname.length )))
+    {
+        ws_free( heap, prefix_bytes, prefix.length );
+        return WS_E_QUOTA_EXCEEDED;
+    }
+    memcpy( localname_bytes, localname.bytes, localname.length );
+
+    if (!(ns_bytes = ws_alloc( heap, ns->length )))
+    {
+        ws_free( heap, prefix_bytes, prefix.length );
+        ws_free( heap, localname_bytes, localname.length );
+        return WS_E_QUOTA_EXCEEDED;
+    }
+    memcpy( ns_bytes, ns->bytes, ns->length );
+
+    prefix_ret->bytes  = prefix_bytes;
+    prefix_ret->length = prefix.length;
+
+    localname_ret->bytes  = localname_bytes;
+    localname_ret->length = localname.length;
+
+    ns_ret->bytes  = ns_bytes;
+    ns_ret->length = ns->length;
+
+    return S_OK;
+}
+
+/**************************************************************************
+ *          WsReadQualifiedName		[webservices.@]
+ */
+HRESULT WINAPI WsReadQualifiedName( WS_XML_READER *handle, WS_HEAP *heap, WS_XML_STRING *prefix,
+                                    WS_XML_STRING *localname, WS_XML_STRING *ns,
+                                    WS_ERROR *error )
+{
+    struct reader *reader = (struct reader *)handle;
+    HRESULT hr;
+
+    TRACE( "%p %p %s %s %s %p\n", handle, heap, debugstr_xmlstr(prefix), debugstr_xmlstr(localname),
+           debugstr_xmlstr(ns), error );
+    if (error) FIXME( "ignoring error parameter\n" );
+
+    if (!reader || !heap) return E_INVALIDARG;
+
+    EnterCriticalSection( &reader->cs );
+
+    if (reader->magic != READER_MAGIC)
+    {
+        LeaveCriticalSection( &reader->cs );
+        return E_INVALIDARG;
+    }
+
+    if (!reader->input_type)
+    {
+        LeaveCriticalSection( &reader->cs );
+        return WS_E_INVALID_OPERATION;
+    }
+
+    if (!localname)
+    {
+        LeaveCriticalSection( &reader->cs );
+        return E_INVALIDARG;
+    }
+
+    if (reader->state != READER_STATE_TEXT)
+    {
+        LeaveCriticalSection( &reader->cs );
+        return WS_E_INVALID_FORMAT;
+    }
+
+    hr = read_qualified_name( reader, heap, prefix, localname, ns );
+
+    LeaveCriticalSection( &reader->cs );
+    return hr;
+}
+
 static WCHAR *xmltext_to_widechar( WS_HEAP *heap, const WS_XML_TEXT *text )
 {
     WCHAR *ret;
diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c
index c10b5819ca..1fe37c5ed4 100644
--- a/dlls/webservices/tests/reader.c
+++ b/dlls/webservices/tests/reader.c
@@ -4240,6 +4240,117 @@ static void test_WsReadCharsUtf8(void)
     WsFreeReader( reader );
 }
 
+static void test_WsReadQualifiedName(void)
+{
+    static const char utf8[] = {'<','a','>',0xc3,0xab,'<','/','a','>',0};
+    static const char localname_utf8[] = {0xc3,0xab,0};
+    WS_XML_STRING prefix, localname, ns;
+    WS_XML_READER *reader;
+    WS_HEAP *heap;
+    HRESULT hr;
+    BOOL found;
+    ULONG i;
+    static const struct
+    {
+        const char *str;
+        HRESULT     hr;
+        const char *prefix;
+        const char *localname;
+        const char *ns;
+    } tests[] =
+    {
+        { "<a></a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a> </a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a>:</a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a>t</a>", S_OK, "", "t", "" },
+        { "<a>p:</a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a>p:t</a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a>:t</a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a xmlns:p=\"ns\">p:t</a>", S_OK, "p", "t", "ns" },
+        { "<a xmlns:p=\"ns\">p:t:</a>", S_OK, "p", "t:", "ns" },
+        { "<a xmlns:p=\"ns\">p:</a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a xmlns:p=\"ns\">:t</a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a xmlns:p=\"ns\">:</a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a xmlns:p=\"ns\">t</a>", S_OK, "", "t", "" },
+        { "<a xmlns:p=\"ns\"> </a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a xmlns:p=\"ns\"></a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a xmlns:p=\"ns\">p:t u</a>", S_OK, "p", "t u", "ns" },
+        { utf8, S_OK, "", localname_utf8, "" },
+        { "<a> t </a>", S_OK, "", "t", "" },
+        { "<a xmlns:p=\"ns\"> p:t</a>", S_OK, "p", "t", "ns" },
+        { "<a xmlns:p=\"ns\">p :t</a>", WS_E_INVALID_FORMAT, NULL, NULL, NULL },
+        { "<a xmlns:p=\"ns\">p: t</a>", S_OK, "p", " t", "ns" },
+    };
+
+    hr = WsReadQualifiedName( NULL, NULL, NULL, NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = WsCreateReader( NULL, 0, &reader, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsReadQualifiedName( reader, NULL, NULL, NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    hr = WsReadQualifiedName( reader, heap, NULL, NULL, NULL, NULL );
+    ok( hr == WS_E_INVALID_OPERATION, "got %08x\n", hr );
+
+    hr = set_input( reader, "<t/>", sizeof("<t/>") - 1 );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsReadQualifiedName( reader, heap, NULL, NULL, NULL, NULL );
+    ok( hr == E_INVALIDARG, "got %08x\n", hr );
+
+    hr = set_input( reader, "<t/>", sizeof("<t/>") - 1 );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsReadQualifiedName( reader, heap, NULL, &localname, NULL, NULL );
+    ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
+
+    for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
+    {
+        hr = set_input( reader, tests[i].str, strlen(tests[i].str) );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsReadToStartElement( reader, NULL, NULL, &found, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        hr = WsReadStartElement( reader, NULL );
+        ok( hr == S_OK, "%u: got %08x\n", i, hr );
+
+        prefix.length = localname.length = ns.length = 0xdeadbeef;
+        prefix.bytes = localname.bytes = ns.bytes = (BYTE *)0xdeadbeef;
+
+        hr = WsReadQualifiedName( reader, heap, &prefix, &localname, &ns, NULL );
+        ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
+        if (tests[i].hr == S_OK && hr == S_OK)
+        {
+            ok( prefix.length == strlen( tests[i].prefix ), "%u: got %u\n", i, prefix.length );
+            ok( !memcmp( prefix.bytes, tests[i].prefix, prefix.length ), "%u: wrong data\n", i );
+
+            ok( localname.length == strlen( tests[i].localname ), "%u: got %u\n", i, localname.length );
+            ok( !memcmp( localname.bytes, tests[i].localname, localname.length ), "%u: wrong data\n", i );
+
+            ok( ns.length == strlen( tests[i].ns ), "%u: got %u\n", i, ns.length );
+            ok( !memcmp( ns.bytes, tests[i].ns, ns.length ), "%u: wrong data\n", i );
+        }
+        else if (tests[i].hr != S_OK)
+        {
+            ok( prefix.length == 0xdeadbeef, "got %u\n", prefix.length );
+            ok( prefix.bytes == (BYTE *)0xdeadbeef, "got %p\n", prefix.bytes );
+
+            ok( localname.length == 0xdeadbeef, "got %u\n", localname.length );
+            ok( localname.bytes == (BYTE *)0xdeadbeef, "got %p\n", localname.bytes );
+
+            ok( ns.length == 0xdeadbeef, "got %u\n", ns.length );
+            ok( ns.bytes == (BYTE *)0xdeadbeef, "got %p\n", ns.bytes );
+        }
+    }
+
+    WsFreeHeap( heap );
+    WsFreeReader( reader );
+}
+
 START_TEST(reader)
 {
     test_WsCreateError();
@@ -4279,4 +4390,5 @@ START_TEST(reader)
     test_WsReadBytes();
     test_WsReadChars();
     test_WsReadCharsUtf8();
+    test_WsReadQualifiedName();
 }
diff --git a/dlls/webservices/webservices.spec b/dlls/webservices/webservices.spec
index e63b805659..1ef8aaeb0f 100644
--- a/dlls/webservices/webservices.spec
+++ b/dlls/webservices/webservices.spec
@@ -117,7 +117,7 @@
 @ stdcall WsReadMessageStart(ptr ptr ptr ptr)
 @ stub WsReadMetadata
 @ stdcall WsReadNode(ptr ptr)
-@ stub WsReadQualifiedName
+@ stdcall WsReadQualifiedName(ptr ptr ptr ptr ptr ptr)
 @ stdcall WsReadStartAttribute(ptr long ptr)
 @ stdcall WsReadStartElement(ptr ptr)
 @ stdcall WsReadToStartElement(ptr ptr ptr ptr ptr)
diff --git a/include/webservices.h b/include/webservices.h
index a0857f6bc8..71b12ead49 100644
--- a/include/webservices.h
+++ b/include/webservices.h
@@ -1610,6 +1610,8 @@ HRESULT WINAPI WsReadEnvelopeStart(WS_MESSAGE*, WS_XML_READER*, WS_MESSAGE_DONE_
 HRESULT WINAPI WsReadMessageEnd(WS_CHANNEL*, WS_MESSAGE*, const WS_ASYNC_CONTEXT*, WS_ERROR*);
 HRESULT WINAPI WsReadMessageStart(WS_CHANNEL*, WS_MESSAGE*, const WS_ASYNC_CONTEXT*, WS_ERROR*);
 HRESULT WINAPI WsReadNode(WS_XML_READER*, WS_ERROR*);
+HRESULT WINAPI WsReadQualifiedName(WS_XML_READER*, WS_HEAP*, WS_XML_STRING*, WS_XML_STRING*,
+                                   WS_XML_STRING*, WS_ERROR*);
 HRESULT WINAPI WsReadStartAttribute(WS_XML_READER*, ULONG, WS_ERROR*);
 HRESULT WINAPI WsReadStartElement(WS_XML_READER*, WS_ERROR*);
 HRESULT WINAPI WsReadToStartElement(WS_XML_READER*, const WS_XML_STRING*, const WS_XML_STRING*,
-- 
2.11.0




More information about the wine-patches mailing list