diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 04fa5f2e7a3..1fe129ae249 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1096,7 +1096,7 @@ @ stdcall MoveFileWithProgressA(str str ptr ptr long) @ stdcall MoveFileWithProgressW(wstr wstr ptr ptr long) @ stdcall MulDiv(long long long) -@ stdcall MultiByteToWideChar(long long str long ptr long) +@ stdcall -import MultiByteToWideChar(long long str long ptr long) @ stdcall -import NeedCurrentDirectoryForExePathA(str) @ stdcall -import NeedCurrentDirectoryForExePathW(wstr) # @ stub NlsCheckPolicy @@ -1601,7 +1601,7 @@ # @ stub WerpNotifyLoadStringResourceEx # @ stub WerpNotifyUseStringResource # @ stub WerpStringLookup -@ stdcall WideCharToMultiByte(long long wstr long ptr long ptr ptr) +@ stdcall -import WideCharToMultiByte(long long wstr long ptr long ptr ptr) @ stdcall WinExec(str long) @ stdcall Wow64EnableWow64FsRedirection(long) KERNEL32_Wow64EnableWow64FsRedirection @ stdcall -import Wow64DisableWow64FsRedirection(ptr) diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h index 184c0dad3f4..797b8809bdb 100644 --- a/dlls/kernel32/kernel_private.h +++ b/dlls/kernel32/kernel_private.h @@ -72,9 +72,6 @@ extern void ENV_CopyStartupInformation(void) DECLSPEC_HIDDEN; /* computername.c */ extern void COMPUTERNAME_Init(void) DECLSPEC_HIDDEN; -/* locale.c */ -extern void LOCALE_Init(void) DECLSPEC_HIDDEN; - /* time.c */ extern void TIMEZONE_InitRegistry(void) DECLSPEC_HIDDEN; diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index 02f982966e9..bf77d9af79c 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -50,9 +50,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(nls); #define LOCALE_LOCALEINFOFLAGSMASK (LOCALE_NOUSEROVERRIDE|LOCALE_USE_CP_ACP|\ LOCALE_RETURN_NUMBER|LOCALE_RETURN_GENITIVE_NAMES) -#define MB_FLAGSMASK (MB_PRECOMPOSED|MB_COMPOSITE|MB_USEGLYPHCHARS|MB_ERR_INVALID_CHARS) -#define WC_FLAGSMASK (WC_DISCARDNS|WC_SEPCHARS|WC_DEFAULTCHAR|WC_ERR_INVALID_CHARS|\ - WC_COMPOSITECHECK|WC_NO_BEST_FIT_CHARS) extern BOOL WINAPI Internal_EnumCalendarInfo( CALINFO_ENUMPROCW proc, LCID lcid, CALID id, CALTYPE type, BOOL unicode, BOOL ex, @@ -69,12 +66,6 @@ extern BOOL WINAPI Internal_EnumTimeFormats( TIMEFMT_ENUMPROCW proc, LCID lcid, extern BOOL WINAPI Internal_EnumUILanguages( UILANGUAGE_ENUMPROCW proc, DWORD flags, LONG_PTR param, BOOL unicode ); -/* current code pages */ -static const union cptable *ansi_cptable; -static const union cptable *oem_cptable; -static const union cptable *mac_cptable; -static const union cptable *unix_cptable; /* NULL if UTF8 */ - static const WCHAR iCalendarTypeW[] = {'i','C','a','l','e','n','d','a','r','T','y','p','e',0}; static const WCHAR iCountryW[] = {'i','C','o','u','n','t','r','y',0}; static const WCHAR iCurrDigitsW[] = {'i','C','u','r','r','D','i','g','i','t','s',0}; @@ -199,44 +190,6 @@ static inline UINT get_lcid_codepage( LCID lcid ) } -/*********************************************************************** - * get_codepage_table - * - * Find the table for a given codepage, handling CP_ACP etc. pseudo-codepages - */ -static const union cptable *get_codepage_table( unsigned int codepage ) -{ - const union cptable *ret = NULL; - - assert( ansi_cptable ); /* init must have been done already */ - - switch(codepage) - { - case CP_ACP: - return ansi_cptable; - case CP_OEMCP: - return oem_cptable; - case CP_MACCP: - return mac_cptable; - case CP_UTF7: - case CP_UTF8: - break; - case CP_THREAD_ACP: - if (NtCurrentTeb()->CurrentLocale == GetUserDefaultLCID()) return ansi_cptable; - codepage = get_lcid_codepage( NtCurrentTeb()->CurrentLocale ); - if (!codepage) return ansi_cptable; - /* fall through */ - default: - if (codepage == ansi_cptable->info.codepage) return ansi_cptable; - if (codepage == oem_cptable->info.codepage) return oem_cptable; - if (codepage == mac_cptable->info.codepage) return mac_cptable; - ret = wine_cp_get_table( codepage ); - break; - } - return ret; -} - - /*********************************************************************** * is_genitive_name_supported * @@ -905,518 +858,6 @@ BOOL WINAPI EnumSystemCodePagesA( CODEPAGE_ENUMPROCA proc, DWORD flags ) } -/*********************************************************************** - * utf7_write_w - * - * Helper for utf7_mbstowcs - * - * RETURNS - * TRUE on success, FALSE on error - */ -static inline BOOL utf7_write_w(WCHAR *dst, int dstlen, int *index, WCHAR character) -{ - if (dstlen > 0) - { - if (*index >= dstlen) - return FALSE; - - dst[*index] = character; - } - - (*index)++; - - return TRUE; -} - -/*********************************************************************** - * utf7_mbstowcs - * - * UTF-7 to UTF-16 string conversion, helper for MultiByteToWideChar - * - * RETURNS - * On success, the number of characters written - * On dst buffer overflow, -1 - */ -static int utf7_mbstowcs(const char *src, int srclen, WCHAR *dst, int dstlen) -{ - static const signed char base64_decoding_table[] = - { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0F */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1F */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20-0x2F */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30-0x3F */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40-0x4F */ - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50-0x5F */ - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60-0x6F */ - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70-0x7F */ - }; - - const char *source_end = src + srclen; - int dest_index = 0; - - DWORD byte_pair = 0; - short offset = 0; - - while (src < source_end) - { - if (*src == '+') - { - src++; - if (src >= source_end) - break; - - if (*src == '-') - { - /* just a plus sign escaped as +- */ - if (!utf7_write_w(dst, dstlen, &dest_index, '+')) - return -1; - src++; - continue; - } - - do - { - signed char sextet = *src; - if (sextet == '-') - { - /* skip over the dash and end base64 decoding - * the current, unfinished byte pair is discarded */ - src++; - offset = 0; - break; - } - if (sextet < 0) - { - /* the next character of src is < 0 and therefore not part of a base64 sequence - * the current, unfinished byte pair is NOT discarded in this case - * this is probably a bug in Windows */ - break; - } - - sextet = base64_decoding_table[sextet]; - if (sextet == -1) - { - /* -1 means that the next character of src is not part of a base64 sequence - * in other words, all sextets in this base64 sequence have been processed - * the current, unfinished byte pair is discarded */ - offset = 0; - break; - } - - byte_pair = (byte_pair << 6) | sextet; - offset += 6; - - if (offset >= 16) - { - /* this byte pair is done */ - if (!utf7_write_w(dst, dstlen, &dest_index, (byte_pair >> (offset - 16)) & 0xFFFF)) - return -1; - offset -= 16; - } - - src++; - } - while (src < source_end); - } - else - { - /* we have to convert to unsigned char in case *src < 0 */ - if (!utf7_write_w(dst, dstlen, &dest_index, (unsigned char)*src)) - return -1; - src++; - } - } - - return dest_index; -} - -static int mbstowcs_utf8( DWORD flags, LPCSTR src, INT srclen, LPWSTR dst, INT dstlen ) -{ - DWORD reslen; - NTSTATUS status; - - if (flags & ~MB_FLAGSMASK) - { - SetLastError( ERROR_INVALID_FLAGS ); - return 0; - } - if (!dstlen) dst = NULL; - status = RtlUTF8ToUnicodeN( dst, dstlen * sizeof(WCHAR), &reslen, src, srclen ); - if (status == STATUS_SOME_NOT_MAPPED) - { - if (flags & MB_ERR_INVALID_CHARS) - { - SetLastError( ERROR_NO_UNICODE_TRANSLATION ); - return 0; - } - } - else if (!set_ntstatus( status )) reslen = 0; - - return reslen / sizeof(WCHAR); -} - - -/*********************************************************************** - * MultiByteToWideChar (KERNEL32.@) - * - * Convert a multibyte character string into a Unicode string. - * - * PARAMS - * page [I] Codepage character set to convert from - * flags [I] Character mapping flags - * src [I] Source string buffer - * srclen [I] Length of src (in bytes), or -1 if src is NUL terminated - * dst [O] Destination buffer - * dstlen [I] Length of dst (in WCHARs), or 0 to compute the required length - * - * RETURNS - * Success: If dstlen > 0, the number of characters written to dst. - * If dstlen == 0, the number of characters needed to perform the - * conversion. In both cases the count includes the terminating NUL. - * Failure: 0. Use GetLastError() to determine the cause. Possible errors are - * ERROR_INSUFFICIENT_BUFFER, if not enough space is available in dst - * and dstlen != 0; ERROR_INVALID_PARAMETER, if an invalid parameter - * is passed, and ERROR_NO_UNICODE_TRANSLATION if no translation is - * possible for src. - */ -INT WINAPI MultiByteToWideChar( UINT page, DWORD flags, LPCSTR src, INT srclen, - LPWSTR dst, INT dstlen ) -{ - const union cptable *table; - int ret; - - if (!src || !srclen || (!dst && dstlen) || dstlen < 0) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - - if (srclen < 0) srclen = strlen(src) + 1; - - switch(page) - { - case CP_SYMBOL: - if (flags) - { - SetLastError( ERROR_INVALID_FLAGS ); - return 0; - } - ret = wine_cpsymbol_mbstowcs( src, srclen, dst, dstlen ); - break; - case CP_UTF7: - if (flags) - { - SetLastError( ERROR_INVALID_FLAGS ); - return 0; - } - ret = utf7_mbstowcs( src, srclen, dst, dstlen ); - break; - case CP_UTF8: - return mbstowcs_utf8( flags, src, srclen, dst, dstlen ); - case CP_UNIXCP: - if (unix_cptable) - { - ret = wine_cp_mbstowcs( unix_cptable, flags, src, srclen, dst, dstlen ); - break; - } - ret = mbstowcs_utf8( flags, src, srclen, dst, dstlen ); -#ifdef __APPLE__ /* work around broken Mac OS X filesystem that enforces decomposed Unicode */ - if (ret && dstlen) ret = wine_compose_string( dst, ret ); -#endif - return ret; - default: - if (!(table = get_codepage_table( page ))) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - if (flags & ~MB_FLAGSMASK) - { - SetLastError( ERROR_INVALID_FLAGS ); - return 0; - } - ret = wine_cp_mbstowcs( table, flags, src, srclen, dst, dstlen ); - break; - } - - if (ret < 0) - { - switch(ret) - { - case -1: SetLastError( ERROR_INSUFFICIENT_BUFFER ); break; - case -2: SetLastError( ERROR_NO_UNICODE_TRANSLATION ); break; - } - ret = 0; - } - TRACE("cp %d %s -> %s, ret = %d\n", - page, debugstr_an(src, srclen), debugstr_wn(dst, ret), ret); - return ret; -} - - -/*********************************************************************** - * utf7_can_directly_encode - * - * Helper for utf7_wcstombs - */ -static inline BOOL utf7_can_directly_encode(WCHAR codepoint) -{ - static const BOOL directly_encodable_table[] = - { - 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, /* 0x00 - 0x0F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1F */ - 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* 0x20 - 0x2F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x30 - 0x3F */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x50 - 0x5F */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* 0x70 - 0x7A */ - }; - - return codepoint <= 0x7A ? directly_encodable_table[codepoint] : FALSE; -} - -/*********************************************************************** - * utf7_write_c - * - * Helper for utf7_wcstombs - * - * RETURNS - * TRUE on success, FALSE on error - */ -static inline BOOL utf7_write_c(char *dst, int dstlen, int *index, char character) -{ - if (dstlen > 0) - { - if (*index >= dstlen) - return FALSE; - - dst[*index] = character; - } - - (*index)++; - - return TRUE; -} - -/*********************************************************************** - * utf7_wcstombs - * - * UTF-16 to UTF-7 string conversion, helper for WideCharToMultiByte - * - * RETURNS - * On success, the number of characters written - * On dst buffer overflow, -1 - */ -static int utf7_wcstombs(const WCHAR *src, int srclen, char *dst, int dstlen) -{ - static const char base64_encoding_table[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - const WCHAR *source_end = src + srclen; - int dest_index = 0; - - while (src < source_end) - { - if (*src == '+') - { - if (!utf7_write_c(dst, dstlen, &dest_index, '+')) - return -1; - if (!utf7_write_c(dst, dstlen, &dest_index, '-')) - return -1; - src++; - } - else if (utf7_can_directly_encode(*src)) - { - if (!utf7_write_c(dst, dstlen, &dest_index, *src)) - return -1; - src++; - } - else - { - unsigned int offset = 0; - DWORD byte_pair = 0; - - if (!utf7_write_c(dst, dstlen, &dest_index, '+')) - return -1; - - while (src < source_end && !utf7_can_directly_encode(*src)) - { - byte_pair = (byte_pair << 16) | *src; - offset += 16; - while (offset >= 6) - { - if (!utf7_write_c(dst, dstlen, &dest_index, base64_encoding_table[(byte_pair >> (offset - 6)) & 0x3F])) - return -1; - offset -= 6; - } - src++; - } - - if (offset) - { - /* Windows won't create a padded base64 character if there's no room for the - sign - * as well ; this is probably a bug in Windows */ - if (dstlen > 0 && dest_index + 1 >= dstlen) - return -1; - - byte_pair <<= (6 - offset); - if (!utf7_write_c(dst, dstlen, &dest_index, base64_encoding_table[byte_pair & 0x3F])) - return -1; - } - - /* Windows always explicitly terminates the base64 sequence - even though RFC 2152 (page 3, rule 2) does not require this */ - if (!utf7_write_c(dst, dstlen, &dest_index, '-')) - return -1; - } - } - - return dest_index; -} - -static int wcstombs_utf8( DWORD flags, LPCWSTR src, INT srclen, LPSTR dst, INT dstlen ) -{ - DWORD reslen; - NTSTATUS status; - - if (flags & ~WC_FLAGSMASK) - { - SetLastError( ERROR_INVALID_FLAGS ); - return 0; - } - if (!dstlen) dst = NULL; - status = RtlUnicodeToUTF8N( dst, dstlen, &reslen, src, srclen * sizeof(WCHAR) ); - if (status == STATUS_SOME_NOT_MAPPED) - { - if (flags & WC_ERR_INVALID_CHARS) - { - SetLastError( ERROR_NO_UNICODE_TRANSLATION ); - return 0; - } - } - else if (!set_ntstatus( status )) reslen = 0; - return reslen; -} - -/*********************************************************************** - * WideCharToMultiByte (KERNEL32.@) - * - * Convert a Unicode character string into a multibyte string. - * - * PARAMS - * page [I] Code page character set to convert to - * flags [I] Mapping Flags (MB_ constants from "winnls.h"). - * src [I] Source string buffer - * srclen [I] Length of src (in WCHARs), or -1 if src is NUL terminated - * dst [O] Destination buffer - * dstlen [I] Length of dst (in bytes), or 0 to compute the required length - * defchar [I] Default character to use for conversion if no exact - * conversion can be made - * used [O] Set if default character was used in the conversion - * - * RETURNS - * Success: If dstlen > 0, the number of characters written to dst. - * If dstlen == 0, number of characters needed to perform the - * conversion. In both cases the count includes the terminating NUL. - * Failure: 0. Use GetLastError() to determine the cause. Possible errors are - * ERROR_INSUFFICIENT_BUFFER, if not enough space is available in dst - * and dstlen != 0, and ERROR_INVALID_PARAMETER, if an invalid - * parameter was given. - */ -INT WINAPI WideCharToMultiByte( UINT page, DWORD flags, LPCWSTR src, INT srclen, - LPSTR dst, INT dstlen, LPCSTR defchar, BOOL *used ) -{ - const union cptable *table; - int ret, used_tmp; - - if (!src || !srclen || (!dst && dstlen) || dstlen < 0) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - - if (srclen < 0) srclen = strlenW(src) + 1; - - switch(page) - { - case CP_SYMBOL: - /* when using CP_SYMBOL, ERROR_INVALID_FLAGS takes precedence */ - if (flags) - { - SetLastError( ERROR_INVALID_FLAGS ); - return 0; - } - if (defchar || used) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - ret = wine_cpsymbol_wcstombs( src, srclen, dst, dstlen ); - break; - case CP_UTF7: - /* when using CP_UTF7, ERROR_INVALID_PARAMETER takes precedence */ - if (defchar || used) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - if (flags) - { - SetLastError( ERROR_INVALID_FLAGS ); - return 0; - } - ret = utf7_wcstombs( src, srclen, dst, dstlen ); - break; - case CP_UNIXCP: - if (unix_cptable) - { - ret = wine_cp_wcstombs( unix_cptable, flags, src, srclen, dst, dstlen, - defchar, used ? &used_tmp : NULL ); - if (used) *used = used_tmp; - break; - } - if (used) *used = FALSE; - return wcstombs_utf8( flags, src, srclen, dst, dstlen ); - case CP_UTF8: - if (defchar || used) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - return wcstombs_utf8( flags, src, srclen, dst, dstlen ); - default: - if (!(table = get_codepage_table( page ))) - { - SetLastError( ERROR_INVALID_PARAMETER ); - return 0; - } - if (flags & ~WC_FLAGSMASK) - { - SetLastError( ERROR_INVALID_FLAGS ); - return 0; - } - ret = wine_cp_wcstombs( table, flags, src, srclen, dst, dstlen, - defchar, used ? &used_tmp : NULL ); - if (used) *used = used_tmp; - break; - } - - if (ret < 0) - { - switch(ret) - { - case -1: SetLastError( ERROR_INSUFFICIENT_BUFFER ); break; - case -2: SetLastError( ERROR_NO_UNICODE_TRANSLATION ); break; - } - ret = 0; - } - TRACE("cp %d %s -> %s, ret = %d\n", - page, debugstr_wn(src, srclen), debugstr_an(dst, ret), ret); - return ret; -} - - /****************************************************************************** * GetStringTypeW (KERNEL32.@) * @@ -2345,36 +1786,6 @@ INT WINAPI CompareStringA(LCID lcid, DWORD flags, return ret; } -/****************************************************************************** - * LOCALE_Init - */ -void LOCALE_Init(void) -{ - extern UINT CDECL __wine_get_unix_codepage(void); - - UINT ansi_cp = 1252, oem_cp = 437, mac_cp = 10000, unix_cp; - - ansi_cp = get_lcid_codepage( LOCALE_SYSTEM_DEFAULT ); - GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTMACCODEPAGE | LOCALE_RETURN_NUMBER, - (LPWSTR)&mac_cp, sizeof(mac_cp)/sizeof(WCHAR) ); - GetLocaleInfoW( LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER, - (LPWSTR)&oem_cp, sizeof(oem_cp)/sizeof(WCHAR) ); - - if (!(ansi_cptable = wine_cp_get_table( ansi_cp ))) - ansi_cptable = wine_cp_get_table( 1252 ); - if (!(oem_cptable = wine_cp_get_table( oem_cp ))) - oem_cptable = wine_cp_get_table( 437 ); - if (!(mac_cptable = wine_cp_get_table( mac_cp ))) - mac_cptable = wine_cp_get_table( 10000 ); - - unix_cp = __wine_get_unix_codepage(); - if (unix_cp != CP_UTF8) unix_cptable = wine_cp_get_table( unix_cp ); - - TRACE( "ansi=%03d oem=%03d mac=%03d unix=%03d\n", - ansi_cptable->info.codepage, oem_cptable->info.codepage, - mac_cptable->info.codepage, unix_cp ); -} - static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName) { UNICODE_STRING keyName; diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 779c13cb54e..e5e51a93d8b 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -173,8 +173,6 @@ void * CDECL __wine_kernel_init(void) kernel32_handle = GetModuleHandleW(kernel32W); RtlSetUnhandledExceptionFilter( UnhandledExceptionFilter ); - LOCALE_Init(); - return start_process_wrapper; } diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index 92cfe5513ac..5985b14a881 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -1118,7 +1118,10 @@ static inline int is_valid_dbcs_mapping( const CPTABLEINFO *info, DWORD flags, WCHAR wch, unsigned short ch ) { if ((flags & WC_NO_BEST_FIT_CHARS) || ch == info->DefaultChar) - return info->DBCSOffsets[info->DBCSOffsets[ch >> 8] + (ch & 0xff)] == wch; + { + if (ch >> 8) return info->DBCSOffsets[info->DBCSOffsets[ch >> 8] + (ch & 0xff)] == wch; + return info->MultiByteTable[ch] == wch; + } return 1; }