diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index 6d15002d00c..9b0fd60b3b0 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; - for (i = 0; i < len; i++) + *prefix = NULL; + *prefix_len = 0; + + *localname = str; + *localname_len = len; + + 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 c10b5819ca2..1fe37c5ed4f 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[] = + { + { "", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { " ", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { ":", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { "t", S_OK, "", "t", "" }, + { "p:", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { "p:t", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { ":t", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { "p:t", S_OK, "p", "t", "ns" }, + { "p:t:", S_OK, "p", "t:", "ns" }, + { "p:", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { ":t", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { ":", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { "t", S_OK, "", "t", "" }, + { " ", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { "", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { "p:t u", S_OK, "p", "t u", "ns" }, + { utf8, S_OK, "", localname_utf8, "" }, + { " t ", S_OK, "", "t", "" }, + { " p:t", S_OK, "p", "t", "ns" }, + { "p :t", WS_E_INVALID_FORMAT, NULL, NULL, NULL }, + { "p: t", 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, "", sizeof("") - 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, "", sizeof("") - 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 e63b8056598..1ef8aaeb0fe 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 a0857f6bc80..71b12ead49e 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*,