webservices: Add support for writing double values.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2016-07-08 10:20:30 +02:00 committed by Alexandre Julliard
parent 10925fa451
commit df4046a370
5 changed files with 224 additions and 4 deletions

View file

@ -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" );
}

View file

@ -21,6 +21,25 @@
#include "webservices.h"
#include "wine/test.h"
#include <math.h>
#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, "<t>0</t>"},
{1.0, "<t>1</t>"},
{-1.0, "<t>-1</t>"},
{1.0000000000000001, "<t>1</t>"},
{1.0000000000000002, "<t>1.0000000000000002</t>"},
{1.0000000000000003, "<t>1.0000000000000002</t>"},
{1.0000000000000004, "<t>1.0000000000000004</t>"},
{100000000000000, "<t>100000000000000</t>"},
{1000000000000000, "<t>1E+15</t>"},
{0.1, "<t>0.1</t>"},
{0.01, "<t>1E-2</t>"},
{-0.1, "<t>-0.1</t>"},
{-0.01, "<t>-1E-2</t>"},
{1.7976931348623158e308, "<t>1.7976931348623157E+308</t>"},
{-1.7976931348623158e308, "<t>-1.7976931348623157E+308</t>"},
};
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, "<t>NaN</t>", __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, "<t>INF</t>", __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, "<t>-INF</t>", __LINE__ );
WsFreeWriter( writer );
}
START_TEST(writer)
{
test_WsCreateWriter();
@ -1896,4 +2008,5 @@ START_TEST(writer)
test_WsWriteNode();
test_WsCopyNode();
test_text_types();
test_double();
}

View file

@ -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
{

View file

@ -18,6 +18,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#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;

View file

@ -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;