From: Hans Leidekker Subject: [2/8] webservices: Fix corner cases in write option handling. Message-Id: <1475059086-6011-2-git-send-email-hans@codeweavers.com> Date: Wed, 28 Sep 2016 12:38:00 +0200 Signed-off-by: Hans Leidekker --- dlls/webservices/tests/writer.c | 113 +++++++++++ dlls/webservices/writer.c | 401 ++++++++++++++++++++++------------------ 2 files changed, 339 insertions(+), 175 deletions(-) diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c index 326aed2..2309ab5 100644 --- a/dlls/webservices/tests/writer.c +++ b/dlls/webservices/tests/writer.c @@ -2435,6 +2435,118 @@ static void test_escapes(void) WsFreeWriter( writer ); } +static void test_write_option(void) +{ + static const WCHAR sW[] = {'s',0}; + static const WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}; + WS_XML_WRITER *writer; + int val_int = -1, val_int_zero = 0, *ptr_int = &val_int, *ptr_int_null = NULL; + const WCHAR *ptr_wsz = sW, *ptr_wsz_null = NULL; + static const WS_XML_STRING val_xmlstr = {1, (BYTE *)"x"}, val_xmlstr_zero = {0, NULL}; + const WS_XML_STRING *ptr_xmlstr = &val_xmlstr, *ptr_xmlstr_null = NULL; + struct + { + WS_TYPE type; + WS_WRITE_OPTION option; + const void *value; + ULONG size; + HRESULT hr; + const char *result; + } + tests[] = + { + { WS_INT32_TYPE, 0, NULL, 0, E_INVALIDARG }, + { WS_INT32_TYPE, 0, "str", 0, E_INVALIDARG }, + { WS_INT32_TYPE, 0, NULL, sizeof(val_int), E_INVALIDARG }, + { WS_INT32_TYPE, 0, &val_int, sizeof(val_int), E_INVALIDARG }, + { WS_INT32_TYPE, 0, &val_int_zero, sizeof(val_int_zero), E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, 0, E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int, 0, E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, sizeof(val_int), E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int, sizeof(val_int), S_OK, "-1" }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int_zero, sizeof(val_int_zero), S_OK, "0" }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, 0, E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int, 0, E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, sizeof(val_int), E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int, sizeof(val_int), E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_VALUE, &val_int_zero, sizeof(val_int_zero), E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int, 0, E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_int), E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int, sizeof(ptr_int), S_OK, "-1" }, + { WS_INT32_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_int_null, sizeof(ptr_int_null), E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int, 0, E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_int), E_INVALIDARG }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int, sizeof(ptr_int), S_OK, "-1" }, + { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int_null, sizeof(ptr_int_null), S_OK, + "" }, + { WS_XML_STRING_TYPE, 0, NULL, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, 0, &val_xmlstr, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, 0, NULL, sizeof(val_xmlstr), E_INVALIDARG }, + { WS_XML_STRING_TYPE, 0, &val_xmlstr, sizeof(val_xmlstr), E_INVALIDARG }, + { WS_XML_STRING_TYPE, 0, &val_xmlstr_zero, sizeof(val_xmlstr_zero), E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, NULL, sizeof(&val_xmlstr), E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr, sizeof(val_xmlstr), S_OK, "x" }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK, "" }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, NULL, sizeof(&val_xmlstr), E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr, sizeof(&val_xmlstr), E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK, + "" }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_xmlstr), E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr, sizeof(ptr_xmlstr), S_OK, "x" }, + { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr, 0, E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_xmlstr), E_INVALIDARG }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr, sizeof(ptr_xmlstr), S_OK, "x" }, + { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), S_OK, + "" }, + { WS_WSZ_TYPE, 0, NULL, 0, E_INVALIDARG }, + { WS_WSZ_TYPE, 0, &ptr_wsz, 0, E_INVALIDARG }, + { WS_WSZ_TYPE, 0, NULL, sizeof(ptr_wsz), E_INVALIDARG }, + { WS_WSZ_TYPE, 0, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG }, + { WS_WSZ_TYPE, 0, &ptr_wsz_null, sizeof(ptr_wsz_null), E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_REQUIRED_VALUE, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_NILLABLE_VALUE, &ptr_wsz, sizeof(ptr_wsz), E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, 0, E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz, 0, E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, NULL, sizeof(ptr_wsz), E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz, sizeof(ptr_wsz), S_OK, "s" }, + { WS_WSZ_TYPE, WS_WRITE_REQUIRED_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, 0, E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz, 0, E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, NULL, sizeof(ptr_wsz), E_INVALIDARG }, + { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz, sizeof(ptr_wsz), S_OK, "s" }, + { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), S_OK, + "" }, + }; + HRESULT hr; + ULONG i; + + hr = WsCreateWriter( NULL, 0, &writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) + { + hr = set_output( writer ); + ok( hr == S_OK, "%u: got %08x\n", i, hr ); + WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); + hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, tests[i].type, NULL, tests[i].option, tests[i].value, + tests[i].size, NULL ); + ok( hr == tests[i].hr, "%u: got %08x\n", i, hr ); + WsWriteEndElement( writer, NULL ); + if (hr == S_OK) check_output( writer, tests[i].result, __LINE__ ); + } + + WsFreeWriter( writer ); +} + START_TEST(writer) { test_WsCreateWriter(); @@ -2465,4 +2577,5 @@ START_TEST(writer) test_WsWriteText(); test_WsWriteArray(); test_escapes(); + test_write_option(); } diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c index 2f74f75..cc734d2 100644 --- a/dlls/webservices/writer.c +++ b/dlls/webservices/writer.c @@ -1403,235 +1403,369 @@ static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, } } +static HRESULT write_add_nil_attribute( struct writer *writer ) +{ + static const WS_XML_STRING prefix = {1, (BYTE *)"a"}; + static const WS_XML_STRING localname = {3, (BYTE *)"nil"}; + static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"}; + static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}}; + HRESULT hr; + + if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr; + if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr; + return write_add_namespace_attribute( writer, &prefix, &ns, FALSE ); +} + +static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, ULONG expected_size, + const void **ptr ) +{ + switch (option) + { + case WS_WRITE_REQUIRED_VALUE: + case WS_WRITE_NILLABLE_VALUE: + if (!value || size != expected_size) return E_INVALIDARG; + *ptr = value; + return S_OK; + + case WS_WRITE_REQUIRED_POINTER: + if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG; + return S_OK; + + case WS_WRITE_NILLABLE_POINTER: + if (size != sizeof(const void *)) return E_INVALIDARG; + *ptr = *(const void **)value; + return S_OK; + + default: + return E_INVALIDARG; + } +} + static HRESULT write_type_bool( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_BOOL_DESCRIPTION *desc, const BOOL *value ) + const WS_BOOL_DESCRIPTION *desc, WS_WRITE_OPTION option, + const BOOL *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[6]; /* "false" */ + const BOOL *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(BOOL), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_bool( value, buf ); + utf8.value.length = format_bool( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_int8( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_INT8_DESCRIPTION *desc, const INT8 *value ) + const WS_INT8_DESCRIPTION *desc, WS_WRITE_OPTION option, + const BOOL *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[5]; /* "-128" */ + const INT8 *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(INT8), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_int8( value, buf ); + utf8.value.length = format_int8( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_int16( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_INT16_DESCRIPTION *desc, const INT16 *value ) + const WS_INT16_DESCRIPTION *desc, WS_WRITE_OPTION option, + const BOOL *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[7]; /* "-32768" */ + const INT16 *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(INT16), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_int16( value, buf ); + utf8.value.length = format_int16( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_int32( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_INT32_DESCRIPTION *desc, const INT32 *value ) + const WS_INT32_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[12]; /* "-2147483648" */ + const INT32 *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(INT32), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_int32( value, buf ); + utf8.value.length = format_int32( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_int64( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_INT64_DESCRIPTION *desc, const INT64 *value ) + const WS_INT64_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[21]; /* "-9223372036854775808" */ + const INT64 *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(INT64), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_int64( value, buf ); + utf8.value.length = format_int64( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_uint8( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_UINT8_DESCRIPTION *desc, const UINT8 *value ) + const WS_UINT8_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[4]; /* "255" */ + const UINT8 *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(UINT8), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_uint8( value, buf ); + utf8.value.length = format_uint8( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_uint16( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_UINT16_DESCRIPTION *desc, const UINT16 *value ) + const WS_UINT16_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[6]; /* "65535" */ + const UINT16 *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(UINT16), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_uint16( value, buf ); + utf8.value.length = format_uint16( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_uint32( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_UINT32_DESCRIPTION *desc, const UINT32 *value ) + const WS_UINT32_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[11]; /* "4294967295" */ + const UINT32 *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(UINT32), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_uint32( value, buf ); + utf8.value.length = format_uint32( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_uint64( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_UINT64_DESCRIPTION *desc, const UINT64 *value ) + const WS_UINT64_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[21]; /* "18446744073709551615" */ + const UINT64 *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(UINT64), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_uint64( value, buf ); + utf8.value.length = format_uint64( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_guid( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_GUID_DESCRIPTION *desc, const GUID *value ) + const WS_GUID_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; unsigned char buf[37]; /* "00000000-0000-0000-0000-000000000000" */ + const GUID *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(GUID), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; utf8.value.bytes = buf; - utf8.value.length = format_guid( value, buf ); + utf8.value.length = format_guid( ptr, buf ); return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type_string( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_STRING_DESCRIPTION *desc, const WS_STRING *value ) + const WS_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF16_TEXT utf16; + const WS_STRING *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(WS_STRING), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + if (!ptr->length) return S_OK; + utf16.text.textType = WS_XML_TEXT_TYPE_UTF16; - utf16.bytes = (BYTE *)value->chars; - utf16.byteCount = value->length * sizeof(WCHAR); + utf16.bytes = (BYTE *)ptr->chars; + utf16.byteCount = ptr->length * sizeof(WCHAR); return write_type_text( writer, mapping, &utf16.text ); } static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_WSZ_DESCRIPTION *desc, const WCHAR *value ) + const WS_WSZ_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF16_TEXT utf16; + const WCHAR *ptr; + HRESULT hr; + int len; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } + + if (!option || option == WS_WRITE_REQUIRED_VALUE || option == WS_WRITE_NILLABLE_VALUE) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, 0, (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + if (!(len = strlenW( ptr ))) return S_OK; + utf16.text.textType = WS_XML_TEXT_TYPE_UTF16; - utf16.bytes = (BYTE *)value; - utf16.byteCount = strlenW( value ) * sizeof(WCHAR); + utf16.bytes = (BYTE *)ptr; + utf16.byteCount = len * sizeof(WCHAR); return write_type_text( writer, mapping, &utf16.text ); } static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_XML_STRING_DESCRIPTION *desc, const WS_XML_STRING *value ) + const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { WS_XML_UTF8_TEXT utf8; + const WS_XML_STRING *ptr; + HRESULT hr; if (desc) { FIXME( "description not supported\n" ); return E_NOTIMPL; } - utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; - utf8.value.bytes = value->bytes; - utf8.value.length = value->length; - return write_type_text( writer, mapping, &utf8.text ); -} -static HRESULT write_add_nil_attribute( struct writer *writer ) -{ - static const WS_XML_STRING prefix = {1, (BYTE *)"a"}; - static const WS_XML_STRING localname = {3, (BYTE *)"nil"}; - static const WS_XML_STRING ns = {41, (BYTE *)"http://www.w3.org/2001/XMLSchema-instance"}; - static const WS_XML_UTF8_TEXT value = {{WS_XML_TEXT_TYPE_UTF8}, {4, (BYTE *)"true"}}; - HRESULT hr; + if (!option) return E_INVALIDARG; + if ((hr = get_value_ptr( option, value, size, sizeof(WS_XML_STRING), (const void **)&ptr )) != S_OK) return hr; + if (option == WS_WRITE_NILLABLE_POINTER && !ptr) return write_add_nil_attribute( writer ); + if (option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) return write_add_nil_attribute( writer ); + if (!ptr->length) return S_OK; - if ((hr = write_add_attribute( writer, &prefix, &localname, &ns, FALSE )) != S_OK) return hr; - if ((hr = write_set_attribute_value( writer, &value.text )) != S_OK) return hr; - return write_add_namespace_attribute( writer, &prefix, &ns, FALSE ); + utf8.text.textType = WS_XML_TEXT_TYPE_UTF8; + utf8.value.bytes = ptr->bytes; + utf8.value.length = ptr->length; + return write_type_text( writer, mapping, &utf8.text ); } static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION, @@ -1643,32 +1777,34 @@ static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DE HRESULT hr; WS_TYPE_MAPPING mapping; WS_WRITE_OPTION option; + ULONG field_options = desc->options; - if (desc->options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) + if (field_options & ~(WS_FIELD_POINTER|WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) { FIXME( "options 0x%x not supported\n", desc->options ); return E_NOTIMPL; } + /* zero-terminated strings are always pointers */ + if (desc->type == WS_WSZ_TYPE) field_options |= WS_FIELD_POINTER; + if (is_nil_value( value, size )) { - if (desc->options & WS_FIELD_NILLABLE) + if (field_options & WS_FIELD_NILLABLE) { - if (desc->options & WS_FIELD_POINTER) - option = WS_WRITE_NILLABLE_POINTER; - else - option = WS_WRITE_NILLABLE_VALUE; + if (field_options & WS_FIELD_POINTER) option = WS_WRITE_NILLABLE_POINTER; + else option = WS_WRITE_NILLABLE_VALUE; } else { - if (desc->options & WS_FIELD_OPTIONAL) return S_OK; + if (field_options & WS_FIELD_OPTIONAL) return S_OK; return E_INVALIDARG; } } else { - if (desc->options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER; - else option = 0; + if (field_options & WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER; + else option = WS_WRITE_REQUIRED_VALUE; } switch (desc->mapping) @@ -1684,10 +1820,6 @@ static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DE case WS_ELEMENT_FIELD_MAPPING: if ((hr = write_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) return hr; - if (option == WS_WRITE_NILLABLE_VALUE || option == WS_WRITE_NILLABLE_POINTER) - { - if ((hr = write_add_nil_attribute( writer )) != S_OK) return hr; - } mapping = WS_ELEMENT_TYPE_MAPPING; break; @@ -1713,11 +1845,8 @@ static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DE return E_NOTIMPL; } - if (option != WS_WRITE_NILLABLE_VALUE && option != WS_WRITE_NILLABLE_POINTER) - { - if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, value, size )) != S_OK) - return hr; - } + if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, value, size )) != S_OK) + return hr; switch (mapping) { @@ -1742,156 +1871,78 @@ static ULONG get_field_size( const WS_STRUCT_DESCRIPTION *desc, ULONG index ) } static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_STRUCT_DESCRIPTION *desc, const void *value ) + const WS_STRUCT_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) { - ULONG i, size; + ULONG i, field_size; + const void *ptr, *field_ptr; HRESULT hr; - const char *ptr; + if (!desc) return E_INVALIDARG; if (desc->structOptions) FIXME( "struct options 0x%x not supported\n", desc->structOptions ); + if ((hr = get_value_ptr( option, value, size, desc->size, (const void **)&ptr )) != S_OK) return hr; + for (i = 0; i < desc->fieldCount; i++) { - ptr = (const char *)value + desc->fields[i]->offset; - size = get_field_size( desc, i ); - if ((hr = write_type_struct_field( writer, desc->fields[i], ptr, size )) != S_OK) + field_ptr = (const char *)ptr + desc->fields[i]->offset; + field_size = get_field_size( desc, i ); + if ((hr = write_type_struct_field( writer, desc->fields[i], field_ptr, field_size )) != S_OK) return hr; } return S_OK; } -static HRESULT get_value_ptr( WS_WRITE_OPTION option, const void *value, ULONG size, const void **ptr ) -{ - switch (option) - { - case WS_WRITE_REQUIRED_VALUE: - case WS_WRITE_NILLABLE_VALUE: - if (!value || !size) return E_INVALIDARG; - *ptr = value; - return S_OK; - - case WS_WRITE_REQUIRED_POINTER: - case WS_WRITE_NILLABLE_POINTER: - if (size != sizeof(const void *) || !(*ptr = *(const void **)value)) return E_INVALIDARG; - return S_OK; - - default: - FIXME( "option %08x not supported\n", option ); - return E_NOTIMPL; - } -} static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TYPE type, const void *desc, WS_WRITE_OPTION option, const void *value, ULONG size ) { - HRESULT hr; - switch (type) { case WS_STRUCT_TYPE: - { - const void *ptr; - if (!desc) return E_INVALIDARG; - if (!option) option = WS_WRITE_REQUIRED_POINTER; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_struct( writer, mapping, desc, ptr ); - } + return write_type_struct( writer, mapping, desc, option, value, size ); + case WS_BOOL_TYPE: - { - const BOOL *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_bool( writer, mapping, desc, ptr ); - } + return write_type_bool( writer, mapping, desc, option, value, size ); + case WS_INT8_TYPE: - { - const INT8 *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_int8( writer, mapping, desc, ptr ); - } + return write_type_int8( writer, mapping, desc, option, value, size ); + case WS_INT16_TYPE: - { - const INT16 *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_int16( writer, mapping, desc, ptr ); - } + return write_type_int16( writer, mapping, desc, option, value, size ); + case WS_INT32_TYPE: - { - const INT32 *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_int32( writer, mapping, desc, ptr ); - } + return write_type_int32( writer, mapping, desc, option, value, size ); + case WS_INT64_TYPE: - { - const INT64 *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_int64( writer, mapping, desc, ptr ); - } + return write_type_int64( writer, mapping, desc, option, value, size ); + case WS_UINT8_TYPE: - { - const UINT8 *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_uint8( writer, mapping, desc, ptr ); - } + return write_type_uint8( writer, mapping, desc, option, value, size ); + case WS_UINT16_TYPE: - { - const UINT16 *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_uint16( writer, mapping, desc, ptr ); - } + return write_type_uint16( writer, mapping, desc, option, value, size ); + case WS_UINT32_TYPE: - { - const UINT32 *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_uint32( writer, mapping, desc, ptr ); - } + return write_type_uint32( writer, mapping, desc, option, value, size ); + case WS_UINT64_TYPE: - { - const UINT64 *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_uint64( writer, mapping, desc, ptr ); - } + return write_type_uint64( writer, mapping, desc, option, value, size ); + case WS_GUID_TYPE: - { - const GUID *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_guid( writer, mapping, desc, ptr ); - } + return write_type_guid( writer, mapping, desc, option, value, size ); + case WS_STRING_TYPE: - { - const WS_STRING *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_string( writer, mapping, desc, ptr ); - } - case WS_WSZ_TYPE: - { - const WCHAR *ptr; + return write_type_string( writer, mapping, desc, option, value, size ); - if (option == WS_WRITE_REQUIRED_VALUE) return E_INVALIDARG; + case WS_WSZ_TYPE: + return write_type_wsz( writer, mapping, desc, option, value, size ); - if (!option) option = WS_WRITE_REQUIRED_POINTER; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_wsz( writer, mapping, desc, ptr ); - } case WS_XML_STRING_TYPE: - { - const WS_XML_STRING *ptr; - if (!option) option = WS_WRITE_REQUIRED_VALUE; - if ((hr = get_value_ptr( option, value, size, (const void **)&ptr )) != S_OK) return hr; - return write_type_xml_string( writer, mapping, desc, ptr ); - } + return write_type_xml_string( writer, mapping, desc, option, value, size ); + default: FIXME( "type %u not supported\n", type ); return E_NOTIMPL; -- 2.1.4