libfreerdp-utils: fix unicode conversion

This commit is contained in:
Marc-André Moreau 2012-12-16 23:00:40 -05:00
parent 15eb66a707
commit a02090c09b
5 changed files with 111 additions and 254 deletions

View File

@ -125,7 +125,7 @@ BOOL ntlm_client_make_spn(rdpNtlm* ntlm, LPCTSTR ServiceClass, char* hostname)
#ifdef UNICODE
length = strlen(hostname);
hostnameX = (LPWSTR) malloc(length * sizeof(TCHAR));
MultiByteToWideChar(CP_ACP, 0, hostname, length, hostnameX, length);
MultiByteToWideChar(CP_UTF8, 0, hostname, length, hostnameX, length);
hostnameX[length] = 0;
#else
hostnameX = hostname;

View File

@ -144,7 +144,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp)
#ifdef UNICODE
credssp->ServicePrincipalName = (LPTSTR) malloc(length * 2 + 2);
MultiByteToWideChar(CP_ACP, 0, spn, length,
MultiByteToWideChar(CP_UTF8, 0, spn, length,
(LPWSTR) credssp->ServicePrincipalName, length);
free(spn);
#else

View File

@ -30,264 +30,35 @@
#include <winpr/crt.h>
/**
* This is a temporary copy of the old buggy implementations of
* MultiByteToWideChar and WideCharToMultiByte
*/
#if 1
#define _MultiByteToWideChar old_MultiByteToWideChar
#define _WideCharToMultiByte old_WideCharToMultiByte
#else
#define _MultiByteToWideChar MultiByteToWideChar
#define _WideCharToMultiByte WideCharToMultiByte
#endif
int old_MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar)
{
size_t ibl;
size_t obl;
char* pin;
char* pout;
char* pout0;
if (lpMultiByteStr == NULL)
return 0;
if (cbMultiByte < 0)
cbMultiByte = strlen(lpMultiByteStr) + 1;
ibl = cbMultiByte;
obl = 2 * ibl;
if (cchWideChar < 1)
return (obl / 2);
pin = (char*) lpMultiByteStr;
pout0 = (char*) lpWideCharStr;
pout = pout0;
#ifdef HAVE_ICONV
{
iconv_t* out_iconv_h;
out_iconv_h = iconv_open(WINDOWS_CODEPAGE, DEFAULT_CODEPAGE);
if (errno == EINVAL)
{
printf("Error opening iconv converter to %s from %s\n", WINDOWS_CODEPAGE, DEFAULT_CODEPAGE);
return 0;
}
if (iconv(out_iconv_h, (ICONV_CONST char **) &pin, &ibl, &pout, &obl) == (size_t) - 1)
{
printf("MultiByteToWideChar: iconv() error\n");
return NULL;
}
iconv_close(out_iconv_h);
}
#else
while ((ibl > 0) && (obl > 0))
{
unsigned int wc;
wc = (unsigned int) (unsigned char) (*pin++);
ibl--;
if (wc >= 0xF0)
{
wc = (wc - 0xF0) << 18;
wc += ((unsigned int) (unsigned char) (*pin++) - 0x80) << 12;
wc += ((unsigned int) (unsigned char) (*pin++) - 0x80) << 6;
wc += ((unsigned int) (unsigned char) (*pin++) - 0x80);
ibl -= 3;
}
else if (wc >= 0xE0)
{
wc = (wc - 0xE0) << 12;
wc += ((unsigned int) (unsigned char) (*pin++) - 0x80) << 6;
wc += ((unsigned int) (unsigned char) (*pin++) - 0x80);
ibl -= 2;
}
else if (wc >= 0xC0)
{
wc = (wc - 0xC0) << 6;
wc += ((unsigned int) (unsigned char) (*pin++) - 0x80);
ibl -= 1;
}
if (wc <= 0xFFFF)
{
*pout++ = (char) (wc & 0xFF);
*pout++ = (char) (wc >> 8);
obl -= 2;
}
else
{
wc -= 0x10000;
*pout++ = (char) ((wc >> 10) & 0xFF);
*pout++ = (char) ((wc >> 18) + 0xD8);
*pout++ = (char) (wc & 0xFF);
*pout++ = (char) (((wc >> 8) & 0x03) + 0xDC);
obl -= 4;
}
}
#endif
if (ibl > 0)
{
printf("MultiByteToWideChar: string not fully converted - %d chars left\n", (int) ibl);
return 0;
}
return (pout - pout0) / 2;
}
/*
* Conversion *from* Unicode
* WideCharToMultiByte: http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130/
*/
int old_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
{
char* pout;
char* conv_pout;
size_t conv_in_len;
size_t conv_out_len;
unsigned char* conv_pin;
/*
* if cbMultiByte is set to 0, the function returns the required buffer size
* for lpMultiByteStr and makes no use of the output parameter itself.
*/
if (cbMultiByte == 0)
return lstrlenW(lpWideCharStr);
/* If cchWideChar is set to 0, the function fails */
if (cchWideChar == 0)
return 0;
/* cchWideChar is set to -1 if the string is null-terminated */
if (cchWideChar == -1)
cchWideChar = lstrlenW(lpWideCharStr);
conv_pin = (unsigned char*) lpWideCharStr;
conv_in_len = cchWideChar * 2;
pout = lpMultiByteStr;
conv_pout = pout;
conv_out_len = cchWideChar * 2;
#ifdef HAVE_ICONV
{
iconv_t* in_iconv_h;
in_iconv_h = iconv_open(DEFAULT_CODEPAGE, WINDOWS_CODEPAGE);
if (errno == EINVAL)
{
printf("Error opening iconv converter to %s from %s\n", DEFAULT_CODEPAGE, WINDOWS_CODEPAGE);
return 0;
}
if (iconv(in_iconv_h, (ICONV_CONST char **) &conv_pin, &conv_in_len, &conv_pout, &conv_out_len) == (size_t) - 1)
{
printf("WideCharToMultiByte: iconv failure\n");
return 0;
}
iconv_close(in_iconv_h);
}
#else
while (conv_in_len >= 2)
{
unsigned int wc;
wc = (unsigned int) (unsigned char) (*conv_pin++);
wc += ((unsigned int) (unsigned char) (*conv_pin++)) << 8;
conv_in_len -= 2;
if (wc >= 0xD800 && wc <= 0xDFFF && conv_in_len >= 2)
{
/* Code points U+10000 to U+10FFFF using surrogate pair */
wc = ((wc - 0xD800) << 10) + 0x10000;
wc += (unsigned int) (unsigned char) (*conv_pin++);
wc += ((unsigned int) (unsigned char) (*conv_pin++) - 0xDC) << 8;
conv_in_len -= 2;
}
if (wc <= 0x7F)
{
*conv_pout++ = (char) wc;
conv_out_len--;
}
else if (wc <= 0x07FF)
{
*conv_pout++ = (char) (0xC0 + (wc >> 6));
*conv_pout++ = (char) (0x80 + (wc & 0x3F));
conv_out_len -= 2;
}
else if (wc <= 0xFFFF)
{
*conv_pout++ = (char) (0xE0 + (wc >> 12));
*conv_pout++ = (char) (0x80 + ((wc >> 6) & 0x3F));
*conv_pout++ = (char) (0x80 + (wc & 0x3F));
conv_out_len -= 3;
}
else
{
*conv_pout++ = (char) (0xF0 + (wc >> 18));
*conv_pout++ = (char) (0x80 + ((wc >> 12) & 0x3F));
*conv_pout++ = (char) (0x80 + ((wc >> 6) & 0x3F));
*conv_pout++ = (char) (0x80 + (wc & 0x3F));
conv_out_len -= 4;
}
}
#endif
if (conv_in_len > 0)
{
printf("WideCharToMultiByte: conversion failure - %d chars left\n", (int) conv_in_len);
return 0;
}
*conv_pout = 0;
return conv_out_len;
}
int freerdp_AsciiToUnicodeAlloc(const CHAR* str, WCHAR** wstr, int length)
{
int status;
*wstr = NULL;
if (!str)
{
*wstr = NULL;
return 0;
}
if (length < 1)
length = strlen(str);
length = -1;
length = _MultiByteToWideChar(CP_UTF8, 0, str, length, NULL, 0);
*wstr = (WCHAR*) malloc((length + 1) * sizeof(WCHAR));
status = ConvertToUnicode(CP_UTF8, 0, str, length, wstr, 0);
_MultiByteToWideChar(CP_UTF8, 0, str, length, (LPWSTR) (*wstr), length * sizeof(WCHAR));
(*wstr)[length] = 0;
return length;
return status;
}
int freerdp_UnicodeToAsciiAlloc(const WCHAR* wstr, CHAR** str, int length)
{
*str = malloc((length * 2) + 1);
memset(*str, 0, (length * 2) + 1);
int status;
_WideCharToMultiByte(CP_UTF8, 0, wstr, length, *str, length, NULL, NULL);
(*str)[length] = 0;
if (length < 1)
{
*str = malloc(1);
(*str)[0] = '\0';
return 0;
}
return length;
status = ConvertFromUnicode(CP_UTF8, 0, wstr, -1, str, 0, NULL, NULL);
return status;
}

