kernel32: Use MultiByteToWideChar() and WideCharToMultiByte() from kernelbase.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2019-12-07 14:47:34 +01:00
parent a2c107fca3
commit 830de63139
5 changed files with 6 additions and 597 deletions

View File

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

View File

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

View File

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

View File

@ -173,8 +173,6 @@ void * CDECL __wine_kernel_init(void)
kernel32_handle = GetModuleHandleW(kernel32W);
RtlSetUnhandledExceptionFilter( UnhandledExceptionFilter );
LOCALE_Init();
return start_process_wrapper;
}

View File

@ -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;
}