[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