[1/6] webservices: Add support for optional values in WsReadType.

Hans Leidekker hans at codeweavers.com
Wed Mar 30 07:12:14 CDT 2016


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/reader.c              | 816 +++++++++++++++++++++++----------
 dlls/webservices/webservices_private.h |   1 +
 dlls/webservices/writer.c              |   2 +-
 3 files changed, 568 insertions(+), 251 deletions(-)

diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index 20b284f..7adc283 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -1987,21 +1987,35 @@ HRESULT WINAPI WsFindAttribute( WS_XML_READER *handle, const WS_XML_STRING *loca
 
 static HRESULT read_get_text( struct reader *reader, WS_TYPE_MAPPING mapping,
                               const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                              WS_XML_UTF8_TEXT **ret )
+                              WS_XML_UTF8_TEXT **ret, BOOL *found )
 {
     switch (mapping)
     {
     case WS_ATTRIBUTE_TYPE_MAPPING:
     {
         ULONG index;
-        if (!find_attribute( reader, localname, ns, &index )) return WS_E_INVALID_FORMAT;
+        if (!(*found = find_attribute( reader, localname, ns, &index ))) return S_OK;
         return read_get_attribute_text( reader, index, ret );
     }
     case WS_ELEMENT_TYPE_MAPPING:
     case WS_ELEMENT_CONTENT_TYPE_MAPPING:
-        /* FIXME: verify localname and ns */
-        return read_get_node_text( reader, ret );
+    {
+        HRESULT hr;
+        *found = TRUE;
+        if (localname)
+        {
+            const WS_XML_ELEMENT_NODE *elem = &reader->current->hdr;
 
+            if (WsXmlStringEquals( localname, elem->localName, NULL ) != S_OK ||
+                WsXmlStringEquals( ns, elem->ns, NULL ) != S_OK)
+            {
+                *found = FALSE;
+                return S_OK;
+            }
+            if ((hr = read_startelement( reader )) != S_OK) return hr;
+        }
+        return read_get_node_text( reader, ret );
+    }
     default:
         FIXME( "mapping %u not supported\n", mapping );
         return E_NOTIMPL;
@@ -2010,318 +2024,596 @@ static HRESULT read_get_text( struct reader *reader, WS_TYPE_MAPPING mapping,
 
 static HRESULT read_type_bool( struct reader *reader, WS_TYPE_MAPPING mapping,
                                const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                               const WS_BOOL_DESCRIPTION *desc, BOOL *ret )
+                               const WS_BOOL_DESCRIPTION *desc, WS_READ_OPTION option,
+                               WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
-    ULONG len;
+    BOOL found, val = FALSE;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-    len = utf8->value.length;
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found)
+    {
+        ULONG len = utf8->value.length;
+        if (len == 4 && !memcmp( utf8->value.bytes, "true", 4 )) val = TRUE;
+        else if (len == 1 && !memcmp( utf8->value.bytes, "1", 1 )) val = TRUE;
+        else if (len == 5 && !memcmp( utf8->value.bytes, "false", 5 )) val = FALSE;
+        else if (len == 1 && !memcmp( utf8->value.bytes, "0", 1 )) val = FALSE;
+        else return WS_E_INVALID_FORMAT;
+    }
 
-    if (len == 4 && !memcmp( utf8->value.bytes, "true", 4 )) *ret = TRUE;
-    else if (len == 1 && !memcmp( utf8->value.bytes, "1", 1 )) *ret = TRUE;
-    else if (len == 5 && !memcmp( utf8->value.bytes, "false", 5 )) *ret = FALSE;
-    else if (len == 1 && !memcmp( utf8->value.bytes, "0", 1 )) *ret = FALSE;
-    else return WS_E_INVALID_FORMAT;
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(BOOL)) return E_INVALIDARG;
+        *(BOOL *)ret = val;
+        break;
+
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
+
+    case WS_READ_OPTIONAL_POINTER:
+    {
+        BOOL *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(BOOL **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
+        return E_NOTIMPL;
+    }
 
     return S_OK;
 }
 
 static HRESULT read_type_int8( struct reader *reader, WS_TYPE_MAPPING mapping,
                                const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                               const WS_INT8_DESCRIPTION *desc, INT8 *ret )
+                               const WS_INT8_DESCRIPTION *desc, WS_READ_OPTION option,
+                               WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
     INT64 val;
+    BOOL found;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-
-    if ((hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT8, MAX_INT8, &val )) != S_OK)
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT8, MAX_INT8, &val )) != S_OK)
         return hr;
 
