The ANSI string may be longer than the Unicode one and the return value should reflect that.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- dlls/kernel32/tests/locale.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index b83cdc6b956..86aa6ee5b12 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -631,6 +631,32 @@ static void test_GetTimeFormatA(void) curtime.wMonth = 60; ret = GetTimeFormatA(lcid, 0, &curtime, "h:m:s", buffer, ARRAY_SIZE(buffer)); expect_str(ret, buffer, "12:56:13"); + + /* The ANSI string may be longer than the Unicode one. + * In particular, in the Japanese code page, "\x93\xfa" = L"\x65e5". + */ + + 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); + 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"); + ok(strcmp(buffer, "pristine") == 0, "Expected a pristine buffer, got '%s'\n", buffer); }
static void test_GetTimeFormatEx(void)
The ANSI string may be longer than the Unicode one and GetDateFormatA()'s return value should reflect that.
Signed-off-by: Francois Gouget fgouget@codeweavers.com --- dlls/kernel32/tests/locale.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 86aa6ee5b12..8d22c9bed9a 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -837,6 +837,7 @@ static void test_GetDateFormatA(void) SYSTEMTIME curtime; LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); LCID lcid_ru = MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_NEUTRAL), SORT_DEFAULT); + LCID lcid_ja = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), SORT_DEFAULT); char buffer[BUFFER_SIZE], Expected[BUFFER_SIZE]; char short_day[10], month[10], genitive_month[10];
@@ -957,6 +958,27 @@ static void test_GetDateFormatA(void) ret = GetDateFormatA(lcid_ru, 0, &curtime, "ddd',' MMMM dd", buffer, ARRAY_SIZE(buffer)); sprintf(Expected, "%s, %s 04", short_day, genitive_month); expect_str(ret, buffer, Expected); + + /* The ANSI string may be longer than the Unicode one. + * In particular, in the Japanese code page, "\x93\xfa" = L"\x65e5". + * See the corresponding GetDateFormatW() test. + */ + + 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); + 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) @@ -1113,6 +1135,20 @@ static void test_GetDateFormatW(void) wcscpy(buffer, L"pristine"); ret = GetDateFormatW (lcid, 0, &curtime, L"dddd d MMMM yyyy", buffer, ARRAY_SIZE(buffer)); expect_werr(ret, buffer, ERROR_INVALID_PARAMETER); + SetLastError(0xdeadbeef); + + /* See the corresponding GetDateFormatA() test */ + + lcid = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), SORT_DEFAULT); + + curtime.wYear = 2002; + curtime.wMonth = 5; + curtime.wDay = 4; + ret = GetDateFormatW(lcid, 0, &curtime, L"d\x65e5", buffer, 3); + expect_wstr(ret, buffer, L"4\x65e5"); + + ret = GetDateFormatW(lcid, 0, &curtime, L"d\x65e5", NULL, 0); + expect_wstr(ret, NULL, L"4\x65e5"); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=96367
Your paranoid android.
=== debiant2 (32 bit report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Arabic:Morocco report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit German report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit French report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Hebrew:Israel report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Hindi:India report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Japanese:Japan report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Chinese:China report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit WoW report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (64 bit WoW report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
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)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=96366
Your paranoid android.
=== debiant2 (32 bit report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Arabic:Morocco report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit German report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit French report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Hebrew:Israel report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Hindi:India report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Japanese:Japan report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit Chinese:China report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (32 bit WoW report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559
=== debiant2 (64 bit WoW report) ===
kernel32: locale.c:658: Test succeeded inside todo block: unexpected gle 3735928559