22#include <winpr/config.h>
23#include <winpr/assert.h>
29#include <winpr/error.h>
30#include <winpr/print.h>
31#include <winpr/endian.h>
150#if !defined(WITH_WINPR_DEPRECATED)
154 MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
int cbMultiByte,
155 LPWSTR lpWideCharStr,
int cchWideChar)
157 return int_MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, lpWideCharStr,
201#if !defined(WITH_WINPR_DEPRECATED)
205 WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr,
int cchWideChar,
206 LPSTR lpMultiByteStr,
int cbMultiByte, LPCSTR lpDefaultChar,
207 LPBOOL lpUsedDefaultChar)
209 return int_WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr,
210 cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
227#if defined(WITH_WINPR_DEPRECATED)
228int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
int cbMultiByte,
229 LPWSTR* lpWideCharStr,
int cchWideChar)
232 BOOL allocate = FALSE;
240 if (cbMultiByte == -1)
242 size_t len = strnlen(lpMultiByteStr, INT_MAX);
245 cbMultiByte = (int)(len + 1);
248 if (cchWideChar == 0)
251 MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte,
nullptr, 0);
254 else if (!(*lpWideCharStr))
262 *lpWideCharStr = (LPWSTR)calloc((
size_t)cchWideChar + 1ull,
sizeof(WCHAR));
264 if (!(*lpWideCharStr))
271 status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr,
274 if (status != cchWideChar)
278 free(*lpWideCharStr);
279 *lpWideCharStr =
nullptr;
300#if defined(WITH_WINPR_DEPRECATED)
301int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr,
int cchWideChar,
302 LPSTR* lpMultiByteStr,
int cbMultiByte, LPCSTR lpDefaultChar,
303 LPBOOL lpUsedDefaultChar)
306 BOOL allocate = FALSE;
314 if (cchWideChar == -1)
315 cchWideChar = (int)(_wcslen(lpWideCharStr) + 1);
317 if (cbMultiByte == 0)
319 cbMultiByte = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar,
nullptr, 0,
323 else if (!(*lpMultiByteStr))
331 *lpMultiByteStr = (LPSTR)calloc(1, (
size_t)cbMultiByte + 1ull);
333 if (!(*lpMultiByteStr))
340 status = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, *lpMultiByteStr,
341 cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
343 if ((status != cbMultiByte) && allocate)
348 if ((status <= 0) && allocate)
350 free(*lpMultiByteStr);
351 *lpMultiByteStr =
nullptr;
362const WCHAR* ByteSwapUnicode(WCHAR* wstr,
size_t length)
364 WINPR_ASSERT(wstr || (length == 0));
366 for (
size_t x = 0; x < length; x++)
367 wstr[x] = _byteswap_ushort(wstr[x]);
371SSIZE_T ConvertWCharToUtf8(
const WCHAR* wstr,
char* str,
size_t len)
380 const size_t wlen = _wcslen(wstr);
381 return ConvertWCharNToUtf8(wstr, wlen + 1, str, len);
384SSIZE_T ConvertWCharNToUtf8(
const WCHAR* wstr,
size_t wlen,
char* str,
size_t len)
386 BOOL isNullTerminated = FALSE;
391 size_t iwlen = _wcsnlen(wstr, wlen);
393 if ((len > INT32_MAX) || (wlen > INT32_MAX))
395 SetLastError(ERROR_INVALID_PARAMETER);
401 isNullTerminated = TRUE;
404 WINPR_PRAGMA_DIAG_PUSH
405 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
407 WideCharToMultiByte(CP_UTF8, 0, wstr, (
int)iwlen, str, (
int)len,
nullptr,
nullptr);
408 WINPR_PRAGMA_DIAG_POP
409 if ((rc <= 0) || ((len > 0) && ((
size_t)rc > len)))
411 else if (!isNullTerminated)
413 if (str && ((
size_t)rc < len))
417 else if ((
size_t)rc == len)
419 if (str && (str[rc - 1] !=
'\0'))
425SSIZE_T ConvertMszWCharNToUtf8(
const WCHAR* wstr,
size_t wlen,
char* str,
size_t len)
432 if ((len > INT32_MAX) || (wlen > INT32_MAX))
434 SetLastError(ERROR_INVALID_PARAMETER);
438 const int iwlen = (int)len;
439 WINPR_PRAGMA_DIAG_PUSH
440 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
441 const int rc = WideCharToMultiByte(CP_UTF8, 0, wstr, (
int)wlen, str, iwlen,
nullptr,
nullptr);
442 WINPR_PRAGMA_DIAG_POP
443 if ((rc <= 0) || ((len > 0) && (rc > iwlen)))
449SSIZE_T ConvertUtf8ToWChar(
const char* str, WCHAR* wstr,
size_t wlen)
458 const size_t len = strlen(str);
459 return ConvertUtf8NToWChar(str, len + 1, wstr, wlen);
462SSIZE_T ConvertUtf8NToWChar(
const char* str,
size_t len, WCHAR* wstr,
size_t wlen)
464 size_t ilen = strnlen(str, len);
465 BOOL isNullTerminated = FALSE;
471 if ((len > INT32_MAX) || (wlen > INT32_MAX))
473 SetLastError(ERROR_INVALID_PARAMETER);
478 isNullTerminated = TRUE;
482 const int iwlen = (int)wlen;
483 WINPR_PRAGMA_DIAG_PUSH
484 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
485 const int rc = MultiByteToWideChar(CP_UTF8, 0, str, (
int)ilen, wstr, iwlen);
486 WINPR_PRAGMA_DIAG_POP
487 if ((rc <= 0) || ((wlen > 0) && (rc > iwlen)))
489 if (!isNullTerminated)
491 if (wstr && (rc < iwlen))
495 else if (rc == iwlen)
497 if (wstr && (wstr[rc - 1] !=
'\0'))
503SSIZE_T ConvertMszUtf8NToWChar(
const char* str,
size_t len, WCHAR* wstr,
size_t wlen)
510 if ((len > INT32_MAX) || (wlen > INT32_MAX))
512 SetLastError(ERROR_INVALID_PARAMETER);
516 const int iwlen = (int)wlen;
517 WINPR_PRAGMA_DIAG_PUSH
518 WINPR_PRAGMA_DIAG_IGNORED_DEPRECATED_DECL
519 const int rc = MultiByteToWideChar(CP_UTF8, 0, str, (
int)len, wstr, iwlen);
520 WINPR_PRAGMA_DIAG_POP
521 if ((rc <= 0) || ((wlen > 0) && (rc > iwlen)))
527char* ConvertWCharToUtf8Alloc(
const WCHAR* wstr,
size_t* pUtfCharLength)
530 const SSIZE_T rc = ConvertWCharToUtf8(wstr,
nullptr, 0);
535 tmp = calloc((
size_t)rc + 1ull,
sizeof(
char));
538 const SSIZE_T rc2 = ConvertWCharToUtf8(wstr, tmp, (
size_t)rc + 1ull);
544 WINPR_ASSERT(rc == rc2);
546 *pUtfCharLength = (size_t)rc2;
550char* ConvertWCharNToUtf8Alloc(
const WCHAR* wstr,
size_t wlen,
size_t* pUtfCharLength)
553 const SSIZE_T rc = ConvertWCharNToUtf8(wstr, wlen,
nullptr, 0);
559 tmp = calloc((
size_t)rc + 1ull,
sizeof(
char));
562 const SSIZE_T rc2 = ConvertWCharNToUtf8(wstr, wlen, tmp, (
size_t)rc + 1ull);
568 WINPR_ASSERT(rc == rc2);
570 *pUtfCharLength = (size_t)rc2;
574char* ConvertMszWCharNToUtf8Alloc(
const WCHAR* wstr,
size_t wlen,
size_t* pUtfCharLength)
577 const SSIZE_T rc = ConvertMszWCharNToUtf8(wstr, wlen,
nullptr, 0);
583 tmp = calloc((
size_t)rc + 1ull,
sizeof(
char));
586 const SSIZE_T rc2 = ConvertMszWCharNToUtf8(wstr, wlen, tmp, (
size_t)rc + 1ull);
592 WINPR_ASSERT(rc == rc2);
594 *pUtfCharLength = (size_t)rc2;
598WCHAR* ConvertUtf8ToWCharAlloc(
const char* str,
size_t* pSize)
600 WCHAR* tmp =
nullptr;
601 const SSIZE_T rc = ConvertUtf8ToWChar(str,
nullptr, 0);
606 tmp = calloc((
size_t)rc + 1ull,
sizeof(WCHAR));
609 const SSIZE_T rc2 = ConvertUtf8ToWChar(str, tmp, (
size_t)rc + 1ull);
615 WINPR_ASSERT(rc == rc2);
617 *pSize = (size_t)rc2;
621WCHAR* ConvertUtf8NToWCharAlloc(
const char* str,
size_t len,
size_t* pSize)
623 WCHAR* tmp =
nullptr;
624 const SSIZE_T rc = ConvertUtf8NToWChar(str, len,
nullptr, 0);
629 tmp = calloc((
size_t)rc + 1ull,
sizeof(WCHAR));
632 const SSIZE_T rc2 = ConvertUtf8NToWChar(str, len, tmp, (
size_t)rc + 1ull);
638 WINPR_ASSERT(rc == rc2);
640 *pSize = (size_t)rc2;
644WCHAR* ConvertMszUtf8NToWCharAlloc(
const char* str,
size_t len,
size_t* pSize)
646 WCHAR* tmp =
nullptr;
647 const SSIZE_T rc = ConvertMszUtf8NToWChar(str, len,
nullptr, 0);
652 tmp = calloc((
size_t)rc + 1ull,
sizeof(WCHAR));
655 const SSIZE_T rc2 = ConvertMszUtf8NToWChar(str, len, tmp, (
size_t)rc + 1ull);
661 WINPR_ASSERT(rc == rc2);
663 *pSize = (size_t)rc2;
668static INT8 nnibble(
char c)
670 if ((c >=
'0') && (c <=
'9'))
671 return (INT8)(c -
'0');
672 if ((c >=
'a') && (c <=
'f'))
673 return (INT8)((c -
'a') + 0xa);
674 if ((c >=
'A') && (c <=
'F'))
675 return (INT8)((c -
'A') + 0xa);
680static INT32 escapeToNumber(
char* str,
char** next)
682 if (strncmp(str,
"\\u", 2) != 0)
687 for (
size_t x = 0; x < 4; x++)
689 const INT8 val = nnibble(str[offset++]);
696 *next = &str[offset];
700SSIZE_T winpr_utfEscapedStringToUtf8(
char* str,
size_t len)
704 while ((cur = winpr_strnstr(cur,
"\\u", clen)))
706 char* next =
nullptr;
707 const INT32 code = escapeToNumber(cur, &next);
712 clen = len - (size_t)(cur - str);
716 WCHAR wc[2] = WINPR_C_ARRAY_INIT;
717 wc[0] = ((WCHAR)code);
720 if ((wc[0] & 0xd800) == 0xd800)
722 const INT32 code2 = escapeToNumber(next, &next);
727 if ((code2 & 0xdc00) != 0xdc00)
730 wc[1] = (WCHAR)code2;
733 char utf8[8] = WINPR_C_ARRAY_INIT;
734 const SSIZE_T rc = ConvertWCharNToUtf8(wc, ARRAYSIZE(wc), utf8, ARRAYSIZE(utf8));
738 strncpy(cur, utf8, (
size_t)rc);
740 const size_t diff = (size_t)(next - cur);
741 if (diff > (
size_t)rc)
743 const size_t rlen = strnlen(next, len);
744 memmove(&cur[(
size_t)rc], next, rlen + 1);
749 clen = len - (size_t)(cur - str);
751 return (SSIZE_T)strnlen(str, len);
754char* winpr_utf8ToUtfEscapedString(
char* str,
size_t len,
size_t* pDstLen)
756 WINPR_ASSERT(str || (len == 0));
761 if (len >= SIZE_MAX / 12)
764 char* escaped =
nullptr;
767 WCHAR* wstr = ConvertUtf8NToWCharAlloc(str, len, &wlen);
768 if (!wstr || (wlen == 0))
771 const size_t esclen = len * 12ull;
772 escaped = calloc(len + 1, 12);
776 for (
size_t x = 0; x < wlen; x++)
778 const WCHAR wc = winpr_Data_Get_UINT16(&wstr[x]);
780 escaped[offset++] = (char)wc;
783 const int rc = snprintf(&escaped[offset], esclen - offset,
"\\u%04x", wc);
786 offset += (size_t)rc;
789 escaped[offset] =
'\0';
795 winpr_znfree(wstr, wlen *
sizeof(WCHAR));