From c41e66fe01410ae9e9dff78be63926e8404c32ef Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Mon, 10 Jul 2017 11:02:30 +0200 Subject: [PATCH] webservices: Add support for union types in the reader. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/webservices/reader.c | 76 +++++++++++++++++++++--- dlls/webservices/tests/reader.c | 128 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 193 insertions(+), 11 deletions(-) diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index 254efb9f0e0..c51fb4a63c6 100644 --- a/dlls/webservices/reader.c +++ b/dlls/webservices/reader.c @@ -5168,6 +5168,7 @@ static WS_READ_OPTION get_field_read_option( WS_TYPE type, ULONG options ) case WS_XML_QNAME_TYPE: case WS_STRUCT_TYPE: case WS_ENUM_TYPE: + case WS_UNION_TYPE: if (options & (WS_FIELD_OPTIONAL|WS_FIELD_NILLABLE)) return WS_READ_NILLABLE_VALUE; return WS_READ_REQUIRED_VALUE; @@ -5261,8 +5262,63 @@ static HRESULT read_type_text( struct reader *reader, const WS_FIELD_DESCRIPTION desc->typeDescription, option, heap, ret, size ); } -static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, - WS_HEAP *heap, char *buf, ULONG offset ) +static HRESULT read_type_field( struct reader *, const WS_FIELD_DESCRIPTION *, WS_HEAP *, char *, ULONG ); + +static HRESULT read_type_union( struct reader *reader, const WS_UNION_DESCRIPTION *desc, WS_READ_OPTION option, + WS_HEAP *heap, void *ret, ULONG size ) +{ + ULONG offset, i; + HRESULT hr = WS_E_INVALID_FORMAT; + + switch (option) + { + case WS_READ_REQUIRED_VALUE: + case WS_READ_NILLABLE_VALUE: + if (size != desc->size) return E_INVALIDARG; + break; + + default: + return E_INVALIDARG; + } + + if ((hr = read_type_next_node( reader )) != S_OK) return hr; + if (node_type( reader->current ) != WS_XML_NODE_TYPE_ELEMENT) return WS_E_INVALID_FORMAT; + for (i = 0; i < desc->fieldCount; i++) + { + if (match_element( reader->current, desc->fields[i]->field.localName, desc->fields[i]->field.ns )) + break; + } + if (i == desc->fieldCount) + { + if (!move_to_parent_element( &reader->current )) return WS_E_INVALID_FORMAT; + *(int *)((char *)ret + desc->enumOffset) = desc->noneEnumValue; + } + else + { + offset = desc->fields[i]->field.offset; + if ((hr = read_type_field( reader, &desc->fields[i]->field, heap, ret, offset )) == S_OK) + *(int *)((char *)ret + desc->enumOffset) = desc->fields[i]->value; + } + + switch (option) + { + case WS_READ_NILLABLE_VALUE: + break; + + case WS_READ_REQUIRED_VALUE: + if (hr != S_OK) return hr; + break; + + default: + return E_INVALIDARG; + } + + return S_OK; +} + + +static HRESULT read_type_field( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap, char *buf, + ULONG offset ) { char *ptr; WS_READ_OPTION option; @@ -5299,6 +5355,12 @@ static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DES desc->typeDescription, option, heap, ptr, size ); break; + case WS_ELEMENT_CHOICE_FIELD_MAPPING: + if (desc->type != WS_UNION_TYPE || !desc->typeDescription || + (desc->options & (WS_FIELD_POINTER|WS_FIELD_NILLABLE))) return E_INVALIDARG; + hr = read_type_union( reader, desc->typeDescription, option, heap, ptr, size ); + break; + case WS_REPEATING_ELEMENT_FIELD_MAPPING: { ULONG count; @@ -5341,9 +5403,8 @@ static HRESULT read_type_struct_field( struct reader *reader, const WS_FIELD_DES 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_READ_OPTION option, +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_READ_OPTION option, WS_HEAP *heap, void *ret, ULONG size ) { ULONG i, offset; @@ -5380,8 +5441,7 @@ static HRESULT read_type_struct( struct reader *reader, WS_TYPE_MAPPING mapping, for (i = 0; i < desc->fieldCount; i++) { offset = desc->fields[i]->offset; - if ((hr = read_type_struct_field( reader, desc->fields[i], heap, buf, offset )) != S_OK) - break; + if ((hr = read_type_field( reader, desc->fields[i], heap, buf, offset )) != S_OK) break; } switch (option) @@ -6334,7 +6394,7 @@ static ULONG get_field_size( const WS_FIELD_DESCRIPTION *desc ) static HRESULT read_param( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap, void *ret ) { if (!ret && !(ret = ws_alloc_zero( heap, get_field_size(desc) ))) return WS_E_QUOTA_EXCEEDED; - return read_type_struct_field( reader, desc, heap, ret, 0 ); + return read_type_field( reader, desc, heap, ret, 0 ); } static HRESULT read_param_array( struct reader *reader, const WS_FIELD_DESCRIPTION *desc, WS_HEAP *heap, diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c index 5ce37e8a2ce..ce8590a6574 100644 --- a/dlls/webservices/tests/reader.c +++ b/dlls/webservices/tests/reader.c @@ -2331,9 +2331,6 @@ static void prepare_struct_type_test( WS_XML_READER *reader, const char *data ) hr = set_input( reader, data, size ); ok( hr == S_OK, "got %08x\n", hr ); - - hr = WsFillReader( reader, size, NULL, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); } static void test_simple_struct_type(void) @@ -5758,6 +5755,130 @@ static void test_WsReadXmlBuffer(void) WsFreeHeap( heap ); } +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"}; + HRESULT hr; + WS_XML_READER *reader; + WS_HEAP *heap; + WS_UNION_DESCRIPTION u; + WS_UNION_FIELD_DESCRIPTION f, f2, *fields[2]; + WS_FIELD_DESCRIPTION f_struct, *fields_struct[1]; + WS_STRUCT_DESCRIPTION s; + const WS_XML_NODE *node; + enum choice {CHOICE_A, CHOICE_B, CHOICE_NONE}; + struct test + { + enum choice choice; + union + { + WCHAR *a; + UINT32 b; + } value; + } *test; + + hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsCreateReader( NULL, 0, &reader, 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; + + test = NULL; + prepare_struct_type_test( reader, "test" ); + hr = WsReadType( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, + WS_READ_REQUIRED_POINTER, heap, &test, sizeof(test), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( test != NULL, "test not set\n" ); + ok( test->choice == CHOICE_A, "got %d\n", test->choice ); + ok( !lstrcmpW(test->value.a, testW), "got %s\n", wine_dbgstr_w(test->value.a) ); + + test = NULL; + prepare_struct_type_test( reader, "123" ); + hr = WsReadType( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, + WS_READ_REQUIRED_POINTER, heap, &test, sizeof(test), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( test != NULL, "test not set\n" ); + ok( test->choice == CHOICE_B, "got %d\n", test->choice ); + ok( test->value.b == 123, "got %u\n", test->value.b ); + + prepare_struct_type_test( reader, "456" ); + hr = WsReadType( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, + WS_READ_REQUIRED_POINTER, heap, &test, sizeof(test), NULL ); + ok( hr == WS_E_INVALID_FORMAT, "got %08x\n", hr ); + + f_struct.options = WS_FIELD_NILLABLE; + hr = WsReadType( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, + WS_READ_REQUIRED_POINTER, heap, &test, sizeof(test), NULL ); + ok( hr == E_INVALIDARG, "got %08x\n", hr ); + + f_struct.options = WS_FIELD_POINTER|WS_FIELD_NILLABLE; + hr = WsReadType( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, + WS_READ_REQUIRED_POINTER, heap, &test, sizeof(test), NULL ); + ok( hr == E_INVALIDARG, "got %08x\n", hr ); + + f_struct.options = WS_FIELD_POINTER; + hr = WsReadType( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, + WS_READ_REQUIRED_POINTER, heap, &test, sizeof(test), NULL ); + ok( hr == E_INVALIDARG, "got %08x\n", hr ); + + test = NULL; + f_struct.options = WS_FIELD_OPTIONAL; + prepare_struct_type_test( reader, "456" ); + hr = WsReadType( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, + WS_READ_REQUIRED_POINTER, heap, &test, sizeof(test), NULL ); + todo_wine ok( hr == S_OK, "got %08x\n", hr ); + ok( test != NULL, "test not set\n" ); + ok( test->choice == CHOICE_NONE, "got %d\n", test->choice ); + hr = WsGetReaderNode( reader, &node, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + ok( node->nodeType == WS_XML_NODE_TYPE_ELEMENT, "got %u\n", node->nodeType ); + + WsFreeReader( reader ); + WsFreeHeap( heap ); +} + START_TEST(reader) { test_WsCreateError(); @@ -5803,4 +5924,5 @@ START_TEST(reader) test_binary_encoding(); test_dictionary(); test_WsReadXmlBuffer(); + test_union_type(); } -- 2.11.4.GIT