ntdll: Implement RtlLocaleNameToLcid().
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
4538a137e0
commit
7ac7a902c8
|
@ -30,11 +30,14 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "wine/test.h"
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "winnls.h"
|
||||
#include "winternl.h"
|
||||
|
||||
static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
|
||||
static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
|
||||
|
@ -83,6 +86,7 @@ static BOOL (WINAPI *pEnumUILanguagesA)(UILANGUAGE_ENUMPROCA, DWORD, LONG_PTR);
|
|||
static BOOL (WINAPI *pEnumSystemLocalesEx)(LOCALE_ENUMPROCEX, DWORD, LPARAM, LPVOID);
|
||||
static INT (WINAPI *pLCMapStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM);
|
||||
static LCID (WINAPI *pLocaleNameToLCID)(LPCWSTR, DWORD);
|
||||
static NTSTATUS (WINAPI *pRtlLocaleNameToLcid)(LPCWSTR, LCID *, DWORD);
|
||||
static INT (WINAPI *pLCIDToLocaleName)(LCID, LPWSTR, INT, DWORD);
|
||||
static INT (WINAPI *pFoldStringA)(DWORD, LPCSTR, INT, LPSTR, INT);
|
||||
static INT (WINAPI *pFoldStringW)(DWORD, LPCWSTR, INT, LPWSTR, INT);
|
||||
|
@ -148,6 +152,7 @@ static void InitFunctionPointers(void)
|
|||
|
||||
mod = GetModuleHandleA("ntdll");
|
||||
X(RtlUpcaseUnicodeChar);
|
||||
X(RtlLocaleNameToLcid);
|
||||
#undef X
|
||||
}
|
||||
|
||||
|
@ -2792,9 +2797,12 @@ static const struct neutralsublang_name_t neutralsublang_names[] = {
|
|||
|
||||
static void test_LocaleNameToLCID(void)
|
||||
{
|
||||
LCID lcid;
|
||||
LCID lcid, expect;
|
||||
NTSTATUS status;
|
||||
INT ret;
|
||||
WCHAR buffer[LOCALE_NAME_MAX_LENGTH];
|
||||
const struct neutralsublang_name_t *ptr;
|
||||
|
||||
static const WCHAR enW[] = {'e','n',0};
|
||||
static const WCHAR esesW[] = {'e','s','-','e','s',0};
|
||||
static const WCHAR zhHansW[] = {'z','h','-','H','a','n','s',0};
|
||||
|
@ -2853,9 +2861,7 @@ static void test_LocaleNameToLCID(void)
|
|||
broken(lcid == 0) /* Vista */, "got 0x%04x\n", lcid);
|
||||
if (lcid)
|
||||
{
|
||||
const struct neutralsublang_name_t *ptr = neutralsublang_names;
|
||||
|
||||
while (*ptr->name)
|
||||
for (ptr = neutralsublang_names; *ptr->name; ptr++)
|
||||
{
|
||||
lcid = pLocaleNameToLCID(ptr->name, 0);
|
||||
todo_wine_if (ptr->todo)
|
||||
|
@ -2868,7 +2874,6 @@ static void test_LocaleNameToLCID(void)
|
|||
ok(!lstrcmpW(ptr->sname, buffer), "%s: got wrong locale name %s\n",
|
||||
wine_dbgstr_w(ptr->name), wine_dbgstr_w(buffer));
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* zh-Hant has LCID 0x7c04, but LocaleNameToLCID actually returns 0x0c04, which is the LCID of zh-HK */
|
||||
|
@ -2919,6 +2924,70 @@ static void test_LocaleNameToLCID(void)
|
|||
ok(!lstrcmpW(zhcnW, buffer), "%s: got wrong locale name %s\n",
|
||||
wine_dbgstr_w(zhhansW), wine_dbgstr_w(buffer));
|
||||
}
|
||||
|
||||
if (pRtlLocaleNameToLcid)
|
||||
{
|
||||
status = pRtlLocaleNameToLcid( LOCALE_NAME_USER_DEFAULT, &lcid, 0 );
|
||||
ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %x\n", status );
|
||||
status = pRtlLocaleNameToLcid( LOCALE_NAME_SYSTEM_DEFAULT, &lcid, 0 );
|
||||
ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %x\n", status );
|
||||
status = pRtlLocaleNameToLcid( invalidW, &lcid, 0 );
|
||||
ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %x\n", status );
|
||||
|
||||
lcid = 0;
|
||||
status = pRtlLocaleNameToLcid( LOCALE_NAME_INVARIANT, &lcid, 0 );
|
||||
ok( !status, "failed error %x\n", status );
|
||||
ok( lcid == LANG_INVARIANT, "got %08x\n", lcid );
|
||||
|
||||
lcid = 0;
|
||||
status = pRtlLocaleNameToLcid( localeW, &lcid, 0 );
|
||||
ok( !status, "failed error %x\n", status );
|
||||
ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), "got %08x\n", lcid );
|
||||
|
||||
lcid = 0;
|
||||
status = pRtlLocaleNameToLcid( esesW, &lcid, 0 );
|
||||
ok( !status, "failed error %x\n", status );
|
||||
ok( lcid == MAKELANGID(LANG_SPANISH, SUBLANG_SPANISH_MODERN), "got %08x\n", lcid );
|
||||
|
||||
lcid = 0;
|
||||
status = pRtlLocaleNameToLcid( enW, &lcid, 0 );
|
||||
ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %x\n", status );
|
||||
status = pRtlLocaleNameToLcid( enW, &lcid, 1 );
|
||||
ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %x\n", status );
|
||||
status = pRtlLocaleNameToLcid( enW, &lcid, 2 );
|
||||
ok( !status, "failed error %x\n", status );
|
||||
ok( lcid == MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), "got %08x\n", lcid );
|
||||
status = pRtlLocaleNameToLcid( L"en-RR", &lcid, 2 );
|
||||
ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %x\n", status );
|
||||
status = pRtlLocaleNameToLcid( L"en-Latn-RR", &lcid, 2 );
|
||||
ok( status == STATUS_INVALID_PARAMETER_1, "wrong error %x\n", status );
|
||||
|
||||
for (ptr = neutralsublang_names; *ptr->name; ptr++)
|
||||
{
|
||||
switch (LANGIDFROMLCID(ptr->lcid))
|
||||
{
|
||||
case MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN): expect = LANG_SERBIAN_NEUTRAL; break;
|
||||
case MAKELANGID( LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_CYRILLIC): expect = 0x6c1a; break;
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED ): expect = 0x7804; break;
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG ): expect = LANG_CHINESE_TRADITIONAL; break;
|
||||
default: expect = MAKELANGID( PRIMARYLANGID(ptr->lcid), SUBLANG_NEUTRAL ); break;
|
||||
}
|
||||
|
||||
status = pRtlLocaleNameToLcid( ptr->name, &lcid, 2 );
|
||||
ok( !status || broken(ptr->lcid == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)), /* vista */
|
||||
"%s failed error %x\n", wine_dbgstr_w(ptr->name), status );
|
||||
todo_wine_if(ptr->todo)
|
||||
if (!status) ok( lcid == expect, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
|
||||
wine_dbgstr_w(ptr->name), lcid, expect );
|
||||
status = pRtlLocaleNameToLcid( ptr->sname, &lcid, 0 );
|
||||
ok( !status || broken(ptr->lcid == MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_SERBIA_LATIN)), /* vista */
|
||||
"%s failed error %x\n", wine_dbgstr_w(ptr->name), status );
|
||||
todo_wine_if(ptr->todo)
|
||||
if (!status) ok( lcid == ptr->lcid, "%s: got wrong lcid 0x%04x, expected 0x%04x\n",
|
||||
wine_dbgstr_w(ptr->name), lcid, ptr->lcid );
|
||||
}
|
||||
}
|
||||
else win_skip( "RtlLocaleNameToLcid not available\n" );
|
||||
}
|
||||
|
||||
/* this requires collation table patch to make it MS compatible */
|
||||
|
|
|
@ -4281,6 +4281,8 @@ void __wine_process_init(void)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
init_locale( wm->ldr.BaseAddress );
|
||||
|
||||
params = peb->ProcessParameters;
|
||||
if (!(status = load_dll( params->DllPath.Buffer, params->ImagePathName.Buffer, NULL,
|
||||
DONT_RESOLVE_DLL_REFERENCES, &wm )))
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
|
@ -37,8 +38,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(nls);
|
|||
LCID user_lcid = 0, system_lcid = 0;
|
||||
|
||||
static LANGID user_ui_language, system_ui_language;
|
||||
static HMODULE kernel32_handle;
|
||||
static const union cptable *unix_table; /* NULL if UTF8 */
|
||||
|
||||
static NTSTATUS load_string( ULONG id, LANGID lang, WCHAR *buffer, ULONG len )
|
||||
{
|
||||
const IMAGE_RESOURCE_DATA_ENTRY *data;
|
||||
LDR_RESOURCE_INFO info;
|
||||
NTSTATUS status;
|
||||
WCHAR *p;
|
||||
int i;
|
||||
|
||||
info.Type = 6; /* RT_STRING */
|
||||
info.Name = (id >> 4) + 1;
|
||||
info.Language = lang;
|
||||
if ((status = LdrFindResource_U( kernel32_handle, &info, 3, &data ))) return status;
|
||||
p = (WCHAR *)((char *)kernel32_handle + data->OffsetToData);
|
||||
for (i = 0; i < (id & 0x0f); i++) p += *p + 1;
|
||||
if (*p >= len) return STATUS_BUFFER_TOO_SMALL;
|
||||
memcpy( buffer, p + 1, *p * sizeof(WCHAR) );
|
||||
buffer[*p] = 0;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(__APPLE__) && !defined(__ANDROID__) /* these platforms always use UTF-8 */
|
||||
|
||||
/* charset to codepage map, sorted by name */
|
||||
|
@ -143,6 +166,12 @@ void init_unix_codepage(void) { }
|
|||
#endif /* __APPLE__ || __ANDROID__ */
|
||||
|
||||
|
||||
void init_locale( HMODULE module )
|
||||
{
|
||||
kernel32_handle = module;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* ntdll_umbstowcs
|
||||
*/
|
||||
|
@ -234,3 +263,116 @@ NTSTATUS WINAPI NtQueryInstallUILanguage( LANGID *lang )
|
|||
*lang = system_ui_language;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* RtlLocaleNameToLcid (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI RtlLocaleNameToLcid( const WCHAR *name, LCID *lcid, ULONG flags )
|
||||
{
|
||||
/* locale name format is: lang[-script][-country][_modifier] */
|
||||
|
||||
static const WCHAR sepW[] = {'-','_',0};
|
||||
|
||||
const IMAGE_RESOURCE_DIRECTORY *resdir;
|
||||
const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
|
||||
LDR_RESOURCE_INFO info;
|
||||
WCHAR buf[LOCALE_NAME_MAX_LENGTH];
|
||||
WCHAR lang[LOCALE_NAME_MAX_LENGTH]; /* language ("en") (note: buffer contains the other strings too) */
|
||||
WCHAR *country = NULL; /* country ("US") */
|
||||
WCHAR *script = NULL; /* script ("Latn") */
|
||||
WCHAR *p;
|
||||
int i;
|
||||
|
||||
if (!name) return STATUS_INVALID_PARAMETER_1;
|
||||
|
||||
if (!name[0])
|
||||
{
|
||||
*lcid = LANG_INVARIANT;
|
||||
goto found;
|
||||
}
|
||||
if (strlenW( name ) >= LOCALE_NAME_MAX_LENGTH) return STATUS_INVALID_PARAMETER_1;
|
||||
strcpyW( lang, name );
|
||||
|
||||
if ((p = strpbrkW( lang, sepW )) && *p == '-')
|
||||
{
|
||||
*p++ = 0;
|
||||
country = p;
|
||||
if ((p = strpbrkW( p, sepW )) && *p == '-')
|
||||
{
|
||||
*p++ = 0;
|
||||
script = country;
|
||||
country = p;
|
||||
p = strpbrkW( p, sepW );
|
||||
}
|
||||
if (p) *p = 0; /* FIXME: modifier is ignored */
|
||||
/* second value can be script or country, check length to resolve the ambiguity */
|
||||
if (!script && strlenW( country ) == 4)
|
||||
{
|
||||
script = country;
|
||||
country = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
info.Type = 6; /* RT_STRING */
|
||||
info.Name = (LOCALE_SNAME >> 4) + 1;
|
||||
if (LdrFindResourceDirectory_U( kernel32_handle, &info, 2, &resdir ))
|
||||
return STATUS_INVALID_PARAMETER_1;
|
||||
|
||||
et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
|
||||
for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
|
||||
{
|
||||
LANGID id = et[i].u.Id;
|
||||
|
||||
if (PRIMARYLANGID(id) == LANG_NEUTRAL) continue;
|
||||
|
||||
if (!load_string( LOCALE_SNAME, id, buf, ARRAY_SIZE(buf) ) && !strcmpiW( name, buf ))
|
||||
{
|
||||
*lcid = MAKELCID( id, SORT_DEFAULT ); /* FIXME: handle sort order */
|
||||
goto found;
|
||||
}
|
||||
|
||||
if (load_string( LOCALE_SISO639LANGNAME, id, buf, ARRAY_SIZE(buf) ) || strcmpiW( lang, buf ))
|
||||
continue;
|
||||
|
||||
if (script)
|
||||
{
|
||||
unsigned int len = strlenW( script );
|
||||
if (load_string( LOCALE_SSCRIPTS, id, buf, ARRAY_SIZE(buf) )) continue;
|
||||
p = buf;
|
||||
while (*p)
|
||||
{
|
||||
if (!strncmpiW( p, script, len ) && (!p[len] || p[len] == ';')) break;
|
||||
if (!(p = strchrW( p, ';'))) break;
|
||||
p++;
|
||||
}
|
||||
if (!p || !*p) continue;
|
||||
}
|
||||
|
||||
if (!country && (flags & 2))
|
||||
{
|
||||
if (!script) id = MAKELANGID( PRIMARYLANGID(id), LANG_NEUTRAL );
|
||||
switch (id)
|
||||
{
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_NEUTRAL ):
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE ):
|
||||
*lcid = MAKELCID( 0x7804, SORT_DEFAULT );
|
||||
break;
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL ):
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_MACAU ):
|
||||
case MAKELANGID( LANG_CHINESE, SUBLANG_CHINESE_HONGKONG ):
|
||||
*lcid = MAKELCID( 0x7c04, SORT_DEFAULT );
|
||||
break;
|
||||
default:
|
||||
*lcid = MAKELANGID( PRIMARYLANGID(id), SUBLANG_NEUTRAL );
|
||||
break;
|
||||
}
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
return STATUS_INVALID_PARAMETER_1;
|
||||
|
||||
found:
|
||||
TRACE( "%s -> %04x\n", debugstr_w(name), *lcid );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -807,6 +807,7 @@
|
|||
@ stdcall RtlLengthSecurityDescriptor(ptr)
|
||||
@ stdcall RtlLengthSid(ptr)
|
||||
@ stdcall RtlLocalTimeToSystemTime(ptr ptr)
|
||||
@ stdcall RtlLocaleNameToLcid(wstr ptr long)
|
||||
# @ stub RtlLockBootStatusData
|
||||
@ stdcall RtlLockHeap(long)
|
||||
# @ stub RtlLockMemoryStreamRegion
|
||||
|
|
|
@ -86,6 +86,7 @@ extern void virtual_init_threading(void) DECLSPEC_HIDDEN;
|
|||
extern void fill_cpu_info(void) DECLSPEC_HIDDEN;
|
||||
extern void heap_set_debug_flags( HANDLE handle ) DECLSPEC_HIDDEN;
|
||||
extern void init_unix_codepage(void) DECLSPEC_HIDDEN;
|
||||
extern void init_locale( HMODULE module ) DECLSPEC_HIDDEN;
|
||||
extern void init_user_process_params( SIZE_T data_size ) DECLSPEC_HIDDEN;
|
||||
extern char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -2778,6 +2778,7 @@ NTSYSAPI DWORD WINAPI RtlLengthRequiredSid(DWORD);
|
|||
NTSYSAPI ULONG WINAPI RtlLengthSecurityDescriptor(PSECURITY_DESCRIPTOR);
|
||||
NTSYSAPI DWORD WINAPI RtlLengthSid(PSID);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlLocalTimeToSystemTime(const LARGE_INTEGER*,PLARGE_INTEGER);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlLocaleNameToLcid(const WCHAR*,LCID*,ULONG);
|
||||
NTSYSAPI BOOLEAN WINAPI RtlLockHeap(HANDLE);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlLookupAtomInAtomTable(RTL_ATOM_TABLE,const WCHAR*,RTL_ATOM*);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlMakeSelfRelativeSD(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,LPDWORD);
|
||||
|
|
Loading…
Reference in New Issue