mirror of
https://github.com/reactos/reactos.git
synced 2025-06-04 08:50:27 +00:00

Imported from https://www.nuget.org/packages/Microsoft.Windows.SDK.CRTSource/10.0.22621.3 License: MIT
203 lines
5.2 KiB
C++
203 lines
5.2 KiB
C++
/***
|
|
*mbsncat_s.inl - general implementation of _mbsncat_s and _mbsnbcat_s
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
* This file contains the general algorithm for _mbsncat_s and _mbsnbcat_s.
|
|
*
|
|
****/
|
|
|
|
errno_t __cdecl _FUNC_NAME(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _COUNT, _LOCALE_ARG_DECL)
|
|
{
|
|
unsigned char *p;
|
|
size_t available;
|
|
BOOL fIsLeadPrefix;
|
|
BOOL fFoundInvalidMBC;
|
|
|
|
fFoundInvalidMBC = FALSE;
|
|
|
|
if (_COUNT == 0 && _Dst == nullptr && _SizeInBytes == 0)
|
|
{
|
|
/* this case is allowed; nothing to do */
|
|
_RETURN_NO_ERROR;
|
|
}
|
|
|
|
/* validation section */
|
|
_VALIDATE_STRING(_Dst, _SizeInBytes);
|
|
if (_COUNT != 0)
|
|
{
|
|
_VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
|
|
}
|
|
|
|
_LOCALE_UPDATE;
|
|
if (_LOCALE_SHORTCUT_TEST)
|
|
{
|
|
return strncat_s((char *)_Dst, _SizeInBytes, (const char *)_Src, _COUNT);
|
|
}
|
|
|
|
p = _Dst;
|
|
available = _SizeInBytes;
|
|
while (available > 0 && *p != 0)
|
|
{
|
|
p++;
|
|
available--;
|
|
}
|
|
|
|
/*
|
|
* Ran out of room while looking for end of dst string.
|
|
* p points 1 past end of buffer. We can't look past
|
|
* end of buffer so can't tell if dst ended with an
|
|
* invalid mbc.
|
|
*/
|
|
|
|
if (available == 0)
|
|
{
|
|
_RESET_STRING(_Dst, _SizeInBytes);
|
|
_RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
|
|
}
|
|
|
|
|
|
if (available < _SizeInBytes)
|
|
{
|
|
/*
|
|
* Dst may have terminated with an invalid MBCS, in that case we clear
|
|
* the bogus lead byte.
|
|
*/
|
|
fIsLeadPrefix = FALSE;
|
|
_ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, &p[-1]);
|
|
if (fIsLeadPrefix) {
|
|
/* the original string ended with a lead byte: we remove it */
|
|
p--;
|
|
*p = 0;
|
|
available++;
|
|
fFoundInvalidMBC = TRUE;
|
|
}
|
|
}
|
|
|
|
if (_COUNT == _TRUNCATE)
|
|
{
|
|
while ((*p++ = *_Src++) != 0 && --available > 0)
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if _COUNT_IN_BYTES
|
|
while (_COUNT > 0 && (*p++ = *_Src++) != 0 && --available > 0)
|
|
{
|
|
_COUNT--;
|
|
}
|
|
#else /* _COUNT_IN_BYTES */
|
|
while (_COUNT > 0)
|
|
{
|
|
if (_ISMBBLEAD(*_Src))
|
|
{
|
|
if (_Src[1] == 0)
|
|
{
|
|
/* the source string ended with a lead byte: we remove it */
|
|
*p = 0;
|
|
fFoundInvalidMBC = TRUE;
|
|
break;
|
|
}
|
|
if (available <= 2)
|
|
{
|
|
/* not enough space */
|
|
available = 0;
|
|
break;
|
|
}
|
|
*p++ = *_Src++;
|
|
*p++ = *_Src++;
|
|
available -= 2;
|
|
}
|
|
else
|
|
{
|
|
if ((*p++ = *_Src++) == 0 || --available == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
_COUNT--;
|
|
}
|
|
#endif /* _COUNT_IN_BYTES */
|
|
if (_COUNT == 0)
|
|
{
|
|
*p++ = 0;
|
|
}
|
|
}
|
|
|
|
if (available == 0)
|
|
{
|
|
#if _COUNT_IN_BYTES
|
|
/*
|
|
* defined(_COUNT_IN_BYTES) loop does not track mbc context,
|
|
* so we must iterate backwards to discover character context.
|
|
*/
|
|
if (*_Src == 0 || _COUNT == 1)
|
|
{
|
|
_ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, &p[-1]);
|
|
if (fIsLeadPrefix)
|
|
{
|
|
/* the source string ended with a lead byte: we remove it */
|
|
p[-1] = 0;
|
|
_RETURN_MBCS_ERROR;
|
|
}
|
|
}
|
|
#endif /* _COUNT_IN_BYTES */
|
|
|
|
/*
|
|
* _COUNT == _TRUNCATE loop terminated because available became 0.
|
|
* This means that we copied at least one character, and it wasn't
|
|
* a null. If this last character acted as a lead then overwrite
|
|
* it with null. Do not set the mbcs error in this case, due that the
|
|
* user cannot predict this case and he/she's only asking for truncation.
|
|
*/
|
|
if (_COUNT == _TRUNCATE)
|
|
{
|
|
if (fFoundInvalidMBC)
|
|
{
|
|
_SET_MBCS_ERROR;
|
|
}
|
|
|
|
if (_SizeInBytes > 1)
|
|
{
|
|
fIsLeadPrefix = FALSE;
|
|
_ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, &_Dst[_SizeInBytes - 2]);
|
|
if (fIsLeadPrefix)
|
|
{
|
|
_Dst[_SizeInBytes - 2] = 0;
|
|
_FILL_BYTE(_Dst[_SizeInBytes - 1]);
|
|
_RETURN_TRUNCATE;
|
|
}
|
|
}
|
|
|
|
_Dst[_SizeInBytes - 1] = 0;
|
|
|
|
_RETURN_TRUNCATE;
|
|
}
|
|
_RESET_STRING(_Dst, _SizeInBytes);
|
|
_RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
|
|
}
|
|
#if _COUNT_IN_BYTES
|
|
if (available < _SizeInBytes)
|
|
{
|
|
_ISMBBLEADPREFIX(fIsLeadPrefix, _Dst, &p[-2]);
|
|
if (fIsLeadPrefix)
|
|
{
|
|
/* the source string ended with a lead byte: we remove it */
|
|
p[-2] = 0;
|
|
available++;
|
|
fFoundInvalidMBC = TRUE;
|
|
}
|
|
}
|
|
#endif /* _COUNT_IN_BYTES */
|
|
_FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
|
|
|
|
if (fFoundInvalidMBC)
|
|
{
|
|
_RETURN_MBCS_ERROR;
|
|
}
|
|
|
|
_RETURN_NO_ERROR;
|
|
}
|
|
|