webservices: Add support for dynamic string callbacks.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2017-06-22 10:43:11 +02:00 committed by Alexandre Julliard
parent f7488ac67d
commit 4019682855
2 changed files with 118 additions and 18 deletions

View File

@ -3649,6 +3649,34 @@ static const WS_XML_STRING *init_xmlstring_dict( WS_XML_DICTIONARY *dict, ULONG
return str;
}
static HRESULT CALLBACK dict_cb( void *state, const WS_XML_STRING *str, BOOL *found, ULONG *id, WS_ERROR *error )
{
ULONG *call_count = state;
(*call_count)++;
switch (str->bytes[0])
{
case 't':
*id = 1;
*found = TRUE;
break;
case 'n':
*id = 2;
*found = TRUE;
break;
case 'v':
*found = FALSE;
return WS_E_OTHER;
default:
*found = FALSE;
break;
}
return S_OK;
}
static void test_dictionary(void)
{
static const char res[] =
@ -3659,6 +3687,12 @@ static void test_dictionary(void)
{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 res5[] =
{0x42,0x03,0x0a,0x05,0x01};
static const char res6[] =
{0x40,0x01,0x75,0x0a,0x05,0x01};
static const char res7[] =
{0x40,0x01,0x76,0x0a,0x05,0x01};
static const char res100[] =
{0x42,0x06,0x06,0x06,0x98,0x00,0x01};
static const char res101[] =
@ -3672,7 +3706,7 @@ static void test_dictionary(void)
WS_XML_DICTIONARY dict;
WS_XML_WRITER *writer;
HRESULT hr;
ULONG i;
ULONG i, call_count;
static const struct
{
ULONG prefix;
@ -3768,12 +3802,55 @@ static void test_dictionary(void)
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 );
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, attr_tests[i].result, attr_tests[i].len_result, __LINE__ );
}
/* callback */
bin.staticDictionary = NULL;
bin.dynamicStringCallback = dict_cb;
bin.dynamicStringCallbackState = &call_count;
hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
ok( hr == S_OK, "got %08x\n", hr );
init_xmlstring( "t", &localname );
init_xmlstring( "ns", &ns );
call_count = 0;
hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteEndElement( writer, NULL );
ok( hr == S_OK, "got %08x\n", hr );
ok( call_count == 2, "got %u\n", call_count );
check_output_bin( writer, res5, sizeof(res5), __LINE__ );
/* unknown string */
hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
ok( hr == S_OK, "got %08x\n", hr );
init_xmlstring( "u", &localname );
init_xmlstring( "ns", &ns );
call_count = 0;
hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteEndElement( writer, NULL );
ok( hr == S_OK, "got %08x\n", hr );
ok( call_count == 2, "got %u\n", call_count );
check_output_bin( writer, res6, sizeof(res6), __LINE__ );
/* unknown string, error return from callback */
hr = WsSetOutput( writer, &bin.encoding, &buf.output, NULL, 0, NULL );
ok( hr == S_OK, "got %08x\n", hr );
init_xmlstring( "v", &localname );
init_xmlstring( "ns", &ns );
call_count = 0;
hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL );
ok( hr == S_OK, "got %08x\n", hr );
hr = WsWriteEndElement( writer, NULL );
ok( hr == S_OK, "got %08x\n", hr );
ok( call_count == 2, "got %u\n", call_count );
check_output_bin( writer, res7, sizeof(res7), __LINE__ );
WsFreeWriter( writer );
}

View File

