kernelbase: Use linguistic case table for LCMAP_LINGUISTIC_CASING.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7ad740cd29
commit
b780e5f5b1
2 changed files with 127 additions and 32 deletions
|
@ -6471,7 +6471,6 @@ static void test_SpecialCasing(void)
|
||||||
WCHAR ch;
|
WCHAR ch;
|
||||||
WCHAR exp; /* 0 if self */
|
WCHAR exp; /* 0 if self */
|
||||||
WCHAR exp_ling; /* 0 if exp */
|
WCHAR exp_ling; /* 0 if exp */
|
||||||
BOOL todo;
|
|
||||||
} tests[] = {
|
} tests[] = {
|
||||||
{deDEW, LCMAP_UPPERCASE, 0x00DF}, /* LATIN SMALL LETTER SHARP S */
|
{deDEW, LCMAP_UPPERCASE, 0x00DF}, /* LATIN SMALL LETTER SHARP S */
|
||||||
|
|
||||||
|
@ -6580,29 +6579,29 @@ static void test_SpecialCasing(void)
|
||||||
|
|
||||||
{enUSW, LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */
|
{enUSW, LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */
|
||||||
{ltLTW, LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */
|
{ltLTW, LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */
|
||||||
{trTRW, LCMAP_UPPERCASE, 'i', 'I', 0x0130, TRUE}, /* LATIN SMALL LETTER I */
|
{trTRW, LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
|
||||||
{TRTRW, LCMAP_UPPERCASE, 'i', 'I', 0x0130, TRUE}, /* LATIN SMALL LETTER I */
|
{TRTRW, LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
|
||||||
{azCyrlazW, LCMAP_UPPERCASE, 'i', 'I', 0x0130, TRUE}, /* LATIN SMALL LETTER I */
|
{azCyrlazW, LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
|
||||||
{azLatnazW, LCMAP_UPPERCASE, 'i', 'I', 0x0130, TRUE}, /* LATIN SMALL LETTER I */
|
{azLatnazW, LCMAP_UPPERCASE, 'i', 'I', 0x0130}, /* LATIN SMALL LETTER I */
|
||||||
|
|
||||||
{enUSW, LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
|
{enUSW, LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
|
||||||
{ltLTW, LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
|
{ltLTW, LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
|
||||||
{trTRW, LCMAP_LOWERCASE, 'I', 'i', 0x0131, TRUE}, /* LATIN CAPITAL LETTER I */
|
{trTRW, LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
|
||||||
{TRTRW, LCMAP_LOWERCASE, 'I', 'i', 0x0131, TRUE}, /* LATIN CAPITAL LETTER I */
|
{TRTRW, LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
|
||||||
{azCyrlazW, LCMAP_LOWERCASE, 'I', 'i', 0x0131, TRUE}, /* LATIN CAPITAL LETTER I */
|
{azCyrlazW, LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
|
||||||
{azLatnazW, LCMAP_LOWERCASE, 'I', 'i', 0x0131, TRUE}, /* LATIN CAPITAL LETTER I */
|
{azLatnazW, LCMAP_LOWERCASE, 'I', 'i', 0x0131}, /* LATIN CAPITAL LETTER I */
|
||||||
|
|
||||||
{enUSW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
{enUSW, LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||||
{trTRW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
{trTRW, LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||||
{TRTRW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
{TRTRW, LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||||
{azCyrlazW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
{azCyrlazW, LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||||
{azLatnazW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
{azLatnazW, LCMAP_LOWERCASE, 0x0130,0,'i'}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
|
||||||
|
|
||||||
{enUSW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
|
{enUSW, LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
|
||||||
{trTRW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
|
{trTRW, LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
|
||||||
{TRTRW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
|
{TRTRW, LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
|
||||||
{azCyrlazW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
|
{azCyrlazW, LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
|
||||||
{azLatnazW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
|
{azLatnazW, LCMAP_UPPERCASE, 0x0131,0,'I'}, /* LATIN SMALL LETTER DOTLESS I */
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!pLCMapStringEx)
|
if (!pLCMapStringEx)
|
||||||
|
@ -6628,7 +6627,6 @@ static void test_SpecialCasing(void)
|
||||||
ok(ret == 1, "expected 1, got %d for %04x for %s\n", ret, tests[i].ch,
|
ok(ret == 1, "expected 1, got %d for %04x for %s\n", ret, tests[i].ch,
|
||||||
wine_dbgstr_w(tests[i].lang));
|
wine_dbgstr_w(tests[i].lang));
|
||||||
exp = tests[i].exp_ling ? tests[i].exp_ling : exp;
|
exp = tests[i].exp_ling ? tests[i].exp_ling : exp;
|
||||||
todo_wine_if(tests[i].todo)
|
|
||||||
ok(buffer[0] == exp || broken(buffer[0] != exp),
|
ok(buffer[0] == exp || broken(buffer[0] != exp),
|
||||||
"expected %04x, got %04x for %04x for %s\n",
|
"expected %04x, got %04x for %04x for %s\n",
|
||||||
exp, buffer[0], tests[i].ch, wine_dbgstr_w(tests[i].lang));
|
exp, buffer[0], tests[i].ch, wine_dbgstr_w(tests[i].lang));
|
||||||
|
|
|
@ -576,12 +576,34 @@ static unsigned int nb_codepages;
|
||||||
|
|
||||||
static struct norm_table *norm_info;
|
static struct norm_table *norm_info;
|
||||||
|
|
||||||
|
struct sortguid
|
||||||
|
{
|
||||||
|
GUID id; /* sort GUID */
|
||||||
|
DWORD flags; /* flags */
|
||||||
|
DWORD compr; /* offset to compression table */
|
||||||
|
DWORD except; /* exception table offset in sortkey table */
|
||||||
|
DWORD ling_except; /* exception table offset for linguistic casing */
|
||||||
|
DWORD casemap; /* linguistic casemap table offset */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FLAG_HAS_3_BYTE_WEIGHTS 0x01
|
||||||
|
#define FLAG_REVERSEDIACRITICS 0x10
|
||||||
|
#define FLAG_DOUBLECOMPRESSION 0x20
|
||||||
|
#define FLAG_INVERSECASING 0x40
|
||||||
|
|
||||||
|
static const struct sortguid *current_locale_sort;
|
||||||
|
|
||||||
|
static const GUID default_sort_guid = { 0x00000001, 0x57ee, 0x1e5c, { 0x00, 0xb4, 0xd0, 0x00, 0x0b, 0xb1, 0xe1, 0x1e }};
|
||||||
|
|
||||||
static struct
|
static struct
|
||||||
{
|
{
|
||||||
DWORD *keys; /* sortkey table, indexed by char */
|
DWORD *keys; /* sortkey table, indexed by char */
|
||||||
USHORT *casemap; /* casemap table, in l_intl.nls format */
|
USHORT *casemap; /* casemap table, in l_intl.nls format */
|
||||||
WORD *ctypes; /* CT_CTYPE1,2,3 values */
|
WORD *ctypes; /* CT_CTYPE1,2,3 values */
|
||||||
BYTE *ctype_idx; /* index to map char to ctypes array entry */
|
BYTE *ctype_idx; /* index to map char to ctypes array entry */
|
||||||
|
DWORD version; /* NLS version */
|
||||||
|
DWORD guid_count; /* number of sort GUIDs */
|
||||||
|
struct sortguid *guids; /* table of sort GUIDs */
|
||||||
} sort;
|
} sort;
|
||||||
|
|
||||||
static CRITICAL_SECTION locale_section;
|
static CRITICAL_SECTION locale_section;
|
||||||
|
@ -594,18 +616,82 @@ static CRITICAL_SECTION_DEBUG critsect_debug =
|
||||||
static CRITICAL_SECTION locale_section = { &critsect_debug, -1, 0, 0, 0, 0 };
|
static CRITICAL_SECTION locale_section = { &critsect_debug, -1, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* init_sortkeys
|
|
||||||
*/
|
|
||||||
static void init_sortkeys( DWORD *ptr )
|
static void init_sortkeys( DWORD *ptr )
|
||||||
{
|
{
|
||||||
WORD *ctype;
|
WORD *ctype;
|
||||||
|
DWORD *table;
|
||||||
|
|
||||||
sort.keys = (DWORD *)((char *)ptr + ptr[0]);
|
sort.keys = (DWORD *)((char *)ptr + ptr[0]);
|
||||||
sort.casemap = (USHORT *)((char *)ptr + ptr[1]);
|
sort.casemap = (USHORT *)((char *)ptr + ptr[1]);
|
||||||
ctype = (WORD *)((char *)ptr + ptr[2]);
|
|
||||||
sort.ctypes = ctype + 2;
|
ctype = (WORD *)((char *)ptr + ptr[2]);
|
||||||
|
sort.ctypes = ctype + 2;
|
||||||
sort.ctype_idx = (BYTE *)ctype + ctype[1] + 2;
|
sort.ctype_idx = (BYTE *)ctype + ctype[1] + 2;
|
||||||
|
|
||||||
|
table = (DWORD *)((char *)ptr + ptr[3]);
|
||||||
|
sort.version = table[0];
|
||||||
|
sort.guid_count = table[1];
|
||||||
|
sort.guids = (struct sortguid *)(table + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct sortguid *find_sortguid( const GUID *guid )
|
||||||
|
{
|
||||||
|
int pos, ret, min = 0, max = sort.guid_count - 1;
|
||||||
|
|
||||||
|
while (min <= max)
|
||||||
|
{
|
||||||
|
pos = (min + max) / 2;
|
||||||
|
ret = memcmp( guid, &sort.guids[pos].id, sizeof(*guid) );
|
||||||
|
if (!ret) return &sort.guids[pos];
|
||||||
|
if (ret > 0) min = pos + 1;
|
||||||
|
else max = pos - 1;
|
||||||
|
}
|
||||||
|
ERR( "no sort found for %s\n", debugstr_guid( guid ));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct sortguid *get_language_sort( const WCHAR *locale )
|
||||||
|
{
|
||||||
|
WCHAR *p, *end, buffer[LOCALE_NAME_MAX_LENGTH], guidstr[39];
|
||||||
|
const struct sortguid *ret;
|
||||||
|
UNICODE_STRING str;
|
||||||
|
GUID guid;
|
||||||
|
HKEY key;
|
||||||
|
DWORD size, type;
|
||||||
|
|
||||||
|
if (locale == LOCALE_NAME_USER_DEFAULT)
|
||||||
|
{
|
||||||
|
if (current_locale_sort) return current_locale_sort;
|
||||||
|
GetUserDefaultLocaleName( buffer, ARRAY_SIZE( buffer ));
|
||||||
|
}
|
||||||
|
else lstrcpynW( buffer, locale, LOCALE_NAME_MAX_LENGTH );
|
||||||
|
|
||||||
|
if (buffer[0] && !RegOpenKeyExW( nls_key, L"Sorting\\Ids", 0, KEY_READ, &key ))
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
size = sizeof(guidstr);
|
||||||
|
if (!RegQueryValueExW( key, buffer, NULL, &type, (BYTE *)guidstr, &size ) && type == REG_SZ)
|
||||||
|
{
|
||||||
|
RtlInitUnicodeString( &str, guidstr );
|
||||||
|
if (!RtlGUIDFromString( &str, &guid ))
|
||||||
|
{
|
||||||
|
ret = find_sortguid( &guid );
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (p = end = buffer; *p; p++) if (*p == '-' || *p == '_') end = p;
|
||||||
|
if (end == buffer) break;
|
||||||
|
*end = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = find_sortguid( &default_sort_guid );
|
||||||
|
done:
|
||||||
|
RegCloseKey( key );
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -648,6 +734,8 @@ void init_locale(void)
|
||||||
RtlInitNlsTables( ansi_ptr, oem_ptr, sort.casemap, &nls_info );
|
RtlInitNlsTables( ansi_ptr, oem_ptr, sort.casemap, &nls_info );
|
||||||
RtlResetRtlTranslations( &nls_info );
|
RtlResetRtlTranslations( &nls_info );
|
||||||
|
|
||||||
|
current_locale_sort = get_language_sort( LOCALE_NAME_USER_DEFAULT );
|
||||||
|
|
||||||
RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Nls",
|
RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Nls",
|
||||||
0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &nls_key, NULL );
|
0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &nls_key, NULL );
|
||||||
RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
|
RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
|
||||||
|
@ -4737,6 +4825,7 @@ INT WINAPI DECLSPEC_HOTPATCH LCMapStringEx( const WCHAR *locale, DWORD flags, co
|
||||||
WCHAR *dst, int dstlen, NLSVERSIONINFO *version,
|
WCHAR *dst, int dstlen, NLSVERSIONINFO *version,
|
||||||
void *reserved, LPARAM handle )
|
void *reserved, LPARAM handle )
|
||||||
{
|
{
|
||||||
|
const struct sortguid *sortid;
|
||||||
LPWSTR dst_ptr;
|
LPWSTR dst_ptr;
|
||||||
INT len;
|
INT len;
|
||||||
|
|
||||||
|
@ -4767,6 +4856,13 @@ INT WINAPI DECLSPEC_HOTPATCH LCMapStringEx( const WCHAR *locale, DWORD flags, co
|
||||||
|
|
||||||
if (!dstlen) dst = NULL;
|
if (!dstlen) dst = NULL;
|
||||||
|
|
||||||
|
if (!(sortid = get_language_sort( locale )))
|
||||||
|
{
|
||||||
|
FIXME( "unknown locale %s\n", debugstr_w(locale) );
|
||||||
|
SetLastError( ERROR_INVALID_PARAMETER );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & LCMAP_SORTKEY)
|
if (flags & LCMAP_SORTKEY)
|
||||||
{
|
{
|
||||||
INT ret;
|
INT ret;
|
||||||
|
@ -4910,7 +5006,8 @@ INT WINAPI DECLSPEC_HOTPATCH LCMapStringEx( const WCHAR *locale, DWORD flags, co
|
||||||
|
|
||||||
if (flags & (LCMAP_UPPERCASE | LCMAP_LOWERCASE))
|
if (flags & (LCMAP_UPPERCASE | LCMAP_LOWERCASE))
|
||||||
{
|
{
|
||||||
USHORT *table = (flags & LCMAP_LOWERCASE) ? nls_info.LowerCaseTable : nls_info.UpperCaseTable;
|
const USHORT *table = sort.casemap + (flags & LCMAP_LINGUISTIC_CASING ? sortid->casemap : 0);
|
||||||
|
table = table + 2 + (flags & LCMAP_LOWERCASE ? table[1] : 0);
|
||||||
for (len = dstlen, dst_ptr = dst; srclen && len; src++, srclen--, len--)
|
for (len = dstlen, dst_ptr = dst; srclen && len; src++, srclen--, len--)
|
||||||
*dst_ptr++ = casemap( table, *src );
|
*dst_ptr++ = casemap( table, *src );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue