Commit 098e71ad authored by Alexandre Julliard's avatar Alexandre Julliard

kernel32: Move the CompareString functions to kernelbase.

parent 94a3add0
......@@ -239,10 +239,10 @@
@ stdcall CommConfigDialogW(wstr long ptr)
# @ stub CompareCalendarDates
@ stdcall -import CompareFileTime(ptr ptr)
@ stdcall CompareStringA(long long str long str long)
@ stdcall CompareStringW(long long wstr long wstr long)
@ stdcall CompareStringEx(wstr long wstr long wstr long ptr ptr long)
@ stdcall -import CompareStringA(long long str long str long)
@ stdcall -import CompareStringEx(wstr long wstr long wstr long ptr ptr long)
@ stdcall -import CompareStringOrdinal(wstr long wstr long long)
@ stdcall -import CompareStringW(long long wstr long wstr long)
@ stdcall -import ConnectNamedPipe(long ptr)
@ stub ConsoleMenuControl
@ stub ConsoleSubst
......@@ -502,8 +502,8 @@
@ stub FindNextVolumeMountPointA
@ stub FindNextVolumeMountPointW
@ stdcall FindNextVolumeW(long ptr long)
# @ stub FindNLSString
@ stdcall FindNLSStringEx(wstr long wstr long wstr long ptr ptr ptr long)
@ stdcall -import FindNLSString(long long wstr long wstr long ptr)
@ stdcall -import FindNLSStringEx(wstr long wstr long wstr long ptr ptr ptr long)
@ stdcall FindResourceA(long str str)
@ stdcall FindResourceExA(long str str long)
@ stdcall -import FindResourceExW(long wstr wstr long)
......
......@@ -445,153 +445,6 @@ FoldStringA_exit:
return ret;
}
/******************************************************************************
* CompareStringW (KERNEL32.@)
*
* See CompareStringA.
*/
INT WINAPI CompareStringW(LCID lcid, DWORD flags,
LPCWSTR str1, INT len1, LPCWSTR str2, INT len2)
{
return CompareStringEx(NULL, flags, str1, len1, str2, len2, NULL, NULL, 0);
}
/******************************************************************************
* CompareStringEx (KERNEL32.@)
*/
INT WINAPI CompareStringEx(LPCWSTR locale, DWORD flags, LPCWSTR str1, INT len1,
LPCWSTR str2, INT len2, LPNLSVERSIONINFO version, LPVOID reserved, LPARAM lParam)
{
DWORD supported_flags = NORM_IGNORECASE|NORM_IGNORENONSPACE|NORM_IGNORESYMBOLS|SORT_STRINGSORT
|NORM_IGNOREKANATYPE|NORM_IGNOREWIDTH|LOCALE_USE_CP_ACP;
DWORD semistub_flags = NORM_LINGUISTIC_CASING|LINGUISTIC_IGNORECASE|0x10000000;
/* 0x10000000 is related to diacritics in Arabic, Japanese, and Hebrew */
INT ret;
static int once;
if (version) FIXME("unexpected version parameter\n");
if (reserved) FIXME("unexpected reserved value\n");
if (lParam) FIXME("unexpected lParam\n");
if (!str1 || !str2)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (flags & ~(supported_flags|semistub_flags))
{
SetLastError(ERROR_INVALID_FLAGS);
return 0;
}
if (flags & semistub_flags)
{
if (!once++)
FIXME("semi-stub behavior for flag(s) 0x%x\n", flags & semistub_flags);
}
if (len1 < 0) len1 = strlenW(str1);
if (len2 < 0) len2 = strlenW(str2);
ret = wine_compare_string(flags, str1, len1, str2, len2);
if (ret) /* need to translate result */
return (ret < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN;
return CSTR_EQUAL;
}
/******************************************************************************
* CompareStringA (KERNEL32.@)
*
* Compare two locale sensitive strings.
*
* PARAMS
* lcid [I] LCID for the comparison
* flags [I] Flags for the comparison (NORM_ constants from "winnls.h").
* str1 [I] First string to compare
* len1 [I] Length of str1, or -1 if str1 is NUL terminated
* str2 [I] Second string to compare
* len2 [I] Length of str2, or -1 if str2 is NUL terminated
*
* RETURNS
* Success: CSTR_LESS_THAN, CSTR_EQUAL or CSTR_GREATER_THAN depending on whether
* str1 is less than, equal to or greater than str2 respectively.
* Failure: FALSE. Use GetLastError() to determine the cause.
*/
INT WINAPI CompareStringA(LCID lcid, DWORD flags,
LPCSTR str1, INT len1, LPCSTR str2, INT len2)
{
WCHAR *buf1W = NtCurrentTeb()->StaticUnicodeBuffer;
WCHAR *buf2W = buf1W + 130;
LPWSTR str1W, str2W;
INT len1W = 0, len2W = 0, ret;
UINT locale_cp = CP_ACP;
if (!str1 || !str2)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (len1 < 0) len1 = strlen(str1);
if (len2 < 0) len2 = strlen(str2);
if (!(flags & LOCALE_USE_CP_ACP)) locale_cp = get_lcid_codepage( lcid );
if (len1)
{
if (len1 <= 130) len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, buf1W, 130);
if (len1W)
str1W = buf1W;
else
{
len1W = MultiByteToWideChar(locale_cp, 0, str1, len1, NULL, 0);
str1W = HeapAlloc(GetProcessHeap(), 0, len1W * sizeof(WCHAR));
if (!str1W)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
MultiByteToWideChar(locale_cp, 0, str1, len1, str1W, len1W);
}
}
else
{
len1W = 0;
str1W = buf1W;
}
if (len2)
{
if (len2 <= 130) len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, buf2W, 130);
if (len2W)
str2W = buf2W;
else
{
len2W = MultiByteToWideChar(locale_cp, 0, str2, len2, NULL, 0);
str2W = HeapAlloc(GetProcessHeap(), 0, len2W * sizeof(WCHAR));
if (!str2W)
{
if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W);
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
MultiByteToWideChar(locale_cp, 0, str2, len2, str2W, len2W);
}
}
else
{
len2W = 0;
str2W = buf2W;
}
ret = CompareStringEx(NULL, flags, str1W, len1W, str2W, len2W, NULL, NULL, 0);
if (str1W != buf1W) HeapFree(GetProcessHeap(), 0, str1W);
if (str2W != buf2W) HeapFree(GetProcessHeap(), 0, str2W);
return ret;
}
static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName)
{
UNICODE_STRING keyName;
......@@ -1900,54 +1753,3 @@ BOOL WINAPI GetFileMUIInfo(DWORD flags, PCWSTR path, FILEMUIINFO *info, DWORD *s
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/******************************************************************************
* FindNLSStringEx (KERNEL32.@)
*/
INT WINAPI FindNLSStringEx(const WCHAR *localename, DWORD flags, const WCHAR *src,
INT src_size, const WCHAR *value, INT value_size,
INT *found, NLSVERSIONINFO *version_info, void *reserved,
LPARAM sort_handle)
{
/* FIXME: this function should normalize strings before calling CompareStringEx() */
DWORD mask = flags;
int offset, inc, count;
TRACE("%s %x %s %d %s %d %p %p %p %ld\n", wine_dbgstr_w(localename), flags,
wine_dbgstr_w(src), src_size, wine_dbgstr_w(value), value_size, found,
version_info, reserved, sort_handle);
if (version_info != NULL || reserved != NULL || sort_handle != 0 ||
!IsValidLocaleName(localename) || src == NULL || src_size == 0 ||
src_size < -1 || value == NULL || value_size == 0 || value_size < -1)
{
SetLastError(ERROR_INVALID_PARAMETER);
return -1;
}
if (src_size == -1)
src_size = strlenW(src);
if (value_size == -1)
value_size = strlenW(value);
src_size -= value_size;
if (src_size < 0) return -1;
mask = flags & ~(FIND_FROMSTART | FIND_FROMEND | FIND_STARTSWITH | FIND_ENDSWITH);
count = flags & (FIND_FROMSTART | FIND_FROMEND) ? src_size + 1 : 1;
offset = flags & (FIND_FROMSTART | FIND_STARTSWITH) ? 0 : src_size;
inc = flags & (FIND_FROMSTART | FIND_STARTSWITH) ? 1 : -1;
while (count--)
{
if (CompareStringEx(localename, mask, src + offset, value_size, value, value_size, NULL, NULL, 0) == CSTR_EQUAL)
{
if (found)
*found = value_size;
return offset;
}
offset += inc;
}
return -1;
}
......@@ -153,10 +153,10 @@
# @ stub CommitStateAtom
@ stdcall CompareFileTime(ptr ptr)
# @ stub CompareObjectHandles
@ stdcall CompareStringA(long long str long str long) kernel32.CompareStringA
@ stdcall CompareStringEx(wstr long wstr long wstr long ptr ptr long) kernel32.CompareStringEx
@ stdcall CompareStringA(long long str long str long)
@ stdcall CompareStringEx(wstr long wstr long wstr long ptr ptr long)
@ stdcall CompareStringOrdinal(wstr long wstr long long)
@ stdcall CompareStringW(long long wstr long wstr long) kernel32.CompareStringW
@ stdcall CompareStringW(long long wstr long wstr long)
@ stdcall ConnectNamedPipe(long ptr)
@ stdcall ContinueDebugEvent(long long long)
@ stdcall ConvertDefaultLocale(long)
......@@ -362,8 +362,8 @@
@ stdcall FindFirstFreeAce(ptr ptr)
@ stdcall FindFirstStreamW(wstr long ptr long) kernel32.FindFirstStreamW
@ stdcall FindFirstVolumeW(ptr long) kernel32.FindFirstVolumeW
@ stub FindNLSString
@ stdcall FindNLSStringEx(wstr long wstr long wstr long ptr ptr ptr long) kernel32.FindNLSStringEx
@ stdcall FindNLSString(long long wstr long wstr long ptr)
@ stdcall FindNLSStringEx(wstr long wstr long wstr long ptr ptr ptr long)
@ stdcall FindNextChangeNotification(long)
@ stdcall FindNextFileA(long ptr) kernel32.FindNextFileA
# @ stub FindNextFileNameW
......
......@@ -1805,6 +1805,125 @@ static int map_to_halfwidth( WCHAR c, WCHAR *dst, int dstlen )
}
/* 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.
*/
enum weight { UNICODE_WEIGHT, DIACRITIC_WEIGHT, CASE_WEIGHT };
static unsigned int get_weight( WCHAR ch, enum weight type )
{
unsigned int ret = collation_table[collation_table[ch >> 8] + (ch & 0xff)];
if (ret == (unsigned int)-1) return ch;
switch (type)
{
case UNICODE_WEIGHT: return ret >> 16;
case DIACRITIC_WEIGHT: return (ret >> 8) & 0xff;
case CASE_WEIGHT: return (ret >> 4) & 0x0f;
default: return 0;
}
}
static void inc_str_pos( const WCHAR **str, int *len, int *dpos, int *dlen )
{
(*dpos)++;
if (*dpos == *dlen)
{
*dpos = *dlen = 0;
(*str)++;
(*len)--;
}
}
static int compare_weights(int flags, const WCHAR *str1, int len1,
const WCHAR *str2, int len2, enum weight type )
{
int dpos1 = 0, dpos2 = 0, dlen1 = 0, dlen2 = 0;
WCHAR dstr1[4], dstr2[4];
unsigned int ce1, ce2;
while (len1 > 0 && len2 > 0)
{
if (!dlen1) dlen1 = wine_decompose( 0, *str1, dstr1, 4 );
if (!dlen2) dlen2 = wine_decompose( 0, *str2, dstr2, 4 );
if (flags & NORM_IGNORESYMBOLS)
{
int skip = 0;
/* FIXME: not tested */
if (get_table_entry( wctype_table, dstr1[dpos1] ) & (C1_PUNCT | C1_SPACE))
{
inc_str_pos( &str1, &len1, &dpos1, &dlen1 );
skip = 1;
}
if (get_table_entry( wctype_table, dstr2[dpos1] ) & (C1_PUNCT | C1_SPACE))
{
inc_str_pos( &str2, &len2, &dpos2, &dlen2 );
skip = 1;
}
if (skip) continue;
}
/* hyphen and apostrophe are treated differently depending on
* whether SORT_STRINGSORT specified or not
*/
if (type == UNICODE_WEIGHT && !(flags & SORT_STRINGSORT))
{
if (dstr1[dpos1] == '-' || dstr1[dpos1] == '\'')
{
if (dstr2[dpos2] != '-' && dstr2[dpos2] != '\'')
{
inc_str_pos( &str1, &len1, &dpos1, &dlen1 );
continue;
}
}
else if (dstr2[dpos2] == '-' || dstr2[dpos2] == '\'')
{
inc_str_pos( &str2, &len2, &dpos2, &dlen2 );
continue;
}
}
ce1 = get_weight( dstr1[dpos1], type );
if (!ce1)
{
inc_str_pos( &str1, &len1, &dpos1, &dlen1 );
continue;
}
ce2 = get_weight( dstr2[dpos2], type );
if (!ce2)
{
inc_str_pos( &str2, &len2, &dpos2, &dlen2 );
continue;
}
if (ce1 - ce2) return ce1 - ce2;
inc_str_pos( &str1, &len1, &dpos1, &dlen1 );
inc_str_pos( &str2, &len2, &dpos2, &dlen2 );
}
while (len1)
{
if (!dlen1) dlen1 = wine_decompose( 0, *str1, dstr1, 4 );
ce1 = get_weight( dstr1[dpos1], type );
if (ce1) break;
inc_str_pos( &str1, &len1, &dpos1, &dlen1 );
}
while (len2)
{
if (!dlen2) dlen2 = wine_decompose( 0, *str2, dstr2, 4 );
ce2 = get_weight( dstr2[dpos2], type );
if (ce2) break;
inc_str_pos( &str2, &len2, &dpos2, &dlen2 );
}
return len1 - len2;
}
/* Note: the Internal_ functions are not documented. The number of parameters
* should be correct, but their exact meaning may not.
*/
......@@ -2139,6 +2258,141 @@ BOOL WINAPI DECLSPEC_HOTPATCH Internal_EnumUILanguages( UILANGUAGE_ENUMPROCW pro
/******************************************************************************
* CompareStringEx (kernelbase.@)
*/
INT WINAPI CompareStringEx( const WCHAR *locale, DWORD flags, const WCHAR *str1, int len1,
const WCHAR *str2, int len2, NLSVERSIONINFO *version,
void *reserved, LPARAM handle )
{
DWORD supported_flags = NORM_IGNORECASE | NORM_IGNORENONSPACE | NORM_IGNORESYMBOLS | SORT_STRINGSORT |
NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH | LOCALE_USE_CP_ACP;
DWORD semistub_flags = NORM_LINGUISTIC_CASING | LINGUISTIC_IGNORECASE | 0x10000000;
/* 0x10000000 is related to diacritics in Arabic, Japanese, and Hebrew */
INT ret;
static int once;
if (version) FIXME( "unexpected version parameter\n" );
if (reserved) FIXME( "unexpected reserved value\n" );
if (handle) FIXME( "unexpected handle\n" );
if (!str1 || !str2)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (flags & ~(supported_flags | semistub_flags))
{
SetLastError( ERROR_INVALID_FLAGS );
return 0;
}
if (flags & semistub_flags)
{
if (!once++) FIXME( "semi-stub behavior for flag(s) 0x%x\n", flags & semistub_flags );
}
if (len1 < 0) len1 = lstrlenW(str1);
if (len2 < 0) len2 = lstrlenW(str2);
ret = compare_weights( flags, str1, len1, str2, len2, UNICODE_WEIGHT );
if (!ret)
{
if (!(flags & NORM_IGNORENONSPACE))
ret = compare_weights( flags, str1, len1, str2, len2, DIACRITIC_WEIGHT );
if (!ret && !(flags & NORM_IGNORECASE))
ret = compare_weights( flags, str1, len1, str2, len2, CASE_WEIGHT );
}
if (!ret) return CSTR_EQUAL;
return (ret < 0) ? CSTR_LESS_THAN : CSTR_GREATER_THAN;
}
/******************************************************************************
* CompareStringA (kernelbase.@)
*/
INT WINAPI DECLSPEC_HOTPATCH CompareStringA( LCID lcid, DWORD flags, const char *str1, int len1,
const char *str2, int len2 )
{
WCHAR *buf1W = NtCurrentTeb()->StaticUnicodeBuffer;
WCHAR *buf2W = buf1W + 130;
LPWSTR str1W, str2W;
INT len1W = 0, len2W = 0, ret;
UINT locale_cp = CP_ACP;
if (!str1 || !str2)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
if (len1 < 0) len1 = strlen(str1);
if (len2 < 0) len2 = strlen(str2);
locale_cp = get_lcid_codepage( lcid, flags );
if (len1)
{
if (len1 <= 130) len1W = MultiByteToWideChar( locale_cp, 0, str1, len1, buf1W, 130 );
if (len1W) str1W = buf1W;
else
{
len1W = MultiByteToWideChar( locale_cp, 0, str1, len1, NULL, 0 );
str1W = HeapAlloc( GetProcessHeap(), 0, len1W * sizeof(WCHAR) );
if (!str1W)
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
}
MultiByteToWideChar( locale_cp, 0, str1, len1, str1W, len1W );
}
}
else
{
len1W = 0;
str1W = buf1W;
}
if (len2)
{
if (len2 <= 130) len2W = MultiByteToWideChar( locale_cp, 0, str2, len2, buf2W, 130 );
if (len2W) str2W = buf2W;
else
{
len2W = MultiByteToWideChar( locale_cp, 0, str2, len2, NULL, 0 );
str2W = HeapAlloc( GetProcessHeap(), 0, len2W * sizeof(WCHAR) );
if (!str2W)
{
if (str1W != buf1W) HeapFree( GetProcessHeap(), 0, str1W );
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return 0;
}
MultiByteToWideChar( locale_cp, 0, str2, len2, str2W, len2W );
}
}
else
{
len2W = 0;
str2W = buf2W;
}
ret = CompareStringW( lcid, flags, str1W, len1W, str2W, len2W );
if (str1W != buf1W) HeapFree( GetProcessHeap(), 0, str1W );
if (str2W != buf2W) HeapFree( GetProcessHeap(), 0, str2W );
return ret;
}
/******************************************************************************
* CompareStringW (kernelbase.@)
*/
INT WINAPI DECLSPEC_HOTPATCH CompareStringW( LCID lcid, DWORD flags, const WCHAR *str1, int len1,
const WCHAR *str2, int len2 )
{
return CompareStringEx( NULL, flags, str1, len1, str2, len2, NULL, NULL, 0 );
}
/******************************************************************************
* CompareStringOrdinal (kernelbase.@)
*/
INT WINAPI DECLSPEC_HOTPATCH CompareStringOrdinal( const WCHAR *str1, INT len1,
......@@ -2422,6 +2676,64 @@ BOOL WINAPI DECLSPEC_HOTPATCH EnumTimeFormatsEx( TIMEFMT_ENUMPROCEX proc, const
}
/**************************************************************************
* FindNLSString (kernelbase.@)
*/
INT WINAPI DECLSPEC_HOTPATCH FindNLSString( LCID lcid, DWORD flags, const WCHAR *src,
int srclen, const WCHAR *value, int valuelen, int *found )
{
WCHAR locale[LOCALE_NAME_MAX_LENGTH];
LCIDToLocaleName( lcid, locale, ARRAY_SIZE(locale), 0 );
return FindNLSStringEx( locale, flags, src, srclen, value, valuelen, found, NULL, NULL, 0 );
}
/**************************************************************************
* FindNLSStringEx (kernelbase.@)
*/
INT WINAPI DECLSPEC_HOTPATCH FindNLSStringEx( const WCHAR *locale, DWORD flags, const WCHAR *src,
int srclen, const WCHAR *value, int valuelen, int *found,
NLSVERSIONINFO *version, void *reserved, LPARAM handle )
{
/* FIXME: this function should normalize strings before calling CompareStringEx() */
DWORD mask = flags;
int offset, inc, count;
TRACE( "%s %x %s %d %s %d %p %p %p %ld\n", wine_dbgstr_w(locale), flags,
wine_dbgstr_w(src), srclen, wine_dbgstr_w(value), valuelen, found,
version, reserved, handle );
if (version || reserved || handle || !IsValidLocaleName(locale) ||
!src || !srclen || srclen < -1 || !value || !valuelen || valuelen < -1)
{
SetLastError( ERROR_INVALID_PARAMETER );
return -1;
}
if (srclen == -1) srclen = lstrlenW(src);
if (valuelen == -1) valuelen = lstrlenW(value);
srclen -= valuelen;
if (srclen < 0) return -1;
mask = flags & ~(FIND_FROMSTART | FIND_FROMEND | FIND_STARTSWITH | FIND_ENDSWITH);
count = flags & (FIND_FROMSTART | FIND_FROMEND) ? srclen + 1 : 1;
offset = flags & (FIND_FROMSTART | FIND_STARTSWITH) ? 0 : srclen;
inc = flags & (FIND_FROMSTART | FIND_STARTSWITH) ? 1 : -1;
while (count--)
{
if (CompareStringEx( locale, mask, src + offset, valuelen,
value, valuelen, NULL, NULL, 0 ) == CSTR_EQUAL)
{
if (found) *found = valuelen;
return offset;
}
offset += inc;
}
return -1;
}
/******************************************************************************
* FindStringOrdinal (kernelbase.@)
*/
......
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