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
......
......@@ -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