@ -85,6 +85,8 @@ struct writer
struct xmlbuf *output_buf;
WS_HEAP *output_heap;
WS_XML_DICTIONARY *dict;
WS_DYNAMIC_STRING_CALLBACK dict_cb;
void *dict_cb_state;
ULONG prop_count;
struct prop prop[sizeof(writer_props)/sizeof(writer_props[0])];
};
@ -168,6 +170,8 @@ static HRESULT init_writer( struct writer *writer )
writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_TEXT;
writer->output_charset = WS_CHARSET_UTF8;
writer->dict = NULL;
writer->dict_cb = NULL;
writer->dict_cb_state = NULL;
return S_OK;
}
@ -388,6 +392,8 @@ HRESULT WINAPI WsSetOutput( WS_XML_WRITER *handle, const WS_XML_WRITER_ENCODING
writer->output_enc = WS_XML_WRITER_ENCODING_TYPE_BINARY;
writer->output_charset = 0;
writer->dict = bin->staticDictionary;
writer->dict_cb = bin->dynamicStringCallback;
writer->dict_cb_state = bin->dynamicStringCallbackState;
break;
}
default:
@ -638,8 +644,8 @@ static HRESULT write_string( struct writer *writer, const BYTE *bytes, ULONG len
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;
if (id > 0x7fffffff) return E_INVALIDARG;
if ((hr = write_int31( writer, id )) != S_OK) return hr;
return S_OK;
}
@ -678,6 +684,23 @@ static HRESULT write_attribute_value_bin( struct writer *writer, const WS_XML_TE
}
}
static BOOL lookup_string_id( struct writer *writer, const WS_XML_STRING *str, ULONG *id )
{
if (writer->dict && str->dictionary == writer->dict)
{
*id = str->id << 1;
return TRUE;
}
if (writer->dict_cb)
{
BOOL found = FALSE;
writer->dict_cb( writer->dict_cb_state, str, &found, id, NULL );
if (found) *id = (*id << 1) | 1;
return found;
}
return FALSE;
}
static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL use_dict )
{
if (!attr->prefix || !attr->prefix->length)
@ -696,8 +719,8 @@ static enum record_type get_attr_record_type( const WS_XML_ATTRIBUTE *attr, BOOL
static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
{
BOOL use_dict = (writer->dict && attr->localName->dictionary == writer->dict);
enum record_type type = get_attr_record_type( attr, use_dict );
ULONG id;
enum record_type type = get_attr_record_type( attr, lookup_string_id(writer, attr->localName, &id) );
HRESULT hr;
if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
@ -710,7 +733,7 @@ static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUT
}
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;
if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
return write_attribute_value_bin( writer, attr->value );
}
@ -726,12 +749,12 @@ static HRESULT write_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUT
break;
case RECORD_SHORT_DICTIONARY_ATTRIBUTE:
if ((hr = write_dict_string( writer, attr->localName->id )) != S_OK) return hr;
if ((hr = write_dict_string( writer, 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;
if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
break;
default:
@ -844,8 +867,8 @@ static enum record_type get_xmlns_record_type( const WS_XML_ATTRIBUTE *attr, BOO
static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XML_ATTRIBUTE *attr )
{
BOOL use_dict = (writer->dict && attr->ns->dictionary == writer->dict);
enum record_type type = get_xmlns_record_type( attr, use_dict );
ULONG id;
enum record_type type = get_xmlns_record_type( attr, lookup_string_id(writer, attr->ns, &id) );
HRESULT hr;
if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
@ -861,11 +884,11 @@ static HRESULT write_namespace_attribute_bin( struct writer *writer, const WS_XM
break;
case RECORD_SHORT_DICTIONARY_XMLNS_ATTRIBUTE:
return write_dict_string( writer, attr->ns->id );
return write_dict_string( writer, 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 );
return write_dict_string( writer, id );
default:
ERR( "unhandled record type %02x\n", type );
@ -1063,8 +1086,8 @@ static enum record_type get_elem_record_type( const WS_XML_ELEMENT_NODE *elem, B
static HRESULT write_startelement_bin( struct writer *writer )
{
const WS_XML_ELEMENT_NODE *elem = &writer->current->hdr;
BOOL use_dict = (writer->dict && elem->localName->dictionary == writer->dict);
enum record_type type = get_elem_record_type( elem, use_dict );
ULONG id;
enum record_type type = get_elem_record_type( elem, lookup_string_id(writer, elem->localName, &id) );
HRESULT hr;
if ((hr = write_grow_buffer( writer, 1 )) != S_OK) return hr;
@ -1077,7 +1100,7 @@ static HRESULT write_startelement_bin( struct writer *writer )
}
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;
if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
return write_attributes( writer, elem );
}
@ -1093,12 +1116,12 @@ static HRESULT write_startelement_bin( struct writer *writer )
break;
case RECORD_SHORT_DICTIONARY_ELEMENT:
if ((hr = write_dict_string( writer, elem->localName->id )) != S_OK) return hr;
if ((hr = write_dict_string( writer, 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;
if ((hr = write_dict_string( writer, id )) != S_OK) return hr;
break;
default: