Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
b631c147
Commit
b631c147
authored
Mar 22, 2022
by
Alexandre Julliard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ntdll: Reimplement RtlLocaleNameToLcid() using the locale.nls data.
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
4b0f1163
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
91 additions
and
145 deletions
+91
-145
locale.c
dlls/kernel32/tests/locale.c
+48
-42
locale.c
dlls/ntdll/locale.c
+43
-103
No files found.
dlls/kernel32/tests/locale.c
View file @
b631c147
...
...
@@ -2673,15 +2673,6 @@ static void test_LocaleNameToLCID(void)
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
};
static
const
WCHAR
zhhansW
[]
=
{
'z'
,
'h'
,
'-'
,
'h'
,
'a'
,
'n'
,
's'
,
0
};
static
const
WCHAR
zhHantW
[]
=
{
'z'
,
'h'
,
'-'
,
'H'
,
'a'
,
'n'
,
't'
,
0
};
static
const
WCHAR
zhhantW
[]
=
{
'z'
,
'h'
,
'-'
,
'h'
,
'a'
,
'n'
,
't'
,
0
};
static
const
WCHAR
zhcnW
[]
=
{
'z'
,
'h'
,
'-'
,
'C'
,
'N'
,
0
};
static
const
WCHAR
zhhkW
[]
=
{
'z'
,
'h'
,
'-'
,
'H'
,
'K'
,
0
};
if
(
!
pLocaleNameToLCID
)
{
win_skip
(
"LocaleNameToLCID not available
\n
"
);
...
...
@@ -2722,14 +2713,14 @@ static void test_LocaleNameToLCID(void)
"Expected lcid == 0, got %08lx, error %ld
\n
"
,
lcid
,
GetLastError
());
/* lower-case */
lcid
=
pLocaleNameToLCID
(
esesW
,
0
);
lcid
=
pLocaleNameToLCID
(
L"es-es"
,
0
);
ok
(
lcid
==
MAKELCID
(
MAKELANGID
(
LANG_SPANISH
,
SUBLANG_SPANISH_MODERN
),
SORT_DEFAULT
),
"Got wrong lcid for es-es: 0x%lx
\n
"
,
lcid
);
/* english neutral name */
lcid
=
pLocaleNameToLCID
(
enW
,
LOCALE_ALLOW_NEUTRAL_NAMES
);
lcid
=
pLocaleNameToLCID
(
L"en"
,
LOCALE_ALLOW_NEUTRAL_NAMES
);
ok
(
lcid
==
MAKELCID
(
MAKELANGID
(
LANG_ENGLISH
,
SUBLANG_NEUTRAL
),
SORT_DEFAULT
)
||
broken
(
lcid
==
0
)
/* Vista */
,
"got 0x%04lx
\n
"
,
lcid
);
lcid
=
pLocaleNameToLCID
(
enW
,
0
);
lcid
=
pLocaleNameToLCID
(
L"en"
,
0
);
ok
(
lcid
==
MAKELCID
(
MAKELANGID
(
LANG_ENGLISH
,
SUBLANG_ENGLISH_US
),
SORT_DEFAULT
)
||
broken
(
lcid
==
0
)
/* Vista */
,
"got 0x%04lx
\n
"
,
lcid
);
if
(
lcid
)
...
...
@@ -2749,52 +2740,52 @@ static void test_LocaleNameToLCID(void)
}
/* zh-Hant has LCID 0x7c04, but LocaleNameToLCID actually returns 0x0c04, which is the LCID of zh-HK */
lcid
=
pLocaleNameToLCID
(
zhHantW
,
0
);
lcid
=
pLocaleNameToLCID
(
L"zh-Hant"
,
0
);
ok
(
lcid
==
MAKELCID
(
MAKELANGID
(
LANG_CHINESE
,
SUBLANG_CHINESE_HONGKONG
),
SORT_DEFAULT
),
"%s: got wrong lcid 0x%04lx
\n
"
,
wine_dbgstr_w
(
zhHantW
),
lcid
);
"%s: got wrong lcid 0x%04lx
\n
"
,
wine_dbgstr_w
(
L"zh-Hant"
),
lcid
);
ret
=
pLCIDToLocaleName
(
lcid
,
buffer
,
ARRAY_SIZE
(
buffer
),
0
);
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
zhHantW
),
ret
);
ok
(
!
lstrcmpW
(
zhhkW
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
zhHantW
),
wine_dbgstr_w
(
buffer
));
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
L"zh-Hant"
),
ret
);
ok
(
!
lstrcmpW
(
L"zh-HK"
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
L"zh-Hant"
),
wine_dbgstr_w
(
buffer
));
/* check that 0x7c04 also works and is mapped to zh-HK */
ret
=
pLCIDToLocaleName
(
MAKELANGID
(
LANG_CHINESE_TRADITIONAL
,
SUBLANG_CHINESE_TRADITIONAL
),
buffer
,
ARRAY_SIZE
(
buffer
),
0
);
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
zhHantW
),
ret
);
ok
(
!
lstrcmpW
(
zhhkW
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
zhHantW
),
wine_dbgstr_w
(
buffer
));
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
L"zh-Hant"
),
ret
);
ok
(
!
lstrcmpW
(
L"zh-HK"
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
L"zh-Hant"
),
wine_dbgstr_w
(
buffer
));
/* zh-hant */
lcid
=
pLocaleNameToLCID
(
zhhantW
,
0
);
lcid
=
pLocaleNameToLCID
(
L"zh-hant"
,
0
);
ok
(
lcid
==
MAKELCID
(
MAKELANGID
(
LANG_CHINESE
,
SUBLANG_CHINESE_HONGKONG
),
SORT_DEFAULT
),
"%s: got wrong lcid 0x%04lx
\n
"
,
wine_dbgstr_w
(
zhhantW
),
lcid
);
"%s: got wrong lcid 0x%04lx
\n
"
,
wine_dbgstr_w
(
L"zh-hant"
),
lcid
);
ret
=
pLCIDToLocaleName
(
lcid
,
buffer
,
ARRAY_SIZE
(
buffer
),
0
);
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
zhhantW
),
ret
);
ok
(
!
lstrcmpW
(
zhhkW
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
zhhantW
),
wine_dbgstr_w
(
buffer
));
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
L"zh-hant"
),
ret
);
ok
(
!
lstrcmpW
(
L"zh-HK"
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
L"zh-hant"
),
wine_dbgstr_w
(
buffer
));
/* zh-Hans has LCID 0x0004, but LocaleNameToLCID actually returns 0x0804, which is the LCID of zh-CN */
lcid
=
pLocaleNameToLCID
(
zhHansW
,
0
);
lcid
=
pLocaleNameToLCID
(
L"zh-Hans"
,
0
);
/* check that LocaleNameToLCID actually returns 0x0804 */
ok
(
lcid
==
MAKELCID
(
MAKELANGID
(
LANG_CHINESE_SIMPLIFIED
,
SUBLANG_CHINESE_SIMPLIFIED
),
SORT_DEFAULT
),
"%s: got wrong lcid 0x%04lx
\n
"
,
wine_dbgstr_w
(
zhHansW
),
lcid
);
"%s: got wrong lcid 0x%04lx
\n
"
,
wine_dbgstr_w
(
L"zh-Hans"
),
lcid
);
ret
=
pLCIDToLocaleName
(
lcid
,
buffer
,
ARRAY_SIZE
(
buffer
),
0
);
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
zhHansW
),
ret
);
ok
(
!
lstrcmpW
(
zhcnW
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
zhHansW
),
wine_dbgstr_w
(
buffer
));
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
L"zh-Hans"
),
ret
);
ok
(
!
lstrcmpW
(
L"zh-CN"
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
L"zh-Hans"
),
wine_dbgstr_w
(
buffer
));
/* check that 0x0004 also works and is mapped to zh-CN */
ret
=
pLCIDToLocaleName
(
MAKELANGID
(
LANG_CHINESE
,
SUBLANG_NEUTRAL
),
buffer
,
ARRAY_SIZE
(
buffer
),
0
);
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
zhHansW
),
ret
);
ok
(
!
lstrcmpW
(
zhcnW
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
zhHansW
),
wine_dbgstr_w
(
buffer
));
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
L"zh-Hans"
),
ret
);
ok
(
!
lstrcmpW
(
L"zh-CN"
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
L"zh-Hans"
),
wine_dbgstr_w
(
buffer
));
/* zh-hans */
lcid
=
pLocaleNameToLCID
(
zhhansW
,
0
);
lcid
=
pLocaleNameToLCID
(
L"zh-hans"
,
0
);
ok
(
lcid
==
MAKELCID
(
MAKELANGID
(
LANG_CHINESE_SIMPLIFIED
,
SUBLANG_CHINESE_SIMPLIFIED
),
SORT_DEFAULT
),
"%s: got wrong lcid 0x%04lx
\n
"
,
wine_dbgstr_w
(
zhhansW
),
lcid
);
"%s: got wrong lcid 0x%04lx
\n
"
,
wine_dbgstr_w
(
L"zh-hans"
),
lcid
);
ret
=
pLCIDToLocaleName
(
lcid
,
buffer
,
ARRAY_SIZE
(
buffer
),
0
);
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
zhhansW
),
ret
);
ok
(
!
lstrcmpW
(
zhcnW
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
zhhansW
),
wine_dbgstr_w
(
buffer
));
ok
(
ret
>
0
,
"%s: got %d
\n
"
,
wine_dbgstr_w
(
L"zh-hans"
),
ret
);
ok
(
!
lstrcmpW
(
L"zh-CN"
,
buffer
),
"%s: got wrong locale name %s
\n
"
,
wine_dbgstr_w
(
L"zh-hans"
),
wine_dbgstr_w
(
buffer
));
}
if
(
pRtlLocaleNameToLcid
)
...
...
@@ -2817,16 +2808,31 @@ static void test_LocaleNameToLCID(void)
ok
(
lcid
==
MAKELANGID
(
LANG_ENGLISH
,
SUBLANG_ENGLISH_US
),
"got %08lx
\n
"
,
lcid
);
lcid
=
0
;
status
=
pRtlLocaleNameToLcid
(
esesW
,
&
lcid
,
0
);
status
=
pRtlLocaleNameToLcid
(
L"es-es"
,
&
lcid
,
0
);
ok
(
!
status
,
"failed error %lx
\n
"
,
status
);
ok
(
lcid
==
MAKELANGID
(
LANG_SPANISH
,
SUBLANG_SPANISH_MODERN
),
"got %08lx
\n
"
,
lcid
);
lcid
=
0
;
status
=
pRtlLocaleNameToLcid
(
enW
,
&
lcid
,
0
);
status
=
pRtlLocaleNameToLcid
(
L"de-DE_phoneb"
,
&
lcid
,
0
);
ok
(
!
status
,
"failed error %lx
\n
"
,
status
);
ok
(
lcid
==
0x00010407
,
"got %08lx
\n
"
,
lcid
);
lcid
=
0
;
status
=
pRtlLocaleNameToLcid
(
L"DE_de-PHONEB"
,
&
lcid
,
0
);
ok
(
!
status
||
broken
(
status
==
STATUS_INVALID_PARAMETER_1
),
"failed error %lx
\n
"
,
status
);
if
(
!
status
)
ok
(
lcid
==
0x00010407
,
"got %08lx
\n
"
,
lcid
);
lcid
=
0xdeadbeef
;
status
=
pRtlLocaleNameToLcid
(
L"de+de+phoneb"
,
&
lcid
,
0
);
ok
(
status
==
STATUS_INVALID_PARAMETER_1
,
"failed error %lx
\n
"
,
status
);
ok
(
lcid
==
0xdeadbeef
,
"got %08lx
\n
"
,
lcid
);
lcid
=
0
;
status
=
pRtlLocaleNameToLcid
(
L"en"
,
&
lcid
,
0
);
ok
(
status
==
STATUS_INVALID_PARAMETER_1
,
"wrong error %lx
\n
"
,
status
);
status
=
pRtlLocaleNameToLcid
(
enW
,
&
lcid
,
1
);
status
=
pRtlLocaleNameToLcid
(
L"en"
,
&
lcid
,
1
);
ok
(
status
==
STATUS_INVALID_PARAMETER_1
,
"wrong error %lx
\n
"
,
status
);
status
=
pRtlLocaleNameToLcid
(
enW
,
&
lcid
,
2
);
status
=
pRtlLocaleNameToLcid
(
L"en"
,
&
lcid
,
2
);
ok
(
!
status
,
"failed error %lx
\n
"
,
status
);
ok
(
lcid
==
MAKELANGID
(
LANG_ENGLISH
,
SUBLANG_NEUTRAL
),
"got %08lx
\n
"
,
lcid
);
status
=
pRtlLocaleNameToLcid
(
L"en-RR"
,
&
lcid
,
2
);
...
...
dlls/ntdll/locale.c
View file @
b631c147
...
...
@@ -238,6 +238,44 @@ invalid:
}
static
int
compare_locale_names
(
const
WCHAR
*
n1
,
const
WCHAR
*
n2
)
{
for
(;;)
{
WCHAR
ch1
=
casemap_ascii
(
*
n1
++
);
WCHAR
ch2
=
casemap_ascii
(
*
n2
++
);
if
(
ch1
==
'_'
)
ch1
=
'-'
;
if
(
ch2
==
'_'
)
ch2
=
'-'
;
if
(
!
ch1
||
ch1
!=
ch2
)
return
ch1
-
ch2
;
}
}
static
const
NLS_LOCALE_LCNAME_INDEX
*
find_lcname_entry
(
const
WCHAR
*
name
)
{
int
min
=
0
,
max
=
locale_table
->
nb_lcnames
-
1
;
if
(
!
name
)
return
NULL
;
while
(
min
<=
max
)
{
int
res
,
pos
=
(
min
+
max
)
/
2
;
const
WCHAR
*
str
=
locale_strings
+
lcnames_index
[
pos
].
name
;
res
=
compare_locale_names
(
name
,
str
+
1
);
if
(
res
<
0
)
max
=
pos
-
1
;
else
if
(
res
>
0
)
min
=
pos
+
1
;
else
return
&
lcnames_index
[
pos
];
}
return
NULL
;
}
static
const
NLS_LOCALE_DATA
*
get_locale_data
(
UINT
idx
)
{
ULONG
offset
=
locale_table
->
locales_offset
+
idx
*
locale_table
->
locale_size
;
return
(
const
NLS_LOCALE_DATA
*
)((
const
char
*
)
locale_table
+
offset
);
}
void
locale_init
(
void
)
{
LARGE_INTEGER
unused
;
...
...
@@ -1191,110 +1229,12 @@ WCHAR __cdecl towupper( WCHAR ch )
*/
NTSTATUS
WINAPI
RtlLocaleNameToLcid
(
const
WCHAR
*
name
,
LCID
*
lcid
,
ULONG
flags
)
{
/* locale name format is: lang[-script][-country][_modifier] */
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
(
wcslen
(
name
)
>=
LOCALE_NAME_MAX_LENGTH
)
return
STATUS_INVALID_PARAMETER_1
;
wcscpy
(
lang
,
name
);
if
((
p
=
wcspbrk
(
lang
,
L"-_"
))
&&
*
p
==
'-'
)
{
*
p
++
=
0
;
country
=
p
;
if
((
p
=
wcspbrk
(
p
,
L"-_"
))
&&
*
p
==
'-'
)
{
*
p
++
=
0
;
script
=
country
;
country
=
p
;
p
=
wcspbrk
(
p
,
L"-_"
);
}
if
(
p
)
*
p
=
0
;
/* FIXME: modifier is ignored */
/* second value can be script or country, check length to resolve the ambiguity */
if
(
!
script
&&
wcslen
(
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
)
)
&&
!
wcsicmp
(
name
,
buf
))
{
*
lcid
=
MAKELCID
(
id
,
SORT_DEFAULT
);
/* FIXME: handle sort order */
goto
found
;
}
if
(
load_string
(
LOCALE_SISO639LANGNAME
,
id
,
buf
,
ARRAY_SIZE
(
buf
)
)
||
wcsicmp
(
lang
,
buf
))
continue
;
if
(
script
)
{
unsigned
int
len
=
wcslen
(
script
);
if
(
load_string
(
LOCALE_SSCRIPTS
,
id
,
buf
,
ARRAY_SIZE
(
buf
)
))
continue
;
p
=
buf
;
while
(
*
p
)
{
if
(
!
wcsnicmp
(
p
,
script
,
len
)
&&
(
!
p
[
len
]
||
p
[
len
]
==
';'
))
break
;
if
(
!
(
p
=
wcschr
(
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
;
case
MAKELANGID
(
LANG_SERBIAN
,
SUBLANG_NEUTRAL
):
*
lcid
=
LANG_SERBIAN_NEUTRAL
;
break
;
default:
*
lcid
=
MAKELANGID
(
PRIMARYLANGID
(
id
),
SUBLANG_NEUTRAL
);
break
;
}
goto
found
;
}
}
return
STATUS_INVALID_PARAMETER_1
;
const
NLS_LOCALE_LCNAME_INDEX
*
entry
=
find_lcname_entry
(
name
);
found:
if
(
!
entry
)
return
STATUS_INVALID_PARAMETER_1
;
/* reject neutral locale unless flag 2 is set */
if
(
!
(
flags
&
2
)
&&
!
get_locale_data
(
entry
->
idx
)
->
inotneutral
)
return
STATUS_INVALID_PARAMETER_1
;
*
lcid
=
entry
->
id
;
TRACE
(
"%s -> %04x
\n
"
,
debugstr_w
(
name
),
*
lcid
);
return
STATUS_SUCCESS
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment