From 9e4524ffb09be6bba828ea66b8fe1bb64b996b66 Mon Sep 17 00:00:00 2001 From: Francois Gouget Date: Fri, 6 Aug 2021 12:53:09 +0200 Subject: [PATCH] oleaut32: Fix VarParseNumFromStr()'s handling of currency thousands separators. They are have no default, are not allowed before the first digit, are unaffected by the presence / absence of a currency symbol, can be mixed with regular digit separators, are incompatible with hexadecimal and octal numbers (as are regular digit separators), and mask trailing spaces. Also they don't match regular spaces when set to a non-breaking space. Signed-off-by: Francois Gouget Signed-off-by: Alexandre Julliard --- dlls/oleaut32/tests/vartest.c | 19 +++++------------- dlls/oleaut32/variant.c | 36 ++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index ecc8e8b0f11..fbcfba32c80 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -1600,11 +1600,8 @@ static void test_VarParseNumFromStrEn(void) /* With flag, thousands sep. and following digits consumed */ CONVERT("&h1,000", NUMPRS_HEX_OCT|NUMPRS_THOUSANDS); - if (broken(1)) /* FIXME Reenable once Wine is less broken */ EXPECT(1,NUMPRS_HEX_OCT|NUMPRS_THOUSANDS,NUMPRS_HEX_OCT,3,4,0); - todo_wine ok(np.dwOutFlags == NUMPRS_HEX_OCT, "Got dwOutFlags=%08x\n", np.dwOutFlags); - EXPECTRGB(0,1); - todo_wine EXPECTRGB(1,FAILDIG); + EXPECTRGB(1,FAILDIG); /* With flag and decimal point, thousands sep. but not decimals consumed */ CONVERT("1,001.0", NUMPRS_THOUSANDS); @@ -2174,7 +2171,7 @@ static void test_VarParseNumFromStrMisc(void) SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHOUSANDSEP, L"~"); SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, L""); hres = wconvert_str(L"1,000", ARRAY_SIZE(rgb), NUMPRS_THOUSANDS|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - todo_wine EXPECTFAIL; + EXPECTFAIL; SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, L"~"); /* But SMONTHOUSANDSEP defaults to ','! */ @@ -2236,9 +2233,7 @@ static void test_VarParseNumFromStrMisc(void) EXPECTRGB(4,FAILDIG); hres = wconvert_str(L"1 000", ARRAY_SIZE(rgb), NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - if (broken(1)) /* FIXME Reenable once Wine is less broken */ EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_THOUSANDS|NUMPRS_CURRENCY,5,0,3); - todo_wine ok(np.dwOutFlags == (NUMPRS_THOUSANDS|NUMPRS_CURRENCY), "Got dwOutFlags=%08x\n", np.dwOutFlags); EXPECTRGB(0,1); /* Don't test extra digits, see "1,000" test */ EXPECTRGB(4,FAILDIG); @@ -2249,15 +2244,13 @@ static void test_VarParseNumFromStrMisc(void) /* But trailing ones are allowed (same as sThousand) */ hres = wconvert_str(L"1 000 ", ARRAY_SIZE(rgb), NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - if (broken(1)) /* FIXME Reenable once Wine is less broken */ EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_THOUSANDS|NUMPRS_CURRENCY,6,0,3); - todo_wine ok(np.dwOutFlags == (NUMPRS_THOUSANDS|NUMPRS_CURRENCY), "Got dwOutFlags=%08x\n", np.dwOutFlags); EXPECTRGB(0,1); /* Don't test extra digits, see "1,000" test */ EXPECTRGB(4,FAILDIG); /* And they break NUMPRS_TRAILING_WHITE (same as sThousand) */ hres = wconvert_str(L"1000 ", ARRAY_SIZE(rgb), NUMPRS_TRAILING_WHITE|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - todo_wine EXPECTFAIL; + EXPECTFAIL; /* NUMPRS_CURRENCY is not enough for sMonThousandSep */ @@ -2272,13 +2265,13 @@ static void test_VarParseNumFromStrMisc(void) */ SetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONDECIMALSEP, L"/"); hres = wconvert_str(L"$1|000", ARRAY_SIZE(rgb), NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - todo_wine EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_THOUSANDS|NUMPRS_CURRENCY,6,0,3); + EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_THOUSANDS|NUMPRS_CURRENCY,6,0,3); EXPECTRGB(0,1); /* Don't test extra digits, see "1,000" test */ EXPECTRGB(4,FAILDIG); /* Mixing both thousands separators is allowed */ hres = wconvert_str(L"1 000|000", ARRAY_SIZE(rgb), NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - todo_wine EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_THOUSANDS|NUMPRS_CURRENCY,9,0,6); + EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_THOUSANDS|NUMPRS_CURRENCY,9,0,6); EXPECTRGB(0,1); /* Don't test extra digits, see "1,000" test */ EXPECTRGB(7,FAILDIG); @@ -2330,9 +2323,7 @@ static void test_VarParseNumFromStrMisc(void) EXPECTRGB(1,FAILDIG); hres = wconvert_str(L"1~", ARRAY_SIZE(rgb), NUMPRS_THOUSANDS|NUMPRS_DECIMAL|NUMPRS_CURRENCY|NUMPRS_USE_ALL, &np, rgb, LOCALE_USER_DEFAULT, 0); - if (broken(1)) /* FIXME Reenable once Wine is less broken */ EXPECT(1,NUMPRS_THOUSANDS|NUMPRS_DECIMAL|NUMPRS_CURRENCY|NUMPRS_USE_ALL,NUMPRS_THOUSANDS|NUMPRS_CURRENCY,2,0,0); - todo_wine ok(np.dwOutFlags == (NUMPRS_THOUSANDS|NUMPRS_CURRENCY), "Got dwOutFlags=%08x\n", np.dwOutFlags); EXPECT2(1,FAILDIG); diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 264b9f6594b..2ec07817460 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -1510,7 +1510,7 @@ HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate) /* Get the valid number characters for an lcid */ static void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, DWORD dwFlags) { - static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',',','$',0,'.',',' }; + static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',0,'$',0,'.',',' }; LCTYPE lctype = dwFlags & LOCALE_NOUSEROVERRIDE; WCHAR buff[4]; @@ -1633,6 +1633,11 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla { return DISP_E_TYPEMISMATCH; /* Not allowed before the first digit */ } + else if ((pNumprs->dwInFlags & (NUMPRS_THOUSANDS|NUMPRS_CURRENCY)) == (NUMPRS_THOUSANDS|NUMPRS_CURRENCY) && + chars.cCurrencyDigitSeparator && *lpszStr == chars.cCurrencyDigitSeparator) + { + return DISP_E_TYPEMISMATCH; /* Not allowed before the first digit */ + } else if (pNumprs->dwInFlags & NUMPRS_LEADING_PLUS && *lpszStr == chars.cPositiveSymbol && !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS)) @@ -1659,8 +1664,6 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla lpszStr += chars.cCurrencyLocal2 ? 2 : 1; /* Only accept currency characters */ chars.cDecimalPoint = chars.cCurrencyDecimalPoint; - chars.cDigitSeparator = chars.cCurrencyDigitSeparator; - cDigitSeparator2 = chars.cDigitSeparator == 0xa0 ? ' ' : 0; } else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == '(' && !(pNumprs->dwOutFlags & NUMPRS_PARENS)) @@ -1677,7 +1680,6 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla { /* Only accept non-currency characters */ chars.cCurrencyDecimalPoint = chars.cDecimalPoint; - chars.cCurrencyDigitSeparator = chars.cDigitSeparator; } if ((*lpszStr == '&' && (*(lpszStr+1) == 'H' || *(lpszStr+1) == 'h')) && @@ -1769,12 +1771,20 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla } } else if (pNumprs->dwInFlags & NUMPRS_THOUSANDS && + !(pNumprs->dwOutFlags & NUMPRS_HEX_OCT) && ((chars.cDigitSeparator && *lpszStr == chars.cDigitSeparator) || (cDigitSeparator2 && *lpszStr == cDigitSeparator2))) { pNumprs->dwOutFlags |= NUMPRS_THOUSANDS; cchUsed++; } + else if ((pNumprs->dwInFlags & (NUMPRS_THOUSANDS|NUMPRS_CURRENCY)) == (NUMPRS_THOUSANDS|NUMPRS_CURRENCY) && + !(pNumprs->dwOutFlags & NUMPRS_HEX_OCT) && + chars.cCurrencyDigitSeparator && *lpszStr == chars.cCurrencyDigitSeparator) + { + pNumprs->dwOutFlags |= NUMPRS_THOUSANDS|NUMPRS_CURRENCY; + cchUsed++; + } else if (*lpszStr == chars.cDecimalPoint && pNumprs->dwInFlags & NUMPRS_DECIMAL && !(pNumprs->dwOutFlags & (NUMPRS_DECIMAL|NUMPRS_EXPONENT))) @@ -1901,7 +1911,8 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla if ((chars.cDigitSeparator && *lpszStr == chars.cDigitSeparator) || (cDigitSeparator2 && *lpszStr == cDigitSeparator2)) { - if (pNumprs->dwInFlags & NUMPRS_THOUSANDS) + if (pNumprs->dwInFlags & NUMPRS_THOUSANDS && + !(pNumprs->dwOutFlags & NUMPRS_HEX_OCT)) { pNumprs->dwOutFlags |= NUMPRS_THOUSANDS; cchUsed++; @@ -1913,6 +1924,21 @@ HRESULT WINAPI VarParseNumFromStr(const OLECHAR *lpszStr, LCID lcid, ULONG dwFla break; } } + else if (*lpszStr == chars.cCurrencyDigitSeparator) + { + if ((pNumprs->dwInFlags & (NUMPRS_THOUSANDS|NUMPRS_CURRENCY)) == (NUMPRS_THOUSANDS|NUMPRS_CURRENCY) && + !(pNumprs->dwOutFlags & NUMPRS_HEX_OCT)) + { + pNumprs->dwOutFlags |= NUMPRS_THOUSANDS|NUMPRS_CURRENCY; + cchUsed++; + lpszStr++; + } + else + { + /* Not allowed, even with NUMPRS_TRAILING_WHITE */ + break; + } + } else if ((pNumprs->dwInFlags & NUMPRS_TRAILING_WHITE) && iswspace(*lpszStr)) { pNumprs->dwOutFlags |= NUMPRS_TRAILING_WHITE;