msvcrt: Use GetLocaleInfoEx to compare locale info.

GetLocaleInfoA doesn't return the proper sname for neutral LCIDs.
This commit is contained in:
Victor Chiletto 2023-06-06 20:12:08 -03:00 committed by Alexandre Julliard
parent ec7816a42a
commit 8f663f3d5e

View file

@ -241,11 +241,11 @@ static BOOL remap_synonym(char *name)
#define FOUND_COUNTRY 0x1 #define FOUND_COUNTRY 0x1
typedef struct { typedef struct {
char search_language[MAX_ELEM_LEN]; WCHAR search_language[MAX_ELEM_LEN];
char search_country[MAX_ELEM_LEN]; WCHAR search_country[MAX_ELEM_LEN];
WCHAR found_lang_sname[LOCALE_NAME_MAX_LENGTH];
DWORD found_codepage; DWORD found_codepage;
unsigned int match_flags; unsigned int match_flags;
LANGID found_lang_id;
BOOL allow_sname; BOOL allow_sname;
} locale_search_t; } locale_search_t;
@ -253,50 +253,48 @@ typedef struct {
#define STOP_LOOKING FALSE #define STOP_LOOKING FALSE
/* INTERNAL: Get and compare locale info with a given string */ /* INTERNAL: Get and compare locale info with a given string */
static int compare_info(LCID lcid, DWORD flags, char* buff, const char* cmp, BOOL exact) static int compare_info(WCHAR *name, DWORD flags, WCHAR *buff, const WCHAR *cmp, BOOL exact)
{ {
int len; int len;
if(!cmp[0]) if(!cmp[0])
return 0; return 0;
buff[0] = 0; buff[0] = 0;
GetLocaleInfoA(lcid, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN); GetLocaleInfoEx(name, flags|LOCALE_NOUSEROVERRIDE, buff, MAX_ELEM_LEN);
if (!buff[0]) if (!buff[0])
return 0; return 0;
/* Partial matches are only allowed on language/country names */ /* Partial matches are only allowed on language/country names */
len = strlen(cmp); len = wcslen(cmp);
if(exact || len<=3) if(exact || len<=3)
return !_stricmp(cmp, buff); return !_wcsicmp(cmp, buff);
else else
return !_strnicmp(cmp, buff, len); return !_wcsnicmp(cmp, buff, len);
} }
static BOOL CALLBACK static BOOL CALLBACK
find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam ) find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam )
{ {
locale_search_t *res = (locale_search_t *)lParam; locale_search_t *res = (locale_search_t *)lParam;
const LCID lcid = LocaleNameToLCID( name, LCID_CONVERSION_FLAGS ); WCHAR buff[MAX_ELEM_LEN];
char buff[MAX_ELEM_LEN];
unsigned int flags = 0; unsigned int flags = 0;
if (lcid == LOCALE_CUSTOM_UNSPECIFIED) return CONTINUE_LOOKING; if (res->allow_sname && compare_info(name,LOCALE_SNAME,buff,res->search_language, TRUE))
if (res->allow_sname && compare_info(lcid,LOCALE_SNAME,buff,res->search_language, TRUE))
{ {
TRACE(":Found locale: %s->%s\n", res->search_language, buff); TRACE(":Found locale: %s->%s\n", wine_dbgstr_w(res->search_language), wine_dbgstr_w(buff));
res->match_flags = FOUND_SNAME; res->match_flags = FOUND_SNAME;
res->found_lang_id = LANGIDFROMLCID(lcid); wcscpy(res->found_lang_sname, name);
return STOP_LOOKING; return STOP_LOOKING;
} }
/* Check Language */ /* Check Language */
if (compare_info(lcid,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) || if (compare_info(name,LOCALE_SISO639LANGNAME,buff,res->search_language, TRUE) ||
compare_info(lcid,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) || compare_info(name,LOCALE_SABBREVLANGNAME,buff,res->search_language, TRUE) ||
compare_info(lcid,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE)) compare_info(name,LOCALE_SENGLANGUAGE,buff,res->search_language, FALSE))
{ {
TRACE(":Found language: %s->%s\n", res->search_language, buff); TRACE(":Found language: %s->%s\n", wine_dbgstr_w(res->search_language), wine_dbgstr_w(buff));
flags |= FOUND_LANGUAGE; flags |= FOUND_LANGUAGE;
} }
else if (res->match_flags & FOUND_LANGUAGE) else if (res->match_flags & FOUND_LANGUAGE)
@ -305,11 +303,11 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam )
} }
/* Check Country */ /* Check Country */
if (compare_info(lcid,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) || if (compare_info(name,LOCALE_SISO3166CTRYNAME,buff,res->search_country, TRUE) ||
compare_info(lcid,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) || compare_info(name,LOCALE_SABBREVCTRYNAME,buff,res->search_country, TRUE) ||
compare_info(lcid,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE)) compare_info(name,LOCALE_SENGCOUNTRY,buff,res->search_country, FALSE))
{ {
TRACE("Found country:%s->%s\n", res->search_country, buff); TRACE("Found country:%s->%s\n", wine_dbgstr_w(res->search_country), wine_dbgstr_w(buff));
flags |= FOUND_COUNTRY; flags |= FOUND_COUNTRY;
} }
else if (!flags && (res->match_flags & FOUND_COUNTRY)) else if (!flags && (res->match_flags & FOUND_COUNTRY))
@ -321,7 +319,7 @@ find_best_locale_proc( WCHAR *name, DWORD locale_flags, LPARAM lParam )
{ {
/* Found a better match than previously */ /* Found a better match than previously */
res->match_flags = flags; res->match_flags = flags;
res->found_lang_id = LANGIDFROMLCID(lcid); wcscpy(res->found_lang_sname, name);
} }
if ((flags & (FOUND_LANGUAGE | FOUND_COUNTRY)) == if ((flags & (FOUND_LANGUAGE | FOUND_COUNTRY)) ==
(FOUND_LANGUAGE | FOUND_COUNTRY)) (FOUND_LANGUAGE | FOUND_COUNTRY))
@ -354,27 +352,27 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m
if(!locale[0] || (cp == locale && !region)) { if(!locale[0] || (cp == locale && !region)) {
GetUserDefaultLocaleName(sname, sname_size); GetUserDefaultLocaleName(sname, sname_size);
} else { } else {
WCHAR wbuf[LOCALE_NAME_MAX_LENGTH]; char search_language_buf[MAX_ELEM_LEN] = { 0 }, search_country_buf[MAX_ELEM_LEN] = { 0 };
locale_search_t search; locale_search_t search;
BOOL remapped = FALSE; BOOL remapped = FALSE;
memset(&search, 0, sizeof(locale_search_t)); memset(&search, 0, sizeof(locale_search_t));
lstrcpynA(search.search_language, locale, MAX_ELEM_LEN); lstrcpynA(search_language_buf, locale, MAX_ELEM_LEN);
if(region) { if(region) {
lstrcpynA(search.search_country, region+1, MAX_ELEM_LEN); lstrcpynA(search_country_buf, region+1, MAX_ELEM_LEN);
if(region-locale < MAX_ELEM_LEN) if(region-locale < MAX_ELEM_LEN)
search.search_language[region-locale] = '\0'; search_language_buf[region-locale] = '\0';
} else } else
search.search_country[0] = '\0'; search_country_buf[0] = '\0';
if(cp) { if(cp) {
if(region && cp-region-1<MAX_ELEM_LEN) if(region && cp-region-1<MAX_ELEM_LEN)
search.search_country[cp-region-1] = '\0'; search_country_buf[cp-region-1] = '\0';
if(cp-locale < MAX_ELEM_LEN) if(cp-locale < MAX_ELEM_LEN)
search.search_language[cp-locale] = '\0'; search_language_buf[cp-locale] = '\0';
} }
if ((remapped = remap_synonym(search.search_language))) if ((remapped = remap_synonym(search_language_buf)))
{ {
search.allow_sname = TRUE; search.allow_sname = TRUE;
} }
@ -386,14 +384,15 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m
} }
#endif #endif
MultiByteToWideChar(CP_ACP, 0, search.search_language, -1, wbuf, LOCALE_NAME_MAX_LENGTH); MultiByteToWideChar(CP_ACP, 0, search_language_buf, -1, search.search_language, MAX_ELEM_LEN);
if (search.allow_sname && IsValidLocaleName(wbuf)) if (search.allow_sname && IsValidLocaleName(search.search_language))
{ {
search.match_flags = FOUND_SNAME; search.match_flags = FOUND_SNAME;
wcsncpy(sname, wbuf, sname_size); wcsncpy(sname, search.search_language, sname_size);
} }
else else
{ {
MultiByteToWideChar(CP_ACP, 0, search_country_buf, -1, search.search_country, MAX_ELEM_LEN);
EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL); EnumSystemLocalesEx( find_best_locale_proc, 0, (LPARAM)&search, NULL);
if (!search.match_flags) if (!search.match_flags)
@ -405,7 +404,7 @@ BOOL locale_to_sname(const char *locale, unsigned short *codepage, BOOL *sname_m
if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY)) if (search.search_country[0] && !(search.match_flags & FOUND_COUNTRY))
return FALSE; return FALSE;
LCIDToLocaleName(search.found_lang_id, sname, sname_size, LOCALE_ALLOW_NEUTRAL_NAMES); wcsncpy(sname, search.found_lang_sname, sname_size);
} }
is_sname = !remapped && (search.match_flags & FOUND_SNAME) != 0; is_sname = !remapped && (search.match_flags & FOUND_SNAME) != 0;