Commit 33f9dcb1 authored by Dmitry Timoshkov's avatar Dmitry Timoshkov Committed by Alexandre Julliard

Move CompareString implementation to libwine_unicode, add a bunch of

CompareString tests.
parent 1bcbd546
...@@ -1971,6 +1971,12 @@ INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen, ...@@ -1971,6 +1971,12 @@ INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen,
} }
} }
if (srclen)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
return dst_ptr - dst; return dst_ptr - dst;
} }
...@@ -1994,7 +2000,7 @@ INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen, ...@@ -1994,7 +2000,7 @@ INT WINAPI LCMapStringW(LCID lcid, DWORD flags, LPCWSTR src, INT srclen,
INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen, INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen,
LPSTR dst, INT dstlen) LPSTR dst, INT dstlen)
{ {
WCHAR bufW[128]; WCHAR *bufW = NtCurrentTeb()->StaticUnicodeBuffer;
LPWSTR srcW, dstW; LPWSTR srcW, dstW;
INT ret = 0, srclenW, dstlenW; INT ret = 0, srclenW, dstlenW;
UINT locale_cp; UINT locale_cp;
...@@ -2007,7 +2013,7 @@ INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen, ...@@ -2007,7 +2013,7 @@ INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen,
locale_cp = get_lcid_codepage(lcid); locale_cp = get_lcid_codepage(lcid);
srclenW = MultiByteToWideChar(locale_cp, 0, src, srclen, bufW, 128); srclenW = MultiByteToWideChar(locale_cp, 0, src, srclen, bufW, 260);
if (srclenW) if (srclenW)
srcW = bufW; srcW = bufW;
else else
...@@ -2040,6 +2046,9 @@ INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen, ...@@ -2040,6 +2046,9 @@ INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen,
} }
dstlenW = LCMapStringW(lcid, flags, srcW, srclenW, NULL, 0); dstlenW = LCMapStringW(lcid, flags, srcW, srclenW, NULL, 0);
if (!dstlenW)
goto map_string_exit;
dstW = HeapAlloc(GetProcessHeap(), 0, dstlenW * sizeof(WCHAR)); dstW = HeapAlloc(GetProcessHeap(), 0, dstlenW * sizeof(WCHAR));
if (!dstW) if (!dstW)
{ {
...@@ -2172,7 +2181,7 @@ INT WINAPI FoldStringW(DWORD dwFlags, LPCWSTR src, INT srclen, ...@@ -2172,7 +2181,7 @@ INT WINAPI FoldStringW(DWORD dwFlags, LPCWSTR src, INT srclen,
INT WINAPI CompareStringW(LCID lcid, DWORD style, INT WINAPI CompareStringW(LCID lcid, DWORD style,
LPCWSTR str1, INT len1, LPCWSTR str2, INT len2) LPCWSTR str1, INT len1, LPCWSTR str2, INT len2)
{ {
INT ret, len; INT ret;
if (!str1 || !str2) if (!str1 || !str2)
{ {
...@@ -2180,19 +2189,24 @@ INT WINAPI CompareStringW(LCID lcid, DWORD style, ...@@ -2180,19 +2189,24 @@ INT WINAPI CompareStringW(LCID lcid, DWORD style,
return 0; return 0;
} }
if (len1 < 0) len1 = lstrlenW(str1); if( style & ~(NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS|
if (len2 < 0) len2 = lstrlenW(str2); SORT_STRINGSORT|NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH|0x10000000) )
{
SetLastError(ERROR_INVALID_FLAGS);
return 0;
}
len = (len1 < len2) ? len1 : len2; if (style & 0x10000000)
ret = (style & NORM_IGNORECASE) ? strncmpiW(str1, str2, len) : FIXME("Ignoring unknown style 0x10000000\n");
strncmpW(str1, str2, len);
if (len1 < 0) len1 = strlenW(str1);
if (len2 < 0) len2 = strlenW(str2);
ret = wine_compare_string(style, str1, len1, str2, len2);
if (ret) /* need to translate result */ if (ret) /* need to translate result */
return (ret < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN; return (ret < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN;
return CSTR_EQUAL;
if (len1 == len2) return CSTR_EQUAL;
/* the longer one is lexically greater */
return (len1 < len2) ? CSTR_LESS_THAN : CSTR_GREATER_THAN;
} }
/****************************************************************************** /******************************************************************************
...@@ -2216,7 +2230,8 @@ INT WINAPI CompareStringW(LCID lcid, DWORD style, ...@@ -2216,7 +2230,8 @@ INT WINAPI CompareStringW(LCID lcid, DWORD style,
INT WINAPI CompareStringA(LCID lcid, DWORD style, INT WINAPI CompareStringA(LCID lcid, DWORD style,
LPCSTR str1, INT len1, LPCSTR str2, INT len2) LPCSTR str1, INT len1, LPCSTR str2, INT len2)
{ {
WCHAR buf1W[128], buf2W[128]; WCHAR *buf1W = NtCurrentTeb()->StaticUnicodeBuffer;
WCHAR *buf2W = buf1W + 130;
LPWSTR str1W, str2W; LPWSTR str1W, str2W;
INT len1W, len2W, ret; INT len1W, len2W, ret;
UINT locale_cp; UINT locale_cp;
...@@ -2226,13 +2241,12 @@ INT WINAPI CompareStringA(LCID lcid, DWORD style, ...@@ -2226,13 +2241,12 @@ INT WINAPI CompareStringA(LCID lcid, DWORD style,
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
return 0; return 0;
} }
if (len1 < 0) len1 = strlen(str1); if (len1 < 0) len1 = strlen(str1);
if (len2 < 0) len2 = strlen(str2); if (len2 < 0) len2 = strlen(str2);
locale_cp = get_lcid_codepage(lcid); locale_cp = get_lcid_codepage(lcid);
len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, buf1W, 128); len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, buf1W, 130);
if (len1W) if (len1W)
str1W = buf1W; str1W = buf1W;
else else
...@@ -2246,7 +2260,7 @@ INT WINAPI CompareStringA(LCID lcid, DWORD style, ...@@ -2246,7 +2260,7 @@ INT WINAPI CompareStringA(LCID lcid, DWORD style,
} }
MultiByteToWideChar(locale_cp, 0, str1, len1, str1W, len1W); MultiByteToWideChar(locale_cp, 0, str1, len1, str1W, len1W);
} }
len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, buf2W, 128); len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, buf2W, 130);
if (len2W) if (len2W)
str2W = buf2W; str2W = buf2W;
else else
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
* even when the user has overridden their default i8n settings (e.g. in * even when the user has overridden their default i8n settings (e.g. in
* the control panel i8n page), we will still get the expected results. * the control panel i8n page), we will still get the expected results.
*/ */
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include "wine/test.h" #include "wine/test.h"
...@@ -774,8 +777,151 @@ static void test_CompareStringA() ...@@ -774,8 +777,151 @@ static void test_CompareStringA()
ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0); ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0);
ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret); ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret);
ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "SaLuT", -1); ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1);
ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret); ok (ret == 2, "(Salut/saLuT) Expected 2, got %d\n", ret);
SetLastError(0xdeadbeef);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0x10, "NULL", -1, "NULL", -1);
ok(GetLastError() == ERROR_INVALID_FLAGS,
"unexpected error code %ld\n", GetLastError());
ok(!ret, "CompareStringA must fail with invalid flag\n");
ret = lstrcmpA("", "");
ok (!ret, "lstrcmpA(\"\", \"\") should return 0, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"EndDialog",-1,"_Property",-1);
ok( ret == 3, "EndDialog vs _Property ... expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0070",-1,"_IEWWBrowserComp",-1);
ok( ret == 3, "osp_vba.sreg0070 vs _IEWWBrowserComp ... expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"r",-1,"\\",-1);
ok( ret == 3, "r vs \\ ... expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT,0,"osp_vba.sreg0031", -1, "OriginalDatabase", -1 );
ok( ret == 3, "osp_vba.sreg0031 vs OriginalDatabase ... expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aaa", -1 );
ok( ret == 3, "AAA vs aaa expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "aab", -1 );
ok( ret == 1, "AAA vs aab expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "AAA", -1, "Aab", -1 );
ok( ret == 1, "AAA vs Aab expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "Aab", -1 );
ok( ret == 1, ".AAA vs Aab expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, ".AAA", -1, "A.ab", -1 );
ok( ret == 1, ".AAA vs A.ab expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "AB", -1 );
ok( ret == 1, "aa vs AB expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aa", -1, "Aab", -1 );
ok( ret == 1, "aa vs Aab expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "aB", -1, "Aab", -1 );
ok( ret == 3, "aB vs Aab expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "Ba", -1, "bab", -1 );
ok( ret == 1, "Ba vs bab expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "{100}{83}{71}{71}{71}", -1, "Global_DataAccess_JRO", -1 );
ok( ret == 1, "{100}{83}{71}{71}{71} vs Global_DataAccess_JRO expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "a", -1, "{", -1 );
ok( ret == 3, "a vs { expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "A", -1, "{", -1 );
ok( ret == 3, "A vs { expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", 0, "4.0", -1 );
ok(ret == 1, "3.5/0 vs 4.0/-1 expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.5", -1, "4.0", -1 );
ok(ret == 1, "3.5 vs 4.0 expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "3.520.4403.2", -1, "4.0.2927.10", -1 );
ok(ret == 1, "3.520.4403.2 vs 4.0.2927.10 expected 1, got %d", ret);
/* hyphen and apostrophe are treated differently depending on
* whether SORT_STRINGSORT specified or not
*/
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-o", -1, "/m", -1 );
ok(ret == 3, "-o vs /m expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "-o", -1 );
ok(ret == 1, "/m vs -o expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-o", -1, "/m", -1 );
ok(ret == 1, "-o vs /m expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "-o", -1 );
ok(ret == 3, "/m vs -o expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "/m", -1 );
ok(ret == 3, "'o vs /m expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "'o", -1 );
ok(ret == 1, "/m vs 'o expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "/m", -1 );
ok(ret == 1, "'o vs /m expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "'o", -1 );
ok(ret == 3, "/m vs 'o expected 3, got %d", ret);
#if 0 /* this requires collation table patch to make it MS compatible */
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
ok(ret == 1, "'o vs -o expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'o", -1, "-o", -1 );
ok(ret == 1, "'o vs -o expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'", -1, "-", -1 );
ok(ret == 1, "' vs - expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "'", -1, "-", -1 );
ok(ret == 1, "' vs - expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "/m", -1 );
ok(ret == 3, "`o vs /m expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "/m", -1, "`o", -1 );
ok(ret == 1, "/m vs `o expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "/m", -1 );
ok(ret == 3, "`o vs /m expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "/m", -1, "`o", -1 );
ok(ret == 1, "/m vs `o expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "`o", -1, "-m", -1 );
ok(ret == 1, "`o vs -m expected 1, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "-m", -1, "`o", -1 );
ok(ret == 3, "-m vs `o expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "`o", -1, "-m", -1 );
ok(ret == 3, "`o vs -m expected 3, got %d", ret);
ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, SORT_STRINGSORT, "-m", -1, "`o", -1 );
ok(ret == 1, "-m vs `o expected 1, got %d", ret);
#endif
ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ", 9);
ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0 expected 2, got %d", ret);
ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 7, "aLuZkUtZ\0A", 10);
ok(ret == 1, "aLuZkUtZ vs aLuZkUtZ\\0A expected 1, got %d", ret);
ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLuZkUtZ", 8, "aLuZkUtZ\0A", 10);
ok(ret == 2, "aLuZkUtZ vs aLuZkUtZ\\0A expected 2, got %d", ret);
ret = CompareStringA(LOCALE_USER_DEFAULT, 0, "aLu\0ZkUtZ", 8, "aLu\0ZkUtZ\0A", 10);
ok(ret == 2, "aLu\\0ZkUtZ vs aLu\\0ZkUtZ\\0A expected 2, got %d", ret);
} }
void test_LCMapStringA(void) void test_LCMapStringA(void)
...@@ -834,6 +980,13 @@ void test_LCMapStringA(void) ...@@ -834,6 +980,13 @@ void test_LCMapStringA(void)
ret, GetLastError(), lstrlenA(lower_case) + 1); ret, GetLastError(), lstrlenA(lower_case) + 1);
ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf); ok(!lstrcmpA(buf, upper_case), "LCMapStringA should return %s, but not %s\n", upper_case, buf);
/* test buffer overflow */
SetLastError(0xdeadbeef);
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
lower_case, -1, buf, 4);
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
/* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */ /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
lstrcpyA(buf, lower_case); lstrcpyA(buf, lower_case);
ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
...@@ -924,6 +1077,13 @@ void test_LCMapStringA(void) ...@@ -924,6 +1077,13 @@ void test_LCMapStringA(void)
ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n", ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n",
lstrlenA(symbols_stripped) + 1, ret); lstrlenA(symbols_stripped) + 1, ret);
ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf); ok(!lstrcmpA(buf, symbols_stripped), "LCMapStringA should return %s, but not %s\n", lower_case, buf);
/* test srclen = 0 */
SetLastError(0xdeadbeef);
ret = LCMapStringA(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
ok(!ret, "LCMapStringA should fail with srclen = 0");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"unexpected error code %ld\n", GetLastError());
} }
void test_LCMapStringW(void) void test_LCMapStringW(void)
...@@ -988,6 +1148,13 @@ void test_LCMapStringW(void) ...@@ -988,6 +1148,13 @@ void test_LCMapStringW(void)
ret, GetLastError(), lstrlenW(lower_case) + 1); ret, GetLastError(), lstrlenW(lower_case) + 1);
ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n"); ok(!lstrcmpW(buf, upper_case), "string compare mismatch\n");
/* test buffer overflow */
SetLastError(0xdeadbeef);
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
lower_case, -1, buf, 4);
ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", ret);
/* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */ /* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
lstrcpyW(buf, lower_case); lstrcpyW(buf, lower_case);
ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE,
...@@ -1069,9 +1236,143 @@ void test_LCMapStringW(void) ...@@ -1069,9 +1236,143 @@ void test_LCMapStringW(void)
ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n", ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n",
lstrlenW(symbols_stripped) + 1, ret); lstrlenW(symbols_stripped) + 1, ret);
ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n"); ok(!lstrcmpW(buf, symbols_stripped), "string comparison mismatch\n");
/* test srclen = 0 */
SetLastError(0xdeadbeef);
ret = LCMapStringW(LOCALE_USER_DEFAULT, 0, upper_case, 0, buf, sizeof(buf));
ok(!ret, "LCMapStringW should fail with srclen = 0");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"unexpected error code %ld\n", GetLastError());
}
#if 0 /* this requires collation table patch to make it MS compatible */
const char *strings_sorted[] =
{
"'",
"-",
"!",
"\"",
".",
":",
"\\",
"_",
"`",
"{",
"}",
"+",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"a",
"A",
"b",
"B",
"c",
"C"
};
const char *strings[] =
{
"C",
"\"",
"9",
"'",
"}",
"-",
"7",
"+",
"`",
"1",
"a",
"5",
"\\",
"8",
"B",
"3",
"_",
"6",
"{",
"2",
"c",
"4",
"!",
"0",
"A",
":",
"b",
"."
};
static int compare_string1(const void *e1, const void *e2)
{
const char *s1 = *(const char **)e1;
const char *s2 = *(const char **)e2;
return lstrcmpA(s1, s2);
} }
void test_FoldStringA(void) static int compare_string2(const void *e1, const void *e2)
{
const char *s1 = *(const char **)e1;
const char *s2 = *(const char **)e2;
return CompareStringA(0, 0, s1, -1, s2, -1) - 2;
}
static int compare_string3(const void *e1, const void *e2)
{
const char *s1 = *(const char **)e1;
const char *s2 = *(const char **)e2;
char key1[256], key2[256];
LCMapStringA(0, LCMAP_SORTKEY, s1, -1, key1, sizeof(key1));
LCMapStringA(0, LCMAP_SORTKEY, s2, -1, key2, sizeof(key2));
return strcmp(key1, key2);
}
static void test_sorting(void)
{
char buf[256];
char **str_buf = (char **)buf;
int i;
assert(sizeof(buf) >= sizeof(strings));
/* 1. sort using lstrcmpA */
memcpy(buf, strings, sizeof(strings));
qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string1);
for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
{
ok(!strcmp(strings_sorted[i], str_buf[i]),
"qsort using lstrcmpA failed for element %d\n", i);
}
/* 2. sort using CompareStringA */
memcpy(buf, strings, sizeof(strings));
qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string2);
for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
{
ok(!strcmp(strings_sorted[i], str_buf[i]),
"qsort using CompareStringA failed for element %d\n", i);
}
/* 3. sort using sort keys */
memcpy(buf, strings, sizeof(strings));
qsort(buf, sizeof(strings)/sizeof(strings[0]), sizeof(strings[0]), compare_string3);
for (i = 0; i < sizeof(strings)/sizeof(strings[0]); i++)
{
ok(!strcmp(strings_sorted[i], str_buf[i]),
"qsort using sort keys failed for element %d\n", i);
}
}
#endif
static void test_FoldStringA(void)
{ {
int ret, i; int ret, i;
char src[256], dst[256]; char src[256], dst[256];
...@@ -1118,6 +1419,13 @@ void test_FoldStringA(void) ...@@ -1118,6 +1419,13 @@ void test_FoldStringA(void)
if (!pFoldStringA) if (!pFoldStringA)
return; /* FoldString is present in NT v3.1+, but not 95/98/Me */ return; /* FoldString is present in NT v3.1+, but not 95/98/Me */
/* these tests are locale specific */
if (GetACP() != 1252)
{
trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
return;
}
/* MAP_FOLDDIGITS */ /* MAP_FOLDDIGITS */
SetLastError(0); SetLastError(0);
ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256); ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
...@@ -1212,7 +1520,7 @@ void test_FoldStringA(void) ...@@ -1212,7 +1520,7 @@ void test_FoldStringA(void)
} }
} }
void test_FoldStringW(void) static void test_FoldStringW(void)
{ {
int ret; int ret;
size_t i, j; size_t i, j;
...@@ -1596,8 +1904,8 @@ static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName, ...@@ -1596,8 +1904,8 @@ static BOOL CALLBACK langgrp_procA(LGRPID lgrpid, LPSTR lpszNum, LPSTR lpszName,
"Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags); "Enumerated grp %ld not valid (flags %ld)\n", lgrpid, dwFlags);
/* If lParam is one, we are calling with flags defaulted from 0 */ /* If lParam is one, we are calling with flags defaulted from 0 */
ok(!lParam || dwFlags == LGRPID_INSTALLED, ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
"Expected dwFlags == LGRPID_INSTALLED, got %ld\n", dwFlags); "Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %ld\n", dwFlags);
return TRUE; return TRUE;
} }
...@@ -1710,4 +2018,7 @@ START_TEST(locale) ...@@ -1710,4 +2018,7 @@ START_TEST(locale)
test_EnumSystemLanguageGroupsA(); test_EnumSystemLanguageGroupsA();
test_EnumLanguageGroupLocalesA(); test_EnumLanguageGroupLocalesA();
test_SetLocaleInfoA(); test_SetLocaleInfoA();
#if 0 /* this requires collation table patch to make it MS compatible */
test_sorting();
#endif
} }
...@@ -64,7 +64,7 @@ static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags) ...@@ -64,7 +64,7 @@ static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
char str1[3], str2[3]; char str1[3], str2[3];
str1[0] = LOBYTE(ch1); str1[0] = LOBYTE(ch1);
if (IsDBCSLeadByte(ch1)) if (IsDBCSLeadByte(str1[0]))
{ {
str1[1] = HIBYTE(ch1); str1[1] = HIBYTE(ch1);
str1[2] = '\0'; str1[2] = '\0';
...@@ -73,7 +73,7 @@ static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags) ...@@ -73,7 +73,7 @@ static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
str1[1] = '\0'; str1[1] = '\0';
str2[0] = LOBYTE(ch2); str2[0] = LOBYTE(ch2);
if (IsDBCSLeadByte(ch2)) if (IsDBCSLeadByte(str2[0]))
{ {
str2[1] = HIBYTE(ch2); str2[1] = HIBYTE(ch2);
str2[2] = '\0'; str2[2] = '\0';
......
...@@ -156,33 +156,37 @@ static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = { ...@@ -156,33 +156,37 @@ static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = {
static void test_StrChrA(void) static void test_StrChrA(void)
{ {
char string[129]; char string[129];
int count; WORD count;
ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!"); /* this test crashes on win2k SP4 */
/*ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!");*/
for (count = 32; count < 128; count++) for (count = 32; count < 128; count++)
string[count] = count; string[count] = (char)count;
string[128] = '\0'; string[128] = '\0';
for (count = 32; count < 128; count++) for (count = 32; count < 128; count++)
{ {
LPSTR result = StrChrA(string+32, count); LPSTR result = StrChrA(string+32, count);
ok(result - string == count, "found char %d in wrong place", count); ok(result - string == count,
"found char '%c' in wrong place: got %d, expected %d\n",
count, result - string, count);
} }
for (count = 32; count < 128; count++) for (count = 32; count < 128; count++)
{ {
LPSTR result = StrChrA(string+count+1, count); LPSTR result = StrChrA(string+count+1, count);
ok(!result, "found char not in the string"); ok(!result, "found char '%c' not in the string\n", count);
} }
} }
static void test_StrChrW(void) static void test_StrChrW(void)
{ {
WCHAR string[16385]; WCHAR string[16385];
int count; WORD count;
ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!"); /* this test crashes on win2k SP4 */
/*ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!");*/
for (count = 32; count < 16384; count++) for (count = 32; count < 16384; count++)
string[count] = count; string[count] = count;
...@@ -204,12 +208,13 @@ static void test_StrChrW(void) ...@@ -204,12 +208,13 @@ static void test_StrChrW(void)
static void test_StrChrIA(void) static void test_StrChrIA(void)
{ {
char string[129]; char string[129];
int count; WORD count;
ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!"); /* this test crashes on win2k SP4 */
/*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!");*/
for (count = 32; count < 128; count++) for (count = 32; count < 128; count++)
string[count] = count; string[count] = (char)count;
string[128] = '\0'; string[128] = '\0';
for (count = 'A'; count <= 'X'; count++) for (count = 'A'; count <= 'X'; count++)
...@@ -230,9 +235,10 @@ static void test_StrChrIA(void) ...@@ -230,9 +235,10 @@ static void test_StrChrIA(void)
static void test_StrChrIW(void) static void test_StrChrIW(void)
{ {
WCHAR string[129]; WCHAR string[129];
int count; WORD count;
ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!"); /* this test crashes on win2k SP4 */
/*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!");*/
for (count = 32; count < 128; count++) for (count = 32; count < 128; count++)
string[count] = count; string[count] = count;
...@@ -256,12 +262,13 @@ static void test_StrChrIW(void) ...@@ -256,12 +262,13 @@ static void test_StrChrIW(void)
static void test_StrRChrA(void) static void test_StrRChrA(void)
{ {
char string[129]; char string[129];
int count; WORD count;
ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!"); /* this test crashes on win2k SP4 */
/*ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!");*/
for (count = 32; count < 128; count++) for (count = 32; count < 128; count++)
string[count] = count; string[count] = (char)count;
string[128] = '\0'; string[128] = '\0';
for (count = 32; count < 128; count++) for (count = 32; count < 128; count++)
...@@ -285,31 +292,34 @@ static void test_StrRChrA(void) ...@@ -285,31 +292,34 @@ static void test_StrRChrA(void)
static void test_StrRChrW(void) static void test_StrRChrW(void)
{ {
WCHAR string[16385]; WCHAR string[129];
int count; WORD count;
ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!"); /* this test crashes on win2k SP4 */
/*ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!");*/
for (count = 32; count < 16384; count++) for (count = 32; count < 128; count++)
string[count] = count; string[count] = count;
string[16384] = '\0'; string[128] = '\0';
for (count = 32; count < 16384; count++) for (count = 32; count < 128; count++)
{ {
LPWSTR result = StrRChrW(string+32, NULL, count); LPWSTR result = StrRChrW(string+32, NULL, count);
ok(result - string == count, "found char %d in wrong place", count); ok(result - string == count,
"found char %d in wrong place: got %d, expected %d\n",
count, result - string, count);
} }
for (count = 32; count < 16384; count++) for (count = 32; count < 128; count++)
{ {
LPWSTR result = StrRChrW(string+count+1, NULL, count); LPWSTR result = StrRChrW(string+count+1, NULL, count);
ok(!result, "found char not in the string"); ok(!result, "found char %d not in the string\n", count);
} }
for (count = 32; count < 16384; count++) for (count = 32; count < 128; count++)
{ {
LPWSTR result = StrRChrW(string+count+1, string + 127, count); LPWSTR result = StrRChrW(string+count+1, string + 127, count);
ok(!result, "found char not in the string"); ok(!result, "found char %d not in the string\n", count);
} }
} }
...@@ -455,6 +465,8 @@ static void test_StrDupA() ...@@ -455,6 +465,8 @@ static void test_StrDupA()
static void test_StrFormatByteSize64A(void) static void test_StrFormatByteSize64A(void)
{ {
/* this test fails on locales which do not use '.' as a decimal separator */
#if 0
char szBuff[256]; char szBuff[256];
const StrFormatSizeResult* result = StrFormatSize_results; const StrFormatSizeResult* result = StrFormatSize_results;
...@@ -462,10 +474,13 @@ static void test_StrFormatByteSize64A(void) ...@@ -462,10 +474,13 @@ static void test_StrFormatByteSize64A(void)
{ {
StrFormatByteSize64A(result->value, szBuff, 256); StrFormatByteSize64A(result->value, szBuff, 256);
ok(!strcmp(result->byte_size_64, szBuff), "Formatted %lld wrong", result->value); ok(!strcmp(result->byte_size_64, szBuff),
"Formatted %lx%08lx wrong: got %s, expected %s\n",
(LONG)(result->value >> 32), (LONG)result->value, szBuff, result->byte_size_64);
result++; result++;
} }
#endif
} }
static void test_StrFormatKBSizeW(void) static void test_StrFormatKBSizeW(void)
...@@ -480,8 +495,9 @@ static void test_StrFormatKBSizeW(void) ...@@ -480,8 +495,9 @@ static void test_StrFormatKBSizeW(void)
{ {
StrFormatKBSizeW(result->value, szBuffW, 256); StrFormatKBSizeW(result->value, szBuffW, 256);
WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0); WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0);
ok(!strcmp(result->kb_size, szBuff), "Formatted %lld wrong", ok(!strcmp(result->kb_size, szBuff),
result->value); "Formatted %lx%08lx wrong: got %s, expected %s\n",
(LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
result++; result++;
} }
#endif #endif
...@@ -489,6 +505,7 @@ static void test_StrFormatKBSizeW(void) ...@@ -489,6 +505,7 @@ static void test_StrFormatKBSizeW(void)
static void test_StrFormatKBSizeA(void) static void test_StrFormatKBSizeA(void)
{ {
/* this test fails on locales which do not use '.' as a decimal separator */
#if 0 #if 0
char szBuff[256]; char szBuff[256];
const StrFormatSizeResult* result = StrFormatSize_results; const StrFormatSizeResult* result = StrFormatSize_results;
...@@ -497,8 +514,9 @@ static void test_StrFormatKBSizeA(void) ...@@ -497,8 +514,9 @@ static void test_StrFormatKBSizeA(void)
{ {
StrFormatKBSizeA(result->value, szBuff, 256); StrFormatKBSizeA(result->value, szBuff, 256);
ok(!strcmp(result->kb_size, szBuff), "Formatted %lld wrong", ok(!strcmp(result->kb_size, szBuff),
result->value); "Formatted %lx%08lx wrong: got %s, expected %s\n",
(LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
result++; result++;
} }
#endif #endif
......
...@@ -74,6 +74,7 @@ extern int wine_cp_wcstombs( const union cptable *table, int flags, ...@@ -74,6 +74,7 @@ extern int wine_cp_wcstombs( const union cptable *table, int flags,
extern int wine_utf8_wcstombs( const WCHAR *src, int srclen, char *dst, int dstlen ); extern int wine_utf8_wcstombs( const WCHAR *src, int srclen, char *dst, int dstlen );
extern int wine_utf8_mbstowcs( int flags, const char *src, int srclen, WCHAR *dst, int dstlen ); extern int wine_utf8_mbstowcs( int flags, const char *src, int srclen, WCHAR *dst, int dstlen );
extern int wine_compare_string( int flags, const WCHAR *str1, int len1, const WCHAR *str2, int len2 );
extern int wine_get_sortkey( int flags, const WCHAR *src, int srclen, char *dst, int dstlen ); extern int wine_get_sortkey( int flags, const WCHAR *src, int srclen, char *dst, int dstlen );
extern int wine_fold_string( int flags, const WCHAR *src, int srclen , WCHAR *dst, int dstlen ); extern int wine_fold_string( int flags, const WCHAR *src, int srclen , WCHAR *dst, int dstlen );
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "wine/unicode.h" #include "wine/unicode.h"
extern int get_decomposition(WCHAR src, WCHAR *dst, unsigned int dstlen); extern int get_decomposition(WCHAR src, WCHAR *dst, unsigned int dstlen);
extern const unsigned int collation_table[];
/* /*
* flags - normalization NORM_* flags * flags - normalization NORM_* flags
...@@ -28,7 +29,6 @@ extern int get_decomposition(WCHAR src, WCHAR *dst, unsigned int dstlen); ...@@ -28,7 +29,6 @@ extern int get_decomposition(WCHAR src, WCHAR *dst, unsigned int dstlen);
*/ */
int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dstlen) int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dstlen)
{ {
extern const unsigned int collation_table[];
WCHAR dummy[4]; /* no decomposition is larger than 4 chars */ WCHAR dummy[4]; /* no decomposition is larger than 4 chars */
int key_len[4]; int key_len[4];
char *key_ptr[4]; char *key_ptr[4];
...@@ -38,7 +38,8 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst ...@@ -38,7 +38,8 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst
key_len[0] = key_len[1] = key_len[2] = key_len[3] = 0; key_len[0] = key_len[1] = key_len[2] = key_len[3] = 0;
for (; srclen; srclen--, src++) for (; srclen; srclen--, src++)
{ {
int decomposed_len = get_decomposition(*src, dummy, 4); int decomposed_len = 1;/*get_decomposition(*src, dummy, 4);*/
dummy[0] = *src;
if (decomposed_len) if (decomposed_len)
{ {
int i; int i;
...@@ -62,18 +63,18 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst ...@@ -62,18 +63,18 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst
if (ce >> 16) key_len[0] += 2; if (ce >> 16) key_len[0] += 2;
if ((ce >> 8) & 0xff) key_len[1]++; if ((ce >> 8) & 0xff) key_len[1]++;
if ((ce >> 4) & 0x0f) key_len[2]++; if ((ce >> 4) & 0x0f) key_len[2]++;
/*if (ce & 1) if (ce & 1)
{ {
if (wch >> 8) key_len[3]++; if (wch >> 8) key_len[3]++;
key_len[3]++; key_len[3]++;
}*/
} }
/*else }
else
{ {
key_len[0] += 2; key_len[0] += 2;
if (wch >> 8) key_len[0]++; if (wch >> 8) key_len[0]++;
if (wch & 0xff) key_len[0]++; if (wch & 0xff) key_len[0]++;
}*/ }
} }
} }
} }
...@@ -95,7 +96,8 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst ...@@ -95,7 +96,8 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst
for (; srclen; srclen--, src++) for (; srclen; srclen--, src++)
{ {
int decomposed_len = get_decomposition(*src, dummy, 4); int decomposed_len = 1;/*get_decomposition(*src, dummy, 4);*/
dummy[0] = *src;
if (decomposed_len) if (decomposed_len)
{ {
int i; int i;
...@@ -127,19 +129,19 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst ...@@ -127,19 +129,19 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst
/* make key 2 start from 2 */ /* make key 2 start from 2 */
if ((key = (ce >> 4) & 0x0f)) *key_ptr[2]++ = key + 1; if ((key = (ce >> 4) & 0x0f)) *key_ptr[2]++ = key + 1;
/* key 3 is always a character code */ /* key 3 is always a character code */
/*if (ce & 1) if (ce & 1)
{ {
if (wch >> 8) *key_ptr[3]++ = wch >> 8; if (wch >> 8) *key_ptr[3]++ = wch >> 8;
if (wch & 0xff) *key_ptr[3]++ = wch & 0xff; if (wch & 0xff) *key_ptr[3]++ = wch & 0xff;
}*/
} }
/*else }
else
{ {
*key_ptr[0]++ = 0xff; *key_ptr[0]++ = 0xff;
*key_ptr[0]++ = 0xfe; *key_ptr[0]++ = 0xfe;
if (wch >> 8) *key_ptr[0]++ = wch >> 8; if (wch >> 8) *key_ptr[0]++ = wch >> 8;
if (wch & 0xff) *key_ptr[0]++ = wch & 0xff; if (wch & 0xff) *key_ptr[0]++ = wch & 0xff;
}*/ }
} }
} }
} }
...@@ -152,3 +154,198 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst ...@@ -152,3 +154,198 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dst
return key_ptr[3] - dst; return key_ptr[3] - dst;
} }
static inline int compare_unicode_weights(int flags, const WCHAR *str1, int len1,
const WCHAR *str2, int len2)
{
unsigned int ce1, ce2;
int ret;
/* 32-bit collation element table format:
* unicode weight - high 16 bit, diacritic weight - high 8 bit of low 16 bit,
* case weight - high 4 bit of low 8 bit.
*/
while (len1 > 0 && len2 > 0)
{
if (flags & NORM_IGNORESYMBOLS)
{
int skip = 0;
/* FIXME: not tested */
if (get_char_typeW(*str1) & (C1_PUNCT | C1_SPACE))
{
str1++;
len1--;
skip = 1;
}
if (get_char_typeW(*str2) & (C1_PUNCT | C1_SPACE))
{
str2++;
len2--;
skip = 1;
}
if (skip) continue;
}
/* hyphen and apostrophe are treated differently depending on
* whether SORT_STRINGSORT specified or not
*/
if (!(flags & SORT_STRINGSORT))
{
if (*str1 == '-' || *str1 == '\'')
{
if (*str2 != '-' && *str2 != '\'')
{
str1++;
len1--;
continue;
}
}
else if (*str2 == '-' || *str2 == '\'')
{
str2++;
len2--;
continue;
}
}
ce1 = collation_table[collation_table[*str1 >> 8] + (*str1 & 0xff)];
ce2 = collation_table[collation_table[*str2 >> 8] + (*str2 & 0xff)];
if (ce1 != (unsigned int)-1 && ce2 != (unsigned int)-1)
ret = (ce1 >> 16) - (ce2 >> 16);
else
ret = *str1 - *str2;
if (ret) return ret;
str1++;
str2++;
len1--;
len2--;
}
return len1 - len2;
}
static inline int compare_diacritic_weights(int flags, const WCHAR *str1, int len1,
const WCHAR *str2, int len2)
{
unsigned int ce1, ce2;
int ret;
/* 32-bit collation element table format:
* unicode weight - high 16 bit, diacritic weight - high 8 bit of low 16 bit,
* case weight - high 4 bit of low 8 bit.
*/
while (len1 > 0 && len2 > 0)
{
if (flags & NORM_IGNORESYMBOLS)
{
int skip = 0;
/* FIXME: not tested */
if (get_char_typeW(*str1) & (C1_PUNCT | C1_SPACE))
{
str1++;
len1--;
skip = 1;
}
if (get_char_typeW(*str2) & (C1_PUNCT | C1_SPACE))
{
str2++;
len2--;
skip = 1;
}
if (skip) continue;
}
ce1 = collation_table[collation_table[*str1 >> 8] + (*str1 & 0xff)];
ce2 = collation_table[collation_table[*str2 >> 8] + (*str2 & 0xff)];
if (ce1 != (unsigned int)-1 && ce2 != (unsigned int)-1)
ret = ((ce1 >> 8) & 0xff) - ((ce2 >> 8) & 0xff);
else
ret = *str1 - *str2;
if (ret) return ret;
str1++;
str2++;
len1--;
len2--;
}
return len1 - len2;
}
static inline int compare_case_weights(int flags, const WCHAR *str1, int len1,
const WCHAR *str2, int len2)
{
unsigned int ce1, ce2;
int ret;
/* 32-bit collation element table format:
* unicode weight - high 16 bit, diacritic weight - high 8 bit of low 16 bit,
* case weight - high 4 bit of low 8 bit.
*/
while (len1 > 0 && len2 > 0)
{
if (flags & NORM_IGNORESYMBOLS)
{
int skip = 0;
/* FIXME: not tested */
if (get_char_typeW(*str1) & (C1_PUNCT | C1_SPACE))
{
str1++;
len1--;
skip = 1;
}
if (get_char_typeW(*str2) & (C1_PUNCT | C1_SPACE))
{
str2++;
len2--;
skip = 1;
}
if (skip) continue;
}
ce1 = collation_table[collation_table[*str1 >> 8] + (*str1 & 0xff)];
ce2 = collation_table[collation_table[*str2 >> 8] + (*str2 & 0xff)];
if (ce1 != (unsigned int)-1 && ce2 != (unsigned int)-1)
ret = ((ce1 >> 4) & 0x0f) - ((ce2 >> 4) & 0x0f);
else
ret = *str1 - *str2;
if (ret) return ret;
str1++;
str2++;
len1--;
len2--;
}
return len1 - len2;
}
static inline int real_length(const WCHAR *str, int len)
{
int real_len = 0;
while (len-- && *str++) real_len++;
return real_len;
}
int wine_compare_string(int flags, const WCHAR *str1, int len1,
const WCHAR *str2, int len2)
{
int ret;
len1 = real_length(str1, len1);
len2 = real_length(str2, len2);
ret = compare_unicode_weights(flags, str1, len1, str2, len2);
if (!ret)
{
if (!(flags & NORM_IGNORENONSPACE))
ret = compare_diacritic_weights(flags, str1, len1, str2, len2);
if (!ret && !(flags & NORM_IGNORECASE))
ret = compare_case_weights(flags, str1, len1, str2, len2);
}
return ret;
}
...@@ -27,7 +27,7 @@ int strcmpiW( const WCHAR *str1, const WCHAR *str2 ) ...@@ -27,7 +27,7 @@ int strcmpiW( const WCHAR *str1, const WCHAR *str2 )
{ {
for (;;) for (;;)
{ {
int ret = toupperW(*str1) - toupperW(*str2); int ret = tolowerW(*str1) - tolowerW(*str2);
if (ret || !*str1) return ret; if (ret || !*str1) return ret;
str1++; str1++;
str2++; str2++;
...@@ -38,7 +38,7 @@ int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n ) ...@@ -38,7 +38,7 @@ int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n )
{ {
int ret = 0; int ret = 0;
for ( ; n > 0; n--, str1++, str2++) for ( ; n > 0; n--, str1++, str2++)
if ((ret = toupperW(*str1) - toupperW(*str2)) || !*str1) break; if ((ret = tolowerW(*str1) - tolowerW(*str2)) || !*str1) break;
return ret; return ret;
} }
......
...@@ -12,6 +12,7 @@ EXPORTS ...@@ -12,6 +12,7 @@ EXPORTS
vsprintfW vsprintfW
wine_casemap_lower wine_casemap_lower
wine_casemap_upper wine_casemap_upper
wine_compare_string
wine_cp_enum_table wine_cp_enum_table
wine_cp_get_table wine_cp_get_table
wine_cp_mbstowcs wine_cp_mbstowcs
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment