Various CompareString fixes

Dmitry Timoshkov dmitry at baikal.ru
Mon Nov 3 07:55:59 CST 2003


Hello,

now all is remaining is a collation table patch to make it
MS compatible.

Changelog:
    Dmitry Timoshkov <dmitry at codeweavers.com>
    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






More information about the wine-patches mailing list