[2/7] webservices: Add support for union types in the writer.

Hans Leidekker hans at codeweavers.com
Mon Jul 10 04:02:29 CDT 2017


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/webservices/reader.c              |  15 +++--
 dlls/webservices/tests/writer.c        | 117 +++++++++++++++++++++++++++++++++
 dlls/webservices/webservices_private.h |   2 +-
 dlls/webservices/writer.c              |  56 ++++++++++++++--
 include/webservices.h                  |  15 +++++
 5 files changed, 194 insertions(+), 11 deletions(-)

diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index 9d75f94..254efb9 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -5073,7 +5073,7 @@ static HRESULT read_type_next_element_node( struct reader *reader, const WS_XML_
     return WS_E_INVALID_FORMAT;
 }
 
-ULONG get_type_size( WS_TYPE type, const WS_STRUCT_DESCRIPTION *desc )
+ULONG get_type_size( WS_TYPE type, const void *desc )
 {
     switch (type)
     {
@@ -5119,12 +5119,19 @@ ULONG get_type_size( WS_TYPE type, const WS_STRUCT_DESCRIPTION *desc )
     case WS_XML_QNAME_TYPE:
         return sizeof(WS_XML_QNAME);
 
-    case WS_STRUCT_TYPE:
-        return desc->size;
-
     case WS_DESCRIPTION_TYPE:
         return sizeof(WS_STRUCT_DESCRIPTION *);
 
+    case WS_STRUCT_TYPE:
+    {
+        const WS_STRUCT_DESCRIPTION *desc_struct = desc;
+        return desc_struct->size;
+    }
+    case WS_UNION_TYPE:
+    {
+        const WS_UNION_DESCRIPTION *desc_union = desc;
+        return desc_union->size;
+    }
     default:
         ERR( "unhandled type %u\n", type );
         return 0;
diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c
index 0a8d753..f08c4ce 100644
--- a/dlls/webservices/tests/writer.c
+++ b/dlls/webservices/tests/writer.c
@@ -3909,6 +3909,122 @@ static void test_dictionary(void)
     WsFreeWriter( writer );
 }
 
+static void test_union_type(void)
+{
+    static const WCHAR testW[] = {'t','e','s','t',0};
+    static WS_XML_STRING str_ns = {0, NULL}, str_a = {1, (BYTE *)"a"}, str_b = {1, (BYTE *)"b"};
+    static WS_XML_STRING str_s = {1, (BYTE *)"s"}, str_t = {1, (BYTE *)"t"};
+    HRESULT hr;
+    WS_XML_WRITER *writer;
+    WS_UNION_DESCRIPTION u;
+    WS_UNION_FIELD_DESCRIPTION f, f2, *fields[2];
+    WS_FIELD_DESCRIPTION f_struct, *fields_struct[1];
+    WS_STRUCT_DESCRIPTION s;
+    enum choice {CHOICE_A, CHOICE_B, CHOICE_NONE};
+    struct test
+    {
+        enum choice choice;
+        union
+        {
+            const WCHAR *a;
+            UINT32       b;
+        } value;
+    } test;
+
+    hr = WsCreateWriter( NULL, 0, &writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    memset( &f, 0, sizeof(f) );
+    f.value           = CHOICE_A;
+    f.field.mapping   = WS_ELEMENT_FIELD_MAPPING;
+    f.field.localName = &str_a;
+    f.field.ns        = &str_ns;
+    f.field.type      = WS_WSZ_TYPE;
+    f.field.offset    = FIELD_OFFSET(struct test, value.a);
+    fields[0] = &f;
+
+    memset( &f2, 0, sizeof(f2) );
+    f2.value           = CHOICE_B;
+    f2.field.mapping   = WS_ELEMENT_FIELD_MAPPING;
+    f2.field.localName = &str_b;
+    f2.field.ns        = &str_ns;
+    f2.field.type      = WS_UINT32_TYPE;
+    f2.field.offset    = FIELD_OFFSET(struct test, value.b);
+    fields[1] = &f2;
+
+    memset( &u, 0, sizeof(u) );
+    u.size          = sizeof(struct test);
+    u.alignment     = TYPE_ALIGNMENT(struct test);
+    u.fields        = fields;
+    u.fieldCount    = 2;
+    u.enumOffset    = FIELD_OFFSET(struct test, choice);
+    u.noneEnumValue = CHOICE_NONE;
+
+    memset( &f_struct, 0, sizeof(f_struct) );
+    f_struct.mapping         = WS_ELEMENT_CHOICE_FIELD_MAPPING;
+    f_struct.type            = WS_UNION_TYPE;
+    f_struct.typeDescription = &u;
+    fields_struct[0] = &f_struct;
+
+    memset( &s, 0, sizeof(s) );
+    s.size          = sizeof(struct test);
+    s.alignment     = TYPE_ALIGNMENT(struct test);
+    s.fields        = fields_struct;
+    s.fieldCount    = 1;
+    s.typeLocalName = &str_s;
+    s.typeNs        = &str_ns;
+
+    hr = set_output( writer );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    test.choice  = CHOICE_A;
+    test.value.a = testW;
+    hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
+                      WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteEndElement( writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    check_output( writer, "<t><a>test</a></t>", __LINE__ );
+
+    hr = set_output( writer );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    test.choice  = CHOICE_B;
+    test.value.b = 123;
+    hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
+                      WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteEndElement( writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    check_output( writer, "<t><b>123</b></t>", __LINE__ );
+
+    hr = set_output( writer );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    test.choice  = CHOICE_NONE;
+    hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
+                      WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
+    ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr );
+
+    hr = set_output( writer );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteStartElement( writer, NULL, &str_t, &str_ns, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    test.choice = CHOICE_NONE;
+    f_struct.options = WS_FIELD_OPTIONAL;
+    hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s,
+                      WS_WRITE_REQUIRED_VALUE, &test, sizeof(test), NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    hr = WsWriteEndElement( writer, NULL );
+    ok( hr == S_OK, "got %08x\n", hr );
+    check_output( writer, "<t/>", __LINE__ );
+
+    WsFreeWriter( writer );
+}
+
 START_TEST(writer)
 {
     test_WsCreateWriter();
@@ -3949,4 +4065,5 @@ START_TEST(writer)
     test_binary_encoding();
     test_namespaces();
     test_dictionary();
+    test_union_type();
 }
diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h
index 1938587..68837db 100644
--- a/dlls/webservices/webservices_private.h
+++ b/dlls/webservices/webservices_private.h
@@ -67,7 +67,7 @@ WS_TYPE map_value_type( WS_VALUE_TYPE ) DECLSPEC_HIDDEN;
 BOOL set_fpword( unsigned short, unsigned short * ) DECLSPEC_HIDDEN;
 void restore_fpword( unsigned short ) DECLSPEC_HIDDEN;
 HRESULT set_output( WS_XML_WRITER * ) DECLSPEC_HIDDEN;
-ULONG get_type_size( WS_TYPE, const WS_STRUCT_DESCRIPTION * ) DECLSPEC_HIDDEN;
+ULONG get_type_size( WS_TYPE, const void * ) DECLSPEC_HIDDEN;
 HRESULT read_header( WS_XML_READER *, const WS_XML_STRING *, const WS_XML_STRING *, WS_TYPE,
                      const void *, WS_READ_OPTION, WS_HEAP *, void *, ULONG ) DECLSPEC_HIDDEN;
 
diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c
index 95ebd7c..b4793f9 100644
--- a/dlls/webservices/writer.c
+++ b/dlls/webservices/writer.c
@@ -2923,8 +2923,49 @@ static HRESULT write_type_repeating_element( struct writer *writer, const WS_FIE
     return hr;
 }
 
-static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc,
-                                        const char *buf, ULONG offset )
+static HRESULT write_type_field( struct writer *, const WS_FIELD_DESCRIPTION *, const char *, ULONG );
+
+static HRESULT write_type_union( struct writer *writer, const WS_UNION_DESCRIPTION *desc, WS_WRITE_OPTION option,
+                                 const void *value, ULONG size )
+{
+    ULONG i, offset;
+    const void *ptr;
+    int enum_value;
+    HRESULT hr;
+
+    if ((hr = get_value_ptr( option, value, size, desc->size, &ptr )) != S_OK) return hr;
+
+    if (size < sizeof(enum_value)) return E_INVALIDARG;
+    if ((enum_value = *(int *)(char *)ptr + desc->enumOffset) == desc->noneEnumValue)
+    {
+        switch (option)
+        {
+        case WS_WRITE_REQUIRED_VALUE:
+            return WS_E_INVALID_FORMAT;
+
+        case WS_WRITE_NILLABLE_VALUE:
+            return S_OK;
+
+        default:
+            ERR( "unhandled write option %u\n", option );
+            return E_INVALIDARG;
+        }
+    }
+
+    for (i = 0; i < desc->fieldCount; i++)
+    {
+        if (desc->fields[i]->value == enum_value)
+        {
+            offset = desc->fields[i]->field.offset;
+            return write_type_field( writer, &desc->fields[i]->field, ptr, offset );
+        }
+    }
+
+    return E_INVALIDARG;
+}
+
+static HRESULT write_type_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const char *buf,
+                                 ULONG offset )
 {
     HRESULT hr;
     WS_TYPE_MAPPING mapping;
@@ -2982,6 +3023,11 @@ static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DE
         mapping = WS_ELEMENT_TYPE_MAPPING;
         break;
 
+    case WS_ELEMENT_CHOICE_FIELD_MAPPING:
+        if (desc->type != WS_UNION_TYPE || !desc->typeDescription) return E_INVALIDARG;
+        option = (field_options & WS_FIELD_OPTIONAL) ? WS_WRITE_NILLABLE_VALUE : WS_WRITE_REQUIRED_VALUE;
+        return write_type_union( writer, desc->typeDescription, option, ptr, size );
+
     case WS_REPEATING_ELEMENT_FIELD_MAPPING:
         count = *(const ULONG *)(buf + desc->countOffset);
         return write_type_repeating_element( writer, desc, *(const char **)ptr, count );
@@ -3043,14 +3089,12 @@ static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping
     for (i = 0; i < desc->fieldCount; i++)
     {
         offset = desc->fields[i]->offset;
-        if ((hr = write_type_struct_field( writer, desc->fields[i], ptr, offset )) != S_OK)
-            return hr;
+        if ((hr = write_type_field( writer, desc->fields[i], ptr, offset )) != S_OK) return hr;
     }
 
     return S_OK;
 }
 
-
 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 )
@@ -4023,7 +4067,7 @@ done:
 
 static HRESULT write_param( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, const void *value )
 {
-    return write_type_struct_field( writer, desc, value, 0 );
+    return write_type_field( writer, desc, value, 0 );
 }
 
 static ULONG get_array_len( const WS_PARAMETER_DESCRIPTION *params, ULONG count, ULONG index, const void **args )
diff --git a/include/webservices.h b/include/webservices.h
index bea4ade..2af333a 100644
--- a/include/webservices.h
+++ b/include/webservices.h
@@ -531,6 +531,21 @@ typedef struct _WS_STRUCT_DESCRIPTION {
     ULONG structOptions;
 } WS_STRUCT_DESCRIPTION;
 
+typedef struct _WS_UNION_FIELD_DESCRIPTION {
+    int value;
+    WS_FIELD_DESCRIPTION field;
+} WS_UNION_FIELD_DESCRIPTION;
+
+typedef struct _WS_UNION_DESCRIPTION {
+    ULONG size;
+    ULONG alignment;
+    WS_UNION_FIELD_DESCRIPTION **fields;
+    ULONG fieldCount;
+    ULONG enumOffset;
+    int noneEnumValue;
+    ULONG *valueIndices;
+} WS_UNION_DESCRIPTION;
+
 typedef struct _WS_ATTRIBUTE_DESCRIPTION {
     WS_XML_STRING *attributeLocalName;
     WS_XML_STRING *attributeNs;
-- 
2.1.4




More information about the wine-patches mailing list