-    *ret = val;
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(INT8)) return E_INVALIDARG;
+        *(INT8 *)ret = val;
+        break;
+
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
+
+    case WS_READ_OPTIONAL_POINTER:
+    {
+        INT8 *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(INT8 **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
+        return E_NOTIMPL;
+    }
+
     return S_OK;
 }
 
 static HRESULT read_type_int16( struct reader *reader, WS_TYPE_MAPPING mapping,
                                 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                                const WS_INT16_DESCRIPTION *desc, INT16 *ret )
+                                const WS_INT16_DESCRIPTION *desc, WS_READ_OPTION option,
+                                WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
     INT64 val;
+    BOOL found;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-
-    if ((hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT16, MAX_INT16, &val )) != S_OK)
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT16, MAX_INT16, &val )) != S_OK)
         return hr;
 
-    *ret = val;
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(INT16)) return E_INVALIDARG;
+        *(INT16 *)ret = val;
+        break;
+
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
+
+    case WS_READ_OPTIONAL_POINTER:
+    {
+        INT16 *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(INT16 **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
+        return E_NOTIMPL;
+    }
+
     return S_OK;
 }
 
 static HRESULT read_type_int32( struct reader *reader, WS_TYPE_MAPPING mapping,
                                 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                                const WS_INT32_DESCRIPTION *desc, INT32 *ret )
+                                const WS_INT32_DESCRIPTION *desc, WS_READ_OPTION option,
+                                WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
     INT64 val;
+    BOOL found;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-
-    if ((hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT32, MAX_INT32, &val )) != S_OK)
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT32, MAX_INT32, &val )) != S_OK)
         return hr;
 
-    *ret = val;
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(INT32)) return E_INVALIDARG;
+        *(INT32 *)ret = val;
+        break;
+
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
+
+    case WS_READ_OPTIONAL_POINTER:
+    {
+        INT32 *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(INT32 **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
+        return E_NOTIMPL;
+    }
+
     return S_OK;
 }
 
 static HRESULT read_type_int64( struct reader *reader, WS_TYPE_MAPPING mapping,
                                 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                                const WS_INT64_DESCRIPTION *desc, INT64 *ret )
+                                const WS_INT64_DESCRIPTION *desc, WS_READ_OPTION option,
+                                WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
     INT64 val;
+    BOOL found;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-
-    if ((hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT64, MAX_INT64, &val )) != S_OK)
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && (hr = str_to_int64( utf8->value.bytes, utf8->value.length, MIN_INT64, MAX_INT64, &val )) != S_OK)
         return hr;
 
-    *ret = val;
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(INT64)) return E_INVALIDARG;
+        *(INT64 *)ret = val;
+        break;
+
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
+
+    case WS_READ_OPTIONAL_POINTER:
+    {
+        INT64 *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(INT64 **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
+        return E_NOTIMPL;
+    }
+
     return S_OK;
 }
 
 static HRESULT read_type_uint8( struct reader *reader, WS_TYPE_MAPPING mapping,
                                 const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                                const WS_UINT8_DESCRIPTION *desc, UINT8 *ret )
+                                const WS_UINT8_DESCRIPTION *desc, WS_READ_OPTION option,
+                                WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
     UINT64 val;
+    BOOL found;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-
-    if ((hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT8, &val )) != S_OK)
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT8, &val )) != S_OK)
         return hr;
 
-    *ret = val;
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(UINT8)) return E_INVALIDARG;
+        *(UINT8 *)ret = val;
+        break;
+
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
+
+    case WS_READ_OPTIONAL_POINTER:
+    {
+        UINT8 *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(UINT8 **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
+        return E_NOTIMPL;
+    }
+
     return S_OK;
 }
 
 static HRESULT read_type_uint16( struct reader *reader, WS_TYPE_MAPPING mapping,
                                  const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                                 const WS_UINT16_DESCRIPTION *desc, UINT16 *ret )
