diff options
Diffstat (limited to 'src/pal/inc/rt/safecrt.h')
-rw-r--r-- | src/pal/inc/rt/safecrt.h | 3381 |
1 files changed, 3381 insertions, 0 deletions
diff --git a/src/pal/inc/rt/safecrt.h b/src/pal/inc/rt/safecrt.h new file mode 100644 index 0000000000..6b95e28dfb --- /dev/null +++ b/src/pal/inc/rt/safecrt.h @@ -0,0 +1,3381 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +// +/*** +*safecrt.h - secure crt downlevel for windows build +* +*Purpose: +* This file contains a subset of the Secure CRT. It is meant to +* be used in the Windows source tree. +* +****/ + +/* #pragma once */ + +/* guard against other includes */ +#if !defined(_CRT_ALTERNATIVE_INLINES) +#error "_CRT_ALTERNATIVE_INLINES needs to be defined to use safecrt.h. This will make sure the safecrt functions are not declared in the standard headers." +#endif + +#if defined(_CRT_ALTERNATIVE_IMPORTED) +#error "_CRT_ALTERNATIVE_IMPORTED is defined. This means some files were included with _CRT_ALTERNATIVE_INLINES undefined." +#endif + +#if !defined(_INC_SAFECRT) +#define _INC_SAFECRT + +#if !defined(_SAFECRT_NO_INCLUDES) +#include <stdarg.h> /* for va_start, etc. */ +#endif + +/* _SAFECRT switches */ +#if !defined(_SAFECRT_USE_INLINES) +#define _SAFECRT_USE_INLINES 0 +#endif + +#if !defined(_SAFECRT_SET_ERRNO) +#define _SAFECRT_SET_ERRNO 1 +#endif + +#if !defined(_SAFECRT_DEFINE_TCS_MACROS) +#define _SAFECRT_DEFINE_TCS_MACROS 0 +#endif + +#if !defined(_SAFECRT_DEFINE_MBS_FUNCTIONS) +#define _SAFECRT_DEFINE_MBS_FUNCTIONS 1 +#endif + +#if !defined(_SAFECRT_USE_CPP_OVERLOADS) +#define _SAFECRT_USE_CPP_OVERLOADS 0 +#endif + +#if !defined(_SAFECRT_FILL_BUFFER) +#if defined(_DEBUG) +#define _SAFECRT_FILL_BUFFER 1 +#else +#define _SAFECRT_FILL_BUFFER 0 +#endif +#endif + +#if !defined(_SAFECRT_FILL_BUFFER_PATTERN) +#define _SAFECRT_FILL_BUFFER_PATTERN 0xFD +#endif + +#if !defined(_SAFECRT_INVALID_PARAMETER_DEBUG_INFO) +#define _SAFECRT_INVALID_PARAMETER_DEBUG_INFO 0 +#endif + +#if !defined(_SAFECRT_IMPL) && defined (_SAFECRT_USE_INLINES) +#define _SAFECRT__INLINE __inline +#else +#define _SAFECRT__INLINE +#endif + +/* additional includes */ +#if _SAFECRT_USE_INLINES && !defined(_SAFECRT_NO_INCLUDES) +#include <stdlib.h> /* for _MAX_DRIVE */ +#include <string.h> /* for memset */ +#include <windows.h> /* for NTSTATUS, RaiseException */ +#if _SAFECRT_SET_ERRNO +#include <errno.h> +#endif +#if _SAFECRT_DEFINE_MBS_FUNCTIONS +#include <mbctype.h> +#endif +#endif + +/* NULL */ +#if !defined(NULL) +#if !defined(__cplusplus) +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +/* WCHAR */ +#if defined (SAFECRT_INCLUDE_REDEFINES) +#if !defined(_WCHAR_T_DEFINED) +typedef unsigned short WCHAR; +#define _WCHAR_T_DEFINED +#endif +#endif + +/* _W64 */ +#if !defined(_W64) +#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +#define _W64 __w64 +#else +#define _W64 +#endif +#endif + +/* size_t */ +#if defined (SAFECRT_INCLUDE_REDEFINES) +#if !defined(_SIZE_T_DEFINED) +#if defined(_WIN64) +typedef unsigned __int64 size_t; +#else +typedef _W64 unsigned int size_t; +#endif +#define _SIZE_T_DEFINED +#endif +#endif + +/* uintptr_t */ +#if !defined(_UINTPTR_T_DEFINED) +#if defined(_WIN64) +typedef unsigned __int64 uintptr_t; +#else +typedef _W64 unsigned int uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ >= 3)) +#define SAFECRT_DEPRECATED __declspec(deprecated) +#else +#define SAFECRT_DEPRECATED +#endif + +/* errno_t */ +#if !defined(_ERRCODE_DEFINED) +#define _ERRCODE_DEFINED +/* errcode is deprecated in favor or errno_t, which is part of the standard proposal */ +SAFECRT_DEPRECATED typedef int errcode; +typedef int errno_t; /* standard */ +#endif + +/* error codes */ +#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED) +#define _SECURECRT_ERRCODE_VALUES_DEFINED +#if !defined(EINVAL) +#define EINVAL 22 +#endif +#if !defined(ERANGE) +#define ERANGE 34 +#endif +#if !defined(EILSEQ) +#define EILSEQ 42 +#endif +#if !defined(STRUNCATE) +#define STRUNCATE 80 +#endif +#endif + +/* _TRUNCATE */ +#if !defined(_TRUNCATE) +#define _TRUNCATE ((size_t)-1) +#endif + +/* _SAFECRT_AUTOMATICALLY_REPLACED_CALL */ +#if !defined(_SAFECRT_AUTOMATICALLY_REPLACED_CALL) +#define _SAFECRT_AUTOMATICALLY_REPLACED_CALL(v) (v) +#endif + +/* internal macros */ +#if _SAFECRT_USE_INLINES +#define _SAFECRT__EXTERN_C +#else +#if defined(__cplusplus) +#define _SAFECRT__EXTERN_C extern "C" +#else +#define _SAFECRT__EXTERN_C extern +#endif +#endif /* _SAFECRT_USE_INLINES */ + +#if !defined(_SAFECRT_IMPL) + +#define _SAFECRT__STR2WSTR(str) L##str + +#define _SAFECRT__STR2WSTR2(str) _SAFECRT__STR2WSTR(str) + +#if !defined(__FILEW__) +#define __FILEW__ _SAFECRT__STR2WSTR2(__FILE__) +#endif + +#if !defined(__FUNCTIONW__) +#define __FUNCTIONW__ _SAFECRT__STR2WSTR2(__FUNCTION__) +#endif + +#endif + +/* validation macros */ +#if !defined(_SAFECRT_INVALID_PARAMETER) +#if _SAFECRT_INVALID_PARAMETER_DEBUG_INFO +#define _SAFECRT_INVALID_PARAMETER(message) _invalid_parameter(message, __FUNCTIONW__, __FILEW__, __LINE__, 0) +#else +#define _SAFECRT_INVALID_PARAMETER(message) _invalid_parameter(nullptr, nullptr, nullptr, 0, 0) +#endif +#endif + +#if !defined(_SAFECRT__SET_ERRNO) +#if _SAFECRT_SET_ERRNO +#define _SAFECRT__SET_ERRNO(_ErrorCode) errno = (_ErrorCode) +#else +#define _SAFECRT__SET_ERRNO(_ErrorCode) +#endif +#endif + +#if !defined(_SAFECRT__RETURN_ERROR) +#define _SAFECRT__RETURN_ERROR(_Msg, _Ret) \ + _SAFECRT__SET_ERRNO(EINVAL); \ + _SAFECRT_INVALID_PARAMETER(_Msg); \ + return _Ret +#endif + +#if !defined(_SAFECRT__VALIDATE_STRING_ERROR) +#define _SAFECRT__VALIDATE_STRING_ERROR(_String, _Size, _Ret) \ + if ((_String) == nullptr || (_Size) == 0) \ + { \ + _SAFECRT__SET_ERRNO(EINVAL); \ + _SAFECRT_INVALID_PARAMETER(L"String " _SAFECRT__STR2WSTR(#_String) L" is invalid"); \ + return _Ret; \ + } +#endif + +#if !defined(_SAFECRT__VALIDATE_STRING) +#define _SAFECRT__VALIDATE_STRING(_String, _Size) _SAFECRT__VALIDATE_STRING_ERROR(_String, _Size, EINVAL) +#endif + +#if !defined(_SAFECRT__VALIDATE_POINTER_ERROR_RETURN) +#define _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Pointer, _ErrorCode, _Ret) \ + if ((_Pointer) == nullptr) \ + { \ + _SAFECRT__SET_ERRNO(_ErrorCode); \ + _SAFECRT_INVALID_PARAMETER(L"Pointer " _SAFECRT__STR2WSTR(#_Pointer) L" is invalid"); \ + return _Ret; \ + } +#endif + +#if !defined(_SAFECRT__VALIDATE_POINTER_ERROR) +#define _SAFECRT__VALIDATE_POINTER_ERROR(_Pointer, _Ret) \ + _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Pointer, EINVAL, _Ret) +#endif + +#if !defined(_SAFECRT__VALIDATE_POINTER) +#define _SAFECRT__VALIDATE_POINTER(_Pointer) \ + _SAFECRT__VALIDATE_POINTER_ERROR(_Pointer, EINVAL) +#endif + +#if !defined(_SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR) +#define _SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, _Ret) \ + if ((_Pointer) == nullptr) \ + { \ + _SAFECRT__SET_ERRNO(EINVAL); \ + _SAFECRT__RESET_STRING(_String, _Size); \ + _SAFECRT_INVALID_PARAMETER(L"Pointer " _SAFECRT__STR2WSTR(#_Pointer) L" is invalid"); \ + return _Ret; \ + } +#endif + +#if !defined(_SAFECRT__VALIDATE_POINTER_RESET_STRING) +#define _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Pointer, _String, _Size) \ + _SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, EINVAL) +#endif + +#if !defined(_SAFECRT__VALIDATE_CONDITION_ERROR_RETURN) +#define _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_Condition, _ErrorCode, _Ret) \ + if (!(_Condition)) \ + { \ + _SAFECRT__SET_ERRNO(_ErrorCode); \ + _SAFECRT_INVALID_PARAMETER(_SAFECRT__STR2WSTR(#_Condition)); \ + return _Ret; \ + } +#endif + +#if !defined(_SAFECRT__VALIDATE_CONDITION_ERROR) +#define _SAFECRT__VALIDATE_CONDITION_ERROR(_Condition, _Ret) \ + _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_Condition, EINVAL, _Ret) +#endif + +/* if _SAFECRT_FILL_BUFFER is on, fill the interval [_Offset, _Size) with _SAFECRT_FILL_BUFFER_PATTERN; + * assume that the string has been validated with _SAFECRT__VALIDATE_STRING + */ +#if !defined(_SAFECRT__FILL_STRING) +#if _SAFECRT_FILL_BUFFER +#define _SAFECRT__FILL_STRING(_String, _Size, _Offset) \ + if ((size_t)(_Offset) < (_Size)) \ + { \ + memset((_String) + (_Offset), _SAFECRT_FILL_BUFFER_PATTERN, ((_Size) - (_Offset)) * sizeof(*(_String))); \ + } +#else +#define _SAFECRT__FILL_STRING(_String, _Size, _Offset) +#endif +#endif + +/* if _SAFECRT_FILL_BUFFER is on, set the byte to _SAFECRT_FILL_BUFFER_PATTERN + */ +#if !defined(_SAFECRT__FILL_BYTE) +#if _SAFECRT_FILL_BUFFER +#define _SAFECRT__FILL_BYTE(_Position) \ + (_Position) = _SAFECRT_FILL_BUFFER_PATTERN +#else +#define _SAFECRT__FILL_BYTE(_Position) +#endif +#endif + +/* put a null terminator at the beginning of the string and then calls _SAFECRT__FILL_STRING; + * assume that the string has been validated with _SAFECRT__VALIDATE_STRING + */ +#if !defined(_SAFECRT__RESET_STRING) +#define _SAFECRT__RESET_STRING(_String, _Size) \ + *(_String) = 0; \ + _SAFECRT__FILL_STRING(_String, _Size, 1); +#endif + +#if !defined(_SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR) +#define _SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, _Ret) \ + _SAFECRT__SET_ERRNO(ERANGE); \ + _SAFECRT_INVALID_PARAMETER(L"Buffer " _SAFECRT__STR2WSTR(#_String) L" is too small"); \ + return _Ret; +#endif + +#if !defined(_SAFECRT__RETURN_BUFFER_TOO_SMALL) +#define _SAFECRT__RETURN_BUFFER_TOO_SMALL(_String, _Size) \ + _SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, ERANGE) +#endif + +#if !defined(_SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED) +#define _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_String, _Size) \ + _SAFECRT__SET_ERRNO(EINVAL); \ + _SAFECRT_INVALID_PARAMETER(L"String " _SAFECRT__STR2WSTR(#_String) L" is not terminated"); \ + return EINVAL; +#endif + +#if !defined(_SAFECRT__RETURN_EINVAL) +#define _SAFECRT__RETURN_EINVAL \ + _SAFECRT__SET_ERRNO(EINVAL); \ + _SAFECRT_INVALID_PARAMETER(L"Invalid parameter"); \ + return EINVAL; +#endif + +/* MBCS handling: change these definitions if you do not need to support mbcs strings */ +#if !defined(_SAFECRT__ISMBBLEAD) +#define _SAFECRT__ISMBBLEAD(_Character) \ + _ismbblead(_Character) +#endif + +#if !defined(_SAFECRT__MBSDEC) +#define _SAFECRT__MBSDEC(_String, _Current) \ + _mbsdec(_String, _Current) +#endif + +_SAFECRT__EXTERN_C +void __cdecl _invalid_parameter(const WCHAR *_Message, const WCHAR *_FunctionName, const WCHAR *_FileName, unsigned int _LineNumber, uintptr_t _Reserved); + +#if (_SAFECRT_USE_INLINES || _SAFECRT_IMPL) && !defined(_SAFECRT_DO_NOT_DEFINE_INVALID_PARAMETER) + +#ifndef STATUS_INVALID_PARAMETER +#if defined (SAFECRT_INCLUDE_REDEFINES) +typedef LONG NTSTATUS; +#endif +#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#endif + +_SAFECRT__INLINE +void __cdecl _invalid_parameter(const WCHAR *_Message, const WCHAR *_FunctionName, const WCHAR *_FileName, unsigned int _LineNumber, uintptr_t _Reserved) +{ +#ifdef _MSC_VER + (_Message); + (_FunctionName); + (_FileName); + (_LineNumber); + (_Reserved); +#endif + /* invoke Watson */ + RaiseException((DWORD)STATUS_INVALID_PARAMETER, 0, 0, nullptr); +} + +#endif + +//#if !defined(_SAFECRT_IMPL) + +#if _SAFECRT_DEFINE_TCS_MACROS + +/* _tcs macros */ +#if !defined(_UNICODE) && !defined(UNICODE) && !defined(_MBCS) + +#define _tcscpy_s strcpy_s +#define _tcsncpy_s strncpy_s +#define _tcscat_s strcat_s +#define _tcsncat_s strncat_s +#define _tcsset_s _strset_s +#define _tcsnset_s _strnset_s +#define _tcstok_s strtok_s +#define _tmakepath_s _makepath_s +#define _tsplitpath_s _splitpath_s +#define _stprintf_s sprintf_s +#define _vstprintf_s vsprintf_s +#define _sntprintf_s _snprintf_s +#define _vsntprintf_s _vsnprintf_s +#define _tscanf_s scanf_s +#define _tsscanf_s sscanf_s +#define _tsnscanf_s _snscanf_s + +#elif defined(_UNICODE) || defined(UNICODE) + +#define _tcscpy_s wcscpy_s +#define _tcsncpy_s wcsncpy_s +#define _tcscat_s wcscat_s +#define _tcsncat_s wcsncat_s +#define _tcsset_s _wcsset_s +#define _tcsnset_s _wcsnset_s +#define _tcstok_s wcstok_s +#define _tmakepath_s _wmakepath_s +#define _tsplitpath_s _wsplitpath_s +#define _stprintf_s swprintf_s +#define _vstprintf_s vswprintf_s +#define _sntprintf_s _snwprintf_s +#define _vsntprintf_s _vsnwprintf_s +#define _tscanf_s wscanf_s +#define _tsscanf_s swscanf_s +#define _tsnscanf_s _swnscanf_s + +#elif defined(_MBCS) + +#define _tcscpy_s _mbscpy_s +#define _tcsncpy_s _mbsnbcpy_s +#define _tcscat_s _mbscat_s +#define _tcsncat_s _mbsnbcat_s +#define _tcsset_s _mbsset_s +#define _tcsnset_s _mbsnbset_s +#define _tcstok_s _mbstok_s +#define _tmakepath_s _makepath_s +#define _tsplitpath_s _splitpath_s +#define _stprintf_s sprintf_s +#define _vstprintf_s vsprintf_s +#define _sntprintf_s _snprintf_s +#define _vsntprintf_s _vsnprintf_s +#define _tscanf_s scanf_s +#define _tsscanf_s sscanf_s +#define _tsnscanf_s _snscanf_s + +#else + +#error We should not get here... + +#endif + +#endif /* _SAFECRT_DEFINE_TCS_MACROS */ + +/* strcpy_s */ +/* + * strcpy_s, wcscpy_s copy string _Src into _Dst; + * will call _SAFECRT_INVALID_PARAMETER if string _Src does not fit into _Dst + */ + + +_SAFECRT__EXTERN_C +errno_t __cdecl strcpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl strcpy_s(char (&_Dst)[_SizeInBytes], const char *_Src) +{ + return strcpy_s(_Dst, _SizeInBytes, _Src); +} +#endif + + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + + +_SAFECRT__INLINE +errno_t __cdecl strcpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src) +{ + + char *p; + size_t available; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +/* wcscpy_s */ +_SAFECRT__EXTERN_C +errno_t __cdecl wcscpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +errno_t __cdecl wcscpy_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src) +{ + return wcscpy_s(_Dst, _SizeInWords, _Src); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl wcscpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src) +{ + WCHAR *p; + size_t available; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords); + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords); + + p = _Dst; + available = _SizeInWords; + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1); + return 0; +} + +#endif + +/* _mbscpy_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbscpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbscpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src) +{ + return _mbscpy_s(_Dst, _SizeInBytes, _Src); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbscpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src) +{ + unsigned char *p; + size_t available; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + + if (available == 0) + { + if (*_Src == 0 && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the source string ended with a lead byte: we remove it */ + p[-1] = 0; + return 0; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2])) + { + /* the source string ended with a lead byte: we remove it */ + p[-2] = 0; + available++; + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* strncpy_s */ +/* + * strncpy_s, wcsncpy_s copy at max _Count characters from string _Src into _Dst; + * string _Dst will always be null-terminated; + * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst; + * if _Count == _TRUNCATE, we will copy as many characters as we can from _Src into _Dst, and + * return STRUNCATE if _Src does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER); + * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed + */ +_SAFECRT__EXTERN_C +errno_t __cdecl strncpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl strncpy_s(char (&_Dst)[_SizeInBytes], const char *_Src, size_t _Count) +{ + return strncpy_s(_Dst, _SizeInBytes, _Src, _Count); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl strncpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count) +{ + char *p; + size_t available; + + if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + if (_Count == 0) + { + /* notice that the source string pointer can be nullptr in this case */ + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + return 0; + } + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + if (_Count == _TRUNCATE) + { + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + } + else + { + while ((*p++ = *_Src++) != 0 && --available > 0 && --_Count > 0) + { + } + if (_Count == 0) + { + *p = 0; + } + } + + if (available == 0) + { + if (_Count == _TRUNCATE) + { + _Dst[_SizeInBytes - 1] = 0; + return STRUNCATE; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +/* wcsncpy_s */ +_SAFECRT__EXTERN_C +errno_t __cdecl wcsncpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +errno_t __cdecl wcsncpy_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src, size_t _Count) +{ + return wcsncpy_s(_Dst, _SizeInWords, _Src, _Count); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl wcsncpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count) +{ + WCHAR *p; + size_t available; + + if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords); + if (_Count == 0) + { + /* notice that the source string pointer can be nullptr in this case */ + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + return 0; + } + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords); + + p = _Dst; + available = _SizeInWords; + if (_Count == _TRUNCATE) + { + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + } + else + { + while ((*p++ = *_Src++) != 0 && --available > 0 && --_Count > 0) + { + } + if (_Count == 0) + { + *p = 0; + } + } + + if (available == 0) + { + if (_Count == _TRUNCATE) + { + _Dst[_SizeInWords - 1] = 0; + return STRUNCATE; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1); + return 0; +} + +#endif + +/* _mbsnbcpy_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbsnbcpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInBytes) +{ + return _mbsnbcpy_s(_Dst, _SizeInBytes, _Src, _CountInBytes); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes) +{ + unsigned char *p; + size_t available; + + if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + if (_CountInBytes == 0) + { + /* notice that the source string pointer can be nullptr in this case */ + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + return 0; + } + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + if (_CountInBytes == _TRUNCATE) + { + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + } + else + { + while ((*p++ = *_Src++) != 0 && --available > 0 && --_CountInBytes > 0) + { + } + if (_CountInBytes == 0) + { + *p++ = 0; + } + } + + if (available == 0) + { + if ((*_Src == 0 || _CountInBytes == 1) && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the source string ended with a lead byte: we remove it */ + p[-1] = 0; + return 0; + } + if (_CountInBytes == _TRUNCATE) + { + if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2])) + { + _Dst[_SizeInBytes - 2] = 0; + _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]); + } + else + { + _Dst[_SizeInBytes - 1] = 0; + } + return STRUNCATE; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2])) + { + /* the source string ended with a lead byte: we remove it */ + p[-2] = 0; + available++; + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* _mbsncpy_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbsncpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbsncpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInChars) +{ + return _mbsncpy_s(_Dst, _SizeInBytes, _Src, _CountInChars); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbsncpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars) +{ + unsigned char *p; + size_t available; + + if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + if (_CountInChars == 0) + { + /* notice that the source string pointer can be nullptr in this case */ + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + return 0; + } + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + if (_CountInChars == _TRUNCATE) + { + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + } + else + { + do + { + if (_SAFECRT__ISMBBLEAD(*_Src)) + { + if (_Src[1] == 0) + { + /* the source string ended with a lead byte: we remove it */ + *p = 0; + break; + } + if (available <= 2) + { + /* not enough space */ + available = 0; + break; + } + *p++ = *_Src++; + *p++ = *_Src++; + available -= 2; + } + else + { + if ((*p++ = *_Src++) == 0 || --available == 0) + { + break; + } + } + } + while (--_CountInChars > 0); + if (_CountInChars == 0) + { + *p++ = 0; + } + } + + if (available == 0) + { + if (_CountInChars == _TRUNCATE) + { + if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2])) + { + _Dst[_SizeInBytes - 2] = 0; + _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]); + } + else + { + _Dst[_SizeInBytes - 1] = 0; + } + return STRUNCATE; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* strcat_s */ +/* + * strcat_s, wcscat_s append string _Src to _Dst; + * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst + */ +_SAFECRT__EXTERN_C +errno_t __cdecl strcat_s(char *_Dst, size_t _SizeInBytes, const char *_Src); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl strcat_s(char (&_Dst)[_SizeInBytes], const char *_Src) +{ + return strcat_s(_Dst, _SizeInBytes, _Src); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl strcat_s(char *_Dst, size_t _SizeInBytes, const char *_Src) +{ + char *p; + size_t available; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +/* wcscat_s */ +_SAFECRT__EXTERN_C +errno_t __cdecl wcscat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +errno_t __cdecl wcscat_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src) +{ + return wcscat_s(_Dst, _SizeInWords, _Src); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl wcscat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src) +{ + WCHAR *p; + size_t available; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords); + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords); + + p = _Dst; + available = _SizeInWords; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords); + } + + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1); + return 0; +} + +#endif + +/* _mbscat_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbscat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbscat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src) +{ + return _mbscat_s(_Dst, _SizeInBytes, _Src); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbscat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src) +{ + unsigned char *p; + size_t available; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the original string ended with a lead byte: we remove it */ + p--; + *p = 0; + available = 1; + } + else + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + } + if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the original string ended with a lead byte: we remove it */ + p--; + *p = 0; + available++; + } + + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + + if (available == 0) + { + if (*_Src == 0 && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the source string ended with a lead byte: we remove it */ + p[-1] = 0; + return 0; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2])) + { + /* the source string ended with a lead byte: we remove it */ + p[-2] = 0; + available++; + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* strncat_s */ +/* + * strncat_s, wcsncat_s append at max _Count characters from string _Src to _Dst; + * string _Dst will always be null-terminated; + * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst; + * if _Count == _TRUNCATE, we will append as many characters as we can from _Src to _Dst, and + * return STRUNCATE if _Src does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER); + * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed + */ +_SAFECRT__EXTERN_C +errno_t __cdecl strncat_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl strncat_s(char (&_Dst)[_SizeInBytes], const char *_Src, size_t _Count) +{ + return strncat_s(_Dst, _SizeInBytes, _Src, _Count); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl strncat_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count) +{ + char *p; + size_t available; + if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + if (_Count != 0) + { + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + } + + p = _Dst; + available = _SizeInBytes; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + + if (_Count == _TRUNCATE) + { + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + } + else + { + while (_Count > 0 && (*p++ = *_Src++) != 0 && --available > 0) + { + _Count--; + } + if (_Count == 0) + { + *p = 0; + } + } + + if (available == 0) + { + if (_Count == _TRUNCATE) + { + _Dst[_SizeInBytes - 1] = 0; + return STRUNCATE; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +/* wcsncat_s */ +_SAFECRT__EXTERN_C +errno_t __cdecl wcsncat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +errno_t __cdecl wcsncat_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src, size_t _Count) +{ + return wcsncat_s(_Dst, _SizeInWords, _Src, _Count); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl wcsncat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count) +{ + WCHAR *p; + size_t available; + if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords); + if (_Count != 0) + { + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords); + } + + p = _Dst; + available = _SizeInWords; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords); + } + + if (_Count == _TRUNCATE) + { + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + } + else + { + while (_Count > 0 && (*p++ = *_Src++) != 0 && --available > 0) + { + _Count--; + } + if (_Count == 0) + { + *p = 0; + } + } + + if (available == 0) + { + if (_Count == _TRUNCATE) + { + _Dst[_SizeInWords - 1] = 0; + return STRUNCATE; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1); + return 0; +} + +#endif + +/* _mbsnbcat_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbsnbcat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInBytes) +{ + return _mbsnbcat_s(_Dst, _SizeInBytes, _Src, size_t _CountInBytes); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes) +{ + unsigned char *p; + size_t available; + if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + if (_CountInBytes != 0) + { + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + } + + p = _Dst; + available = _SizeInBytes; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the original string ended with a lead byte: we remove it */ + p--; + *p = 0; + available = 1; + } + else + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + } + if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the original string ended with a lead byte: we remove it */ + p--; + *p = 0; + available++; + } + + if (_CountInBytes == _TRUNCATE) + { + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + } + else + { + while (_CountInBytes > 0 && (*p++ = *_Src++) != 0 && --available > 0) + { + _CountInBytes--; + } + if (_CountInBytes == 0) + { + *p++ = 0; + } + } + + if (available == 0) + { + if ((*_Src == 0 || _CountInBytes == 1) && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the source string ended with a lead byte: we remove it */ + p[-1] = 0; + return 0; + } + if (_CountInBytes == _TRUNCATE) + { + if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2])) + { + _Dst[_SizeInBytes - 2] = 0; + _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]); + } + else + { + _Dst[_SizeInBytes - 1] = 0; + } + return STRUNCATE; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2])) + { + /* the source string ended with a lead byte: we remove it */ + p[-2] = 0; + available++; + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* _mbsncat_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbsncat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbsncat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInChars) +{ + return _mbsncat_s(_Dst, _SizeInBytes, _Src, size_t _CountInChars); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbsncat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars) +{ + unsigned char *p; + size_t available; + if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + if (_CountInChars != 0) + { + _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes); + } + + p = _Dst; + available = _SizeInBytes; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the original string ended with a lead byte: we remove it */ + p--; + *p = 0; + available = 1; + } + else + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + } + if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1])) + { + /* the original string ended with a lead byte: we remove it */ + p--; + *p = 0; + available++; + } + + if (_CountInChars == _TRUNCATE) + { + while ((*p++ = *_Src++) != 0 && --available > 0) + { + } + } + else + { + while (_CountInChars > 0) + { + if (_SAFECRT__ISMBBLEAD(*_Src)) + { + if (_Src[1] == 0) + { + /* the source string ended with a lead byte: we remove it */ + *p = 0; + break; + } + if (available <= 2) + { + /* not enough space */ + available = 0; + break; + } + *p++ = *_Src++; + *p++ = *_Src++; + available -= 2; + } + else + { + if ((*p++ = *_Src++) == 0 || --available == 0) + { + break; + } + } + _CountInChars--; + } + if (_CountInChars == 0) + { + *p++ = 0; + } + } + + if (available == 0) + { + if (_CountInChars == _TRUNCATE) + { + if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2])) + { + _Dst[_SizeInBytes - 2] = 0; + _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]); + } + else + { + _Dst[_SizeInBytes - 1] = 0; + } + return STRUNCATE; + } + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* _strset_s */ +/* + * _strset_s, _wcsset_s ; + * will call _SAFECRT_INVALID_PARAMETER if _Dst is not null terminated. + */ +_SAFECRT__EXTERN_C +errno_t __cdecl _strset_s(char *_Dst, size_t _SizeInBytes, int _Value); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _strset_s(char (&_Dst)[_SizeInBytes], int _Value) +{ + return _strset_s(_Dst, _SizeInBytes, _Value); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _strset_s(char *_Dst, size_t _SizeInBytes, int _Value) +{ + char *p; + size_t available; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + while (*p != 0 && --available > 0) + { + *p++ = (char)_Value; + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +/* _wcsset_s */ +_SAFECRT__EXTERN_C +errno_t __cdecl _wcsset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +errno_t __cdecl _wcsset_s(WCHAR (&_Dst)[_SizeInWords], WCHAR _Value) +{ + return _wcsset_s(_Dst, _SizeInWords, _Value); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _wcsset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value) +{ + WCHAR *p; + size_t available; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords); + + p = _Dst; + available = _SizeInWords; + while (*p != 0 && --available > 0) + { + *p++ = (WCHAR)_Value; + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1); + return 0; +} + +#endif + +/* _mbsset_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbsset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbsset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value) +{ + return _mbsset_s(_Dst, _SizeInBytes, _Value); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbsset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value) +{ + int mbcs_error = 0; + unsigned char *p; + size_t available; + unsigned char highval, lowval; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + highval = (unsigned char)(_Value >> 8); + lowval = (unsigned char)(_Value & 0x00ff); + if (highval != 0) + { + if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0) + { + while (*p != 0 && --available > 0) + { + if (p[1] == 0) + { + /* do not orphan leadbyte */ + *p++ = ' '; + break; + } + *p++ = highval; + if (--available == 0) + { + break; + } + *p++ = lowval; + } + } + else + { + mbcs_error = 1; + highval = 0; + lowval = ' '; + } + } + else + { + if (_SAFECRT__ISMBBLEAD(lowval)) + { + mbcs_error = 1; + lowval = ' '; + } + } + if (highval == 0) + { + while (*p != 0 && --available > 0) + { + *p++ = lowval; + } + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + if (mbcs_error) + { + _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ; + } + else + { + return 0; + } +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* _strnset_s */ +/* + * _strnset_s, _wcsnset_s ; + * will call _SAFECRT_INVALID_PARAMETER if _Dst is not null terminated. + */ +_SAFECRT__EXTERN_C +errno_t __cdecl _strnset_s(char *_Dst, size_t _SizeInBytes, int _Value, size_t _Count); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _strnset_s(char (&_Dst)[_SizeInBytes], int _Value, size_t _Count) +{ + return _strnset_s(_Dst, _SizeInBytes, _Value, _Count); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _strnset_s(char *_Dst, size_t _SizeInBytes, int _Value, size_t _Count) +{ + char *p; + size_t available; + + /* validation section */ + if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + while (*p != 0 && _Count > 0 && --available > 0) + { + *p++ = (char)_Value; + --_Count; + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + if (_Count == 0) + { + *p = 0; + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + return 0; +} + +#endif + +/* _wcsnset_s */ +_SAFECRT__EXTERN_C +errno_t __cdecl _wcsnset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value, size_t _Count); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +errno_t __cdecl _wcsnset_s(WCHAR (&_Dst)[_SizeInWords], WCHAR _Value, size_t _Count) +{ + return _wcsnset_s(_Dst, _SizeInWords, _Value, _Count); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _wcsnset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value, size_t _Count) +{ + WCHAR *p; + size_t available; + + /* validation section */ + if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords); + + p = _Dst; + available = _SizeInWords; + while (*p != 0 && _Count > 0 && --available > 0) + { + *p++ = (WCHAR)_Value; + --_Count; + } + + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords); + } + if (_Count == 0) + { + *p = 0; + } + _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1); + return 0; +} + +#endif + +/* _mbsnbset_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbsnbset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInBytes); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbsnbset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value, size_t _CountInBytes) +{ + return _mbsnbset_s(_Dst, _SizeInBytes, _Value, _CountInBytes); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbsnbset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInBytes) +{ + int mbcs_error = 0; + unsigned char *p; + size_t available; + unsigned char highval, lowval; + + /* validation section */ + if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + highval = (unsigned char)(_Value >> 8); + lowval = (unsigned char)(_Value & 0x00ff); + if (highval != 0) + { + if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0) + { + while (*p != 0 && _CountInBytes > 0 && --available > 0) + { + if (_CountInBytes == 1 || p[1] == 0) + { + /* do not orphan leadbyte */ + *p++ = ' '; + --_CountInBytes; + break; + } + *p++ = highval; + if (--available == 0) + { + break; + } + *p++ = lowval; + _CountInBytes -= 2; + } + } + else + { + mbcs_error = 1; + highval = 0; + lowval = ' '; + } + } + else + { + if (_SAFECRT__ISMBBLEAD(lowval)) + { + mbcs_error = 1; + lowval = ' '; + } + } + if (highval == 0) + { + while (*p != 0 && available > 0 && _CountInBytes > 0) + { + *p++ = lowval; + --available; + --_CountInBytes; + } + } + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + if (_CountInBytes == 0) + { + *p = 0; + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + if (mbcs_error) + { + _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ; + } + else + { + return 0; + } +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* _mbsnset_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbsnset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInChars); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbsnset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value, size_t _CountInChars) +{ + return _mbsnset_s(_Dst, _SizeInBytes, _Value, _CountInChars); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbsnset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInChars) +{ + int mbcs_error = 0; + unsigned char *p; + size_t available; + unsigned char highval, lowval; + + /* validation section */ + if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + + p = _Dst; + available = _SizeInBytes; + highval = (unsigned char)(_Value >> 8); + lowval = (unsigned char)(_Value & 0x00ff); + if (highval != 0) + { + if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0) + { + while (*p != 0 && _CountInChars > 0 && --available > 0) + { + if (p[1] == 0) + { + /* do not orphan leadbyte */ + *p++ = ' '; + break; + } + *p++ = highval; + if (--available == 0) + { + break; + } + *p++ = lowval; + --_CountInChars; + } + } + else + { + mbcs_error = 1; + highval = 0; + lowval = ' '; + } + } + else + { + if (_SAFECRT__ISMBBLEAD(lowval)) + { + mbcs_error = 1; + lowval = ' '; + } + } + if (highval == 0) + { + while (*p != 0 && available > 0 && _CountInChars > 0) + { + *p++ = lowval; + --available; + --_CountInChars; + } + } + if (available == 0) + { + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes); + } + if (_CountInChars == 0) + { + *p = 0; + } + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1); + if (mbcs_error) + { + _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ; + } + else + { + return 0; + } +} + +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* _mbccpy_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +errno_t __cdecl _mbccpy_s(unsigned char *_Dst, size_t _SizeInBytes, int *_PCopied, const unsigned char *_Src); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _mbccpy_s(unsigned char (&_Dst)[_SizeInBytes], int *_PCopied, const unsigned char *_Src) +{ + return _mbccpy_s(_Dst, _SizeInBytes, _PCopied, _Src); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _mbccpy_s(unsigned char *_Dst, size_t _SizeInBytes, int *_PCopied, const unsigned char *_Src) +{ + /* validation section */ + if (_PCopied != nullptr) { *_PCopied = 0; }; + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + if (_Src == nullptr) + { + *_Dst = '\0'; + _SAFECRT__RETURN_EINVAL; + } + + /* copy */ + if (_SAFECRT__ISMBBLEAD(*_Src)) + { + if (_Src[1] == '\0') + { + /* the source string contained a lead byte followed by the null terminator: + we copy only the null terminator and return EILSEQ to indicate the + malformed char */ + *_Dst = '\0'; + if (_PCopied != nullptr) { *_PCopied = 1; }; + _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ; + } + if (_SizeInBytes < 2) + { + *_Dst = '\0'; + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + } + *_Dst++ = *_Src++; + *_Dst = *_Src; + if (_PCopied != nullptr) { *_PCopied = 2; }; + } + else + { + *_Dst = *_Src; + if (_PCopied != nullptr) { *_PCopied = 1; }; + } + + return 0; +} +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +/* strtok_s */ +/* + * strtok_s, wcstok_s ; + * uses _Context to keep track of the position in the string. + */ +_SAFECRT__EXTERN_C +char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context); + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context) +{ + unsigned char *str; + const unsigned char *ctl = (const unsigned char *)_Control; + unsigned char map[32]; + int count; + + /* validation section */ + _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr); + _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr); + _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr); + + /* Clear control map */ + for (count = 0; count < 32; count++) + { + map[count] = 0; + } + + /* Set bits in delimiter table */ + do { + map[*ctl >> 3] |= (1 << (*ctl & 7)); + } while (*ctl++); + + /* If string is nullptr, set str to the saved + * pointer (i.e., continue breaking tokens out of the string + * from the last strtok call) */ + if (_String != nullptr) + { + str = (unsigned char *)_String; + } + else + { + str = (unsigned char *)*_Context; + } + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets str to point to the terminal + * null (*str == 0) */ + while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0) + { + str++; + } + + _String = (char *)str; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. */ + for ( ; *str != 0 ; str++ ) + { + if (map[*str >> 3] & (1 << (*str & 7))) + { + *str++ = 0; + break; + } + } + + /* Update context */ + *_Context = (char *)str; + + /* Determine if a token has been found. */ + if (_String == (char *)str) + { + return nullptr; + } + else + { + return _String; + } +} +#endif + +/* wcstok_s */ +_SAFECRT__EXTERN_C +WCHAR * __cdecl wcstok_s(WCHAR *_String, const WCHAR *_Control, WCHAR **_Context); + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +WCHAR * __cdecl wcstok_s(WCHAR *_String, const WCHAR *_Control, WCHAR **_Context) +{ + WCHAR *token; + const WCHAR *ctl; + + /* validation section */ + _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr); + _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr); + _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr); + + /* If string==nullptr, continue with previous string */ + if (!_String) + { + _String = *_Context; + } + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets string to point to the terminal null. */ + for ( ; *_String != 0 ; _String++) + { + for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++) + ; + if (*ctl == 0) + { + break; + } + } + + token = _String; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. */ + for ( ; *_String != 0 ; _String++) + { + for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++) + ; + if (*ctl != 0) + { + *_String++ = 0; + break; + } + } + + /* Update the context */ + *_Context = _String; + + /* Determine if a token has been found. */ + if (token == _String) + { + return nullptr; + } + else + { + return token; + } +} +#endif + +/* _mbstok_s */ +#if _SAFECRT_DEFINE_MBS_FUNCTIONS + +_SAFECRT__EXTERN_C +unsigned char * __cdecl _mbstok_s(unsigned char *_String, const unsigned char *_Control, unsigned char **_Context); + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +unsigned char * __cdecl _mbstok_s(unsigned char *_String, const unsigned char *_Control, unsigned char **_Context) +{ + unsigned char *token; + const unsigned char *ctl; + int dbc; + + /* validation section */ + _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr); + _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr); + _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr); + + /* If string==nullptr, continue with previous string */ + if (!_String) + { + _String = *_Context; + } + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets string to point to the terminal null. */ + for ( ; *_String != 0; _String++) + { + for (ctl = _Control; *ctl != 0; ctl++) + { + if (_SAFECRT__ISMBBLEAD(*ctl)) + { + if (*ctl == *_String && (ctl[1] == 0 || ctl[1] == _String[1])) + { + break; + } + ctl++; + } + else + { + if (*ctl == *_String) + { + break; + } + } + } + if (*ctl == 0) + { + break; + } + if (_SAFECRT__ISMBBLEAD(*_String)) + { + _String++; + if (*_String == 0) + { + break; + } + } + } + + token = _String; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. */ + for ( ; *_String != 0; _String++) + { + for (ctl = _Control, dbc = 0; *ctl != 0; ctl++) + { + if (_SAFECRT__ISMBBLEAD(*ctl)) + { + if (*ctl == *_String && (ctl[1] == 0 || ctl[1] == _String[1])) + { + dbc = 1; + break; + } + ctl++; + } + else + { + if (*ctl == *_String) + { + break; + } + } + } + if (*ctl != 0) + { + *_String++ = 0; + if (dbc && ctl[1] != 0) + { + *_String++ = 0; + } + break; + } + if (_SAFECRT__ISMBBLEAD(*_String)) + { + _String++; + if (*_String == 0) + { + break; + } + } + } + + /* Update the context */ + *_Context = _String; + + /* Determine if a token has been found. */ + if (token == _String) + { + return nullptr; + } + else + { + return token; + } +} +#endif + +#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */ + +#ifndef PAL_STDCPP_COMPAT +/* strnlen */ +/* + * strnlen, wcsnlen ; + * returns inMaxSize if the null character is not found. + */ +_SAFECRT__EXTERN_C +size_t __cdecl strnlen(const char* inString, size_t inMaxSize); + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +size_t __cdecl strnlen(const char* inString, size_t inMaxSize) +{ + size_t n; + + /* Note that we do not check if s == nullptr, because we do not + * return errno_t... + */ + + for (n = 0; n < inMaxSize && *inString; n++, inString++) + ; + + return n; +} + +#endif + +/* wcsnlen */ +_SAFECRT__EXTERN_C +size_t __cdecl wcsnlen(const WCHAR *inString, size_t inMaxSize); + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +size_t __cdecl wcsnlen(const WCHAR *inString, size_t inMaxSize) +{ + size_t n; + + /* Note that we do not check if s == nullptr, because we do not + * return errno_t... + */ + + for (n = 0; n < inMaxSize && *inString; n++, inString++) + ; + + return n; +} + +#endif +#endif // PAL_STDCPP_COMPAT + +/* _makepath_s */ +/* + * _makepath_s, _wmakepath_s build up a path starting from the specified components; + * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst; + * any of _Drive, _Dir, _Filename and _Ext can be nullptr + */ +_SAFECRT__EXTERN_C +errno_t __cdecl _makepath_s(char *_Dst, size_t _SizeInBytes, const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +errno_t __cdecl _makepath_s(char (&_Dst)[_SizeInBytes], const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext) +{ + return _makepath_s(_Dst, _SizeInBytes, _Drive, _Dir, _Filename, _Ext); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _makepath_s(char *_Dst, size_t _SizeInBytes, const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext) +{ + size_t written; + const char *p; + char *d; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes); + + /* copy drive */ + written = 0; + d = _Dst; + if (_Drive != nullptr && *_Drive != 0) + { + written += 2; + if(written >= _SizeInBytes) + { + goto error_return; + } + *d++ = *_Drive; + *d++ = ':'; + } + + /* copy dir */ + p = _Dir; + if (p != nullptr && *p != 0) + { + do { + if(++written >= _SizeInBytes) + { + goto error_return; + } + *d++ = *p++; + } while (*p != 0); + + p = (const char *)_SAFECRT__MBSDEC((const unsigned char *)_Dir, (const unsigned char *)p); + if (*p != '/' && *p != '\\') + { + if(++written >= _SizeInBytes) + { + goto error_return; + } + *d++ = '\\'; + } + } + + /* copy fname */ + p = _Filename; + if (p != nullptr) + { + while (*p != 0) + { + if(++written >= _SizeInBytes) + { + goto error_return; + } + *d++ = *p++; + } + } + + /* copy extension; check to see if a '.' needs to be inserted */ + p = _Ext; + if (p != nullptr) + { + if (*p != 0 && *p != '.') + { + if(++written >= _SizeInBytes) + { + goto error_return; + } + *d++ = '.'; + } + while (*p != 0) + { + if(++written >= _SizeInBytes) + { + goto error_return; + } + *d++ = *p++; + } + } + + if(++written > _SizeInBytes) + { + goto error_return; + } + *d = 0; + _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, written); + return 0; + +error_return: + _SAFECRT__RESET_STRING(_Dst, _SizeInBytes); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes); + /* should never happen, but compiler can't tell */ + return EINVAL; +} +#endif + +/* _wmakepath_s */ +_SAFECRT__EXTERN_C +errno_t __cdecl _wmakepath_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +errno_t __cdecl _wmakepath_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext) +{ + return _wmakepath_s(_Dst, _SizeInWords, _Drive, _Dir, _Filename, _Ext); +} +#endif + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _wmakepath_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext) +{ + size_t written; + const WCHAR *p; + WCHAR *d; + + /* validation section */ + _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords); + + /* copy drive */ + written = 0; + d = _Dst; + if (_Drive != nullptr && *_Drive != 0) + { + written += 2; + if(written >= _SizeInWords) + { + goto error_return; + } + *d++ = *_Drive; + *d++ = L':'; + } + + /* copy dir */ + p = _Dir; + if (p != nullptr && *p != 0) + { + do { + if(++written >= _SizeInWords) + { + goto error_return; + } + *d++ = *p++; + } while (*p != 0); + + p = p - 1; + if (*p != L'/' && *p != L'\\') + { + if(++written >= _SizeInWords) + { + goto error_return; + } + *d++ = L'\\'; + } + } + + /* copy fname */ + p = _Filename; + if (p != nullptr) + { + while (*p != 0) + { + if(++written >= _SizeInWords) + { + goto error_return; + } + *d++ = *p++; + } + } + + /* copy extension; check to see if a '.' needs to be inserted */ + p = _Ext; + if (p != nullptr) + { + if (*p != 0 && *p != L'.') + { + if(++written >= _SizeInWords) + { + goto error_return; + } + *d++ = L'.'; + } + while (*p != 0) + { + if(++written >= _SizeInWords) + { + goto error_return; + } + *d++ = *p++; + } + } + + if(++written > _SizeInWords) + { + goto error_return; + } + *d = 0; + _SAFECRT__FILL_STRING(_Dst, _SizeInWords, written); + return 0; + +error_return: + _SAFECRT__RESET_STRING(_Dst, _SizeInWords); + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords); + /* should never happen, but compiler can't tell */ + return EINVAL; +} +#endif + +/* _splitpath_s */ +/* + * _splitpath_s, _wsplitpath_s decompose a path into the specified components; + * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in + * any of _Drive, _Dir, _Filename and _Ext; + * any of _Drive, _Dir, _Filename and _Ext can be nullptr, but the correspondent size must + * be set to 0, e.g. (_Drive == nullptr && _DriveSize == 0) is allowed, but + * (_Drive == nullptr && _DriveSize != 0) is considered an invalid parameter + */ +_SAFECRT__EXTERN_C +errno_t __cdecl _splitpath_s( + const char *_Path, + char *_Drive, size_t _DriveSize, + char *_Dir, size_t _DirSize, + char *_Filename, size_t _FilenameSize, + char *_Ext, size_t _ExtSize +); + +/* no C++ overload for _splitpath_s */ + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _splitpath_s( + const char *_Path, + char *_Drive, size_t _DriveSize, + char *_Dir, size_t _DirSize, + char *_Filename, size_t _FilenameSize, + char *_Ext, size_t _ExtSize +) +{ + const char *tmp; + const char *last_slash; + const char *dot; + int drive_set = 0; + size_t length = 0; + int bEinval = 0; + + /* validation section */ + _SAFECRT__VALIDATE_POINTER(_Path); + if ((_Drive == nullptr && _DriveSize != 0) || (_Drive != nullptr && _DriveSize == 0)) + { + goto error_einval; + } + if ((_Dir == nullptr && _DirSize != 0) || (_Dir != nullptr && _DirSize == 0)) + { + goto error_einval; + } + if ((_Filename == nullptr && _FilenameSize != 0) || (_Filename != nullptr && _FilenameSize == 0)) + { + goto error_einval; + } + if ((_Ext == nullptr && _ExtSize != 0) || (_Ext != nullptr && _ExtSize == 0)) + { + goto error_einval; + } + + /* check if _Path begins with the longpath prefix */ + if (_Path[0] == '\\' && _Path[1] == '\\' && _Path[2] == '?' && _Path[3] == '\\') + { + _Path += 4; + } + + /* extract drive letter and ':', if any */ + if (!drive_set) + { + size_t skip = _MAX_DRIVE - 2; + tmp = _Path; + while (skip > 0 && *tmp != 0) + { + skip--; + tmp++; + } + if (*tmp == ':') + { + if (_Drive != nullptr) + { + if (_DriveSize < _MAX_DRIVE) + { + goto error_erange; + } + strncpy_s(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1); + } + _Path = tmp + 1; + } + else + { + if (_Drive != nullptr) + { + _SAFECRT__RESET_STRING(_Drive, _DriveSize); + } + } + } + + /* extract path string, if any. _Path now points to the first character + * of the path, if any, or the filename or extension, if no path was + * specified. Scan ahead for the last occurence, if any, of a '/' or + * '\' path separator character. If none is found, there is no path. + * We will also note the last '.' character found, if any, to aid in + * handling the extension. + */ + last_slash = nullptr; + dot = nullptr; + tmp = _Path; + for (; *tmp != 0; ++tmp) + { +#if _SAFECRT_DEFINE_MBS_FUNCTIONS +#pragma warning(push) +#pragma warning(disable:4127) + if (_SAFECRT__ISMBBLEAD(*tmp)) +#pragma warning(pop) +#else + if (0) +#endif + { + tmp++; + } + else + { + if (*tmp == '/' || *tmp == '\\') + { + /* point to one beyond for later copy */ + last_slash = tmp + 1; + } + else if (*tmp == '.') + { + dot = tmp; + } + } + } + + if (last_slash != nullptr) + { + /* found a path - copy up through last_slash or max characters + * allowed, whichever is smaller + */ + if (_Dir != nullptr) { + length = (size_t)(last_slash - _Path); + if (_DirSize <= length) + { + goto error_erange; + } + strncpy_s(_Dir, _DirSize, _Path, length); + } + _Path = last_slash; + } + else + { + /* there is no path */ + if (_Dir != nullptr) + { + _SAFECRT__RESET_STRING(_Dir, _DirSize); + } + } + + /* extract file name and extension, if any. Path now points to the + * first character of the file name, if any, or the extension if no + * file name was given. Dot points to the '.' beginning the extension, + * if any. + */ + if (dot != nullptr && (dot >= _Path)) + { + /* found the marker for an extension - copy the file name up to the '.' */ + if (_Filename) + { + length = (size_t)(dot - _Path); + if (_FilenameSize <= length) + { + goto error_erange; + } + strncpy_s(_Filename, _FilenameSize, _Path, length); + } + /* now we can get the extension - remember that tmp still points + * to the terminating nullptr character of path. + */ + if (_Ext) + { + length = (size_t)(tmp - dot); + if (_ExtSize <= length) + { + goto error_erange; + } + strncpy_s(_Ext, _ExtSize, dot, length); + } + } + else + { + /* found no extension, give empty extension and copy rest of + * string into fname. + */ + if (_Filename) + { + length = (size_t)(tmp - _Path); + if (_FilenameSize <= length) + { + goto error_erange; + } + strncpy_s(_Filename, _FilenameSize, _Path, length); + } + if (_Ext) + { + _SAFECRT__RESET_STRING(_Ext, _ExtSize); + } + } + + return 0; + +error_einval: + bEinval = 1; + +error_erange: + if (_Drive != nullptr && _DriveSize > 0) + { + _SAFECRT__RESET_STRING(_Drive, _DriveSize); + } + if (_Dir != nullptr && _DirSize > 0) + { + _SAFECRT__RESET_STRING(_Dir, _DirSize); + } + if (_Filename != nullptr && _FilenameSize > 0) + { + _SAFECRT__RESET_STRING(_Filename, _FilenameSize); + } + if (_Ext != nullptr && _ExtSize > 0) + { + _SAFECRT__RESET_STRING(_Ext, _ExtSize); + } + + if (bEinval) + { + _SAFECRT__RETURN_EINVAL; + } + + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Strings, _StringSizes); + /* should never happen, but compiler can't tell */ + return EINVAL; +} +#endif + +/* _wsplitpath_s */ +_SAFECRT__EXTERN_C +errno_t __cdecl _wsplitpath_s( + const WCHAR *_Path, + WCHAR *_Drive, size_t _DriveSize, + WCHAR *_Dir, size_t _DirSize, + WCHAR *_Filename, size_t _FilenameSize, + WCHAR *_Ext, size_t _ExtSize +); + +/* no C++ overload for _wsplitpath_s */ + +#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL + +_SAFECRT__INLINE +errno_t __cdecl _wsplitpath_s( + const WCHAR *_Path, + WCHAR *_Drive, size_t _DriveSize, + WCHAR *_Dir, size_t _DirSize, + WCHAR *_Filename, size_t _FilenameSize, + WCHAR *_Ext, size_t _ExtSize +) +{ + const WCHAR *tmp; + const WCHAR *last_slash; + const WCHAR *dot; + int drive_set = 0; + size_t length = 0; + int bEinval = 0; + + /* validation section */ + _SAFECRT__VALIDATE_POINTER(_Path); + if ((_Drive == nullptr && _DriveSize != 0) || (_Drive != nullptr && _DriveSize == 0)) + { + goto error_einval; + } + if ((_Dir == nullptr && _DirSize != 0) || (_Dir != nullptr && _DirSize == 0)) + { + goto error_einval; + } + if ((_Filename == nullptr && _FilenameSize != 0) || (_Filename != nullptr && _FilenameSize == 0)) + { + goto error_einval; + } + if ((_Ext == nullptr && _ExtSize != 0) || (_Ext != nullptr && _ExtSize == 0)) + { + goto error_einval; + } + + /* check if _Path begins with the longpath prefix */ + if (_Path[0] == L'\\' && _Path[1] == L'\\' && _Path[2] == L'?' && _Path[3] == L'\\') + { + _Path += 4; + } + + /* extract drive letter and ':', if any */ + if (!drive_set) + { + size_t skip = _MAX_DRIVE - 2; + tmp = _Path; + while (skip > 0 && *tmp != 0) + { + skip--; + tmp++; + } + if (*tmp == L':') + { + if (_Drive != nullptr) + { + if (_DriveSize < _MAX_DRIVE) + { + goto error_erange; + } + wcsncpy_s(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1); + } + _Path = tmp + 1; + } + else + { + if (_Drive != nullptr) + { + _SAFECRT__RESET_STRING(_Drive, _DriveSize); + } + } + } + + /* extract path string, if any. _Path now points to the first character + * of the path, if any, or the filename or extension, if no path was + * specified. Scan ahead for the last occurence, if any, of a '/' or + * '\' path separator character. If none is found, there is no path. + * We will also note the last '.' character found, if any, to aid in + * handling the extension. + */ + last_slash = nullptr; + dot = nullptr; + tmp = _Path; + for (; *tmp != 0; ++tmp) + { + { + if (*tmp == L'/' || *tmp == L'\\') + { + /* point to one beyond for later copy */ + last_slash = tmp + 1; + } + else if (*tmp == L'.') + { + dot = tmp; + } + } + } + + if (last_slash != nullptr) + { + /* found a path - copy up through last_slash or max characters + * allowed, whichever is smaller + */ + if (_Dir != nullptr) { + length = (size_t)(last_slash - _Path); + if (_DirSize <= length) + { + goto error_erange; + } + wcsncpy_s(_Dir, _DirSize, _Path, length); + } + _Path = last_slash; + } + else + { + /* there is no path */ + if (_Dir != nullptr) + { + _SAFECRT__RESET_STRING(_Dir, _DirSize); + } + } + + /* extract file name and extension, if any. Path now points to the + * first character of the file name, if any, or the extension if no + * file name was given. Dot points to the '.' beginning the extension, + * if any. + */ + if (dot != nullptr && (dot >= _Path)) + { + /* found the marker for an extension - copy the file name up to the '.' */ + if (_Filename) + { + length = (size_t)(dot - _Path); + if (_FilenameSize <= length) + { + goto error_erange; + } + wcsncpy_s(_Filename, _FilenameSize, _Path, length); + } + /* now we can get the extension - remember that tmp still points + * to the terminating nullptr character of path. + */ + if (_Ext) + { + length = (size_t)(tmp - dot); + if (_ExtSize <= length) + { + goto error_erange; + } + wcsncpy_s(_Ext, _ExtSize, dot, length); + } + } + else + { + /* found no extension, give empty extension and copy rest of + * string into fname. + */ + if (_Filename) + { + length = (size_t)(tmp - _Path); + if (_FilenameSize <= length) + { + goto error_erange; + } + wcsncpy_s(_Filename, _FilenameSize, _Path, length); + } + if (_Ext) + { + _SAFECRT__RESET_STRING(_Ext, _ExtSize); + } + } + + return 0; + +error_einval: + bEinval = 1; + +error_erange: + if (_Drive != nullptr && _DriveSize > 0) + { + _SAFECRT__RESET_STRING(_Drive, _DriveSize); + } + if (_Dir != nullptr && _DirSize > 0) + { + _SAFECRT__RESET_STRING(_Dir, _DirSize); + } + if (_Filename != nullptr && _FilenameSize > 0) + { + _SAFECRT__RESET_STRING(_Filename, _FilenameSize); + } + if (_Ext != nullptr && _ExtSize > 0) + { + _SAFECRT__RESET_STRING(_Ext, _ExtSize); + } + + if (bEinval) + { + _SAFECRT__RETURN_EINVAL; + } + + _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Strings, _StringSizes); + /* should never happen, but compiler can't tell */ + return EINVAL; +} +#endif + +/* sprintf_s, vsprintf_s */ +/* + * sprintf_s, swprintf_s, vsprintf_s, vswprintf_s format a string and copy it into _Dst; + * need safecrt.lib and msvcrt.dll; + * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst; + * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed; + * the %n format type is not allowed; + * return the length of string _Dst; + * return a negative number if something goes wrong with mbcs conversions (we will not call _SAFECRT_INVALID_PARAMETER); + * _SizeInBytes/_SizeInWords must be <= (INT_MAX / sizeof(char/WCHAR)); + * cannot be used without safecrt.lib + */ +_SAFECRT__EXTERN_C +int __cdecl sprintf_s(char *_Dst, size_t _SizeInBytes, const char *_Format, ...); +_SAFECRT__EXTERN_C +int __cdecl vsprintf_s(char *_Dst, size_t _SizeInBytes, const char *_Format, va_list _ArgList); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +int __cdecl sprintf_s(char (&_Dst)[_SizeInBytes], const char *_Format, ...) +{ + int ret; + va_list _ArgList; + va_start(_ArgList, _Format); + ret = vsprintf_s(_Dst, _SizeInBytes, _Format, _ArgList); + va_end(_ArgList); + return ret; +} + +template <size_t _SizeInBytes> +inline +int __cdecl vsprintf_s(char (&_Dst)[_SizeInBytes], const char *_Format, va_list _ArgList) +{ + return vsprintf_s(_Dst, _SizeInBytes, _Format, _ArgList); +} +#endif + +/* no inline version of sprintf_s, vsprintf_s */ + +/* swprintf_s, vswprintf_s */ +_SAFECRT__EXTERN_C +int __cdecl swprintf_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Format, ...); +_SAFECRT__EXTERN_C +int __cdecl vswprintf_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Format, va_list _ArgList); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +int __cdecl swprintf_s(char (&_Dst)[_SizeInWords], const char *_Format, ...) +{ + int ret; + va_list _ArgList; + va_start(_ArgList, _Format); + ret = vswprintf_s(_Dst, _SizeInWords, _Format, _ArgList); + va_end(_ArgList); + return ret; +} + +template <size_t _SizeInWords> +inline +int __cdecl vswprintf_s(char (&_Dst)[_SizeInWords], const char *_Format, va_list _ArgList) +{ + return vswprintf_s(_Dst, _SizeInWords, _Format, _ArgList); +} +#endif + +/* no inline version of swprintf_s, vswprintf_s */ + +/* _snprintf_s, _vsnprintf_s */ +/* + * _snprintf_s, _snwprintf_s, _vsnprintf_s, _vsnwprintf_s format a string and copy at max _Count characters into _Dst; + * need safecrt.lib and msvcrt.dll; + * string _Dst will always be null-terminated; + * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst; + * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed; + * the %n format type is not allowed; + * return the length of string _Dst; + * return a negative number if something goes wrong with mbcs conversions (we will not call _SAFECRT_INVALID_PARAMETER); + * _SizeInBytes/_SizeInWords must be <= (INT_MAX / sizeof(char/WCHAR)); + * cannot be used without safecrt.lib; + * if _Count == _TRUNCATE, we will copy into _Dst as many characters as we can, and + * return -1 if the formatted string does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER); + * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed + */ +_SAFECRT__EXTERN_C +int __cdecl _snprintf_s(char *_Dst, size_t _SizeInBytes, size_t _Count, const char *_Format, ...); +_SAFECRT__EXTERN_C +int __cdecl _vsnprintf_s(char *_Dst, size_t _SizeInBytes, size_t _Count, const char *_Format, va_list _ArgList); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInBytes> +inline +int __cdecl _snprintf_s(char (&_Dst)[_SizeInBytes], size_t _Count, const char *_Format, ...) +{ + int ret; + va_list _ArgList; + va_start(_ArgList, _Format); + ret = _vsnprintf_s(_Dst, _SizeInBytes, _Count, _Format, _ArgList); + va_end(_ArgList); + return ret; +} + +template <size_t _SizeInBytes> +inline +int __cdecl _vsnprintf_s(char (&_Dst)[_SizeInBytes], size_t _Count, const char *_Format, va_list _ArgList) +{ + return _vsnprintf_s(_Dst, _SizeInBytes, _Count, _Format, _ArgList); +} +#endif + +/* no inline version of _snprintf_s, _vsnprintf_s */ + +/* _snwprintf_s, _vsnwprintf_s */ +_SAFECRT__EXTERN_C +int __cdecl _snwprintf_s(WCHAR *_Dst, size_t _SizeInWords, size_t _Count, const WCHAR *_Format, ...); +_SAFECRT__EXTERN_C +int __cdecl _vsnwprintf_s(WCHAR *_Dst, size_t _SizeInWords, size_t _Count, const WCHAR *_Format, va_list _ArgList); + +#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS +template <size_t _SizeInWords> +inline +int __cdecl _snwprintf_s(char (&_Dst)[_SizeInWords], size_t _Count, const char *_Format, ...) +{ + int ret; + va_list _ArgList; + va_start(_ArgList, _Format); + ret = _vsnwprintf_s(_Dst, _SizeInWords, _Count, _Format, _ArgList); + va_end(_ArgList); + return ret; +} + +template <size_t _SizeInWords> +inline +int __cdecl _vsnwprintf_s(char (&_Dst)[_SizeInWords], size_t _Count, const char *_Format, va_list _ArgList) +{ + return _vsnwprintf_s(_Dst, _SizeInWords, _Count, _Format, _ArgList); +} +#endif + +/* no inline version of _snwprintf_s, _vsnwprintf_s */ + +/* scanf_s */ +/* + * read formatted data from the standard input stream; + * need safecrt.lib and msvcrt.dll; + * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed; + * for format types %s, %S, %[, %c and %C, in the argument list the buffer pointer + * need to be followed by the size of the buffer, e.g.: + * #define BUFFSIZE 100 + * char buff[BUFFSIZE]; + * scanf_s("%s", buff, BUFFSIZE); + * as scanf, returns the number of fields successfully converted and assigned; + * if a buffer field is too small, scanf set the buffer to the empty string and returns. + * do not support floating-point, for now + */ +_SAFECRT__EXTERN_C +int __cdecl scanf_s(const char *_Format, ...); + +/* no C++ overload for scanf_s */ + +/* no inline version of scanf_s */ + +/* wscanf_s */ +_SAFECRT__EXTERN_C +int __cdecl wscanf_s(const WCHAR *_Format, ...); + +/* no C++ overload for wscanf_s */ + +/* no inline version of wscanf_s */ + +/* sscanf_s */ +_SAFECRT__EXTERN_C +int __cdecl sscanf_s(const char *_String, const char *_Format, ...); + +/* no C++ overload for sscanf_s */ + +/* no inline version of sscanf_s */ + +/* swscanf_s */ +_SAFECRT__EXTERN_C +int __cdecl swscanf_s(const WCHAR *_String, const WCHAR *_Format, ...); + +/* no C++ overload for swscanf_s */ + +/* no inline version of swscanf_s */ + +/* _snscanf_s */ +_SAFECRT__EXTERN_C +int __cdecl _snscanf_s(const char *_String, size_t _Count, const char *_Format, ...); + +/* no C++ overload for snscanf_s */ + +/* no inline version of snscanf_s */ + +/* _swnscanf_s */ +_SAFECRT__EXTERN_C +int __cdecl _swnscanf_s(const WCHAR *_String, size_t _Count, const WCHAR *_Format, ...); + +/* no C++ overload for _swnscanf_s */ + +/* no inline version of _swnscanf_s */ + +//#endif /* ndef _SAFECRT_IMPL */ + +#endif /* _INC_SAFECRT */ |