mirror of
https://github.com/reactos/reactos.git
synced 2025-05-23 02:56:09 +00:00

Imported from https://www.nuget.org/packages/Microsoft.Windows.SDK.CRTSource/10.0.22621.3 License: MIT
326 lines
9.3 KiB
C++
326 lines
9.3 KiB
C++
/***
|
|
*mbstowcs.c - Convert multibyte char string to wide char string.
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
* Convert a multibyte char string into the equivalent wide char string.
|
|
*
|
|
*******************************************************************************/
|
|
#include <corecrt_internal_mbstring.h>
|
|
#include <corecrt_internal_ptd_propagation.h>
|
|
#include <corecrt_internal_securecrt.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <locale.h>
|
|
#include <stdlib.h>
|
|
|
|
using namespace __crt_mbstring;
|
|
|
|
/***
|
|
*size_t mbstowcs() - Convert multibyte char string to wide char string.
|
|
*
|
|
*Purpose:
|
|
* Convert a multi-byte char string into the equivalent wide char string,
|
|
* according to the LC_CTYPE category of the current locale.
|
|
* [ANSI].
|
|
*
|
|
*Entry:
|
|
* wchar_t *pwcs = pointer to destination wide character string buffer
|
|
* const char *s = pointer to source multibyte character string
|
|
* size_t n = maximum number of wide characters to store
|
|
*
|
|
*Exit:
|
|
* If pwcs != nullptr returns the number of words modified (<=n): note that
|
|
* if the return value == n, then no destination string is not 0 terminated.
|
|
* If pwcs == nullptr returns the length (not size) needed for the destination buffer.
|
|
*
|
|
*Exceptions:
|
|
* Returns (size_t)-1 if s is nullptr or invalid mbcs character encountered
|
|
* and errno is set to EILSEQ.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
/* Helper shared by secure and non-secure functions */
|
|
|
|
static size_t __cdecl _mbstowcs_l_helper(
|
|
_Out_writes_opt_z_(n) wchar_t * pwcs,
|
|
_In_reads_or_z_(n) _Pre_z_ const char * s,
|
|
_In_ size_t n,
|
|
_In_opt_ __crt_cached_ptd_host& ptd
|
|
) throw()
|
|
{
|
|
size_t count = 0;
|
|
|
|
if (pwcs && n == 0)
|
|
{
|
|
/* dest string exists, but 0 bytes converted */
|
|
return (size_t) 0;
|
|
}
|
|
|
|
if (pwcs && n > 0)
|
|
{
|
|
*pwcs = '\0';
|
|
}
|
|
|
|
/* validation section */
|
|
_UCRT_VALIDATE_RETURN(ptd, s != nullptr, EINVAL, (size_t) - 1);
|
|
|
|
_locale_t const locale = ptd.get_locale();
|
|
|
|
if (locale->locinfo->_public._locale_lc_codepage == CP_UTF8)
|
|
{
|
|
mbstate_t state{};
|
|
return __mbsrtowcs_utf8(pwcs, &s, n, &state, ptd);
|
|
}
|
|
|
|
/* if destination string exists, fill it in */
|
|
if (pwcs)
|
|
{
|
|
if (locale->locinfo->locale_name[LC_CTYPE] == nullptr)
|
|
{
|
|
/* C locale: easy and fast */
|
|
while (count < n)
|
|
{
|
|
*pwcs = (wchar_t) ((unsigned char) s[count]);
|
|
if (!s[count])
|
|
{
|
|
return count;
|
|
}
|
|
count++;
|
|
pwcs++;
|
|
}
|
|
return count;
|
|
|
|
}
|
|
else {
|
|
int bytecnt, charcnt;
|
|
unsigned char *p;
|
|
|
|
/* Assume that the buffer is large enough */
|
|
if ((count = __acrt_MultiByteToWideChar(locale->locinfo->_public._locale_lc_codepage,
|
|
MB_PRECOMPOSED |
|
|
MB_ERR_INVALID_CHARS,
|
|
s,
|
|
-1,
|
|
pwcs,
|
|
(int) n)) != 0)
|
|
{
|
|
return count - 1; /* don't count NUL */
|
|
}
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
ptd.get_errno().set(EILSEQ);
|
|
*pwcs = '\0';
|
|
return (size_t) - 1;
|
|
}
|
|
|
|
/* User-supplied buffer not large enough. */
|
|
|
|
/* How many bytes are in n characters of the string? */
|
|
charcnt = (int) n;
|
|
for (p = (unsigned char *) s; (charcnt-- && *p); p++)
|
|
{
|
|
if (_isleadbyte_fast_internal(*p, locale))
|
|
{
|
|
if (p[1] == '\0')
|
|
{
|
|
/* this is a leadbyte followed by EOS -- a dud MBCS string
|
|
We choose not to assert here because this
|
|
function is defined to deal with dud strings on
|
|
input and return a known value
|
|
*/
|
|
ptd.get_errno().set(EILSEQ);
|
|
*pwcs = '\0';
|
|
return (size_t) - 1;
|
|
}
|
|
else
|
|
{
|
|
p++;
|
|
}
|
|
}
|
|
}
|
|
bytecnt = ((int) ((char *) p - (char *) s));
|
|
|
|
if ((count = __acrt_MultiByteToWideChar(locale->locinfo->_public._locale_lc_codepage,
|
|
MB_PRECOMPOSED,
|
|
s,
|
|
bytecnt,
|
|
pwcs,
|
|
(int) n)) == 0)
|
|
{
|
|
ptd.get_errno().set(EILSEQ);
|
|
*pwcs = '\0';
|
|
return (size_t) - 1;
|
|
}
|
|
|
|
return count; /* no NUL in string */
|
|
}
|
|
}
|
|
else {
|
|
/* pwcs == nullptr, get size only, s must be NUL-terminated */
|
|
if (locale->locinfo->locale_name[LC_CTYPE] == nullptr)
|
|
{
|
|
return strlen(s);
|
|
}
|
|
else if ((count = __acrt_MultiByteToWideChar(locale->locinfo->_public._locale_lc_codepage,
|
|
MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
|
|
s,
|
|
-1,
|
|
nullptr,
|
|
0)) == 0)
|
|
{
|
|
ptd.get_errno().set(EILSEQ);
|
|
return (size_t) - 1;
|
|
}
|
|
else
|
|
{
|
|
return count - 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
extern "C" size_t __cdecl _mbstowcs_l(
|
|
wchar_t *pwcs,
|
|
const char *s,
|
|
size_t n,
|
|
_locale_t plocinfo
|
|
)
|
|
{
|
|
/* Call a non-deprecated helper to do the work. */
|
|
__crt_cached_ptd_host ptd(plocinfo);
|
|
return _mbstowcs_l_helper(pwcs, s, n, ptd);
|
|
}
|
|
|
|
extern "C" size_t __cdecl mbstowcs(
|
|
wchar_t *pwcs,
|
|
const char *s,
|
|
size_t n
|
|
)
|
|
{
|
|
__crt_cached_ptd_host ptd;
|
|
return _mbstowcs_l_helper(pwcs, s, n, ptd);
|
|
}
|
|
|
|
/***
|
|
*errno_t mbstowcs_s() - Convert multibyte char string to wide char string.
|
|
*
|
|
*Purpose:
|
|
* Convert a multi-byte char string into the equivalent wide char string,
|
|
* according to the LC_CTYPE category of the current locale.
|
|
* Same as mbstowcs(), but the destination is ensured to be null terminated.
|
|
* If there's not enough space, we return EINVAL.
|
|
*
|
|
*Entry:
|
|
* size_t *pConvertedChars = Number of bytes modified including the terminating nullptr
|
|
* This pointer can be nullptr.
|
|
* wchar_t *pwcs = pointer to destination wide character string buffer
|
|
* size_t sizeInWords = size of the destination buffer
|
|
* const char *s = pointer to source multibyte character string
|
|
* size_t n = maximum number of wide characters to store (not including the terminating nullptr)
|
|
*
|
|
*Exit:
|
|
* The error code.
|
|
*
|
|
*Exceptions:
|
|
* Input parameters are validated. Refer to the validation section of the function.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
static errno_t __cdecl _mbstowcs_internal(
|
|
size_t * pConvertedChars,
|
|
wchar_t * pwcs,
|
|
size_t sizeInWords,
|
|
const char * s,
|
|
size_t n,
|
|
__crt_cached_ptd_host& ptd
|
|
)
|
|
{
|
|
size_t retsize;
|
|
errno_t retvalue = 0;
|
|
|
|
/* validation section */
|
|
_UCRT_VALIDATE_RETURN_ERRCODE(ptd, (pwcs == nullptr && sizeInWords == 0) || (pwcs != nullptr && sizeInWords > 0), EINVAL);
|
|
|
|
if (pwcs != nullptr)
|
|
{
|
|
_RESET_STRING(pwcs, sizeInWords);
|
|
}
|
|
|
|
if (pConvertedChars != nullptr)
|
|
{
|
|
*pConvertedChars = 0;
|
|
}
|
|
|
|
size_t bufferSize = n > sizeInWords ? sizeInWords : n;
|
|
/* n must fit into an int for MultiByteToWideChar */
|
|
_UCRT_VALIDATE_RETURN_ERRCODE(ptd, bufferSize <= INT_MAX, EINVAL);
|
|
|
|
/* Call a non-deprecated helper to do the work. */
|
|
|
|
retsize = _mbstowcs_l_helper(pwcs, s, bufferSize, ptd);
|
|
|
|
if (retsize == (size_t) - 1)
|
|
{
|
|
if (pwcs != nullptr)
|
|
{
|
|
_RESET_STRING(pwcs, sizeInWords);
|
|
}
|
|
return ptd.get_errno().value_or(0);
|
|
}
|
|
|
|
/* count the null terminator */
|
|
retsize++;
|
|
|
|
if (pwcs != nullptr)
|
|
{
|
|
/* return error if the string does not fit, unless n == _TRUNCATE */
|
|
if (retsize > sizeInWords)
|
|
{
|
|
if (n != _TRUNCATE)
|
|
{
|
|
_RESET_STRING(pwcs, sizeInWords);
|
|
_UCRT_VALIDATE_RETURN_ERRCODE(ptd, retsize <= sizeInWords, ERANGE);
|
|
}
|
|
retsize = sizeInWords;
|
|
retvalue = STRUNCATE;
|
|
}
|
|
|
|
/* ensure the string is null terminated */
|
|
pwcs[retsize - 1] = '\0';
|
|
}
|
|
|
|
if (pConvertedChars != nullptr)
|
|
{
|
|
*pConvertedChars = retsize;
|
|
}
|
|
|
|
return retvalue;
|
|
}
|
|
|
|
extern "C" errno_t __cdecl _mbstowcs_s_l(
|
|
size_t * pConvertedChars,
|
|
wchar_t * pwcs,
|
|
size_t sizeInWords,
|
|
const char * s,
|
|
size_t n,
|
|
_locale_t plocinfo
|
|
)
|
|
{
|
|
__crt_cached_ptd_host ptd(plocinfo);
|
|
return _mbstowcs_internal(pConvertedChars, pwcs, sizeInWords, s, n, ptd);
|
|
}
|
|
|
|
extern "C" errno_t __cdecl mbstowcs_s(
|
|
size_t *pConvertedChars,
|
|
wchar_t *pwcs,
|
|
size_t sizeInWords,
|
|
const char *s,
|
|
size_t n
|
|
)
|
|
{
|
|
__crt_cached_ptd_host ptd;
|
|
return _mbstowcs_internal(pConvertedChars, pwcs, sizeInWords, s, n, ptd);
|
|
}
|