+                                 const WS_UINT16_DESCRIPTION *desc, WS_READ_OPTION option,
+                                 WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
     UINT64 val;
+    BOOL found;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-
-    if ((hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT16, &val )) != S_OK)
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT16, &val )) != S_OK)
         return hr;
 
-    *ret = val;
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(UINT16)) return E_INVALIDARG;
+        *(UINT16 *)ret = val;
+        break;
+
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
+
+    case WS_READ_OPTIONAL_POINTER:
+    {
+        UINT16 *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(UINT16 **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
+        return E_NOTIMPL;
+    }
+
     return S_OK;
 }
 
 static HRESULT read_type_uint32( struct reader *reader, WS_TYPE_MAPPING mapping,
                                  const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                                 const WS_UINT32_DESCRIPTION *desc, UINT32 *ret )
+                                 const WS_UINT32_DESCRIPTION *desc, WS_READ_OPTION option,
+                                 WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
     UINT64 val;
+    BOOL found;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-
-    if ((hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT32, &val )) != S_OK)
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT32, &val )) != S_OK)
         return hr;
 
-    *ret = val;
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(UINT32)) return E_INVALIDARG;
+        *(UINT32 *)ret = val;
+        break;
+
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
+
+    case WS_READ_OPTIONAL_POINTER:
+    {
+        UINT32 *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(UINT32 **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
+        return E_NOTIMPL;
+    }
+
     return S_OK;
 }
 
 static HRESULT read_type_uint64( struct reader *reader, WS_TYPE_MAPPING mapping,
                                  const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                                 const WS_UINT64_DESCRIPTION *desc, UINT64 *ret )
+                                 const WS_UINT64_DESCRIPTION *desc, WS_READ_OPTION option,
+                                 WS_HEAP *heap, void *ret, ULONG size )
 {
     WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
     UINT64 val;
+    BOOL found;
 
     if (desc)
     {
         FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
-
-    if ((hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT64, &val )) != S_OK)
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && (hr = str_to_uint64( utf8->value.bytes, utf8->value.length, MAX_UINT64, &val )) != S_OK)
         return hr;
 
-    *ret = val;
-    return S_OK;
-}
+    switch (option)
+    {
+    case WS_READ_REQUIRED_VALUE:
+        if (!found) return WS_E_INVALID_FORMAT;
+        if (size != sizeof(UINT64)) return E_INVALIDARG;
+        *(UINT64 *)ret = val;
+        break;
 
-static HRESULT read_type_wsz( struct reader *reader, WS_TYPE_MAPPING mapping,
-                              const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                              const WS_WSZ_DESCRIPTION *desc, WS_HEAP *heap, WCHAR **ret )
-{
-    WS_XML_UTF8_TEXT *utf8;
-    HRESULT hr;
-    WCHAR *str;
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
 
-    if (desc)
+    case WS_READ_OPTIONAL_POINTER:
     {
-        FIXME( "description not supported\n" );
+        UINT64 *heap_val = NULL;
+        if (size != sizeof(heap_val)) return E_INVALIDARG;
+        if (found)
+        {
+            if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+            *heap_val = val;
+        }
+        *(UINT64 **)ret = heap_val;
+        break;
+    }
+    default:
+        FIXME( "read option %u not supported\n", option );
         return E_NOTIMPL;
     }
-    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8 )) != S_OK) return hr;
 
-    if (!(str = xmltext_to_widechar( heap, &utf8->text ))) return WS_E_QUOTA_EXCEEDED;
-    *ret = str;
     return S_OK;
 }
 
