From 6d70b1a66e01315dedf27d65738b8f050552d7ed Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Tue, 7 Jan 2020 12:11:25 +0100 Subject: [PATCH] webservices: Use sscanf to convert strings to doubles. Signed-off-by: Erich E. Hoover Signed-off-by: Hans Leidekker Signed-off-by: Alexandre Julliard --- dlls/webservices/listener.c | 5 ++ dlls/webservices/reader.c | 105 +++++++------------------ dlls/webservices/tests/reader.c | 3 + dlls/webservices/webservices_private.h | 2 + include/msvcrt/stdio.h | 1 + 5 files changed, 39 insertions(+), 77 deletions(-) diff --git a/dlls/webservices/listener.c b/dlls/webservices/listener.c index 6801465f84c..9b32369fd40 100644 --- a/dlls/webservices/listener.c +++ b/dlls/webservices/listener.c @@ -17,6 +17,7 @@ */ #include +#include #include "windef.h" #include "winbase.h" @@ -49,6 +50,8 @@ void winsock_init(void) InitOnceExecuteOnce( &once, winsock_startup, NULL, NULL ); } +_locale_t c_locale; + /****************************************************************** * DllMain (webservices.@) */ @@ -59,11 +62,13 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved ) case DLL_PROCESS_ATTACH: webservices_instance = hinst; DisableThreadLibraryCalls( hinst ); + c_locale = _create_locale( LC_ALL, "C" ); break; case DLL_PROCESS_DETACH: if (reserved) break; if (winsock_loaded) WSACleanup(); + _free_locale( c_locale ); break; } return TRUE; diff --git a/dlls/webservices/reader.c b/dlls/webservices/reader.c index 181739650e0..b328bb779e6 100644 --- a/dlls/webservices/reader.c +++ b/dlls/webservices/reader.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "windef.h" #include "winbase.h" @@ -3726,15 +3727,13 @@ static HRESULT str_to_uint64( const unsigned char *str, ULONG len, UINT64 max, U static HRESULT str_to_double( const unsigned char *str, ULONG len, double *ret ) { + BOOL found_sign = FALSE, found_exponent = FALSE, found_digit = FALSE, found_decimal = FALSE; 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 int fpword = _control87( 0, 0 ); + const char *p = (const char *)str; + double tmp; + ULONG i; while (len && read_isspace( *p )) { p++; len--; } while (len && read_isspace( p[len - 1] )) { len--; } @@ -3756,88 +3755,40 @@ static HRESULT str_to_double( const unsigned char *str, ULONG len, double *ret ) return S_OK; } - *ret = 0.0; - if (*p == '-') + for (i = 0; i < len; i++) { - sign = -1; - p++; len--; - } - else if (*p == '+') { p++; len--; }; - if (!len) return S_OK; - - _control87( _MCW_EM | _RC_NEAR | _PC_64, _MCW_EM | _MCW_RC | _MCW_PC ); - - 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) + if (p[i] >= '0' && p[i] <= '9') { - for (; i < nb_digits; i++) exp++; - break; + found_digit = TRUE; + continue; } - val = tmp; - } - - if (len) - { - if (*q == '.') + if (!found_sign && !found_digit && (p[i] == '+' || p[i] == '-')) { - 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--; - } + found_sign = TRUE; + continue; } - if (len > 1 && tolower(*q) == 'e') + if (!found_exponent && found_digit && (p[i] == 'e' || p[i] == '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; + found_exponent = found_decimal = TRUE; + found_digit = found_sign = FALSE; + continue; } + if (!found_decimal && p[i] == '.') + { + found_decimal = TRUE; + continue; + } + return WS_E_INVALID_FORMAT; } - if (!have_digits || len) goto done; - - if ((neg_exp = exp < 0)) exp = -exp; - for (; exp; exp >>= 1) + if (!found_digit && !found_exponent) { - if (exp & 1) exp_val *= exp_mul; - exp_mul *= exp_mul; + *ret = 0; + return S_OK; } - *ret = sign * (neg_exp ? val / exp_val : val * exp_val); - hr = S_OK; - -done: - _control87( fpword, _MCW_EM | _MCW_RC | _MCW_PC ); - return hr; + if (_snscanf_l( p, len, "%lf", c_locale, &tmp ) != 1) return WS_E_INVALID_FORMAT; + *ret = tmp; + return S_OK; } static HRESULT str_to_float( const unsigned char *str, ULONG len, float *ret ) diff --git a/dlls/webservices/tests/reader.c b/dlls/webservices/tests/reader.c index 70623052de6..96eee2cf772 100644 --- a/dlls/webservices/tests/reader.c +++ b/dlls/webservices/tests/reader.c @@ -3650,7 +3650,10 @@ static void test_double(void) {"-0.0", S_OK, 0x8000000000000000}, {"+0.0", S_OK, 0}, {"-", S_OK, 0}, + {"-.", S_OK, 0}, {"+", S_OK, 0}, + {"+.", S_OK, 0}, + {".", S_OK, 0}, {".0", S_OK, 0}, {"0.", S_OK, 0}, {"0", S_OK, 0}, diff --git a/dlls/webservices/webservices_private.h b/dlls/webservices/webservices_private.h index b12032060f7..6f2b90dad28 100644 --- a/dlls/webservices/webservices_private.h +++ b/dlls/webservices/webservices_private.h @@ -18,6 +18,8 @@ #include "winhttp.h" +_locale_t c_locale DECLSPEC_HIDDEN; + #define STREAM_BUFSIZE 4096 struct xmlbuf diff --git a/include/msvcrt/stdio.h b/include/msvcrt/stdio.h index 6d0aaeaa6c5..fa81f3d5369 100644 --- a/include/msvcrt/stdio.h +++ b/include/msvcrt/stdio.h @@ -191,6 +191,7 @@ int WINAPIV sprintf_s(char*,size_t,const char*,...); int WINAPIV _scprintf(const char *, ...); int WINAPIV sscanf(const char*,const char*,...); int WINAPIV sscanf_s(const char*,const char*,...); +int WINAPIV _snscanf_l(const char*,size_t,const char*,_locale_t,...); FILE* __cdecl tmpfile(void); char* __cdecl tmpnam(char*); int __cdecl ungetc(int,FILE*);