diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c index c817615509f..3bed673b856 100644 --- a/dlls/webservices/tests/writer.c +++ b/dlls/webservices/tests/writer.c @@ -574,6 +574,17 @@ static void test_WsWriteType(void) WsFreeWriter( writer ); } +static void prepare_basic_type_test( WS_XML_WRITER *writer ) +{ + WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}; + HRESULT hr; + + hr = set_output( writer ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); +} + static void test_basic_type(void) { static WCHAR testW[] = {'t','e','s','t',0}; @@ -583,6 +594,7 @@ static void test_basic_type(void) GUID guid; WCHAR *str; WS_STRING string; + WS_BYTES bytes; ULONG i; static const struct { @@ -615,12 +627,7 @@ static void test_basic_type(void) /* element content type mapping */ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { - hr = set_output( writer ); - ok( hr == S_OK, "got %08x\n", hr ); - - hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); - + prepare_basic_type_test( writer ); hr = WsWriteType( writer, WS_ELEMENT_CONTENT_TYPE_MAPPING, tests[i].type, NULL, WS_WRITE_REQUIRED_VALUE, &tests[i].val, tests[i].size, NULL ); ok( hr == S_OK, "%u: got %08x\n", i, hr ); @@ -635,12 +642,7 @@ static void test_basic_type(void) { const INT64 *ptr = &tests[i].val; - hr = set_output( writer ); - ok( hr == S_OK, "got %08x\n", hr ); - - hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); - + prepare_basic_type_test( writer ); hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, tests[i].type, NULL, WS_WRITE_REQUIRED_POINTER, &ptr, sizeof(ptr), NULL ); ok( hr == S_OK, "%u: got %08x\n", i, hr ); @@ -653,12 +655,7 @@ static void test_basic_type(void) /* attribute type mapping */ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { - hr = set_output( writer ); - ok( hr == S_OK, "got %08x\n", hr ); - - hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); - + prepare_basic_type_test( writer ); hr = WsWriteStartAttribute( writer, NULL, &localname, &ns, FALSE, NULL ); ok( hr == S_OK, "got %08x\n", hr ); @@ -674,68 +671,81 @@ static void test_basic_type(void) check_output( writer, tests[i].result2, __LINE__ ); } - hr = set_output( writer ); - ok( hr == S_OK, "got %08x\n", hr ); - - hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); - + prepare_basic_type_test( writer ); memset( &guid, 0, sizeof(guid) ); hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_GUID_TYPE, NULL, WS_WRITE_REQUIRED_VALUE, &guid, sizeof(guid), NULL ); ok( hr == S_OK, "got %08x\n", hr ); - hr = WsWriteEndElement( writer, NULL ); ok( hr == S_OK, "got %08x\n", hr ); check_output( writer, "00000000-0000-0000-0000-000000000000", __LINE__ ); - hr = set_output( writer ); - ok( hr == S_OK, "got %08x\n", hr ); - - hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); - + prepare_basic_type_test( writer ); string.chars = testW; string.length = 4; hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE, &string, sizeof(string), NULL ); ok( hr == S_OK, "got %08x\n", hr ); - hr = WsWriteEndElement( writer, NULL ); ok( hr == S_OK, "got %08x\n", hr ); check_output( writer, "test", __LINE__ ); - hr = set_output( writer ); - ok( hr == S_OK, "got %08x\n", hr ); - - hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); - + prepare_basic_type_test( writer ); str = testW; hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_WSZ_TYPE, NULL, WS_WRITE_REQUIRED_POINTER, &str, sizeof(str), NULL ); ok( hr == S_OK, "got %08x\n", hr ); - hr = WsWriteEndElement( writer, NULL ); ok( hr == S_OK, "got %08x\n", hr ); check_output( writer, "test", __LINE__ ); - hr = set_output( writer ); - ok( hr == S_OK, "got %08x\n", hr ); - - hr = WsWriteStartElement( writer, NULL, &localname, &ns, NULL ); - ok( hr == S_OK, "got %08x\n", hr ); - + prepare_basic_type_test( writer ); xmlstr.bytes = (BYTE *)"test"; xmlstr.length = 4; hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_XML_STRING_TYPE, NULL, WS_WRITE_REQUIRED_VALUE, &xmlstr, sizeof(xmlstr), NULL ); ok( hr == S_OK, "got %08x\n", hr ); - hr = WsWriteEndElement( writer, NULL ); ok( hr == S_OK, "got %08x\n", hr ); check_output( writer, "test", __LINE__ ); + prepare_basic_type_test( writer ); + bytes.bytes = (BYTE *)"test"; + bytes.length = 4; + hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE, + &bytes, sizeof(bytes), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsWriteEndElement( writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + check_output( writer, "dGVzdA==", __LINE__ ); + + prepare_basic_type_test( writer ); + bytes.length = 0; + hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE, + &bytes, sizeof(bytes), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsWriteEndElement( writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + check_output( writer, "", __LINE__ ); + + prepare_basic_type_test( writer ); + bytes.bytes = NULL; + hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_REQUIRED_VALUE, + &bytes, sizeof(bytes), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsWriteEndElement( writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + check_output( writer, "", __LINE__ ); + + prepare_basic_type_test( writer ); + hr = WsWriteType( writer, WS_ELEMENT_TYPE_MAPPING, WS_BYTES_TYPE, NULL, WS_WRITE_NILLABLE_VALUE, + &bytes, sizeof(bytes), NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + hr = WsWriteEndElement( writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + check_output( writer, "", + __LINE__ ); + WsFreeWriter( writer ); } diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c index 7a818eb2398..619ec2b308e 100644 --- a/dlls/webservices/writer.c +++ b/dlls/webservices/writer.c @@ -1265,6 +1265,38 @@ static ULONG format_urn( const GUID *ptr, unsigned char *buf ) ptr->Data4[4], ptr->Data4[5], ptr->Data4[6], ptr->Data4[7] ); } +static ULONG encode_base64( const unsigned char *bin, ULONG len, unsigned char *buf ) +{ + static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + ULONG i = 0, x; + + while (len > 0) + { + buf[i++] = base64[(bin[0] & 0xfc) >> 2]; + x = (bin[0] & 3) << 4; + if (len == 1) + { + buf[i++] = base64[x]; + buf[i++] = '='; + buf[i++] = '='; + break; + } + buf[i++] = base64[x | ((bin[1] & 0xf0) >> 4)]; + x = (bin[1] & 0x0f) << 2; + if (len == 2) + { + buf[i++] = base64[x]; + buf[i++] = '='; + break; + } + buf[i++] = base64[x | ((bin[2] & 0xc0) >> 6)]; + buf[i++] = base64[bin[2] & 0x3f]; + bin += 3; + len -= 3; + } + return i; +} + static HRESULT text_to_utf8text( const WS_XML_TEXT *text, WS_XML_UTF8_TEXT **ret ) { switch (text->textType) @@ -1287,6 +1319,14 @@ static HRESULT text_to_utf8text( const WS_XML_TEXT *text, WS_XML_UTF8_TEXT **ret WideCharToMultiByte( CP_UTF8, 0, str, len, (char *)(*ret)->value.bytes, (*ret)->value.length, NULL, NULL ); return S_OK; } + case WS_XML_TEXT_TYPE_BASE64: + { + const WS_XML_BASE64_TEXT *base64 = (const WS_XML_BASE64_TEXT *)text; + ULONG len = ((4 * base64->length / 3) + 3) & ~3; + if (!(*ret = alloc_utf8_text( NULL, len ))) return E_OUTOFMEMORY; + (*ret)->value.length = encode_base64( base64->bytes, base64->length, (*ret)->value.bytes ); + return S_OK; + } case WS_XML_TEXT_TYPE_BOOL: { const WS_XML_BOOL_TEXT *bool_text = (const WS_XML_BOOL_TEXT *)text; @@ -1837,6 +1877,32 @@ static HRESULT write_type_wsz( struct writer *writer, WS_TYPE_MAPPING mapping, return write_type_text( writer, mapping, &utf16.text ); } +static HRESULT write_type_bytes( struct writer *writer, WS_TYPE_MAPPING mapping, + const WS_BYTES_DESCRIPTION *desc, WS_WRITE_OPTION option, + const void *value, ULONG size ) +{ + WS_XML_BASE64_TEXT base64; + const WS_BYTES *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_BYTES), (const void **)&ptr )) != S_OK) return hr; + if ((option == WS_WRITE_NILLABLE_VALUE && is_nil_value( value, size )) || + (option == WS_WRITE_NILLABLE_POINTER && !ptr)) return write_add_nil_attribute( writer ); + if (!ptr->length) return S_OK; + + base64.text.textType = WS_XML_TEXT_TYPE_BASE64; + base64.bytes = ptr->bytes; + base64.length = ptr->length; + return write_type_text( writer, mapping, &base64.text ); +} + static HRESULT write_type_xml_string( struct writer *writer, WS_TYPE_MAPPING mapping, const WS_XML_STRING_DESCRIPTION *desc, WS_WRITE_OPTION option, const void *value, ULONG size ) @@ -1996,9 +2062,6 @@ static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TY { switch (type) { - case WS_STRUCT_TYPE: - return write_type_struct( writer, mapping, desc, option, value, size ); - case WS_BOOL_TYPE: return write_type_bool( writer, mapping, desc, option, value, size ); @@ -2038,9 +2101,15 @@ static HRESULT write_type( struct writer *writer, WS_TYPE_MAPPING mapping, WS_TY case WS_WSZ_TYPE: return write_type_wsz( writer, mapping, desc, option, value, size ); + case WS_BYTES_TYPE: + return write_type_bytes( writer, mapping, desc, option, value, size ); + case WS_XML_STRING_TYPE: return write_type_xml_string( writer, mapping, desc, option, value, size ); + case WS_STRUCT_TYPE: + return write_type_struct( writer, mapping, desc, option, value, size ); + default: FIXME( "type %u not supported\n", type ); return E_NOTIMPL;