[2/8] webservices: Fix corner cases in write option handling.

Hans Leidekker hans at codeweavers.com
Wed Sep 28 05:38:00 CDT 2016


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 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, "<t>-1</t>" },
+        { WS_INT32_TYPE, WS_WRITE_REQUIRED_VALUE, &val_int_zero, sizeof(val_int_zero), S_OK, "<t>0</t>" },
+        { 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, "<t>-1</t>" },
+        { 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, "<t>-1</t>" },
+        { WS_INT32_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_int_null, sizeof(ptr_int_null), S_OK,
+          "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
+        { 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, "<t>x</t>" },
+        { WS_XML_STRING_TYPE, WS_WRITE_REQUIRED_VALUE, &val_xmlstr_zero, sizeof(val_xmlstr_zero), S_OK, "<t/>" },
+        { 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,
+          "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
+        { 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, "<t>x</t>" },
+        { 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, "<t>x</t>" },
+        { WS_XML_STRING_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_xmlstr_null, sizeof(ptr_xmlstr_null), S_OK,
+          "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
+        { 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, "<t>s</t>" },
+        { 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, "<t>s</t>" },
+        { WS_WSZ_TYPE, WS_WRITE_NILLABLE_POINTER, &ptr_wsz_null, sizeof(ptr_wsz_null), S_OK,
+          "<t a:nil=\"true\" xmlns:a=\"http://www.w3.org/2001/XMLSchema-instance\"/>" },
+    };
+    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




More information about the wine-patches mailing list