View File

@ -130,12 +130,6 @@ WINPR_API BOOL IsCharLowerW(WCHAR ch);
#define IsCharLower IsCharLowerA
#endif
WINPR_API int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
WINPR_API int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
WINPR_API int lstrlenA(LPCSTR lpString);
WINPR_API int lstrlenW(LPCWSTR lpString);
@ -156,6 +150,14 @@ WINPR_API int lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2);
#define sprintf_s snprintf
/* Unicode Conversion */
WINPR_API int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
WINPR_API int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
#else
#define _wcscmp wcscmp
@ -164,4 +166,12 @@ WINPR_API int lstrcmpW(LPCWSTR lpString1, LPCWSTR lpString2);
#endif
/* Extended API */
WINPR_API int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
int cbMultiByte, LPWSTR* lpWideCharStr, int cchWideChar);
WINPR_API int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
#endif /* WINPR_CRT_STRING_H */

View File

@ -275,3 +275,79 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int
#endif
int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
int cbMultiByte, LPWSTR* lpWideCharStr, int cchWideChar)
{
int status;
BOOL allocate = FALSE;
if (!lpMultiByteStr)
return 0;
if (!lpWideCharStr)
return 0;
if (cbMultiByte == -1)
cbMultiByte = strlen(lpMultiByteStr) + 1;
if (cchWideChar == 0)
{
cchWideChar = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, NULL, 0);
allocate = TRUE;
}
if (cchWideChar < 1)
return 0;
if (!(*lpWideCharStr))
allocate = TRUE;
if (allocate)
*lpWideCharStr = (LPWSTR) malloc(cchWideChar * sizeof(WCHAR));
status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr, cchWideChar);
if (status != cchWideChar)
status = 0;
return status;
}
int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar,
LPSTR* lpMultiByteStr, int cbMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)
{
int status;
BOOL allocate = FALSE;
if (!lpWideCharStr)
return 0;
if (!lpMultiByteStr)
return 0;
if (cchWideChar == -1)
cchWideChar = _wcslen(lpWideCharStr) + 1;
if (cbMultiByte == 0)
{
cbMultiByte = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, NULL, 0, NULL, NULL);
allocate = TRUE;
}
if (cbMultiByte < 1)
return 0;
if (!(*lpMultiByteStr))
allocate = TRUE;
if (allocate)
*lpMultiByteStr = (LPSTR) malloc(cbMultiByte);
status = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar,
*lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
if (status != cbMultiByte)
status = 0;
return status;
}