webservices: Add support for dictionary strings in the writer.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2017-05-30 10:09:05 +02:00 committed by Alexandre Julliard
parent e558858d0f
commit 51d934abbc
6 changed files with 263 additions and 38 deletions

View File

@ -467,17 +467,21 @@ static HRESULT get_env_namespace( WS_ENVELOPE_VERSION ver, WS_XML_STRING *str )
case WS_ENVELOPE_VERSION_SOAP_1_1:
str->bytes = (BYTE *)ns_env_1_1;
str->length = sizeof(ns_env_1_1)/sizeof(ns_env_1_1[0]) - 1;
return S_OK;
break;
case WS_ENVELOPE_VERSION_SOAP_1_2:
str->bytes = (BYTE *)ns_env_1_2;
str->length = sizeof(ns_env_1_2)/sizeof(ns_env_1_2[0]) - 1;
return S_OK;
break;
default:
ERR( "unhandled envelope version %u\n", ver );
return E_NOTIMPL;
}
str->dictionary = NULL;
str->id = 0;
return S_OK;
}
static HRESULT get_addr_namespace( WS_ADDRESSING_VERSION ver, WS_XML_STRING *str )
@ -487,22 +491,26 @@ static HRESULT get_addr_namespace( WS_ADDRESSING_VERSION ver, WS_XML_STRING *str
case WS_ADDRESSING_VERSION_0_9:
str->bytes = (BYTE *)ns_addr_0_9;
str->length = sizeof(ns_addr_0_9)/sizeof(ns_addr_0_9[0]) - 1;
return S_OK;
break;
case WS_ADDRESSING_VERSION_1_0:
str->bytes = (BYTE *)ns_addr_1_0;
str->length = sizeof(ns_addr_1_0)/sizeof(ns_addr_1_0[0]) - 1;
return S_OK;
break;
case WS_ADDRESSING_VERSION_TRANSPORT:
str->bytes = NULL;
str->length = 0;
return S_OK;
break;
default:
ERR( "unhandled addressing version %u\n", ver );
return E_NOTIMPL;
}
str->dictionary = NULL;
str->id = 0;
return S_OK;
}
static const WS_XML_STRING *get_header_name( WS_HEADER_TYPE type )

View File

