diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c index e76eb1b91e3..4f6b1b15269 100644 --- a/dlls/webservices/tests/writer.c +++ b/dlls/webservices/tests/writer.c @@ -1306,6 +1306,101 @@ static void test_WsGetPrefixFromNamespace(void) WsFreeWriter( writer ); } +static void test_complex_struct_type(void) +{ + static const char expected[] = + "" + "" + ""; + static const WCHAR timestampW[] = + {'2','0','1','5','-','0','9','-','0','3','T','1','8',':','4','7',':','5','4',0}; + WS_XML_STRING str_officeconfig = {12, (BYTE *)"OfficeConfig"}; + WS_XML_STRING str_services = {8, (BYTE *)"services"}; + WS_XML_STRING str_generationtime = {14, (BYTE *)"GenerationTime"}; + WS_XML_STRING ns = {39, (BYTE *)"urn:schemas-microsoft-com:office:office"}; + WS_XML_STRING prefix = {1, (BYTE *)"o"}; + DWORD size; + HRESULT hr; + WS_HEAP *heap; + WS_XML_BUFFER *buffer; + WS_XML_WRITER *writer; + WS_STRUCT_DESCRIPTION s, s2; + WS_FIELD_DESCRIPTION f, f2, *fields[1], *fields2[1]; + struct services + { + const WCHAR *generationtime; + }; + struct officeconfig + { + struct services *services; + } *test; + + hr = WsCreateWriter( NULL, 0, &writer, NULL ) ; + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsCreateXmlBuffer( heap, NULL, 0, &buffer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsSetOutputToBuffer( writer, buffer, NULL, 0, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsWriteStartElement( writer, &prefix, &str_officeconfig, &ns, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + memset( &f2, 0, sizeof(f2) ); + f2.mapping = WS_ATTRIBUTE_FIELD_MAPPING; + f2.localName = &str_generationtime; + f2.ns = &ns; + f2.type = WS_WSZ_TYPE; + f2.options = WS_FIELD_OPTIONAL; + fields2[0] = &f2; + + memset( &s2, 0, sizeof(s2) ); + s2.size = sizeof(*test->services); + s2.alignment = 4; + s2.fields = fields2; + s2.fieldCount = 1; + s2.typeLocalName = &str_services; + s2.typeNs = &ns; + + memset( &f, 0, sizeof(f) ); + f.mapping = WS_ELEMENT_FIELD_MAPPING; + f.localName = &str_services; + f.ns = &ns; + f.type = WS_STRUCT_TYPE; + f.typeDescription = &s2; + f.options = WS_FIELD_POINTER; + fields[0] = &f; + + memset( &s, 0, sizeof(s) ); + s.size = sizeof(*test); + s.alignment = 4; + s.fields = fields; + s.fieldCount = 1; + s.typeLocalName = &str_officeconfig; + s.typeNs = &ns; + + size = sizeof(struct officeconfig) + sizeof(struct services); + test = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); + test->services = (struct services *)(test + 1); + test->services->generationtime = timestampW; + hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_STRUCT_TYPE, &s, + WS_WRITE_REQUIRED_POINTER, &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_buffer( buffer, expected, __LINE__ ); + + HeapFree( GetProcessHeap(), 0, test ); + WsFreeWriter( writer ); + WsFreeHeap( heap ); +} + + START_TEST(writer) { test_WsCreateWriter(); @@ -1323,4 +1418,5 @@ START_TEST(writer) test_WsWriteStartCData(); test_WsWriteXmlnsAttribute(); test_WsGetPrefixFromNamespace(); + test_complex_struct_type(); } diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c index 8dbe9c20318..858c9d08a6f 100644 --- a/dlls/webservices/writer.c +++ b/dlls/webservices/writer.c @@ -714,7 +714,6 @@ HRESULT WINAPI WsWriteEndAttribute( WS_XML_WRITER *handle, WS_ERROR *error ) if (error) FIXME( "ignoring error parameter\n" ); if (!writer) return E_INVALIDARG; - if (writer->state != WRITER_STATE_STARTATTRIBUTE) return WS_E_INVALID_OPERATION; writer->state = WRITER_STATE_STARTELEMENT; return S_OK; @@ -1115,7 +1114,6 @@ static HRESULT write_type_text( struct writer *writer, WS_TYPE_MAPPING mapping, { case WRITER_STATE_STARTATTRIBUTE: write_set_attribute_value( writer, text ); - writer->state = WRITER_STATE_STARTELEMENT; return S_OK; case WRITER_STATE_STARTELEMENT: @@ -1304,17 +1302,19 @@ static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping, return hr; } -static HRESULT write_type_struct( struct writer *, WS_TYPE_MAPPING, const WS_STRUCT_DESCRIPTION *, - const void * ); +static HRESULT write_type( struct writer *, WS_TYPE_MAPPING, WS_TYPE, const void *, WS_WRITE_OPTION, + const void *, ULONG ); -static HRESULT write_type_struct_field( struct writer *writer, WS_TYPE_MAPPING mapping, - const WS_FIELD_DESCRIPTION *desc, const void *value ) +static HRESULT write_type_struct_field( struct writer *writer, const WS_FIELD_DESCRIPTION *desc, + const void *value, ULONG size ) { HRESULT hr; + WS_TYPE_MAPPING mapping; + WS_WRITE_OPTION option; - if (desc->options && desc->options != WS_FIELD_POINTER && - desc->options != WS_FIELD_OPTIONAL && - desc->options != (WS_FIELD_POINTER | WS_FIELD_OPTIONAL)) + if (!desc->options || desc->options == WS_FIELD_OPTIONAL) option = 0; + else if (desc->options == WS_FIELD_POINTER) option = WS_WRITE_REQUIRED_POINTER; + else { FIXME( "options 0x%x not supported\n", desc->options ); return E_NOTIMPL; @@ -1326,9 +1326,32 @@ static HRESULT write_type_struct_field( struct writer *writer, WS_TYPE_MAPPING m if (!desc->localName || !desc->ns) return E_INVALIDARG; if ((hr = write_add_attribute( writer, NULL, desc->localName, desc->ns, FALSE )) != S_OK) return hr; + + mapping = WS_ATTRIBUTE_TYPE_MAPPING; + break; + + case WS_ELEMENT_FIELD_MAPPING: + if ((hr = write_add_element_node( writer, NULL, desc->localName, desc->ns )) != S_OK) + return hr; + + mapping = WS_ELEMENT_TYPE_MAPPING; break; case WS_TEXT_FIELD_MAPPING: + switch (writer->state) + { + case WRITER_STATE_STARTELEMENT: + mapping = WS_ELEMENT_CONTENT_TYPE_MAPPING; + break; + + case WRITER_STATE_STARTATTRIBUTE: + mapping = WS_ATTRIBUTE_TYPE_MAPPING; + break; + + default: + FIXME( "unhandled writer state %u\n", writer->state ); + return E_NOTIMPL; + } break; default: @@ -1336,86 +1359,35 @@ static HRESULT write_type_struct_field( struct writer *writer, WS_TYPE_MAPPING m return E_NOTIMPL; } - switch (desc->type) + if ((hr = write_type( writer, mapping, desc->type, desc->typeDescription, option, value, size )) != S_OK) + return hr; + + switch (mapping) { - case WS_STRUCT_TYPE: - { - const void * const *ptr = value; - if ((hr = write_type_struct( writer, mapping, desc->typeDescription, *ptr )) != S_OK) return hr; + case WS_ATTRIBUTE_TYPE_MAPPING: + writer->state = WRITER_STATE_STARTELEMENT; break; - } - case WS_BOOL_TYPE: - { - const BOOL *ptr = value; - if ((hr = write_type_bool( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; + + case WS_ELEMENT_TYPE_MAPPING: + if ((hr = write_close_element( writer )) != S_OK) return hr; break; - } - case WS_INT8_TYPE: - { - const INT8 *ptr = value; - if ((hr = write_type_int8( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; - break; - } - case WS_INT16_TYPE: - { - const INT16 *ptr = value; - if ((hr = write_type_int16( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; - break; - } - case WS_INT32_TYPE: - { - const INT32 *ptr = value; - if ((hr = write_type_int32( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; - break; - } - case WS_INT64_TYPE: - { - const INT64 *ptr = value; - if ((hr = write_type_int64( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; - break; - } - case WS_UINT8_TYPE: - { - const UINT8 *ptr = value; - if ((hr = write_type_uint8( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; - break; - } - case WS_UINT16_TYPE: - { - const UINT16 *ptr = value; - if ((hr = write_type_uint16( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; - break; - } - case WS_UINT32_TYPE: - { - const UINT32 *ptr = value; - if ((hr = write_type_uint32( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; - break; - } - case WS_UINT64_TYPE: - { - const UINT64 *ptr = value; - if ((hr = write_type_uint64( writer, mapping, desc->typeDescription, ptr )) != S_OK) return hr; - break; - } - case WS_WSZ_TYPE: - { - const WCHAR * const *ptr = value; - if ((hr = write_type_wsz( writer, mapping, desc->typeDescription, *ptr )) != S_OK) return hr; - break; - } - default: - FIXME( "type %u not implemented\n", desc->type ); - return E_NOTIMPL; + + default: break; } return S_OK; } +static 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; +} + static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_STRUCT_DESCRIPTION *desc, const void *value ) { - ULONG i; + ULONG i, size; HRESULT hr; const char *ptr; @@ -1430,7 +1402,8 @@ static HRESULT write_type_struct( struct writer *writer, WS_TYPE_MAPPING mapping for (i = 0; i < desc->fieldCount; i++) { ptr = (const char *)value + desc->fields[i]->offset; - if ((hr = write_type_struct_field( writer, mapping, desc->fields[i], ptr )) != S_OK) + size = get_field_size( desc, i ); + if ((hr = write_type_struct_field( writer, desc->fields[i], ptr, size )) != S_OK) return hr; } @@ -1447,7 +1420,7 @@ static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TY { const void * const *ptr = value; - if (!desc || option != WS_WRITE_REQUIRED_POINTER || size != sizeof(*ptr)) + if (!desc || (option && option != WS_WRITE_REQUIRED_POINTER) || size != sizeof(*ptr)) return E_INVALIDARG; return write_type_struct( writer, mapping, desc, *ptr ); @@ -1509,7 +1482,7 @@ static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TY case WS_WSZ_TYPE: { const WCHAR * const *ptr = value; - if (option != WS_WRITE_REQUIRED_POINTER || size != sizeof(*ptr)) return E_INVALIDARG; + if ((option && option != WS_WRITE_REQUIRED_POINTER) || size != sizeof(*ptr)) return E_INVALIDARG; return write_type_wsz( writer, mapping, desc, *ptr ); } default: @@ -1539,11 +1512,8 @@ HRESULT WINAPI WsWriteAttribute( WS_XML_WRITER *handle, const WS_ATTRIBUTE_DESCR if ((hr = write_add_attribute( writer, NULL, desc->attributeLocalName, desc->attributeNs, FALSE )) != S_OK) return hr; - if ((hr = write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, - option, value, size )) != S_OK) return hr; - - writer->state = WRITER_STATE_STARTELEMENT; - return S_OK; + return write_type( writer, WS_ATTRIBUTE_TYPE_MAPPING, desc->type, desc->typeDescription, + option, value, size ); } /**************************************************************************