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,
}
}
if (srclen)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
return dst_ptr - dst;
}
......@@ -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,
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 flags, LPCSTR src, INT srclen,
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 flags, LPCSTR src, INT srclen,
}
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, LPCWSTR src, INT srclen,
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, DWORD style,
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;
}
len = (len1 < len2) ? len1 : len2;
ret = (style & NORM_IGNORECASE) ? strncmpiW(str1, str2, len) :
strncmpW(str1, str2, len);
if (style & 0x10000000)
FIXME("Ignoring unknown style 0x10000000\n");
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, DWORD style,
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, DWORD style,
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, DWORD style,
}
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
......
......@@ -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,151 @@ 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);
#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)
......@@ -834,6 +980,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 +1077,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 +1148,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 +1236,143 @@ 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());
}
#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);
}
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);
}
void test_FoldStringA(void)
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;
char src[256], dst[256];
......@@ -1118,6 +1419,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 (GetACP() != 1252)
{
trace("Skipping FoldStringA tests for a not Latin 1 locale\n");
return;
}
/* MAP_FOLDDIGITS */
SetLastError(0);
ret = pFoldStringA(MAP_FOLDDIGITS, digits_src, -1, dst, 256);
......@@ -1212,7 +1520,7 @@ void test_FoldStringA(void)
}
}
void test_FoldStringW(void)
static void test_FoldStringW(void)
{
int ret;
size_t i, j;
......@@ -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);
/* If lParam is one, we are calling with flags defaulted from 0 */
ok(!lParam || dwFlags == LGRPID_INSTALLED,
"Expected dwFlags == LGRPID_INSTALLED, got %ld\n", dwFlags);
ok(!lParam || (dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED),
"Expected dwFlags == LGRPID_INSTALLED || dwFlags == LGRPID_SUPPORTED, got %ld\n", dwFlags);
return TRUE;
}
......@@ -1710,4 +2018,7 @@ START_TEST(locale)
test_EnumSystemLanguageGroupsA();
test_EnumLanguageGroupLocalesA();
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)
char str1[3], str2[3];
str1[0] = LOBYTE(ch1);
if (IsDBCSLeadByte(ch1))
if (IsDBCSLeadByte(str1[0]))
{
str1[1] = HIBYTE(ch1);
str1[2] = '\0';
......@@ -73,7 +73,7 @@ static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
str1[1] = '\0';
str2[0] = LOBYTE(ch2);
if (IsDBCSLeadByte(ch2))
if (IsDBCSLeadByte(str2[0]))
{
str2[1] = HIBYTE(ch2);
str2[2] = '\0';
......
......@@ -156,33 +156,37 @@ static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = {
static void test_StrChrA(void)
{
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++)
string[count] = count;
string[count] = (char)count;
string[128] = '\0';
for (count = 32; count < 128; 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++)
{
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)
{
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++)
string[count] = count;
......@@ -204,12 +208,13 @@ static void test_StrChrW(void)
static void test_StrChrIA(void)
{
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++)
string[count] = count;
string[count] = (char)count;
string[128] = '\0';
for (count = 'A'; count <= 'X'; count++)
......@@ -230,9 +235,10 @@ static void test_StrChrIA(void)
static void test_StrChrIW(void)
{
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++)
string[count] = count;
......@@ -256,12 +262,13 @@ static void test_StrChrIW(void)
static void test_StrRChrA(void)
{
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++)
string[count] = count;
string[count] = (char)count;
string[128] = '\0';
for (count = 32; count < 128; count++)
......@@ -285,31 +292,34 @@ static void test_StrRChrA(void)
static void test_StrRChrW(void)
{
WCHAR string[16385];
int count;
WCHAR string[129];
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[16384] = '\0';
string[128] = '\0';
for (count = 32; count < 16384; count++)
for (count = 32; count < 128; 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);
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);
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()
static void test_StrFormatByteSize64A(void)
{
/* this test fails on locales which do not use '.' as a decimal separator */
#if 0
char szBuff[256];
const StrFormatSizeResult* result = StrFormatSize_results;
......@@ -462,10 +474,13 @@ static void test_StrFormatByteSize64A(void)
{
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++;
}
#endif
}
static void test_StrFormatKBSizeW(void)
......@@ -480,8 +495,9 @@ static void test_StrFormatKBSizeW(void)
{
StrFormatKBSizeW(result->value, szBuffW, 256);
WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0);
ok(!strcmp(result->kb_size, szBuff), "Formatted %lld wrong",
result->value);
ok(!strcmp(result->kb_size, szBuff),
"Formatted %lx%08lx wrong: got %s, expected %s\n",
(LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
result++;
}
#endif
......@@ -489,6 +505,7 @@ static void test_StrFormatKBSizeW(void)
static void test_StrFormatKBSizeA(void)
{
/* this test fails on locales which do not use '.' as a decimal separator */
#if 0
char szBuff[256];
const StrFormatSizeResult* result = StrFormatSize_results;
......@@ -497,8 +514,9 @@ static void test_StrFormatKBSizeA(void)
{
StrFormatKBSizeA(result->value, szBuff, 256);
ok(!strcmp(result->kb_size, szBuff), "Formatted %lld wrong",
result->value);
ok(!strcmp(result->kb_size, szBuff),
"Formatted %lx%08lx wrong: got %s, expected %s\n",
(LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
result++;
}
#endif
......
......@@ -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_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 );
......
......@@ -20,6 +20,7 @@
#include "wine/unicode.h"
extern int get_decomposition(WCHAR src, WCHAR *dst, unsigned int dstlen);
extern const unsigned int collation_table[];
/*
* flags - normalization NORM_* flags
......@@ -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)
{
extern const unsigned int 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 WCHAR *src, int srclen, char *dst, int dst
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;
......@@ -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 >> 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 WCHAR *src, int srclen, char *dst, int dst
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;
......@@ -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 */
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;
}*/
}
}
}
}
......@@ -152,3 +154,198 @@ int wine_get_sortkey(int flags, const WCHAR *src, int srclen, char *dst, int 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 )
{
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 WCHAR *str2, int n )
{
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;
}
......
......@@ -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
......
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