[1/3] webservices: Add support for reading double values.
Hans Leidekker
hans at codeweavers.com
Wed May 18 06:51:20 CDT 2016
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/webservices/reader.c | 210 ++++++++++++++++++++++++++++++++++++++++
dlls/webservices/tests/reader.c | 96 ++++++++++++++++++
2 files changed, 306 insertions(+)
diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c
index 41c76ee..9337f19 100644
--- a/dlls/webservices/reader.c
+++ b/dlls/webservices/reader.c
@@ -1937,6 +1937,160 @@ static HRESULT str_to_uint64( const unsigned char *str, ULONG len, UINT64 max, U
return S_OK;
}
+#if defined(__i386__) || defined(__x86_64__)
+
+#define RC_DOWN 0x100;
+static BOOL set_fp_rounding( unsigned short *save )
+{
+#ifdef __GNUC__
+ unsigned short fpword;
+
+ __asm__ __volatile__( "fstcw %0" : "=m" (fpword) );
+ *save = fpword;
+ fpword |= RC_DOWN;
+ __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
+ return TRUE;
+#else
+ FIXME( "not implemented\n" );
+ return FALSE;
+#endif
+}
+static void restore_fp_rounding( unsigned short fpword )
+{
+#ifdef __GNUC__
+ __asm__ __volatile__( "fldcw %0" : : "m" (fpword) );
+#else
+ FIXME( "not implemented\n" );
+#endif
+}
+#else
+static BOOL set_fp_rounding( unsigned short *save )
+{
+ FIXME( "not implemented\n" );
+ return FALSE;
+}
+static void restore_fp_rounding( unsigned short fpword )
+{
+ FIXME( "not implemented\n" );
+}
+#endif
+
+static HRESULT str_to_double( const unsigned char *str, ULONG len, double *ret )
+{
+ static const unsigned __int64 nan = 0xfff8000000000000;
+ static const unsigned __int64 inf = 0x7ff0000000000000;
+ static const unsigned __int64 inf_min = 0xfff0000000000000;
+ HRESULT hr = WS_E_INVALID_FORMAT;
+ const unsigned char *p = str, *q;
+ int sign = 1, exp_sign = 1, exp = 0, exp_tmp = 0, neg_exp, i, nb_digits, have_digits;
+ unsigned __int64 val = 0, tmp;
+ long double exp_val = 1.0, exp_mul = 10.0;
+ unsigned short fpword;
+
+ while (len && read_isspace( *p )) { p++; len--; }
+ while (len && read_isspace( p[len - 1] )) { len--; }
+ if (!len) return WS_E_INVALID_FORMAT;
+
+ if (len == 3 && !memcmp( p, "NaN", 3 ))
+ {
+ *(unsigned __int64 *)ret = nan;
+ return S_OK;
+ }
+ else if (len == 3 && !memcmp( p, "INF", 3 ))
+ {
+ *(unsigned __int64 *)ret = inf;
+ return S_OK;
+ }
+ else if (len == 4 && !memcmp( p, "-INF", 4 ))
+ {
+ *(unsigned __int64 *)ret = inf_min;
+ return S_OK;
+ }
+
+ *ret = 0.0;
+ if (*p == '-')
+ {
+ sign = -1;
+ p++; len--;
+ }
+ else if (*p == '+') { p++; len--; };
+ if (!len) return S_OK;
+
+ if (!set_fp_rounding( &fpword )) return E_NOTIMPL;
+
+ q = p;
+ while (len && isdigit( *q )) { q++; len--; }
+ have_digits = nb_digits = q - p;
+ for (i = 0; i < nb_digits; i++)
+ {
+ tmp = val * 10 + p[i] - '0';
+ if (val > MAX_UINT64 / 10 || tmp < val)
+ {
+ for (; i < nb_digits; i++) exp++;
+ break;
+ }
+ val = tmp;
+ }
+
+ if (len)
+ {
+ if (*q == '.')
+ {
+ p = ++q; len--;
+ while (len && isdigit( *q )) { q++; len--; };
+ have_digits |= nb_digits = q - p;
+ for (i = 0; i < nb_digits; i++)
+ {
+ tmp = val * 10 + p[i] - '0';
+ if (val > MAX_UINT64 / 10 || tmp < val) break;
+ val = tmp;
+ exp--;
+ }
+ }
+ if (len > 1 && tolower(*q) == 'e')
+ {
+ if (!have_digits) goto done;
+ p = ++q; len--;
+ if (*p == '-')
+ {
+ exp_sign = -1;
+ p++; len--;
+ }
+ else if (*p == '+') { p++; len--; };
+
+ q = p;
+ while (len && isdigit( *q )) { q++; len--; };
+ nb_digits = q - p;
+ if (!nb_digits || len) goto done;
+ for (i = 0; i < nb_digits; i++)
+ {
+ if (exp_tmp > MAX_INT32 / 10 || (exp_tmp = exp_tmp * 10 + p[i] - '0') < 0)
+ exp_tmp = MAX_INT32;
+ }
+ exp_tmp *= exp_sign;
+
+ if (exp < 0 && exp_tmp < 0 && exp + exp_tmp >= 0) exp = MIN_INT32;
+ else if (exp > 0 && exp_tmp > 0 && exp + exp_tmp < 0) exp = MAX_INT32;
+ else exp += exp_tmp;
+ }
+ }
+ if (!have_digits || len) goto done;
+
+ if ((neg_exp = exp < 0)) exp = -exp;
+ for (; exp; exp >>= 1)
+ {
+ if (exp & 1) exp_val *= exp_mul;
+ exp_mul *= exp_mul;
+ }
+
+ *ret = sign * (neg_exp ? val / exp_val : val * exp_val);
+ hr = S_OK;
+
+done:
+ restore_fp_rounding( fpword );
+ return hr;
+}
+
#define TICKS_PER_SEC 10000000
#define TICKS_PER_MIN (60 * (ULONGLONG)TICKS_PER_SEC)
#define TICKS_PER_HOUR (3600 * (ULONGLONG)TICKS_PER_SEC)
@@ -2711,6 +2865,53 @@ static HRESULT read_type_uint64( struct reader *reader, WS_TYPE_MAPPING mapping,
return S_OK;
}
+static HRESULT read_type_double( struct reader *reader, WS_TYPE_MAPPING mapping,
+ const WS_XML_STRING *localname, const WS_XML_STRING *ns,
+ const WS_DOUBLE_DESCRIPTION *desc, WS_READ_OPTION option,
+ WS_HEAP *heap, void *ret, ULONG size )
+{
+ WS_XML_UTF8_TEXT *utf8;
+ HRESULT hr;
+ double val = 0.0;
+ BOOL found;
+
+ if (desc) FIXME( "ignoring description\n" );
+
+ if ((hr = read_get_text( reader, mapping, localname, ns, &utf8, &found )) != S_OK) return hr;
+ if (found && (hr = str_to_double( utf8->value.bytes, utf8->value.length, &val )) != S_OK) return hr;
+
+ switch (option)
+ {
+ case WS_READ_REQUIRED_VALUE:
+ if (!found) return WS_E_INVALID_FORMAT;
+ if (size != sizeof(double)) return E_INVALIDARG;
+ *(double *)ret = val;
+ break;
+
+ case WS_READ_REQUIRED_POINTER:
+ if (!found) return WS_E_INVALID_FORMAT;
+ /* fall through */
+
+ case WS_READ_OPTIONAL_POINTER:
+ {
+ double *heap_val = NULL;
+ if (size != sizeof(heap_val)) return E_INVALIDARG;
+ if (found)
+ {
+ if (!(heap_val = ws_alloc( heap, sizeof(*heap_val) ))) return WS_E_QUOTA_EXCEEDED;
+ *heap_val = val;
+ }
+ *(double **)ret = heap_val;
+ break;
+ }
+ default:
+ FIXME( "read option %u not supported\n", option );
+ return E_NOTIMPL;
+ }
+
+ return S_OK;
+}
+
static HRESULT read_type_wsz( struct reader *reader, WS_TYPE_MAPPING mapping,
const WS_XML_STRING *localname, const WS_XML_STRING *ns,
const WS_WSZ_DESCRIPTION *desc, WS_READ_OPTION option,
@@ -2958,6 +3159,9 @@ static ULONG get_type_size( WS_TYPE type, const WS_STRUCT_DESCRIPTION *desc )
case WS_UINT64_TYPE:
return sizeof(INT64);
+ case WS_DOUBLE_TYPE:
+ return sizeof(double);
+
case WS_DATETIME_TYPE:
return sizeof(WS_DATETIME);
@@ -3091,6 +3295,7 @@ static WS_READ_OPTION get_field_read_option( WS_TYPE type )
case WS_UINT16_TYPE:
case WS_UINT32_TYPE:
case WS_UINT64_TYPE:
+ case WS_DOUBLE_TYPE:
case WS_ENUM_TYPE:
case WS_DATETIME_TYPE:
return WS_READ_REQUIRED_VALUE;
@@ -3322,6 +3527,11 @@ static HRESULT read_type( struct reader *reader, WS_TYPE_MAPPING mapping, WS_TYP
return hr;
break;
+ case WS_DOUBLE_TYPE:
+ if ((hr = read_type_double( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
+ return hr;
+ break;
+
case WS_WSZ_TYPE:
if ((hr = read_type_wsz( reader, mapping, localname, ns, desc, option, heap, value, size )) != S_OK)
return hr;
diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c
index e66100c..bc200e2 100644
--- a/dlls/webservices/tests/reader.c
+++ b/dlls/webservices/tests/reader.c
@@ -3176,6 +3176,101 @@ static void test_WsFileTimeToDateTime(void)
ok( hr == WS_E_NUMERIC_OVERFLOW, "got %08x\n", hr );
}
+static void test_double(void)
+{
+ static const struct
+ {
+ const char *str;
+ HRESULT hr;
+ ULONGLONG val;
+ }
+ tests[] =
+ {
+ {"<t>0.0</t>", S_OK, 0},
+ {"<t>-0.0</t>", S_OK, 0x8000000000000000},
+ {"<t>+0.0</t>", S_OK, 0},
+ {"<t>-</t>", S_OK, 0},
+ {"<t>+</t>", S_OK, 0},
+ {"<t>.0</t>", S_OK, 0},
+ {"<t>0.</t>", S_OK, 0},
+ {"<t>0</t>", S_OK, 0},
+ {"<t> 0 </t>", S_OK, 0},
+ {"<t></t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>0,1</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>1.1.</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>1</t>", S_OK, 0x3ff0000000000000},
+ {"<t>1.0000000000000002</t>", S_OK, 0x3ff0000000000001},
+ {"<t>1.0000000000000004</t>", S_OK, 0x3ff0000000000002},
+ {"<t>10000000000000000000</t>", S_OK, 0x43e158e460913d00},
+ {"<t>100000000000000000000</t>", S_OK, 0x4415af1d78b58c40},
+ {"<t>2</t>", S_OK, 0x4000000000000000},
+ {"<t>-2</t>", S_OK, 0xc000000000000000},
+ {"<t>nodouble</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>INF</t>", S_OK, 0x7ff0000000000000},
+ {"<t>-INF</t>", S_OK, 0xfff0000000000000},
+ {"<t>+INF</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>Infinity</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>-Infinity</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>inf</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>NaN</t>", S_OK, 0xfff8000000000000},
+ {"<t>-NaN</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>NAN</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>0.3</t>", S_OK, 0x3fd3333333333333},
+ {"<t>0.33</t>", S_OK, 0x3fd51eb851eb851f},
+ {"<t>0.333</t>", S_OK, 0x3fd54fdf3b645a1d},
+ {"<t>0.3333</t>", S_OK, 0x3fd554c985f06f69},
+ {"<t>0.33333</t>", S_OK, 0x3fd555475a31a4be},
+ {"<t>0.333333</t>", S_OK, 0x3fd55553ef6b5d46},
+ {"<t>0.3333333</t>", S_OK, 0x3fd55555318abc87},
+ {"<t>0.33333333</t>", S_OK, 0x3fd5555551c112da},
+ {"<t>0.333333333</t>", S_OK, 0x3fd5555554f9b516},
+ {"<t>0.3333333333</t>", S_OK, 0x3fd55555554c2bb5},
+ {"<t>0.33333333333</t>", S_OK, 0x3fd5555555546ac5},
+ {"<t>0.3333333333333</t>", S_OK, 0x3fd55555555552fd},
+ {"<t>0.33333333333333</t>", S_OK, 0x3fd5555555555519},
+ {"<t>0.333333333333333</t>", S_OK, 0x3fd555555555554f},
+ {"<t>0.3333333333333333</t>", S_OK, 0x3fd5555555555555},
+ {"<t>0.33333333333333333</t>", S_OK, 0x3fd5555555555555},
+ {"<t>0.1e10</t>", S_OK, 0x41cdcd6500000000},
+ {"<t>1e</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>1e0</t>", S_OK, 0x3ff0000000000000},
+ {"<t>1e+1</t>", S_OK, 0x4024000000000000},
+ {"<t>1e-1</t>", S_OK, 0x3fb999999999999a},
+ {"<t>e10</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>1e10.</t>", WS_E_INVALID_FORMAT, 0},
+ {"<t>1E10</t>", S_OK, 0x4202a05f20000000},
+ {"<t>1e10</t>", S_OK, 0x4202a05f20000000},
+ {"<t>1e-10</t>", S_OK, 0x3ddb7cdfd9d7bdbb},
+ {"<t>1.7976931348623158e308</t>", S_OK, 0x7fefffffffffffff},
+ {"<t>1.7976931348623159e308</t>", S_OK, 0x7ff0000000000000},
+ {"<t>4.94065645841247e-324</t>", S_OK, 0x1},
+ };
+ HRESULT hr;
+ WS_XML_READER *reader;
+ WS_HEAP *heap;
+ ULONGLONG val;
+ ULONG i;
+
+ hr = WsCreateHeap( 1 << 16, 0, NULL, 0, &heap, NULL );
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ hr = WsCreateReader( NULL, 0, &reader, NULL ) ;
+ ok( hr == S_OK, "got %08x\n", hr );
+
+ for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
+ {
+ val = 0;
+ prepare_type_test( reader, tests[i].str, strlen(tests[i].str) );
+ hr = WsReadType( reader, WS_ELEMENT_CONTENT_TYPE_MAPPING, WS_DOUBLE_TYPE, NULL,
+ WS_READ_REQUIRED_VALUE, heap, &val, sizeof(val), NULL );
+ ok( hr == tests[i].hr, "%u: got %08x\n", i, hr );
+ if (hr == tests[i].hr) ok( val == tests[i].val, "%u: got %x%08x\n", i, (ULONG)(val >> 32), (ULONG)val );
+ }
+
+ WsFreeReader( reader );
+ WsFreeHeap( heap );
+}
+
START_TEST(reader)
{
test_WsCreateError();
@@ -3204,4 +3299,5 @@ START_TEST(reader)
test_datetime();
test_WsDateTimeToFileTime();
test_WsFileTimeToDateTime();
+ test_double();
}
--
2.8.1
More information about the wine-patches
mailing list