Signed-off-by: Francois Gouget fgouget@codeweavers.com --- I suspect most of our Unicode to ANSI conversions are buggy, particularly when given a NULL output buffer. This is true of GetNumberFormatA() and GetCurrencyFormatA() for instance.
GetNumberFormatA() probably only has to deal with [0-9,.] so it may not run into the issue of a Unicode character converting to multiple ANSI characters. But it's quite possible that there is some currency symbol out there that will trigger the issue in GetCurrencyFormatA(). These cases are just harder to test for.
But it's not just these functions. There's also SHFormatDateTimeA() in shlwapi which causes a test failure. And then SHGetWebFolderFilePathA() does not return a failure if the W->A conversion fails which is most likely wrong; neither does PathCompactPathExA() plus it half ignores cchMax, etc. --- dlls/kernel32/lcformat.c | 25 ++++++++----------------- dlls/kernel32/tests/locale.c | 16 +++------------- 2 files changed, 11 insertions(+), 30 deletions(-)
diff --git a/dlls/kernel32/lcformat.c b/dlls/kernel32/lcformat.c index a9dfbf09be2..5711d05b76f 100644 --- a/dlls/kernel32/lcformat.c +++ b/dlls/kernel32/lcformat.c @@ -737,7 +737,7 @@ invalid_flags: /****************************************************************************** * NLS_GetDateTimeFormatA <internal> * - * ASCII wrapper for GetDateFormatA/GetTimeFormatA. + * ANSI wrapper for GetDateFormatA/GetTimeFormatA. */ static INT NLS_GetDateTimeFormatA(LCID lcid, DWORD dwFlags, const SYSTEMTIME* lpTime, @@ -745,12 +745,12 @@ static INT NLS_GetDateTimeFormatA(LCID lcid, DWORD dwFlags, { DWORD cp = CP_ACP; WCHAR szFormat[128], szOut[128]; - INT iRet; + INT iRet, cchOutW;
TRACE("(0x%04x,0x%08x,%p,%s,%p,%d)\n", lcid, dwFlags, lpTime, debugstr_a(lpFormat), lpStr, cchOut);
- if (NLS_IsUnicodeOnlyLcid(lcid)) + if ((cchOut && !lpStr) || NLS_IsUnicodeOnlyLcid(lcid)) { SetLastError(ERROR_INVALID_PARAMETER); return 0; @@ -771,21 +771,12 @@ static INT NLS_GetDateTimeFormatA(LCID lcid, DWORD dwFlags, if (lpFormat) MultiByteToWideChar(cp, 0, lpFormat, -1, szFormat, ARRAY_SIZE(szFormat));
- if (cchOut > (int) ARRAY_SIZE(szOut)) - cchOut = ARRAY_SIZE(szOut); - - szOut[0] = '\0'; - + /* If cchOut == 0 we need the full string to get the accurate ANSI size */ + cchOutW = (cchOut && cchOut <= ARRAY_SIZE(szOut)) ? cchOut : ARRAY_SIZE(szOut); iRet = NLS_GetDateTimeFormatW(lcid, dwFlags, lpTime, lpFormat ? szFormat : NULL, - lpStr ? szOut : NULL, cchOut); - - if (lpStr) - { - if (szOut[0]) - WideCharToMultiByte(cp, 0, szOut, iRet ? -1 : cchOut, lpStr, cchOut, 0, 0); - else if (cchOut && iRet) - *lpStr = '\0'; - } + szOut, cchOutW); + if (iRet) + iRet = WideCharToMultiByte(cp, 0, szOut, -1, lpStr, cchOut, NULL, NULL); return iRet; }
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 8d22c9bed9a..fa0ec374d34 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -639,23 +639,18 @@ static void test_GetTimeFormatA(void) lcid = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), SORT_DEFAULT);
ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 5); - if (broken(1)) /* FIXME Remove once Wine is less broken */ expect_str(ret, buffer, "12\x93\xfa"); /* only 3+1 WCHARs */ - todo_wine ok(ret == strlen("12\x93\xfa") + 1, "Expected ret %d, got %d\n", strlen("12\x93\xfa") + 1, ret); - ok(strcmp(buffer, "12\x93\xfa") == 0, "Expected '12\x93\xfa', got '%s'\n", buffer);
ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 4); - todo_wine expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); + expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); SetLastError(0xdeadbeef);
ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", NULL, 0); - if (broken(1)) /* FIXME Remove once Wine is less broken */ expect_str(ret, NULL, "12\x93\xfa"); - todo_wine ok(ret == strlen("12\x93\xfa") + 1, "Expected ret %d, got %d\n", strlen("12\x93\xfa") + 1, ret);
strcpy(buffer, "pristine"); /* clear previous identical result */ ret = GetTimeFormatA(lcid, 0, &curtime, "h\x93\xfa", buffer, 0); - todo_wine expect_str(ret, NULL, "12\x93\xfa"); + expect_str(ret, NULL, "12\x93\xfa"); ok(strcmp(buffer, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", buffer); }
@@ -965,20 +960,15 @@ static void test_GetDateFormatA(void) */
ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", buffer, 4); - if (broken(1)) /* FIXME Remove once Wine is less broken */ expect_str(ret, buffer, "4\x93\xfa"); /* only 2+1 WCHARs */ - todo_wine ok(ret == strlen("4\x93\xfa") + 1, "Expected ret %d, got %d\n", strlen("4\x93\xfa") + 1, ret); - ok(strcmp(buffer, "4\x93\xfa") == 0, "Expected '4\x93\xfa', got '%s'\n", buffer);
ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", buffer, 3); - todo_wine expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); + expect_err(ret, NULL, ERROR_INSUFFICIENT_BUFFER); SetLastError(0xdeadbeef);
strcpy(buffer, "pristine"); /* clear previous identical result */ ret = GetDateFormatA(lcid_ja, 0, &curtime, "d\x93\xfa", NULL, 0); - if (broken(1)) /* FIXME Remove once Wine is less broken */ expect_str(ret, NULL, "4\x93\xfa"); - todo_wine ok(ret == strlen("4\x93\xfa") + 1, "Expected ret %d, got %d\n", strlen("4\x93\xfa") + 1, ret); }
static void test_GetDateFormatEx(void)