@ -161,9 +161,9 @@ static WS_XML_ATTRIBUTE *dup_attribute( const WS_XML_ATTRIBUTE *src )
dst->isXmlNs = src->isXmlNs;
if (!prefix) dst->prefix = NULL;
else if (!(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
if (!(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
if (!(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
else if (!(dst->prefix = dup_xml_string( prefix ))) goto error;
if (!(dst->localName = dup_xml_string( localname ))) goto error;
if (!(dst->ns = dup_xml_string( ns ))) goto error;
if (text)
{
@ -214,9 +214,9 @@ static struct node *dup_element_node( const WS_XML_ELEMENT_NODE *src )
if (count && !(dst->attributes = dup_attributes( attrs, count ))) goto error;
dst->attributeCount = count;
if (prefix && !(dst->prefix = alloc_xml_string( prefix->bytes, prefix->length ))) goto error;
if (localname && !(dst->localName = alloc_xml_string( localname->bytes, localname->length ))) goto error;
if (ns && !(dst->ns = alloc_xml_string( ns->bytes, ns->length ))) goto error;
if (prefix && !(dst->prefix = dup_xml_string( prefix ))) goto error;
if (localname && !(dst->localName = dup_xml_string( localname ))) goto error;
if (ns && !(dst->ns = dup_xml_string( ns ))) goto error;
return node;
error:
@ -797,6 +797,20 @@ WS_XML_STRING *alloc_xml_string( const unsigned char *data, ULONG len )
return ret;
}
WS_XML_STRING *dup_xml_string( const WS_XML_STRING *src )
{
WS_XML_STRING *ret;
if (!src->dictionary) return alloc_xml_string( src->bytes, src->length );
if (!(ret = heap_alloc( sizeof(*ret) ))) return NULL;
ret->length = src->length;
ret->bytes = src->bytes;
ret->dictionary = src->dictionary;
ret->id = src->id;
return ret;
}
WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *data, ULONG len )
{
WS_XML_UTF8_TEXT *ret;

View File

@ -1,5 +1,5 @@
TESTDLL = webservices.dll
IMPORTS = webservices user32 ws2_32
IMPORTS = webservices user32 rpcrt4 ws2_32
C_SRCS = \
channel.c \

View File

@ -18,6 +18,7 @@
#include <stdio.h>
#include "windows.h"
#include "rpc.h"
#include "webservices.h"
#include "wine/test.h"
@ -3592,6 +3593,144 @@ static void test_namespaces(void)
WsFreeWriter( writer );
}
static const WS_XML_STRING *init_xmlstring_dict( WS_XML_DICTIONARY *dict, ULONG id, WS_XML_STRING *str )
{
if (id >= dict->stringCount) return NULL;
str->length = dict->strings[id].length;
str->bytes = dict->strings[id].bytes;
str->dictionary = dict;
str->id = id;
return str;
}
static void test_dictionary(void)
{
static const char res[] =
{0x42,0x04,0x01};
static const char res2[] =
{0x42,0x06,0x01};
static const char res3[] =
{0x53,0x06,0x0b,0x01,'p',0x0a,0x01};
static const char res4[] =
{0x43,0x02,'p','2',0x06,0x0b,0x02,'p','2',0x0a,0x01};
static const char res100[] =
{0x42,0x06,0x06,0x06,0x98,0x00,0x01};
static const char res101[] =
{0x42,0x06,0x1b,0x06,0x98,0x00,0x0b,0x01,'p',0x0a,0x01};
static const char res102[] =
{0x42,0x06,0x07,0x02,'p','2',0x06,0x98,0x00,0x0b,0x02,'p','2',0x0a,0x01};
WS_XML_WRITER_BINARY_ENCODING bin = {{WS_XML_WRITER_ENCODING_TYPE_BINARY}};
WS_XML_WRITER_BUFFER_OUTPUT buf = {{WS_XML_WRITER_OUTPUT_TYPE_BUFFER}};
WS_XML_STRING prefix, localname, ns, strings[6];
const WS_XML_STRING *prefix_ptr, *localname_ptr, *ns_ptr;
WS_XML_DICTIONARY dict;
WS_XML_WRITER *writer;
HRESULT hr;
ULONG i;
static const struct
{
ULONG prefix;
ULONG localname;
ULONG ns;
const char *result;
int len_result;
}
elem_tests[] =
{
{ ~0u, 2, 0, res, sizeof(res) }, /* short dictionary element, invalid dict id */
{ ~0u, 3, 0, res2, sizeof(res2) }, /* short dictionary element */
{ 1, 3, 5, res3, sizeof(res3) }, /* single character prefix dictionary element */
{ 4, 3, 5, res4, sizeof(res4) }, /* dictionary element */
};
static const struct
{
ULONG prefix;
ULONG localname;
ULONG ns;
const char *result;
int len_result;
}
attr_tests[] =
{
{ ~0u, 3, 0, res100, sizeof(res100) }, /* short dictionary attribute */
{ 1, 3, 5, res101, sizeof(res101) }, /* single character prefix dictionary attribute */
{ 4, 3, 5, res102, sizeof(res102) }, /* dictionary attribute */
};
hr = WsCreateWriter( NULL, 0, &writer, NULL );
ok( hr == S_OK, "got %08x\n", hr );
strings[0].length = 0;
strings[0].bytes = NULL;
strings[0].dictionary = &dict;
strings[0].id = 0;
strings[1].length = 1;
strings[1].bytes = (BYTE *)"p";
strings[1].dictionary = &dict;
strings[1].id = 1;
strings[2].length = 1;
strings[2].bytes = (BYTE *)"t";
strings[2].dictionary = &dict;
strings[2].id = ~0u;
strings[3].length = 1;
strings[3].bytes = (BYTE *)"u";
strings[3].dictionary = &dict;
strings[3].id = 3;
strings[4].length = 2;
strings[4].bytes = (BYTE *)"p2";
strings[4].dictionary = &dict;
strings[4].id = 4;
strings[5].length = 2;
strings[5].bytes = (BYTE *)"ns";
strings[5].dictionary = &dict;
strings[5].id = 5;
UuidCreate( &dict.guid );
dict.strings = strings;
dict.stringCount = sizeof(strings)/sizeof(strings[0]);
dict.isConst = TRUE;
bin.staticDictionary = &dict;
for (i = 0; i < sizeof(elem_tests)/sizeof(elem_tests[0]); i++)
{
hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
prefix_ptr = init_xmlstring_dict( &dict, elem_tests[i].prefix, &prefix );
localname_ptr = init_xmlstring_dict( &dict, elem_tests[i].localname, &localname );
ns_ptr = init_xmlstring_dict( &dict, elem_tests[i].ns, &ns );
hr = WsWriteStartElement( writer, prefix_ptr, localname_ptr, ns_ptr, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
hr = WsWriteEndElement( writer, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
if (hr == S_OK) check_output_bin( writer, elem_tests[i].result, elem_tests[i].len_result, __LINE__ );
}
for (i = 0; i < sizeof(attr_tests)/sizeof(attr_tests[0]); i++)
{
hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
prefix_ptr = init_xmlstring_dict( &dict, attr_tests[i].prefix, &prefix );
localname_ptr = init_xmlstring_dict( &dict, attr_tests[i].localname, &localname );
ns_ptr = init_xmlstring_dict( &dict, attr_tests[i].ns, &ns );
hr = WsWriteStartElement( writer, NULL, &strings[3], &strings[0], NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
hr = WsWriteStartAttribute( writer, prefix_ptr, localname_ptr, ns_ptr, FALSE, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
hr = WsWriteEndAttribute( writer, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteEndElement( writer, NULL );
ok( hr == S_OK, "%u: got %08x\n", i, hr );
if (hr == S_OK) check_output_bin( writer, attr_tests[i].result, attr_tests[i].len_result, __LINE__ );
}
WsFreeWriter( writer );
}
START_TEST(writer)
{
test_WsCreateWriter();
@ -3631,4 +3770,5 @@ START_TEST(writer)
test_WsWriteCharsUtf8();
test_binary_encoding();
test_namespaces();
test_dictionary();
}

View File

@ -35,6 +35,7 @@ void free_xmlbuf( struct xmlbuf * ) DECLSPEC_HIDDEN;
const char *debugstr_xmlstr( const WS_XML_STRING * ) DECLSPEC_HIDDEN;
WS_XML_STRING *alloc_xml_string( const unsigned char *, ULONG ) DECLSPEC_HIDDEN;
WS_XML_STRING *dup_xml_string( const WS_XML_STRING * ) DECLSPEC_HIDDEN;
WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *, ULONG ) DECLSPEC_HIDDEN;
HRESULT append_attribute( WS_XML_ELEMENT_NODE *, WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN;
void free_attribute( WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN;

View File

@ -566,20 +566,12 @@ static HRESULT write_attribute_text( struct writer *writer, const WS_XML_ATTRIBU
return hr;
}
static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr )
{
if (!attr->prefix || !attr->prefix->length) return RECORD_SHORT_ATTRIBUTE;
if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
{
return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
}
return RECORD_ATTRIBUTE;
};
static HRESULT write_int31( struct writer *writer, ULONG len )
{
HRESULT hr;
if (len > 0x7fffffff) return E_INVALIDARG;
if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
if (len < 0x80)
{
@ -630,6 +622,14 @@ static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len
return S_OK;
}
static HRESULT write_dict_string( struct writer *writer, ULONG id )
{
HRESULT hr;
if (id > 0x3fffffff) return E_INVALIDARG;
if ((hr = write_int31( writer, id << 1 )) != S_OK) return hr;
return S_OK;
}
static enum record_type get_text_record_type( const WS_XML_TEXT *text, BOOL attr )
{
const WS_XML_UTF8_TEXT *utf8 = (const WS_XML_UTF8_TEXT *)text;
@ -660,11 +660,27 @@ static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TE
return S_OK;
default:
ERR( "unhandled record type %u\n", type );
ERR( "unhandled record type %02x\n", type );
return WS_E_NOT_SUPPORTED;
}
}
static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr )
{
if (!attr->prefix || !attr->prefix->length)
{
if (attr->localName->dictionary) return RECORD_SHORT_DICTIONARY_ATTRIBUTE;
return RECORD_SHORT_ATTRIBUTE;
}
if (attr->prefix->length == 1 && attr->prefix->bytes[0] >= 'a' && attr->prefix->bytes[0] <= 'z')
{
if (attr->localName->dictionary) return RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
return RECORD_PREFIX_ATTRIBUTE_A + attr->prefix->bytes[0] - 'a';
}
if (attr->localName->dictionary) return RECORD_DICTIONARY_ATTRIBUTE;
return RECORD_ATTRIBUTE;
};
static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
{
enum record_type type = get_attr_record_type( attr );
@ -678,6 +694,11 @@ static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUT
if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
return write_attribute_value_bin( writer, attr->value );
}
if (type >= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_A && type <= RECORD_PREFIX_DICTIONARY_ATTRIBUTE_Z)
{
if ((hr = write_dict_string( writer, attr->localName->id )) != S_OK) return hr;
return write_attribute_value_bin( writer, attr->value );
}
switch (type)
{
@ -690,8 +711,17 @@ static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUT
if ((hr = write_string( writer, attr->localName->bytes, attr->localName->length )) != S_OK) return hr;
break;
case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
if ((hr = write_dict_string( writer, attr->localName->id )) != S_OK) return hr;
break;
case RECORD_DICTIONARY_ATTRIBUTE:
if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
if ((hr = write_dict_string( writer, attr->localName->id )) != S_OK) return hr;
break;
default:
ERR( "unhandled record type %u\n", type );
ERR( "unhandled record type %02x\n", type );
return WS_E_NOT_SUPPORTED;
}
@ -789,7 +819,12 @@ static HRESULT write_namespace_attribute_text( struct writer *writer, const WS_X
static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr )
{
if (!attr->prefix || !attr->prefix->length) return RECORD_SHORT_XMLNS_ATTRIBUTE;
if (!attr->prefix || !attr->prefix->length)
{
if (attr->ns->dictionary) return RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE;
return RECORD_SHORT_XMLNS_ATTRIBUTE;
}
if (attr->ns->dictionary) return RECORD_DICTIONARY_XMLNS_ATTRIBUTE;
return RECORD_XMLNS_ATTRIBUTE;
};
@ -810,8 +845,15 @@ static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XM
if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
break;
case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
return write_dict_string( writer, attr->ns->id );
case RECORD_DICTIONARY_XMLNS_ATTRIBUTE:
if ((hr = write_string( writer, attr->prefix->bytes, attr->prefix->length )) != S_OK) return hr;
return write_dict_string( writer, attr->ns->id );
default:
ERR( "unhandled record type %u\n", type );
ERR( "unhandled record type %02x\n", type );
return WS_E_NOT_SUPPORTED;
}
@ -841,12 +883,12 @@ static HRESULT add_namespace_attribute( struct writer *writer, const WS_XML_STRI
attr->singleQuote = !!single;
attr->isXmlNs = 1;
if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
if (prefix && !(attr->prefix = dup_xml_string( prefix )))
{
free_attribute( attr );
return E_OUTOFMEMORY;
}
if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
if (!(attr->ns = dup_xml_string( ns )))
{
free_attribute( attr );
return E_OUTOFMEMORY;
@ -889,7 +931,7 @@ static BOOL namespace_in_scope( const WS_XML_ELEMENT_NODE *elem, const WS_XML_ST
static HRESULT set_current_namespace( struct writer *writer, const WS_XML_STRING *ns )
{
WS_XML_STRING *str;
if (!(str = alloc_xml_string( ns->bytes, ns->length ))) return E_OUTOFMEMORY;
if (!(str = dup_xml_string( ns ))) return E_OUTOFMEMORY;
heap_free( writer->current_ns );
writer->current_ns = str;
return S_OK;
@ -989,11 +1031,17 @@ static HRESULT write_startelement_text( struct writer *writer )
static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem )
{
if (!elem->prefix || !elem->prefix->length) return RECORD_SHORT_ELEMENT;
if (!elem->prefix || !elem->prefix->length)
{
if (elem->localName->dictionary) return RECORD_SHORT_DICTIONARY_ELEMENT;
return RECORD_SHORT_ELEMENT;
}
if (elem->prefix->length == 1 && elem->prefix->bytes[0] >= 'a' && elem->prefix->bytes[0] <= 'z')
{
if (elem->localName->dictionary) return RECORD_PREFIX_DICTIONARY_ELEMENT_A + elem->prefix->bytes[0] - 'a';
return RECORD_PREFIX_ELEMENT_A + elem->prefix->bytes[0] - 'a';
}
if (elem->localName->dictionary) return RECORD_DICTIONARY_ELEMENT;
return RECORD_ELEMENT;
};
@ -1011,6 +1059,11 @@ static HRESULT write_startelement_bin( struct writer *writer )
if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
return write_attributes( writer, elem );
}
if (type >= RECORD_PREFIX_DICTIONARY_ELEMENT_A && type <= RECORD_PREFIX_DICTIONARY_ELEMENT_Z)
{
if ((hr = write_dict_string( writer, elem->localName->id )) != S_OK) return hr;
return write_attributes( writer, elem );
}
switch (type)
{
@ -1023,8 +1076,17 @@ static HRESULT write_startelement_bin( struct writer *writer )
if ((hr = write_string( writer, elem->localName->bytes, elem->localName->length )) != S_OK) return hr;
break;
case RECORD_SHORT_DICTIONARY_ELEMENT:
if ((hr = write_dict_string( writer, elem->localName->id )) != S_OK) return hr;
break;
case RECORD_DICTIONARY_ELEMENT:
if ((hr = write_string( writer, elem->prefix->bytes, elem->prefix->length )) != S_OK) return hr;
if ((hr = write_dict_string( writer, elem->localName->id )) != S_OK) return hr;
break;
default:
ERR( "unhandled record type %u\n", type );
ERR( "unhandled record type %02x\n", type );
return WS_E_NOT_SUPPORTED;
}
@ -1234,17 +1296,17 @@ static HRESULT write_add_attribute( struct writer *writer, const WS_XML_STRING *
if (!prefix && ns->length) prefix = elem->prefix;
attr->singleQuote = !!single;
if (prefix && !(attr->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
if (prefix && !(attr->prefix = dup_xml_string( prefix )))
{
free_attribute( attr );
return E_OUTOFMEMORY;
}
if (!(attr->localName = alloc_xml_string( localname->bytes, localname->length )))
if (!(attr->localName = dup_xml_string( localname )))
{
free_attribute( attr );
return E_OUTOFMEMORY;
}
if (!(attr->ns = alloc_xml_string( ns->bytes, ns->length )))
if (!(attr->ns = dup_xml_string( ns )))
{
free_attribute( attr );
return E_OUTOFMEMORY;
@ -1439,17 +1501,17 @@ static HRESULT write_add_element_node( struct writer *writer, const WS_XML_STRIN
if (!(node = alloc_node( WS_XML_NODE_TYPE_ELEMENT ))) return E_OUTOFMEMORY;
elem = &node->hdr;
if (prefix && !(elem->prefix = alloc_xml_string( prefix->bytes, prefix->length )))
if (prefix && !(elem->prefix = dup_xml_string( prefix )))
{
free_node( node );
return E_OUTOFMEMORY;
}
if (!(elem->localName = alloc_xml_string( localname->bytes, localname->length )))
if (!(elem->localName = dup_xml_string( localname )))
{
free_node( node );
return E_OUTOFMEMORY;
}
if (!(elem->ns = alloc_xml_string( ns->bytes, ns->length )))
if (!(elem->ns = dup_xml_string( ns )))
{
free_node( node );
return E_OUTOFMEMORY;
@ -1999,7 +2061,7 @@ static HRESULT write_text_bin( struct writer *writer, const WS_XML_TEXT *text, U
return S_OK;
default:
FIXME( "unhandled record type %u\n", type );
FIXME( "unhandled record type %02x\n", type );
return WS_E_NOT_SUPPORTED;
}
}