Hello, now all is remaining is a collation table patch to make it MS compatible. Changelog: Dmitry Timoshkov <dmitry@xxxxxxxxxxxxxxx> Move CompareString implementation to libwine_unicode, add a bunch of CompareString tests. diff -u cvs/hq/wine/dlls/kernel/locale.c wine/dlls/kernel/locale.c --- cvs/hq/wine/dlls/kernel/locale.c Sun Oct 26 16:11:31 2003 +++ wine/dlls/kernel/locale.c Mon Nov 3 18:05:16 2003 @@ -1971,6 +1971,12 @@ INT WINAPI LCMapStringW(LCID lcid, DWORD } } + if (srclen) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + return dst_ptr - dst; } @@ -1994,7 +2000,7 @@ INT WINAPI LCMapStringW(LCID lcid, DWORD INT WINAPI LCMapStringA(LCID lcid, DWORD flags, LPCSTR src, INT srclen, LPSTR dst, INT dstlen) { - WCHAR bufW[128]; + WCHAR *bufW = NtCurrentTeb()->StaticUnicodeBuffer; LPWSTR srcW, dstW; INT ret = 0, srclenW, dstlenW; UINT locale_cp; @@ -2007,7 +2013,7 @@ INT WINAPI LCMapStringA(LCID lcid, DWORD 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) srcW = bufW; else @@ -2040,6 +2046,9 @@ INT WINAPI LCMapStringA(LCID lcid, DWORD } dstlenW = LCMapStringW(lcid, flags, srcW, srclenW, NULL, 0); + if (!dstlenW) + goto map_string_exit; + dstW = HeapAlloc(GetProcessHeap(), 0, dstlenW * sizeof(WCHAR)); if (!dstW) { @@ -2172,7 +2181,7 @@ INT WINAPI FoldStringW(DWORD dwFlags, LP INT WINAPI CompareStringW(LCID lcid, DWORD style, LPCWSTR str1, INT len1, LPCWSTR str2, INT len2) { - INT ret, len; + INT ret; if (!str1 || !str2) { @@ -2180,19 +2189,24 @@ INT WINAPI CompareStringW(LCID lcid, DWO return 0; } - if (len1 < 0) len1 = lstrlenW(str1); - if (len2 < 0) len2 = lstrlenW(str2); + if( style & ~(NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS| + SORT_STRINGSORT|NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH|0x10000000) ) + { + SetLastError(ERROR_INVALID_FLAGS); + return 0; + } + + if (style & 0x10000000) + FIXME("Ignoring unknown style 0x10000000\n"); - len = (len1 < len2) ? len1 : len2; - ret = (style & NORM_IGNORECASE) ? strncmpiW(str1, str2, len) : - 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 */ return (ret < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN; - - if (len1 == len2) return CSTR_EQUAL; - /* the longer one is lexically greater */ - return (len1 < len2) ? CSTR_LESS_THAN : CSTR_GREATER_THAN; + return CSTR_EQUAL; } /****************************************************************************** @@ -2216,7 +2230,8 @@ INT WINAPI CompareStringW(LCID lcid, DWO INT WINAPI CompareStringA(LCID lcid, DWORD style, LPCSTR str1, INT len1, LPCSTR str2, INT len2) { - WCHAR buf1W[128], buf2W[128]; + WCHAR *buf1W = NtCurrentTeb()->StaticUnicodeBuffer; + WCHAR *buf2W = buf1W + 130; LPWSTR str1W, str2W; INT len1W, len2W, ret; UINT locale_cp; @@ -2226,13 +2241,12 @@ INT WINAPI CompareStringA(LCID lcid, DWO SetLastError(ERROR_INVALID_PARAMETER); return 0; } - if (len1 < 0) len1 = strlen(str1); if (len2 < 0) len2 = strlen(str2); 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) str1W = buf1W; else @@ -2246,7 +2260,7 @@ INT WINAPI CompareStringA(LCID lcid, DWO } 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) str2W = buf2W; else diff -u cvs/hq/wine/dlls/kernel/tests/locale.c wine/dlls/kernel/tests/locale.c --- cvs/hq/wine/dlls/kernel/tests/locale.c Thu Oct 30 14:47:28 2003 +++ wine/dlls/kernel/tests/locale.c Mon Nov 3 19:11:43 2003 @@ -24,6 +24,9 @@ * 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. */ + +#include <assert.h> +#include <stdlib.h> #include <stdarg.h> #include "wine/test.h" @@ -774,8 +777,140 @@ static void test_CompareStringA() ret = CompareStringA(lcid, NORM_IGNORECASE, "haha", -1, "hoho", 0); ok (ret== 3, "(haha/hoho) Expected 3, got %d\n", ret); - ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "SaLuT", -1); - ok (ret== 2, "(Salut/SaLuT) Expected 2, got %d\n", ret); + ret = CompareStringA(lcid, NORM_IGNORECASE, "Salut", 5, "saLuT", -1); + 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); + +todo_wine /* this requires collation table patch to make it MS compatible */ +{ + 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); +} /* todo_wine */ + + 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) @@ -834,6 +969,13 @@ void test_LCMapStringA(void) ret, GetLastError(), lstrlenA(lower_case) + 1); 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 */ lstrcpyA(buf, lower_case); ret = LCMapStringA(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, @@ -924,6 +1066,13 @@ void test_LCMapStringA(void) ok(ret == lstrlenA(symbols_stripped) + 1, "LCMapStringA should return %d, ret = %d\n", lstrlenA(symbols_stripped) + 1, ret); 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) @@ -988,6 +1137,13 @@ void test_LCMapStringW(void) ret, GetLastError(), lstrlenW(lower_case) + 1); 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 */ lstrcpyW(buf, lower_case); ret = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, @@ -1069,9 +1225,144 @@ void test_LCMapStringW(void) ok(ret == lstrlenW(symbols_stripped) + 1, "LCMapStringW should return %d, ret = %d\n", lstrlenW(symbols_stripped) + 1, ret); 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()); } -void test_FoldStringA(void) +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); +} + +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)); + +todo_wine /* this requires collation table patch to make it MS compatible */ +{ + /* 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); + } +} /* todo_wine */ +} + +static void test_FoldStringA(void) { int ret, i; char src[256], dst[256]; @@ -1118,6 +1409,13 @@ void test_FoldStringA(void) if (!pFoldStringA) return; /* FoldString is present in NT v3.1+, but not 95/98/Me */ + /* these tests are locale specific */ + if (PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID())) != LANG_ENGLISH) + { + trace("Skipping FoldStringA tests for a not English locale\n"); + return; + } + /* MAP_FOLDDIGITS */ SetLastError(0); ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256); @@ -1212,7 +1510,7 @@ void test_FoldStringA(void) } } -void test_FoldStringW(void) +static void test_FoldStringW(void) { int ret; size_t i, j; @@ -1710,4 +2008,5 @@ START_TEST(locale) test_EnumSystemLanguageGroupsA(); test_EnumLanguageGroupLocalesA(); test_SetLocaleInfoA(); + test_sorting(); } diff -u cvs/hq/wine/include/wine/unicode.h wine/include/wine/unicode.h --- cvs/hq/wine/include/wine/unicode.h Mon Oct 20 13:17:21 2003 +++ wine/include/wine/unicode.h Mon Nov 3 18:05:16 2003 @@ -74,6 +74,7 @@ extern int wine_cp_wcstombs( const union 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_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_fold_string( int flags, const WCHAR *src, int srclen , WCHAR *dst, int dstlen ); diff -u cvs/hq/wine/libs/unicode/collation.c wine/libs/unicode/collation.c --- cvs/hq/wine/libs/unicode/collation.c Fri Jun 27 13:04:59 2003 +++ wine/libs/unicode/collation.c Mon Nov 3 18:05:16 2003 @@ -2,7 +2,7 @@ /* generated from www.unicode.org/reports/tr10/allkeys.txt */ /* DO NOT EDIT!! */ -const unsigned int collation_table[12800] = +const unsigned int unicode_collation_table[12800] = { /* index */ 0x00000200, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000800, 0x00000900, diff -u cvs/hq/wine/libs/unicode/cpmap.pl wine/libs/unicode/cpmap.pl --- cvs/hq/wine/libs/unicode/cpmap.pl Thu Oct 30 14:47:33 2003 +++ wine/libs/unicode/cpmap.pl Mon Nov 3 18:05:16 2003 @@ -607,7 +607,7 @@ sub DUMP_SORTKEYS printf OUTPUT "/* generated from %s */\n", $SORTKEYS; printf OUTPUT "/* DO NOT EDIT!! */\n\n"; - printf OUTPUT "const unsigned int collation_table[%d] =\n{\n", $ranges*256; + printf OUTPUT "const unsigned int unicode_collation_table[%d] =\n{\n", $ranges*256; printf OUTPUT " /* index */\n"; printf OUTPUT "%s,\n", DUMP_ARRAY( "0x%08x", 0, @offsets ); diff -u cvs/hq/wine/libs/unicode/sortkey.c wine/libs/unicode/sortkey.c --- cvs/hq/wine/libs/unicode/sortkey.c Sat Jun 28 04:02:23 2003 +++ wine/libs/unicode/sortkey.c Mon Nov 3 18:05:16 2003 @@ -28,7 +28,7 @@ extern int get_decomposition(WCHAR src, */ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int dstlen) { - extern const unsigned int collation_table[]; + extern const unsigned int unicode_collation_table[]; WCHAR dummy[4]; /* no decomposition is larger than 4 chars */ int key_len[4]; char *key_ptr[4]; @@ -38,7 +38,8 @@ int wine_get_sortkey(int flags, const WC key_len[0] = key_len[1] = key_len[2] = key_len[3] = 0; 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) { int i; @@ -56,24 +57,24 @@ int wine_get_sortkey(int flags, const WC if (flags & NORM_IGNORECASE) wch = tolowerW(wch); - ce = collation_table[collation_table[wch >> 8] + (wch & 0xff)]; + ce = unicode_collation_table[unicode_collation_table[wch >> 8] + (wch & 0xff)]; if (ce != (unsigned int)-1) { if (ce >> 16) key_len[0] += 2; if ((ce >> 8) & 0xff) key_len[1]++; if ((ce >> 4) & 0x0f) key_len[2]++; - /*if (ce & 1) + if (ce & 1) { if (wch >> 8) key_len[3]++; key_len[3]++; - }*/ + } } - /*else + else { key_len[0] += 2; if (wch >> 8) key_len[0]++; if (wch & 0xff) key_len[0]++; - }*/ + } } } } @@ -95,7 +96,8 @@ int wine_get_sortkey(int flags, const WC 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) { int i; @@ -113,7 +115,7 @@ int wine_get_sortkey(int flags, const WC if (flags & NORM_IGNORECASE) wch = tolowerW(wch); - ce = collation_table[collation_table[wch >> 8] + (wch & 0xff)]; + ce = unicode_collation_table[unicode_collation_table[wch >> 8] + (wch & 0xff)]; if (ce != (unsigned int)-1) { WCHAR key; @@ -127,19 +129,19 @@ int wine_get_sortkey(int flags, const WC /* make key 2 start from 2 */ if ((key = (ce >> 4) & 0x0f)) *key_ptr[2]++ = key + 1; /* key 3 is always a character code */ - /*if (ce & 1) + if (ce & 1) { if (wch >> 8) *key_ptr[3]++ = wch >> 8; if (wch & 0xff) *key_ptr[3]++ = wch & 0xff; - }*/ + } } - /*else + else { *key_ptr[0]++ = 0xff; *key_ptr[0]++ = 0xfe; if (wch >> 8) *key_ptr[0]++ = wch >> 8; if (wch & 0xff) *key_ptr[0]++ = wch & 0xff; - }*/ + } } } } @@ -151,4 +153,201 @@ int wine_get_sortkey(int flags, const WC *key_ptr[3] = 0; return key_ptr[3] - dst; +} + +static inline int compare_unicode_weights(int flags, const WCHAR *str1, int len1, + const WCHAR *str2, int len2) +{ + extern const unsigned int unicode_collation_table[]; + 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)) + { + int skip = 0; + if (*str1 == '-' || *str1 == '\'') + { + str1++; + len1--; + skip = 1; + } + if (*str2 == '-' || *str2 == '\'') + { + str2++; + len2--; + skip = 1; + } + if (skip) continue; + } + + ce1 = unicode_collation_table[unicode_collation_table[*str1 >> 8] + (*str1 & 0xff)]; + ce2 = unicode_collation_table[unicode_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) +{ + extern const unsigned int unicode_collation_table[]; + 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 = unicode_collation_table[unicode_collation_table[*str1 >> 8] + (*str1 & 0xff)]; + ce2 = unicode_collation_table[unicode_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) +{ + extern const unsigned int unicode_collation_table[]; + 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 = unicode_collation_table[unicode_collation_table[*str1 >> 8] + (*str1 & 0xff)]; + ce2 = unicode_collation_table[unicode_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; } diff -u cvs/hq/wine/libs/unicode/string.c wine/libs/unicode/string.c --- cvs/hq/wine/libs/unicode/string.c Mon Jul 21 19:06:51 2003 +++ wine/libs/unicode/string.c Mon Nov 3 18:05:16 2003 @@ -27,7 +27,7 @@ int strcmpiW( const WCHAR *str1, const W { for (;;) { - int ret = toupperW(*str1) - toupperW(*str2); + int ret = tolowerW(*str1) - tolowerW(*str2); if (ret || !*str1) return ret; str1++; str2++; @@ -38,7 +38,7 @@ int strncmpiW( const WCHAR *str1, const { int ret = 0; for ( ; n > 0; n--, str1++, str2++) - if ((ret = toupperW(*str1) - toupperW(*str2)) || !*str1) break; + if ((ret = tolowerW(*str1) - tolowerW(*str2)) || !*str1) break; return ret; } diff -u cvs/hq/wine/libs/unicode/wine_unicode.def wine/libs/unicode/wine_unicode.def --- cvs/hq/wine/libs/unicode/wine_unicode.def Mon Oct 20 13:17:22 2003 +++ wine/libs/unicode/wine_unicode.def Mon Nov 3 18:05:16 2003 @@ -12,6 +12,7 @@ EXPORTS vsprintfW wine_casemap_lower wine_casemap_upper + wine_compare_string wine_cp_enum_table wine_cp_get_table wine_cp_mbstowcs