From df4046a3705972978c408cf44ab0fd636e25e31d Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Fri, 8 Jul 2016 10:20:30 +0200 Subject: [PATCH] webservices: Add support for writing double values. Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/webservices/reader.c | 8 +- dlls/webservices/tests/writer.c | 113 +++++++++++++++++++++++++ dlls/webservices/webservices_private.h | 2 + dlls/webservices/writer.c | 100 ++++++++++++++++++++++ include/webservices.h | 5 ++ 5 files changed, 224 insertions(+), 4 deletions(-) diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index 9e3300013d1..1a51257489d 100644 --- a/dlls/webservices/reader.c +++ b/dlls/webservices/reader.c @@ -2271,7 +2271,7 @@ static HRESULT str_to_uint64( const unsigned char *str, ULONG len, UINT64 max, U #if defined(__i386__) || defined(__x86_64__) #define RC_DOWN 0x100; -static BOOL set_fp_rounding( unsigned short *save ) +BOOL set_fp_rounding( unsigned short *save ) { #ifdef __GNUC__ unsigned short fpword; @@ -2286,7 +2286,7 @@ static BOOL set_fp_rounding( unsigned short *save ) return FALSE; #endif } -static void restore_fp_rounding( unsigned short fpword ) +void restore_fp_rounding( unsigned short fpword ) { #ifdef __GNUC__ __asm__ __volatile__( "fldcw %0" : : "m" (fpword) ); @@ -2295,12 +2295,12 @@ static void restore_fp_rounding( unsigned short fpword ) #endif } #else -static BOOL set_fp_rounding( unsigned short *save ) +BOOL set_fp_rounding( unsigned short *save ) { FIXME( "not implemented\n" ); return FALSE; } -static void restore_fp_rounding( unsigned short fpword ) +void restore_fp_rounding( unsigned short fpword ) { FIXME( "not implemented\n" ); } diff --git a/dlls/webservices/tests/writer.c b/dlls/webservices/tests/writer.c index 9055021f1f1..d230cddab55 100644 --- a/dlls/webservices/tests/writer.c +++ b/dlls/webservices/tests/writer.c @@ -21,6 +21,25 @@ #include "webservices.h" #include "wine/test.h" +#include +#ifndef INFINITY +static inline float __port_infinity(void) +{ + static const unsigned __inf_bytes = 0x7f800000; + return *(const float *)&__inf_bytes; +} +#define INFINITY __port_infinity() +#endif + +#ifndef NAN +static inline float __port_nan(void) +{ + static const unsigned __nan_bytes = 0x7fc00000; + return *(const float *)&__nan_bytes; +} +#define NAN __port_nan() +#endif + static HRESULT set_output( WS_XML_WRITER *writer ) { WS_XML_WRITER_TEXT_ENCODING encoding; @@ -1871,6 +1890,99 @@ static void test_text_types(void) WsFreeWriter( writer ); } +static void test_double(void) +{ + WS_XML_STRING localname = {1, (BYTE *)"t"}, ns = {0, NULL}; + static const struct + { + double val; + const char *result; + } + tests[] = + { + {0.0, "0"}, + {1.0, "1"}, + {-1.0, "-1"}, + {1.0000000000000001, "1"}, + {1.0000000000000002, "1.0000000000000002"}, + {1.0000000000000003, "1.0000000000000002"}, + {1.0000000000000004, "1.0000000000000004"}, + {100000000000000, "100000000000000"}, + {1000000000000000, "1E+15"}, + {0.1, "0.1"}, + {0.01, "1E-2"}, + {-0.1, "-0.1"}, + {-0.01, "-1E-2"}, + {1.7976931348623158e308, "1.7976931348623157E+308"}, + {-1.7976931348623158e308, "-1.7976931348623157E+308"}, + }; + HRESULT hr; + WS_XML_WRITER *writer; + WS_XML_DOUBLE_TEXT text; + ULONG i; + + hr = WsCreateWriter( NULL, 0, &writer, NULL ) ; + ok( hr == S_OK, "got %08x\n", hr ); + + text.text.textType = WS_XML_TEXT_TYPE_DOUBLE; + 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, "%u: got %08x\n", i, hr ); + + text.value = tests[i].val; + hr = WsWriteText( writer, &text.text, NULL ); + ok( hr == S_OK, "%u: got %08x\n", i, hr ); + + hr = WsWriteEndElement( writer, NULL ); + ok( hr == S_OK, "%u: got %08x\n", i, hr ); + check_output( writer, tests[i].result, __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 ); + + text.value = NAN; + hr = WsWriteText( writer, &text.text, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsWriteEndElement( writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + check_output( writer, "NaN", __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 ); + + text.value = INFINITY; + hr = WsWriteText( writer, &text.text, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsWriteEndElement( writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + check_output( writer, "INF", __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 ); + + text.value = -INFINITY; + hr = WsWriteText( writer, &text.text, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + + hr = WsWriteEndElement( writer, NULL ); + ok( hr == S_OK, "got %08x\n", hr ); + check_output( writer, "-INF", __LINE__ ); + + WsFreeWriter( writer ); +} + START_TEST(writer) { test_WsCreateWriter(); @@ -1896,4 +2008,5 @@ START_TEST(writer) test_WsWriteNode(); test_WsCopyNode(); test_text_types(); + test_double(); } diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h index bad2dfbf7e7..26cba38e4ee 100644 --- a/dlls/webservices/webservices_private.h +++ b/dlls/webservices/webservices_private.h @@ -33,6 +33,8 @@ WS_XML_UTF8_TEXT *alloc_utf8_text( const unsigned char *, ULONG ) DECLSPEC_HIDDE HRESULT append_attribute( WS_XML_ELEMENT_NODE *, WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN; void free_attribute( WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN; WS_TYPE map_value_type( WS_VALUE_TYPE ) DECLSPEC_HIDDEN; +BOOL set_fp_rounding( unsigned short * ) DECLSPEC_HIDDEN; +void restore_fp_rounding( unsigned short ) DECLSPEC_HIDDEN; struct node { diff --git a/dlls/webservices/writer.c b/dlls/webservices/writer.c index 85a89737ed0..48c738225fe 100644 --- a/dlls/webservices/writer.c +++ b/dlls/webservices/writer.c @@ -18,6 +18,7 @@ #include #include +#include #include "windef.h" #include "winbase.h" @@ -1042,6 +1043,92 @@ static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf ) return wsprintfA( (char *)buf, "%I64u", *ptr ); } +static ULONG format_double( const double *ptr, unsigned char *buf ) +{ + static const double precision = 0.0000000000000001; + unsigned char *p = buf; + double val = *ptr; /* FIXME: use long double */ + int neg, mag, mag2, use_exp; + + if (isnan( val )) + { + memcpy( buf, "NaN", 3 ); + return 3; + } + if (isinf( val )) + { + if (val < 0) + { + memcpy( buf, "-INF", 4 ); + return 4; + } + memcpy( buf, "INF", 3 ); + return 3; + } + if (val == 0.0) + { + *p = '0'; + return 1; + } + + if ((neg = val < 0)) + { + *p++ = '-'; + val = -val; + } + + mag = log10( val ); + use_exp = (mag >= 15 || (neg && mag >= 1) || mag <= -1); + if (use_exp) + { + if (mag < 0) mag -= 1; + val = val / pow( 10.0, mag ); + mag2 = mag; + mag = 0; + } + else if (mag < 1) mag = 0; + + while (val > precision || mag >= 0) + { + double weight = pow( 10.0, mag ); + if (weight > 0 && !isinf( weight )) + { + int digit = floor( val / weight ); + val -= digit * weight; + *(p++) = '0' + digit; + } + if (!mag && val > 0) *(p++) = '.'; + mag--; + } + + if (use_exp) + { + int i, j; + *(p++) = 'E'; + if (mag2 > 0) *(p++) = '+'; + else + { + *(p++) = '-'; + mag2 = -mag2; + } + mag = 0; + while (mag2 > 0) + { + *(p++) = '0' + mag2 % 10; + mag2 /= 10; + mag++; + } + for (i = -mag, j = -1; i < j; i++, j--) + { + p[i] ^= p[j]; + p[j] ^= p[i]; + p[i] ^= p[j]; + } + } + + return p - buf; +} + static ULONG format_guid( const GUID *ptr, unsigned char *buf ) { static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; @@ -1111,6 +1198,19 @@ static HRESULT text_to_utf8text( const WS_XML_TEXT *text, WS_XML_UTF8_TEXT **ret if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY; return S_OK; } + case WS_XML_TEXT_TYPE_DOUBLE: + { + const WS_XML_DOUBLE_TEXT *double_text = (const WS_XML_DOUBLE_TEXT *)text; + unsigned char buf[24]; /* "-1.1111111111111111E-308" */ + unsigned short fpword; + ULONG len; + + if (!set_fp_rounding( &fpword )) return E_NOTIMPL; + len = format_double( &double_text->value, buf ); + restore_fp_rounding( fpword ); + if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY; + return S_OK; + } case WS_XML_TEXT_TYPE_GUID: { const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text; diff --git a/include/webservices.h b/include/webservices.h index c9c2ade9093..e35e3896ebc 100644 --- a/include/webservices.h +++ b/include/webservices.h @@ -577,6 +577,11 @@ typedef struct _WS_XML_UINT64_TEXT { unsigned __int64 value; } WS_XML_UINT64_TEXT; +typedef struct _WS_XML_DOUBLE_TEXT { + WS_XML_TEXT text; + double value; +} WS_XML_DOUBLE_TEXT; + typedef struct _WS_XML_GUID_TEXT { WS_XML_TEXT text; GUID value;