-static HRESULT read_type_struct( struct reader *, WS_TYPE_MAPPING, const WS_XML_STRING *localname,
-                                 const WS_XML_STRING *ns, const WS_STRUCT_DESCRIPTION *, WS_HEAP *,
-                                 void ** );
-
-static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
-                                       WS_HEAP *heap, char *buf )
+static HRESULT read_type_wsz( struct reader *reader, WS_TYPE_MAPPING mapping,
+                              const WS_XML_STRING *localname, const WS_XML_STRING *ns,
+                              const WS_WSZ_DESCRIPTION *desc, WS_READ_OPTION option,
+                              WS_HEAP *heap, WCHAR **ret, ULONG size )
 {
-    char *ptr = buf + desc->offset;
-    WS_TYPE_MAPPING mapping;
+    WS_XML_UTF8_TEXT *utf8;
     HRESULT hr;
+    WCHAR *str = NULL;
+    BOOL found;
 
-    if (desc->options && desc->options != WS_FIELD_POINTER &&
-        desc->options != WS_FIELD_OPTIONAL &&
-        desc->options != (WS_FIELD_POINTER | WS_FIELD_OPTIONAL))
+    if (desc)
     {
-        FIXME( "options 0x%x not supported\n", desc->options );
+        FIXME( "description not supported\n" );
         return E_NOTIMPL;
     }
+    if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+    if (found && !(str = xmltext_to_widechar( heap, &utf8->text ))) return WS_E_QUOTA_EXCEEDED;
 
-    switch (desc->mapping)
+    switch (option)
     {
-    case WS_ATTRIBUTE_FIELD_MAPPING:
-        mapping = WS_ATTRIBUTE_TYPE_MAPPING;
-        break;
+    case WS_READ_REQUIRED_POINTER:
+        if (!found) return WS_E_INVALID_FORMAT;
+        /* fall through */
 
-    case WS_ELEMENT_FIELD_MAPPING:
-        mapping = WS_ELEMENT_TYPE_MAPPING;
+    case WS_READ_OPTIONAL_POINTER:
+        if (size != sizeof(str)) return E_INVALIDARG;
+        *ret = str;
         break;
 
     default:
-        FIXME( "unhandled field mapping %u\n", desc->mapping );
+        FIXME( "read option %u not supported\n", option );
         return E_NOTIMPL;
     }
 
-    switch (desc->type)
+    return S_OK;
+}
+
+static HRESULT read_type( struct reader *, WS_TYPE_MAPPING, WS_TYPE, const WS_XML_STRING *,
+                          const WS_XML_STRING *, const void *, WS_READ_OPTION, WS_HEAP *,
+                          void *, ULONG );
+
+static WS_READ_OPTION map_field_options( WS_TYPE type, ULONG options )
+{
+    if (options & !(WS_FIELD_POINTER | WS_FIELD_OPTIONAL))
     {
-    case WS_STRUCT_TYPE:
-        hr = read_type_struct( reader, mapping, desc->localName, desc->ns, desc->typeDescription, heap, (void **)ptr );
-        break;
+        FIXME( "options %08x not supported\n", options );
+        return 0;
+    }
 
+    switch (type)
+    {
     case WS_BOOL_TYPE:
-        hr = read_type_bool( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (BOOL *)ptr );
-        break;
-
     case WS_INT8_TYPE:
-        hr = read_type_int8( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (INT8 *)ptr );
-        break;
-
     case WS_INT16_TYPE:
-        hr = read_type_int16( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (INT16 *)ptr );
-        break;
-
     case WS_INT32_TYPE:
-        hr = read_type_int32( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (INT32 *)ptr );
-        break;
-
     case WS_INT64_TYPE:
-        hr = read_type_int64( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (INT64 *)ptr );
-        break;
-
     case WS_UINT8_TYPE:
-        hr = read_type_uint8( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (UINT8 *)ptr );
-        break;
-
     case WS_UINT16_TYPE:
-        hr = read_type_uint16( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (UINT16 *)ptr );
-        break;
-
     case WS_UINT32_TYPE:
-        hr = read_type_uint32( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (UINT32 *)ptr );
-        break;
-
     case WS_UINT64_TYPE:
-        hr = read_type_uint64( reader, mapping, desc->localName, desc->ns, desc->typeDescription, (UINT64 *)ptr );
-        break;
+        return WS_READ_REQUIRED_VALUE;
 
     case WS_WSZ_TYPE:
-        hr = read_type_wsz( reader, mapping, desc->localName, desc->ns, desc->typeDescription, heap, (WCHAR **)ptr );
+    case WS_STRUCT_TYPE:
+        return WS_READ_REQUIRED_POINTER;
+
+    default:
+        FIXME( "unhandled type %u\n", type );
+        return 0;
+    }
+}
+
+static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DESCRIPTION *desc,
+                                       WS_HEAP *heap, char *buf, ULONG size )
+{
+    char *ptr = buf + desc->offset;
+    WS_READ_OPTION option;
+    HRESULT hr;
+
+    if (!(option = map_field_options( desc->type, desc->options ))) return E_INVALIDARG;
+
+    switch (desc->mapping)
+    {
+    case WS_ATTRIBUTE_FIELD_MAPPING:
+        hr = read_type( reader, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
+                        desc->typeDescription, option, heap, ptr, size );
+        break;
+
+    case WS_ELEMENT_FIELD_MAPPING:
+        hr = read_type( reader, WS_ELEMENT_TYPE_MAPPING, desc->type, desc->localName, desc->ns,
+                        desc->typeDescription, option, heap, ptr, size );
         break;
 
     default:
-        FIXME( "type %u not implemented\n", desc->type );
+        FIXME( "unhandled field mapping %u\n", desc->mapping );
         return E_NOTIMPL;
     }
 
+
+    if (hr == WS_E_INVALID_FORMAT && desc->options & WS_FIELD_OPTIONAL)
+    {
+        switch (option)
+        {
+        case WS_READ_REQUIRED_VALUE:
+            if (desc->defaultValue) memcpy( ptr, desc->defaultValue->value, desc->defaultValue->valueSize );
+            else memset( ptr, 0, size );
+            return S_OK;
+
+        case WS_READ_REQUIRED_POINTER:
+            *(void **)ptr = NULL;
+            return S_OK;
+
+        default:
+            ERR( "unhandled option %u\n", option );
+            return E_NOTIMPL;
+        }
+    }
+
     return hr;
 }
 
 static HRESULT read_type_struct( struct reader *reader, WS_TYPE_MAPPING mapping,
                                  const WS_XML_STRING *localname, const WS_XML_STRING *ns,
-                                 const WS_STRUCT_DESCRIPTION *desc, WS_HEAP *heap, void **ret )
+                                 const WS_STRUCT_DESCRIPTION *desc, WS_READ_OPTION option,
+                                 WS_HEAP *heap, void *ret, ULONG size )
 {
-    ULONG i;
+    ULONG i, field_size;
     HRESULT hr;
     char *buf;
 
@@ -2329,185 +2621,203 @@ static HRESULT read_type_struct( struct reader *reader, WS_TYPE_MAPPING mapping,
 
     if (desc->structOptions)
     {
-        FIXME( "struct options 0x%x not supported\n", desc->structOptions );
+        FIXME( "struct options %08x not supported\n", desc->structOptions );
         return E_NOTIMPL;
     }
 
-    switch (mapping)
+    switch (option)
     {
-    case WS_ELEMENT_TYPE_MAPPING:
-        if ((hr = read_to_startelement( reader, NULL )) != S_OK) return hr;
+    case WS_READ_REQUIRED_POINTER:
+    case WS_READ_OPTIONAL_POINTER:
+        if (size < sizeof(void *)) return E_INVALIDARG;
+        if (!(buf = ws_alloc_zero( heap, desc->size ))) return WS_E_QUOTA_EXCEEDED;
         break;
 
-    case WS_ELEMENT_CONTENT_TYPE_MAPPING:
-        if ((hr = read_to_startelement( reader, NULL )) != S_OK) return hr;
-        if ((hr = read_startelement( reader )) != S_OK) return hr;
+    case WS_READ_REQUIRED_VALUE:
+        if (size != desc->size) return E_INVALIDARG;
+        buf = ret;
         break;
 
     default:
-        FIXME( "unhandled mapping %u\n", mapping );
+        FIXME( "unhandled read option %u\n", option );
         return E_NOTIMPL;
     }
 
-    if (!(buf = ws_alloc_zero( heap, desc->size ))) return WS_E_QUOTA_EXCEEDED;
-
     for (i = 0; i < desc->fieldCount; i++)
     {
-        if ((hr = read_type_struct_field( reader, desc->fields[i], heap, buf )) != S_OK)
+        field_size = get_field_size( desc, i );
+        if ((hr = read_type_struct_field( reader, desc->fields[i], heap, buf, field_size )) != S_OK)
+            break;
+    }
+
+    switch (option)
+    {
+    case WS_READ_REQUIRED_POINTER:
+        if (hr != S_OK)
         {
             ws_free( heap, buf );
             return hr;
         }
+        *(char **)ret = buf;
+        return S_OK;
+
+    case WS_READ_OPTIONAL_POINTER:
+        if (hr != S_OK)
+        {
+            ws_free( heap, buf );
+            buf = NULL;
+        }
+        *(char **)ret = buf;
+        return S_OK;
+
+    case WS_READ_REQUIRED_VALUE:
+        return hr;
+
+    default:
+        ERR( "unhandled read option %u\n", option );
+        return E_NOTIMPL;
     }
+}
 
-    switch (mapping)
+static BOOL is_empty_text_node( const struct node *node )
+{
+    const WS_XML_TEXT_NODE *text = (const WS_XML_TEXT_NODE *)node;
+    const WS_XML_UTF8_TEXT *utf8;
+    ULONG i;
+
+    if (node->hdr.node.nodeType != WS_XML_NODE_TYPE_TEXT) return FALSE;
+    if (text->text->textType != WS_XML_TEXT_TYPE_UTF8)
     {
-    case WS_ELEMENT_TYPE_MAPPING:
-        if ((hr = read_startelement( reader )) != S_OK) return hr;
-        if ((hr = read_node( reader )) != S_OK) return hr;
-        break;
+        ERR( "unhandled text type %u\n", text->text->textType );
+        return FALSE;
+    }
+    utf8 = (const WS_XML_UTF8_TEXT *)text->text;
+    for (i = 0; i < utf8->value.length; i++) if (!read_isspace( utf8->value.bytes[i] )) return FALSE;
+    return TRUE;
+}
 
-    case WS_ELEMENT_CONTENT_TYPE_MAPPING:
-        if ((hr = read_endelement( reader )) != S_OK) return hr;
-        if ((hr = read_node( reader )) != S_OK) return hr;
-        if (reader->state != READER_STATE_EOF) return WS_E_INVALID_FORMAT;
-        break;
+static HRESULT read_type_next_node( struct reader *reader, const WS_XML_STRING *localname,
+                                    const WS_XML_STRING *ns )
+{
+    const WS_XML_ELEMENT_NODE *elem;
+    WS_XML_NODE_TYPE type;
+    HRESULT hr;
+    BOOL found;
+
+    if (!localname) return S_OK; /* assume reader is already correctly positioned */
+    if ((hr = read_to_startelement( reader, &found ) != S_OK)) return hr;
+    if (!found) return WS_E_INVALID_FORMAT;
 
-    default: break;
+    elem = &reader->current->hdr;
+    if (WsXmlStringEquals( localname, elem->localName, NULL ) == S_OK &&
+        WsXmlStringEquals( ns, elem->ns, NULL ) == S_OK) return S_OK;
+
+    for (;;)
+    {
+        if ((hr = read_node( reader ) != S_OK)) return hr;
+        type = reader->current->hdr.node.nodeType;
+        if (type == WS_XML_NODE_TYPE_COMMENT ||
+            (type == WS_XML_NODE_TYPE_TEXT && is_empty_text_node( reader->current ))) continue;
+        break;
     }
 
-    *ret = buf;
     return S_OK;
 }
 
 static HRESULT read_type( struct reader *reader, WS_TYPE_MAPPING mapping, WS_TYPE type,
+                          const WS_XML_STRING *localname, const WS_XML_STRING *ns,
                           const void *desc, WS_READ_OPTION option, WS_HEAP *heap,
                           void *value, ULONG size )
 {
+    HRESULT hr;
+
+    switch (mapping)
+    {
+    case WS_ELEMENT_TYPE_MAPPING:
+    case WS_ELEMENT_CONTENT_TYPE_MAPPING:
+        if ((hr = read_type_next_node( reader, localname, ns )) != S_OK) return hr;
+        break;
+
+    case WS_ATTRIBUTE_TYPE_MAPPING:
+        break;
+
+    default:
+        FIXME( "unhandled mapping %u\n", mapping );
+        return E_NOTIMPL;
+    }
+
     switch (type)
     {
     case WS_STRUCT_TYPE:
-    {
-        void **ptr = value;
-        if (option != WS_READ_REQUIRED_POINTER || size != sizeof(*ptr))
-            return E_INVALIDARG;
+        if ((hr = read_type_struct( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
 
-        return read_type_struct( reader, mapping, NULL, NULL, desc, heap, ptr );
-    }
     case WS_BOOL_TYPE:
-    {
-        BOOL *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_bool( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_bool( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_INT8_TYPE:
-    {
-        INT8 *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_int8( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_int8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_INT16_TYPE:
-    {
-        INT16 *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_int16( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_int16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_INT32_TYPE:
-    {
-        INT32 *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_int32( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_int32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_INT64_TYPE:
-    {
-        INT64 *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_int64( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_int64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_UINT8_TYPE:
-    {
-        UINT8 *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_uint8( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_uint8( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_UINT16_TYPE:
-    {
-        UINT16 *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_uint16( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_uint16( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_UINT32_TYPE:
-    {
-        UINT32 *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_uint32( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_uint32( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_UINT64_TYPE:
-    {
-        UINT64 *ptr = value;
-        if (option != WS_READ_REQUIRED_VALUE)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_uint64( reader, mapping, NULL, NULL, desc, ptr );
-    }
+        if ((hr = read_type_uint64( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     case WS_WSZ_TYPE:
-    {
-        WCHAR **ptr = value;
-        if (option != WS_READ_REQUIRED_POINTER)
-        {
-            FIXME( "read option %u not supported\n", option );
-            return E_NOTIMPL;
-        }
-        if (size != sizeof(*ptr)) return E_INVALIDARG;
-        return read_type_wsz( reader, mapping, NULL, NULL, desc, heap, ptr );
-    }
+        if ((hr = read_type_wsz( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+            return hr;
+        break;
+
     default:
         FIXME( "type %u not supported\n", type );
         return E_NOTIMPL;
     }
+
+    switch (mapping)
+    {
+    case WS_ELEMENT_TYPE_MAPPING:
+    case WS_ELEMENT_CONTENT_TYPE_MAPPING:
+        return read_node( reader );
+
+    case WS_ATTRIBUTE_TYPE_MAPPING:
+    default:
+        return S_OK;
+    }
 }
 
 /**************************************************************************
@@ -2518,6 +2828,7 @@ HRESULT WINAPI WsReadType( WS_XML_READER *handle, WS_TYPE_MAPPING mapping, WS_TY
                            ULONG size, WS_ERROR *error )
 {
     struct reader *reader = (struct reader *)handle;
+    HRESULT hr;
 
     TRACE( "%p %u %u %p %u %p %p %u %p\n", handle, mapping, type, desc, option, heap, value,
            size, error );
@@ -2525,7 +2836,12 @@ HRESULT WINAPI WsReadType( WS_XML_READER *handle, WS_TYPE_MAPPING mapping, WS_TY
 
     if (!reader || !value) return E_INVALIDARG;
 
-    return read_type( reader, mapping, type, desc, option, heap, value, size );
+    if ((hr = read_type( reader, mapping, type, NULL, NULL, desc, option, heap, value, size )) != S_OK)
+        return hr;
+
+    if ((hr = read_node( reader )) != S_OK) return hr;
+    if (!read_end_of_data( reader )) return WS_E_INVALID_FORMAT;
+    return S_OK;
 }
 
 /**************************************************************************
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index 780c5c4..aa14416 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -32,6 +32,7 @@ WS_XML_STRING *alloc_xml_string( const unsigned char *, ULONG ) 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;
+ULONG get_field_size( const WS_STRUCT_DESCRIPTION *, ULONG ) DECLSPEC_HIDDEN;
 
 struct node
 {
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index 858c9d0..0c5f3cf5 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -1378,7 +1378,7 @@ static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DE
     return S_OK;
 }
 
-static ULONG get_field_size( const WS_STRUCT_DESCRIPTION *desc, ULONG index )
+ULONG get_field_size( const WS_STRUCT_DESCRIPTION *desc, ULONG index )
 {
     if (index < desc->fieldCount - 1) return desc->fields[index + 1]->offset - desc->fields[index]->offset;
     return desc->size - desc->fields[index]->offset;
-- 
2.8.0.rc3




More information about the wine-patches mailing list