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:
parent
10925fa451
commit
df4046a370
|
@ -2271,7 +2271,7 @@ static HRESULT str_to_uint64( const unsigned char *str, ULONG len, UINT64 max, U
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
|
|
||||||
#define RC_DOWN 0x100;
|
#define RC_DOWN 0x100;
|
||||||
static BOOL set_fp_rounding( unsigned short *save )
|
BOOL set_fp_rounding( unsigned short *save )
|
||||||
{
|
{
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
unsigned short fpword;
|
unsigned short fpword;
|
||||||
|
@ -2286,7 +2286,7 @@ static BOOL set_fp_rounding( unsigned short *save )
|
||||||
return FALSE;
|
return FALSE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
static void restore_fp_rounding( unsigned short fpword )
|
void restore_fp_rounding( unsigned short fpword )
|
||||||
{
|
{
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
__asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
|
__asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
|
||||||
|
@ -2295,12 +2295,12 @@ static void restore_fp_rounding( unsigned short fpword )
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static BOOL set_fp_rounding( unsigned short *save )
|
BOOL set_fp_rounding( unsigned short *save )
|
||||||
{
|
{
|
||||||
FIXME( "not implemented\n" );
|
FIXME( "not implemented\n" );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
static void restore_fp_rounding( unsigned short fpword )
|
void restore_fp_rounding( unsigned short fpword )
|
||||||
{
|
{
|
||||||
FIXME( "not implemented\n" );
|
FIXME( "not implemented\n" );
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,25 @@
|
||||||
#include "webservices.h"
|
#include "webservices.h"
|
||||||
#include "wine/test.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 )
|
static HRESULT set_output( WS_XML_WRITER *writer )
|
||||||
{
|
{
|
||||||
WS_XML_WRITER_TEXT_ENCODING encoding;
|
WS_XML_WRITER_TEXT_ENCODING encoding;
|
||||||
|
@ -1871,6 +1890,99 @@ static void test_text_types(void)
|
||||||
WsFreeWriter( writer );
|
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)
|
START_TEST(writer)
|
||||||
{
|
{
|
||||||
test_WsCreateWriter();
|
test_WsCreateWriter();
|
||||||
|
@ -1896,4 +2008,5 @@ START_TEST(writer)
|
||||||
test_WsWriteNode();
|
test_WsWriteNode();
|
||||||
test_WsCopyNode();
|
test_WsCopyNode();
|
||||||
test_text_types();
|
test_text_types();
|
||||||
|
test_double();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
HRESULT append_attribute( WS_XML_ELEMENT_NODE *, WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN;
|
||||||
void free_attribute( WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN;
|
void free_attribute( WS_XML_ATTRIBUTE * ) DECLSPEC_HIDDEN;
|
||||||
WS_TYPE map_value_type( WS_VALUE_TYPE ) 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
|
struct node
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
|
@ -1042,6 +1043,92 @@ static ULONG format_uint64( const UINT64 *ptr, unsigned char *buf )
|
||||||
return wsprintfA( (char *)buf, "%I64u", *ptr );
|
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 ULONG format_guid( const GUID *ptr, unsigned char *buf )
|
||||||
{
|
{
|
||||||
static const char fmt[] = "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
|
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;
|
if (!(*ret = alloc_utf8_text( buf, len ))) return E_OUTOFMEMORY;
|
||||||
return S_OK;
|
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:
|
case WS_XML_TEXT_TYPE_GUID:
|
||||||
{
|
{
|
||||||
const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
|
const WS_XML_GUID_TEXT *id = (const WS_XML_GUID_TEXT *)text;
|
||||||
|
|
|
@ -577,6 +577,11 @@ typedef struct _WS_XML_UINT64_TEXT {
|
||||||
unsigned __int64 value;
|
unsigned __int64 value;
|
||||||
} WS_XML_UINT64_TEXT;
|
} 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 {
|
typedef struct _WS_XML_GUID_TEXT {
|
||||||
WS_XML_TEXT text;
|
WS_XML_TEXT text;
|
||||||
GUID value;
|
GUID value;
|
||||||
|
|
Loading…
Reference in New Issue