1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5
6//
7/***
8*safecrt.h - secure crt downlevel for windows build
9*
10*Purpose:
11* This file contains a subset of the Secure CRT. It is meant to
12* be used in the Windows source tree.
13*
14****/
15
16/* #pragma once */
17
18/* guard against other includes */
19#if !defined(_CRT_ALTERNATIVE_INLINES)
20#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."
21#endif
22
23#if defined(_CRT_ALTERNATIVE_IMPORTED)
24#error "_CRT_ALTERNATIVE_IMPORTED is defined. This means some files were included with _CRT_ALTERNATIVE_INLINES undefined."
25#endif
26
27#if !defined(_INC_SAFECRT)
28#define _INC_SAFECRT
29
30#if !defined(_SAFECRT_NO_INCLUDES)
31#include <stdarg.h> /* for va_start, etc. */
32#endif
33
34/* _SAFECRT switches */
35#if !defined(_SAFECRT_USE_INLINES)
36#define _SAFECRT_USE_INLINES 0
37#endif
38
39#if !defined(_SAFECRT_SET_ERRNO)
40#define _SAFECRT_SET_ERRNO 1
41#endif
42
43#if !defined(_SAFECRT_DEFINE_TCS_MACROS)
44#define _SAFECRT_DEFINE_TCS_MACROS 0
45#endif
46
47#if !defined(_SAFECRT_DEFINE_MBS_FUNCTIONS)
48#define _SAFECRT_DEFINE_MBS_FUNCTIONS 1
49#endif
50
51#if !defined(_SAFECRT_USE_CPP_OVERLOADS)
52#define _SAFECRT_USE_CPP_OVERLOADS 0
53#endif
54
55#if !defined(_SAFECRT_FILL_BUFFER)
56#if defined(_DEBUG)
57#define _SAFECRT_FILL_BUFFER 1
58#else
59#define _SAFECRT_FILL_BUFFER 0
60#endif
61#endif
62
63#if !defined(_SAFECRT_FILL_BUFFER_PATTERN)
64#define _SAFECRT_FILL_BUFFER_PATTERN 0xFD
65#endif
66
67#if !defined(_SAFECRT_INVALID_PARAMETER_DEBUG_INFO)
68#define _SAFECRT_INVALID_PARAMETER_DEBUG_INFO 0
69#endif
70
71#if !defined(_SAFECRT_IMPL) && defined (_SAFECRT_USE_INLINES)
72#define _SAFECRT__INLINE __inline
73#else
74#define _SAFECRT__INLINE
75#endif
76
77/* additional includes */
78#if _SAFECRT_USE_INLINES && !defined(_SAFECRT_NO_INCLUDES)
79#include <stdlib.h> /* for _MAX_DRIVE */
80#include <string.h> /* for memset */
81#include <windows.h> /* for NTSTATUS, RaiseException */
82#if _SAFECRT_SET_ERRNO
83#include <errno.h>
84#endif
85#if _SAFECRT_DEFINE_MBS_FUNCTIONS
86#include <mbctype.h>
87#endif
88#endif
89
90/* NULL */
91#if !defined(NULL)
92#if !defined(__cplusplus)
93#define NULL 0
94#else
95#define NULL ((void *)0)
96#endif
97#endif
98
99/* WCHAR */
100#if defined (SAFECRT_INCLUDE_REDEFINES)
101#if !defined(_WCHAR_T_DEFINED)
102typedef unsigned short WCHAR;
103#define _WCHAR_T_DEFINED
104#endif
105#endif
106
107/* _W64 */
108#if !defined(_W64)
109#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
110#define _W64 __w64
111#else
112#define _W64
113#endif
114#endif
115
116/* size_t */
117#if defined (SAFECRT_INCLUDE_REDEFINES)
118#if !defined(_SIZE_T_DEFINED)
119#if defined(_WIN64)
120typedef unsigned __int64 size_t;
121#else
122typedef _W64 unsigned int size_t;
123#endif
124#define _SIZE_T_DEFINED
125#endif
126#endif
127
128/* uintptr_t */
129#if !defined(_UINTPTR_T_DEFINED)
130#if defined(_WIN64)
131typedef unsigned __int64 uintptr_t;
132#else
133typedef _W64 unsigned int uintptr_t;
134#endif
135#define _UINTPTR_T_DEFINED
136#endif
137
138#define SAFECRT_DEPRECATED __declspec(deprecated)
139
140/* errno_t */
141#if !defined(_ERRCODE_DEFINED)
142#define _ERRCODE_DEFINED
143/* errcode is deprecated in favor or errno_t, which is part of the standard proposal */
144SAFECRT_DEPRECATED typedef int errcode;
145typedef int errno_t; /* standard */
146#endif
147
148/* error codes */
149#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED)
150#define _SECURECRT_ERRCODE_VALUES_DEFINED
151#if !defined(EINVAL)
152#define EINVAL 22
153#endif
154#if !defined(ERANGE)
155#define ERANGE 34
156#endif
157#if !defined(EILSEQ)
158#define EILSEQ 42
159#endif
160#if !defined(STRUNCATE)
161#define STRUNCATE 80
162#endif
163#endif
164
165/* _TRUNCATE */
166#if !defined(_TRUNCATE)
167#define _TRUNCATE ((size_t)-1)
168#endif
169
170/* _SAFECRT_AUTOMATICALLY_REPLACED_CALL */
171#if !defined(_SAFECRT_AUTOMATICALLY_REPLACED_CALL)
172#define _SAFECRT_AUTOMATICALLY_REPLACED_CALL(v) (v)
173#endif
174
175/* internal macros */
176#if _SAFECRT_USE_INLINES
177#define _SAFECRT__EXTERN_C
178#else
179#if defined(__cplusplus)
180#define _SAFECRT__EXTERN_C extern "C"
181#else
182#define _SAFECRT__EXTERN_C extern
183#endif
184#endif /* _SAFECRT_USE_INLINES */
185
186#if !defined(_SAFECRT_IMPL)
187
188#define _SAFECRT__STR2WSTR(str) L##str
189
190#define _SAFECRT__STR2WSTR2(str) _SAFECRT__STR2WSTR(str)
191
192#if !defined(__FILEW__)
193#define __FILEW__ _SAFECRT__STR2WSTR2(__FILE__)
194#endif
195
196#if !defined(__FUNCTIONW__)
197#define __FUNCTIONW__ _SAFECRT__STR2WSTR2(__FUNCTION__)
198#endif
199
200#endif
201
202/* validation macros */
203#if !defined(_SAFECRT_INVALID_PARAMETER)
204#if _SAFECRT_INVALID_PARAMETER_DEBUG_INFO
205#define _SAFECRT_INVALID_PARAMETER(message) _invalid_parameter(message, __FUNCTIONW__, __FILEW__, __LINE__, 0)
206#else
207#define _SAFECRT_INVALID_PARAMETER(message) _invalid_parameter(nullptr, nullptr, nullptr, 0, 0)
208#endif
209#endif
210
211#if !defined(_SAFECRT__SET_ERRNO)
212#if _SAFECRT_SET_ERRNO
213#define _SAFECRT__SET_ERRNO(_ErrorCode) errno = (_ErrorCode)
214#else
215#define _SAFECRT__SET_ERRNO(_ErrorCode)
216#endif
217#endif
218
219#if !defined(_SAFECRT__RETURN_ERROR)
220#define _SAFECRT__RETURN_ERROR(_Msg, _Ret) \
221 _SAFECRT__SET_ERRNO(EINVAL); \
222 _SAFECRT_INVALID_PARAMETER(_Msg); \
223 return _Ret
224#endif
225
226#if !defined(_SAFECRT__VALIDATE_STRING_ERROR)
227#define _SAFECRT__VALIDATE_STRING_ERROR(_String, _Size, _Ret) \
228 if ((_String) == nullptr || (_Size) == 0) \
229 { \
230 _SAFECRT__SET_ERRNO(EINVAL); \
231 _SAFECRT_INVALID_PARAMETER(L"String " _SAFECRT__STR2WSTR(#_String) L" is invalid"); \
232 return _Ret; \
233 }
234#endif
235
236#if !defined(_SAFECRT__VALIDATE_STRING)
237#define _SAFECRT__VALIDATE_STRING(_String, _Size) _SAFECRT__VALIDATE_STRING_ERROR(_String, _Size, EINVAL)
238#endif
239
240#if !defined(_SAFECRT__VALIDATE_POINTER_ERROR_RETURN)
241#define _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Pointer, _ErrorCode, _Ret) \
242 if ((_Pointer) == nullptr) \
243 { \
244 _SAFECRT__SET_ERRNO(_ErrorCode); \
245 _SAFECRT_INVALID_PARAMETER(L"Pointer " _SAFECRT__STR2WSTR(#_Pointer) L" is invalid"); \
246 return _Ret; \
247 }
248#endif
249
250#if !defined(_SAFECRT__VALIDATE_POINTER_ERROR)
251#define _SAFECRT__VALIDATE_POINTER_ERROR(_Pointer, _Ret) \
252 _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Pointer, EINVAL, _Ret)
253#endif
254
255#if !defined(_SAFECRT__VALIDATE_POINTER)
256#define _SAFECRT__VALIDATE_POINTER(_Pointer) \
257 _SAFECRT__VALIDATE_POINTER_ERROR(_Pointer, EINVAL)
258#endif
259
260#if !defined(_SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR)
261#define _SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, _Ret) \
262 if ((_Pointer) == nullptr) \
263 { \
264 _SAFECRT__SET_ERRNO(EINVAL); \
265 _SAFECRT__RESET_STRING(_String, _Size); \
266 _SAFECRT_INVALID_PARAMETER(L"Pointer " _SAFECRT__STR2WSTR(#_Pointer) L" is invalid"); \
267 return _Ret; \
268 }
269#endif
270
271#if !defined(_SAFECRT__VALIDATE_POINTER_RESET_STRING)
272#define _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Pointer, _String, _Size) \
273 _SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, EINVAL)
274#endif
275
276#if !defined(_SAFECRT__VALIDATE_CONDITION_ERROR_RETURN)
277#define _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_Condition, _ErrorCode, _Ret) \
278 if (!(_Condition)) \
279 { \
280 _SAFECRT__SET_ERRNO(_ErrorCode); \
281 _SAFECRT_INVALID_PARAMETER(_SAFECRT__STR2WSTR(#_Condition)); \
282 return _Ret; \
283 }
284#endif
285
286#if !defined(_SAFECRT__VALIDATE_CONDITION_ERROR)
287#define _SAFECRT__VALIDATE_CONDITION_ERROR(_Condition, _Ret) \
288 _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_Condition, EINVAL, _Ret)
289#endif
290
291/* if _SAFECRT_FILL_BUFFER is on, fill the interval [_Offset, _Size) with _SAFECRT_FILL_BUFFER_PATTERN;
292 * assume that the string has been validated with _SAFECRT__VALIDATE_STRING
293 */
294#if !defined(_SAFECRT__FILL_STRING)
295#if _SAFECRT_FILL_BUFFER
296#define _SAFECRT__FILL_STRING(_String, _Size, _Offset) \
297 if ((size_t)(_Offset) < (_Size)) \
298 { \
299 memset((_String) + (_Offset), _SAFECRT_FILL_BUFFER_PATTERN, ((_Size) - (_Offset)) * sizeof(*(_String))); \
300 }
301#else
302#define _SAFECRT__FILL_STRING(_String, _Size, _Offset)
303#endif
304#endif
305
306/* if _SAFECRT_FILL_BUFFER is on, set the byte to _SAFECRT_FILL_BUFFER_PATTERN
307 */
308#if !defined(_SAFECRT__FILL_BYTE)
309#if _SAFECRT_FILL_BUFFER
310#define _SAFECRT__FILL_BYTE(_Position) \
311 (_Position) = _SAFECRT_FILL_BUFFER_PATTERN
312#else
313#define _SAFECRT__FILL_BYTE(_Position)
314#endif
315#endif
316
317/* put a null terminator at the beginning of the string and then calls _SAFECRT__FILL_STRING;
318 * assume that the string has been validated with _SAFECRT__VALIDATE_STRING
319 */
320#if !defined(_SAFECRT__RESET_STRING)
321#define _SAFECRT__RESET_STRING(_String, _Size) \
322 *(_String) = 0; \
323 _SAFECRT__FILL_STRING(_String, _Size, 1);
324#endif
325
326#if !defined(_SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR)
327#define _SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, _Ret) \
328 _SAFECRT__SET_ERRNO(ERANGE); \
329 _SAFECRT_INVALID_PARAMETER(L"Buffer " _SAFECRT__STR2WSTR(#_String) L" is too small"); \
330 return _Ret;
331#endif
332
333#if !defined(_SAFECRT__RETURN_BUFFER_TOO_SMALL)
334#define _SAFECRT__RETURN_BUFFER_TOO_SMALL(_String, _Size) \
335 _SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, ERANGE)
336#endif
337
338#if !defined(_SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED)
339#define _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_String, _Size) \
340 _SAFECRT__SET_ERRNO(EINVAL); \
341 _SAFECRT_INVALID_PARAMETER(L"String " _SAFECRT__STR2WSTR(#_String) L" is not terminated"); \
342 return EINVAL;
343#endif
344
345#if !defined(_SAFECRT__RETURN_EINVAL)
346#define _SAFECRT__RETURN_EINVAL \
347 _SAFECRT__SET_ERRNO(EINVAL); \
348 _SAFECRT_INVALID_PARAMETER(L"Invalid parameter"); \
349 return EINVAL;
350#endif
351
352/* MBCS handling: change these definitions if you do not need to support mbcs strings */
353#if !defined(_SAFECRT__ISMBBLEAD)
354#define _SAFECRT__ISMBBLEAD(_Character) \
355 _ismbblead(_Character)
356#endif
357
358#if !defined(_SAFECRT__MBSDEC)
359#define _SAFECRT__MBSDEC(_String, _Current) \
360 _mbsdec(_String, _Current)
361#endif
362
363_SAFECRT__EXTERN_C
364void __cdecl _invalid_parameter(const WCHAR *_Message, const WCHAR *_FunctionName, const WCHAR *_FileName, unsigned int _LineNumber, uintptr_t _Reserved);
365
366#if (_SAFECRT_USE_INLINES || _SAFECRT_IMPL) && !defined(_SAFECRT_DO_NOT_DEFINE_INVALID_PARAMETER)
367
368#ifndef STATUS_INVALID_PARAMETER
369#if defined (SAFECRT_INCLUDE_REDEFINES)
370typedef LONG NTSTATUS;
371#endif
372#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
373#endif
374
375_SAFECRT__INLINE
376void __cdecl _invalid_parameter(const WCHAR *_Message, const WCHAR *_FunctionName, const WCHAR *_FileName, unsigned int _LineNumber, uintptr_t _Reserved)
377{
378#ifdef _MSC_VER
379 (_Message);
380 (_FunctionName);
381 (_FileName);
382 (_LineNumber);
383 (_Reserved);
384#endif
385 /* invoke Watson */
386 RaiseException((DWORD)STATUS_INVALID_PARAMETER, 0, 0, nullptr);
387}
388
389#endif
390
391//#if !defined(_SAFECRT_IMPL)
392
393#if _SAFECRT_DEFINE_TCS_MACROS
394
395/* _tcs macros */
396#if !defined(_UNICODE) && !defined(UNICODE) && !defined(_MBCS)
397
398#define _tcscpy_s strcpy_s
399#define _tcsncpy_s strncpy_s
400#define _tcscat_s strcat_s
401#define _tcsncat_s strncat_s
402#define _tcsset_s _strset_s
403#define _tcsnset_s _strnset_s
404#define _tcstok_s strtok_s
405#define _tmakepath_s _makepath_s
406#define _tsplitpath_s _splitpath_s
407#define _stprintf_s sprintf_s
408#define _sntprintf_s _snprintf_s
409#define _vsntprintf_s _vsnprintf_s
410#define _tscanf_s scanf_s
411#define _tsscanf_s sscanf_s
412#define _tsnscanf_s _snscanf_s
413
414#elif defined(_UNICODE) || defined(UNICODE)
415
416#define _tcscpy_s wcscpy_s
417#define _tcsncpy_s wcsncpy_s
418#define _tcscat_s wcscat_s
419#define _tcsncat_s wcsncat_s
420#define _tcsset_s _wcsset_s
421#define _tcsnset_s _wcsnset_s
422#define _tcstok_s wcstok_s
423#define _tmakepath_s _wmakepath_s
424#define _tsplitpath_s _wsplitpath_s
425#define _stprintf_s swprintf_s
426#define _vsntprintf_s _vsnwprintf_s
427#define _tscanf_s wscanf_s
428#define _tsscanf_s swscanf_s
429#define _tsnscanf_s _swnscanf_s
430
431#elif defined(_MBCS)
432
433#define _tcscpy_s _mbscpy_s
434#define _tcsncpy_s _mbsnbcpy_s
435#define _tcscat_s _mbscat_s
436#define _tcsncat_s _mbsnbcat_s
437#define _tcsset_s _mbsset_s
438#define _tcsnset_s _mbsnbset_s
439#define _tcstok_s _mbstok_s
440#define _tmakepath_s _makepath_s
441#define _tsplitpath_s _splitpath_s
442#define _stprintf_s sprintf_s
443#define _sntprintf_s _snprintf_s
444#define _tscanf_s scanf_s
445#define _tsscanf_s sscanf_s
446#define _tsnscanf_s _snscanf_s
447
448#else
449
450#error We should not get here...
451
452#endif
453
454#endif /* _SAFECRT_DEFINE_TCS_MACROS */
455
456/* strcpy_s */
457/*
458 * strcpy_s, wcscpy_s copy string _Src into _Dst;
459 * will call _SAFECRT_INVALID_PARAMETER if string _Src does not fit into _Dst
460 */
461
462
463_SAFECRT__EXTERN_C
464errno_t __cdecl strcpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src);
465
466#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
467template <size_t _SizeInBytes>
468inline
469errno_t __cdecl strcpy_s(char (&_Dst)[_SizeInBytes], const char *_Src)
470{
471 return strcpy_s(_Dst, _SizeInBytes, _Src);
472}
473#endif
474
475
476#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
477
478
479_SAFECRT__INLINE
480errno_t __cdecl strcpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src)
481{
482
483 char *p;
484 size_t available;
485
486 /* validation section */
487 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
488 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
489
490 p = _Dst;
491 available = _SizeInBytes;
492 while ((*p++ = *_Src++) != 0 && --available > 0)
493 {
494 }
495
496 if (available == 0)
497 {
498 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
499 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
500 }
501
502 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
503 return 0;
504}
505
506#endif
507
508/* wcscpy_s */
509_SAFECRT__EXTERN_C
510errno_t __cdecl wcscpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src);
511
512#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
513template <size_t _SizeInWords>
514inline
515errno_t __cdecl wcscpy_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src)
516{
517 return wcscpy_s(_Dst, _SizeInWords, _Src);
518}
519#endif
520
521#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
522
523_SAFECRT__INLINE
524errno_t __cdecl wcscpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src)
525{
526 WCHAR *p;
527 size_t available;
528
529 /* validation section */
530 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
531 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords);
532
533 p = _Dst;
534 available = _SizeInWords;
535 while ((*p++ = *_Src++) != 0 && --available > 0)
536 {
537 }
538
539 if (available == 0)
540 {
541 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
542 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
543 }
544 _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
545 return 0;
546}
547
548#endif
549
550/* _mbscpy_s */
551#if _SAFECRT_DEFINE_MBS_FUNCTIONS
552
553_SAFECRT__EXTERN_C
554errno_t __cdecl _mbscpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src);
555
556#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
557template <size_t _SizeInBytes>
558inline
559errno_t __cdecl _mbscpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src)
560{
561 return _mbscpy_s(_Dst, _SizeInBytes, _Src);
562}
563#endif
564
565#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
566
567_SAFECRT__INLINE
568errno_t __cdecl _mbscpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src)
569{
570 unsigned char *p;
571 size_t available;
572
573 /* validation section */
574 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
575 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
576
577 p = _Dst;
578 available = _SizeInBytes;
579 while ((*p++ = *_Src++) != 0 && --available > 0)
580 {
581 }
582
583 if (available == 0)
584 {
585 if (*_Src == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
586 {
587 /* the source string ended with a lead byte: we remove it */
588 p[-1] = 0;
589 return 0;
590 }
591 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
592 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
593 }
594 if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2]))
595 {
596 /* the source string ended with a lead byte: we remove it */
597 p[-2] = 0;
598 available++;
599 }
600 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
601 return 0;
602}
603
604#endif
605
606#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
607
608/* strncpy_s */
609/*
610 * strncpy_s, wcsncpy_s copy at max _Count characters from string _Src into _Dst;
611 * string _Dst will always be null-terminated;
612 * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
613 * if _Count == _TRUNCATE, we will copy as many characters as we can from _Src into _Dst, and
614 * return STRUNCATE if _Src does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER);
615 * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed
616 */
617_SAFECRT__EXTERN_C
618errno_t __cdecl strncpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count);
619
620#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
621template <size_t _SizeInBytes>
622inline
623errno_t __cdecl strncpy_s(char (&_Dst)[_SizeInBytes], const char *_Src, size_t _Count)
624{
625 return strncpy_s(_Dst, _SizeInBytes, _Src, _Count);
626}
627#endif
628
629#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
630
631_SAFECRT__INLINE
632errno_t __cdecl strncpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count)
633{
634 char *p;
635 size_t available;
636
637 if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0)
638 {
639 /* this case is allowed; nothing to do */
640 return 0;
641 }
642
643 /* validation section */
644 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
645 if (_Count == 0)
646 {
647 /* notice that the source string pointer can be nullptr in this case */
648 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
649 return 0;
650 }
651 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
652
653 p = _Dst;
654 available = _SizeInBytes;
655 if (_Count == _TRUNCATE)
656 {
657 while ((*p++ = *_Src++) != 0 && --available > 0)
658 {
659 }
660 }
661 else
662 {
663 while ((*p++ = *_Src++) != 0 && --available > 0 && --_Count > 0)
664 {
665 }
666 if (_Count == 0)
667 {
668 *p = 0;
669 }
670 }
671
672 if (available == 0)
673 {
674 if (_Count == _TRUNCATE)
675 {
676 _Dst[_SizeInBytes - 1] = 0;
677 return STRUNCATE;
678 }
679 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
680 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
681 }
682 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
683 return 0;
684}
685
686#endif
687
688/* wcsncpy_s */
689_SAFECRT__EXTERN_C
690errno_t __cdecl wcsncpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count);
691
692#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
693template <size_t _SizeInWords>
694inline
695errno_t __cdecl wcsncpy_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src, size_t _Count)
696{
697 return wcsncpy_s(_Dst, _SizeInWords, _Src, _Count);
698}
699#endif
700
701#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
702
703_SAFECRT__INLINE
704errno_t __cdecl wcsncpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count)
705{
706 WCHAR *p;
707 size_t available;
708
709 if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0)
710 {
711 /* this case is allowed; nothing to do */
712 return 0;
713 }
714
715 /* validation section */
716 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
717 if (_Count == 0)
718 {
719 /* notice that the source string pointer can be nullptr in this case */
720 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
721 return 0;
722 }
723 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords);
724
725 p = _Dst;
726 available = _SizeInWords;
727 if (_Count == _TRUNCATE)
728 {
729 while ((*p++ = *_Src++) != 0 && --available > 0)
730 {
731 }
732 }
733 else
734 {
735 while ((*p++ = *_Src++) != 0 && --available > 0 && --_Count > 0)
736 {
737 }
738 if (_Count == 0)
739 {
740 *p = 0;
741 }
742 }
743
744 if (available == 0)
745 {
746 if (_Count == _TRUNCATE)
747 {
748 _Dst[_SizeInWords - 1] = 0;
749 return STRUNCATE;
750 }
751 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
752 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
753 }
754 _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
755 return 0;
756}
757
758#endif
759
760/* _mbsnbcpy_s */
761#if _SAFECRT_DEFINE_MBS_FUNCTIONS
762
763_SAFECRT__EXTERN_C
764errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes);
765
766#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
767template <size_t _SizeInBytes>
768inline
769errno_t __cdecl _mbsnbcpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInBytes)
770{
771 return _mbsnbcpy_s(_Dst, _SizeInBytes, _Src, _CountInBytes);
772}
773#endif
774
775#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
776
777_SAFECRT__INLINE
778errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes)
779{
780 unsigned char *p;
781 size_t available;
782
783 if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0)
784 {
785 /* this case is allowed; nothing to do */
786 return 0;
787 }
788
789 /* validation section */
790 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
791 if (_CountInBytes == 0)
792 {
793 /* notice that the source string pointer can be nullptr in this case */
794 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
795 return 0;
796 }
797 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
798
799 p = _Dst;
800 available = _SizeInBytes;
801 if (_CountInBytes == _TRUNCATE)
802 {
803 while ((*p++ = *_Src++) != 0 && --available > 0)
804 {
805 }
806 }
807 else
808 {
809 while ((*p++ = *_Src++) != 0 && --available > 0 && --_CountInBytes > 0)
810 {
811 }
812 if (_CountInBytes == 0)
813 {
814 *p++ = 0;
815 }
816 }
817
818 if (available == 0)
819 {
820 if ((*_Src == 0 || _CountInBytes == 1) && _SAFECRT__ISMBBLEAD(p[-1]))
821 {
822 /* the source string ended with a lead byte: we remove it */
823 p[-1] = 0;
824 return 0;
825 }
826 if (_CountInBytes == _TRUNCATE)
827 {
828 if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2]))
829 {
830 _Dst[_SizeInBytes - 2] = 0;
831 _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]);
832 }
833 else
834 {
835 _Dst[_SizeInBytes - 1] = 0;
836 }
837 return STRUNCATE;
838 }
839 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
840 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
841 }
842 if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2]))
843 {
844 /* the source string ended with a lead byte: we remove it */
845 p[-2] = 0;
846 available++;
847 }
848 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
849 return 0;
850}
851
852#endif
853
854#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
855
856/* _mbsncpy_s */
857#if _SAFECRT_DEFINE_MBS_FUNCTIONS
858
859_SAFECRT__EXTERN_C
860errno_t __cdecl _mbsncpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars);
861
862#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
863template <size_t _SizeInBytes>
864inline
865errno_t __cdecl _mbsncpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInChars)
866{
867 return _mbsncpy_s(_Dst, _SizeInBytes, _Src, _CountInChars);
868}
869#endif
870
871#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
872
873_SAFECRT__INLINE
874errno_t __cdecl _mbsncpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars)
875{
876 unsigned char *p;
877 size_t available;
878
879 if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0)
880 {
881 /* this case is allowed; nothing to do */
882 return 0;
883 }
884
885 /* validation section */
886 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
887 if (_CountInChars == 0)
888 {
889 /* notice that the source string pointer can be nullptr in this case */
890 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
891 return 0;
892 }
893 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
894
895 p = _Dst;
896 available = _SizeInBytes;
897 if (_CountInChars == _TRUNCATE)
898 {
899 while ((*p++ = *_Src++) != 0 && --available > 0)
900 {
901 }
902 }
903 else
904 {
905 do
906 {
907 if (_SAFECRT__ISMBBLEAD(*_Src))
908 {
909 if (_Src[1] == 0)
910 {
911 /* the source string ended with a lead byte: we remove it */
912 *p = 0;
913 break;
914 }
915 if (available <= 2)
916 {
917 /* not enough space */
918 available = 0;
919 break;
920 }
921 *p++ = *_Src++;
922 *p++ = *_Src++;
923 available -= 2;
924 }
925 else
926 {
927 if ((*p++ = *_Src++) == 0 || --available == 0)
928 {
929 break;
930 }
931 }
932 }
933 while (--_CountInChars > 0);
934 if (_CountInChars == 0)
935 {
936 *p++ = 0;
937 }
938 }
939
940 if (available == 0)
941 {
942 if (_CountInChars == _TRUNCATE)
943 {
944 if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2]))
945 {
946 _Dst[_SizeInBytes - 2] = 0;
947 _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]);
948 }
949 else
950 {
951 _Dst[_SizeInBytes - 1] = 0;
952 }
953 return STRUNCATE;
954 }
955 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
956 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
957 }
958 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
959 return 0;
960}
961
962#endif
963
964#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
965
966/* strcat_s */
967/*
968 * strcat_s, wcscat_s append string _Src to _Dst;
969 * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst
970 */
971_SAFECRT__EXTERN_C
972errno_t __cdecl strcat_s(char *_Dst, size_t _SizeInBytes, const char *_Src);
973
974#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
975template <size_t _SizeInBytes>
976inline
977errno_t __cdecl strcat_s(char (&_Dst)[_SizeInBytes], const char *_Src)
978{
979 return strcat_s(_Dst, _SizeInBytes, _Src);
980}
981#endif
982
983#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
984
985_SAFECRT__INLINE
986errno_t __cdecl strcat_s(char *_Dst, size_t _SizeInBytes, const char *_Src)
987{
988 char *p;
989 size_t available;
990
991 /* validation section */
992 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
993 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
994
995 p = _Dst;
996 available = _SizeInBytes;
997 while (available > 0 && *p != 0)
998 {
999 p++;
1000 available--;
1001 }
1002
1003 if (available == 0)
1004 {
1005 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1006 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1007 }
1008
1009 while ((*p++ = *_Src++) != 0 && --available > 0)
1010 {
1011 }
1012
1013 if (available == 0)
1014 {
1015 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1016 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
1017 }
1018 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1019 return 0;
1020}
1021
1022#endif
1023
1024/* wcscat_s */
1025_SAFECRT__EXTERN_C
1026errno_t __cdecl wcscat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src);
1027
1028#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1029template <size_t _SizeInWords>
1030inline
1031errno_t __cdecl wcscat_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src)
1032{
1033 return wcscat_s(_Dst, _SizeInWords, _Src);
1034}
1035#endif
1036
1037#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1038
1039_SAFECRT__INLINE
1040errno_t __cdecl wcscat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src)
1041{
1042 WCHAR *p;
1043 size_t available;
1044
1045 /* validation section */
1046 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
1047 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords);
1048
1049 p = _Dst;
1050 available = _SizeInWords;
1051 while (available > 0 && *p != 0)
1052 {
1053 p++;
1054 available--;
1055 }
1056
1057 if (available == 0)
1058 {
1059 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
1060 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords);
1061 }
1062
1063 while ((*p++ = *_Src++) != 0 && --available > 0)
1064 {
1065 }
1066
1067 if (available == 0)
1068 {
1069 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
1070 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
1071 }
1072 _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
1073 return 0;
1074}
1075
1076#endif
1077
1078/* _mbscat_s */
1079#if _SAFECRT_DEFINE_MBS_FUNCTIONS
1080
1081_SAFECRT__EXTERN_C
1082errno_t __cdecl _mbscat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src);
1083
1084#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1085template <size_t _SizeInBytes>
1086inline
1087errno_t __cdecl _mbscat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src)
1088{
1089 return _mbscat_s(_Dst, _SizeInBytes, _Src);
1090}
1091#endif
1092
1093#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1094
1095_SAFECRT__INLINE
1096errno_t __cdecl _mbscat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src)
1097{
1098 unsigned char *p;
1099 size_t available;
1100
1101 /* validation section */
1102 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
1103 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
1104
1105 p = _Dst;
1106 available = _SizeInBytes;
1107 while (available > 0 && *p != 0)
1108 {
1109 p++;
1110 available--;
1111 }
1112
1113 if (available == 0)
1114 {
1115 if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
1116 {
1117 /* the original string ended with a lead byte: we remove it */
1118 p--;
1119 *p = 0;
1120 available = 1;
1121 }
1122 else
1123 {
1124 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1125 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1126 }
1127 }
1128 if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1]))
1129 {
1130 /* the original string ended with a lead byte: we remove it */
1131 p--;
1132 *p = 0;
1133 available++;
1134 }
1135
1136 while ((*p++ = *_Src++) != 0 && --available > 0)
1137 {
1138 }
1139
1140 if (available == 0)
1141 {
1142 if (*_Src == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
1143 {
1144 /* the source string ended with a lead byte: we remove it */
1145 p[-1] = 0;
1146 return 0;
1147 }
1148 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1149 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
1150 }
1151 if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2]))
1152 {
1153 /* the source string ended with a lead byte: we remove it */
1154 p[-2] = 0;
1155 available++;
1156 }
1157 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1158 return 0;
1159}
1160
1161#endif
1162
1163#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
1164
1165/* strncat_s */
1166/*
1167 * strncat_s, wcsncat_s append at max _Count characters from string _Src to _Dst;
1168 * string _Dst will always be null-terminated;
1169 * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
1170 * if _Count == _TRUNCATE, we will append as many characters as we can from _Src to _Dst, and
1171 * return STRUNCATE if _Src does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER);
1172 * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed
1173 */
1174_SAFECRT__EXTERN_C
1175errno_t __cdecl strncat_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count);
1176
1177#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1178template <size_t _SizeInBytes>
1179inline
1180errno_t __cdecl strncat_s(char (&_Dst)[_SizeInBytes], const char *_Src, size_t _Count)
1181{
1182 return strncat_s(_Dst, _SizeInBytes, _Src, _Count);
1183}
1184#endif
1185
1186#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1187
1188_SAFECRT__INLINE
1189errno_t __cdecl strncat_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count)
1190{
1191 char *p;
1192 size_t available;
1193 if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0)
1194 {
1195 /* this case is allowed; nothing to do */
1196 return 0;
1197 }
1198 /* validation section */
1199 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
1200 if (_Count != 0)
1201 {
1202 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
1203 }
1204
1205 p = _Dst;
1206 available = _SizeInBytes;
1207 while (available > 0 && *p != 0)
1208 {
1209 p++;
1210 available--;
1211 }
1212
1213 if (available == 0)
1214 {
1215 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1216 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1217 }
1218
1219 if (_Count == _TRUNCATE)
1220 {
1221 while ((*p++ = *_Src++) != 0 && --available > 0)
1222 {
1223 }
1224 }
1225 else
1226 {
1227 while (_Count > 0 && (*p++ = *_Src++) != 0 && --available > 0)
1228 {
1229 _Count--;
1230 }
1231 if (_Count == 0)
1232 {
1233 *p = 0;
1234 }
1235 }
1236
1237 if (available == 0)
1238 {
1239 if (_Count == _TRUNCATE)
1240 {
1241 _Dst[_SizeInBytes - 1] = 0;
1242 return STRUNCATE;
1243 }
1244 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1245 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
1246 }
1247 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1248 return 0;
1249}
1250
1251#endif
1252
1253/* wcsncat_s */
1254_SAFECRT__EXTERN_C
1255errno_t __cdecl wcsncat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count);
1256
1257#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1258template <size_t _SizeInWords>
1259inline
1260errno_t __cdecl wcsncat_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src, size_t _Count)
1261{
1262 return wcsncat_s(_Dst, _SizeInWords, _Src, _Count);
1263}
1264#endif
1265
1266#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1267
1268_SAFECRT__INLINE
1269errno_t __cdecl wcsncat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count)
1270{
1271 WCHAR *p;
1272 size_t available;
1273 if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0)
1274 {
1275 /* this case is allowed; nothing to do */
1276 return 0;
1277 }
1278 /* validation section */
1279 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
1280 if (_Count != 0)
1281 {
1282 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords);
1283 }
1284
1285 p = _Dst;
1286 available = _SizeInWords;
1287 while (available > 0 && *p != 0)
1288 {
1289 p++;
1290 available--;
1291 }
1292
1293 if (available == 0)
1294 {
1295 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
1296 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords);
1297 }
1298
1299 if (_Count == _TRUNCATE)
1300 {
1301 while ((*p++ = *_Src++) != 0 && --available > 0)
1302 {
1303 }
1304 }
1305 else
1306 {
1307 while (_Count > 0 && (*p++ = *_Src++) != 0 && --available > 0)
1308 {
1309 _Count--;
1310 }
1311 if (_Count == 0)
1312 {
1313 *p = 0;
1314 }
1315 }
1316
1317 if (available == 0)
1318 {
1319 if (_Count == _TRUNCATE)
1320 {
1321 _Dst[_SizeInWords - 1] = 0;
1322 return STRUNCATE;
1323 }
1324 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
1325 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
1326 }
1327 _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
1328 return 0;
1329}
1330
1331#endif
1332
1333/* _mbsnbcat_s */
1334#if _SAFECRT_DEFINE_MBS_FUNCTIONS
1335
1336_SAFECRT__EXTERN_C
1337errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes);
1338
1339#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1340template <size_t _SizeInBytes>
1341inline
1342errno_t __cdecl _mbsnbcat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInBytes)
1343{
1344 return _mbsnbcat_s(_Dst, _SizeInBytes, _Src, size_t _CountInBytes);
1345}
1346#endif
1347
1348#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1349
1350_SAFECRT__INLINE
1351errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes)
1352{
1353 unsigned char *p;
1354 size_t available;
1355 if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0)
1356 {
1357 /* this case is allowed; nothing to do */
1358 return 0;
1359 }
1360 /* validation section */
1361 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
1362 if (_CountInBytes != 0)
1363 {
1364 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
1365 }
1366
1367 p = _Dst;
1368 available = _SizeInBytes;
1369 while (available > 0 && *p != 0)
1370 {
1371 p++;
1372 available--;
1373 }
1374
1375 if (available == 0)
1376 {
1377 if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
1378 {
1379 /* the original string ended with a lead byte: we remove it */
1380 p--;
1381 *p = 0;
1382 available = 1;
1383 }
1384 else
1385 {
1386 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1387 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1388 }
1389 }
1390 if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1]))
1391 {
1392 /* the original string ended with a lead byte: we remove it */
1393 p--;
1394 *p = 0;
1395 available++;
1396 }
1397
1398 if (_CountInBytes == _TRUNCATE)
1399 {
1400 while ((*p++ = *_Src++) != 0 && --available > 0)
1401 {
1402 }
1403 }
1404 else
1405 {
1406 while (_CountInBytes > 0 && (*p++ = *_Src++) != 0 && --available > 0)
1407 {
1408 _CountInBytes--;
1409 }
1410 if (_CountInBytes == 0)
1411 {
1412 *p++ = 0;
1413 }
1414 }
1415
1416 if (available == 0)
1417 {
1418 if ((*_Src == 0 || _CountInBytes == 1) && _SAFECRT__ISMBBLEAD(p[-1]))
1419 {
1420 /* the source string ended with a lead byte: we remove it */
1421 p[-1] = 0;
1422 return 0;
1423 }
1424 if (_CountInBytes == _TRUNCATE)
1425 {
1426 if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2]))
1427 {
1428 _Dst[_SizeInBytes - 2] = 0;
1429 _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]);
1430 }
1431 else
1432 {
1433 _Dst[_SizeInBytes - 1] = 0;
1434 }
1435 return STRUNCATE;
1436 }
1437 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1438 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
1439 }
1440 if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2]))
1441 {
1442 /* the source string ended with a lead byte: we remove it */
1443 p[-2] = 0;
1444 available++;
1445 }
1446 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1447 return 0;
1448}
1449
1450#endif
1451
1452#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
1453
1454/* _mbsncat_s */
1455#if _SAFECRT_DEFINE_MBS_FUNCTIONS
1456
1457_SAFECRT__EXTERN_C
1458errno_t __cdecl _mbsncat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars);
1459
1460#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1461template <size_t _SizeInBytes>
1462inline
1463errno_t __cdecl _mbsncat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInChars)
1464{
1465 return _mbsncat_s(_Dst, _SizeInBytes, _Src, size_t _CountInChars);
1466}
1467#endif
1468
1469#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1470
1471_SAFECRT__INLINE
1472errno_t __cdecl _mbsncat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars)
1473{
1474 unsigned char *p;
1475 size_t available;
1476 if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0)
1477 {
1478 /* this case is allowed; nothing to do */
1479 return 0;
1480 }
1481 /* validation section */
1482 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
1483 if (_CountInChars != 0)
1484 {
1485 _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
1486 }
1487
1488 p = _Dst;
1489 available = _SizeInBytes;
1490 while (available > 0 && *p != 0)
1491 {
1492 p++;
1493 available--;
1494 }
1495
1496 if (available == 0)
1497 {
1498 if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
1499 {
1500 /* the original string ended with a lead byte: we remove it */
1501 p--;
1502 *p = 0;
1503 available = 1;
1504 }
1505 else
1506 {
1507 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1508 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1509 }
1510 }
1511 if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1]))
1512 {
1513 /* the original string ended with a lead byte: we remove it */
1514 p--;
1515 *p = 0;
1516 available++;
1517 }
1518
1519 if (_CountInChars == _TRUNCATE)
1520 {
1521 while ((*p++ = *_Src++) != 0 && --available > 0)
1522 {
1523 }
1524 }
1525 else
1526 {
1527 while (_CountInChars > 0)
1528 {
1529 if (_SAFECRT__ISMBBLEAD(*_Src))
1530 {
1531 if (_Src[1] == 0)
1532 {
1533 /* the source string ended with a lead byte: we remove it */
1534 *p = 0;
1535 break;
1536 }
1537 if (available <= 2)
1538 {
1539 /* not enough space */
1540 available = 0;
1541 break;
1542 }
1543 *p++ = *_Src++;
1544 *p++ = *_Src++;
1545 available -= 2;
1546 }
1547 else
1548 {
1549 if ((*p++ = *_Src++) == 0 || --available == 0)
1550 {
1551 break;
1552 }
1553 }
1554 _CountInChars--;
1555 }
1556 if (_CountInChars == 0)
1557 {
1558 *p++ = 0;
1559 }
1560 }
1561
1562 if (available == 0)
1563 {
1564 if (_CountInChars == _TRUNCATE)
1565 {
1566 if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2]))
1567 {
1568 _Dst[_SizeInBytes - 2] = 0;
1569 _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]);
1570 }
1571 else
1572 {
1573 _Dst[_SizeInBytes - 1] = 0;
1574 }
1575 return STRUNCATE;
1576 }
1577 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1578 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
1579 }
1580 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1581 return 0;
1582}
1583
1584#endif
1585
1586#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
1587
1588/* _strset_s */
1589/*
1590 * _strset_s, _wcsset_s ;
1591 * will call _SAFECRT_INVALID_PARAMETER if _Dst is not null terminated.
1592 */
1593_SAFECRT__EXTERN_C
1594errno_t __cdecl _strset_s(char *_Dst, size_t _SizeInBytes, int _Value);
1595
1596#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1597template <size_t _SizeInBytes>
1598inline
1599errno_t __cdecl _strset_s(char (&_Dst)[_SizeInBytes], int _Value)
1600{
1601 return _strset_s(_Dst, _SizeInBytes, _Value);
1602}
1603#endif
1604
1605#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1606
1607_SAFECRT__INLINE
1608errno_t __cdecl _strset_s(char *_Dst, size_t _SizeInBytes, int _Value)
1609{
1610 char *p;
1611 size_t available;
1612
1613 /* validation section */
1614 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
1615
1616 p = _Dst;
1617 available = _SizeInBytes;
1618 while (*p != 0 && --available > 0)
1619 {
1620 *p++ = (char)_Value;
1621 }
1622
1623 if (available == 0)
1624 {
1625 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1626 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1627 }
1628 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1629 return 0;
1630}
1631
1632#endif
1633
1634/* _wcsset_s */
1635_SAFECRT__EXTERN_C
1636errno_t __cdecl _wcsset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value);
1637
1638#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1639template <size_t _SizeInWords>
1640inline
1641errno_t __cdecl _wcsset_s(WCHAR (&_Dst)[_SizeInWords], WCHAR _Value)
1642{
1643 return _wcsset_s(_Dst, _SizeInWords, _Value);
1644}
1645#endif
1646
1647#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1648
1649_SAFECRT__INLINE
1650errno_t __cdecl _wcsset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value)
1651{
1652 WCHAR *p;
1653 size_t available;
1654
1655 /* validation section */
1656 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
1657
1658 p = _Dst;
1659 available = _SizeInWords;
1660 while (*p != 0 && --available > 0)
1661 {
1662 *p++ = (WCHAR)_Value;
1663 }
1664
1665 if (available == 0)
1666 {
1667 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
1668 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords);
1669 }
1670 _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
1671 return 0;
1672}
1673
1674#endif
1675
1676/* _mbsset_s */
1677#if _SAFECRT_DEFINE_MBS_FUNCTIONS
1678
1679_SAFECRT__EXTERN_C
1680errno_t __cdecl _mbsset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value);
1681
1682#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1683template <size_t _SizeInBytes>
1684inline
1685errno_t __cdecl _mbsset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value)
1686{
1687 return _mbsset_s(_Dst, _SizeInBytes, _Value);
1688}
1689#endif
1690
1691#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1692
1693_SAFECRT__INLINE
1694errno_t __cdecl _mbsset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value)
1695{
1696 int mbcs_error = 0;
1697 unsigned char *p;
1698 size_t available;
1699 unsigned char highval, lowval;
1700
1701 /* validation section */
1702 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
1703
1704 p = _Dst;
1705 available = _SizeInBytes;
1706 highval = (unsigned char)(_Value >> 8);
1707 lowval = (unsigned char)(_Value & 0x00ff);
1708 if (highval != 0)
1709 {
1710 if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0)
1711 {
1712 while (*p != 0 && --available > 0)
1713 {
1714 if (p[1] == 0)
1715 {
1716 /* do not orphan leadbyte */
1717 *p++ = ' ';
1718 break;
1719 }
1720 *p++ = highval;
1721 if (--available == 0)
1722 {
1723 break;
1724 }
1725 *p++ = lowval;
1726 }
1727 }
1728 else
1729 {
1730 mbcs_error = 1;
1731 highval = 0;
1732 lowval = ' ';
1733 }
1734 }
1735 else
1736 {
1737 if (_SAFECRT__ISMBBLEAD(lowval))
1738 {
1739 mbcs_error = 1;
1740 lowval = ' ';
1741 }
1742 }
1743 if (highval == 0)
1744 {
1745 while (*p != 0 && --available > 0)
1746 {
1747 *p++ = lowval;
1748 }
1749 }
1750
1751 if (available == 0)
1752 {
1753 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1754 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1755 }
1756 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1757 if (mbcs_error)
1758 {
1759 _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ;
1760 }
1761 else
1762 {
1763 return 0;
1764 }
1765}
1766
1767#endif
1768
1769#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
1770
1771/* _strnset_s */
1772/*
1773 * _strnset_s, _wcsnset_s ;
1774 * will call _SAFECRT_INVALID_PARAMETER if _Dst is not null terminated.
1775 */
1776_SAFECRT__EXTERN_C
1777errno_t __cdecl _strnset_s(char *_Dst, size_t _SizeInBytes, int _Value, size_t _Count);
1778
1779#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1780template <size_t _SizeInBytes>
1781inline
1782errno_t __cdecl _strnset_s(char (&_Dst)[_SizeInBytes], int _Value, size_t _Count)
1783{
1784 return _strnset_s(_Dst, _SizeInBytes, _Value, _Count);
1785}
1786#endif
1787
1788#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1789
1790_SAFECRT__INLINE
1791errno_t __cdecl _strnset_s(char *_Dst, size_t _SizeInBytes, int _Value, size_t _Count)
1792{
1793 char *p;
1794 size_t available;
1795
1796 /* validation section */
1797 if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0)
1798 {
1799 /* this case is allowed; nothing to do */
1800 return 0;
1801 }
1802 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
1803
1804 p = _Dst;
1805 available = _SizeInBytes;
1806 while (*p != 0 && _Count > 0 && --available > 0)
1807 {
1808 *p++ = (char)_Value;
1809 --_Count;
1810 }
1811
1812 if (available == 0)
1813 {
1814 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1815 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1816 }
1817 if (_Count == 0)
1818 {
1819 *p = 0;
1820 }
1821 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1822 return 0;
1823}
1824
1825#endif
1826
1827/* _wcsnset_s */
1828_SAFECRT__EXTERN_C
1829errno_t __cdecl _wcsnset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value, size_t _Count);
1830
1831#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1832template <size_t _SizeInWords>
1833inline
1834errno_t __cdecl _wcsnset_s(WCHAR (&_Dst)[_SizeInWords], WCHAR _Value, size_t _Count)
1835{
1836 return _wcsnset_s(_Dst, _SizeInWords, _Value, _Count);
1837}
1838#endif
1839
1840#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1841
1842_SAFECRT__INLINE
1843errno_t __cdecl _wcsnset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value, size_t _Count)
1844{
1845 WCHAR *p;
1846 size_t available;
1847
1848 /* validation section */
1849 if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0)
1850 {
1851 /* this case is allowed; nothing to do */
1852 return 0;
1853 }
1854 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
1855
1856 p = _Dst;
1857 available = _SizeInWords;
1858 while (*p != 0 && _Count > 0 && --available > 0)
1859 {
1860 *p++ = (WCHAR)_Value;
1861 --_Count;
1862 }
1863
1864 if (available == 0)
1865 {
1866 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
1867 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords);
1868 }
1869 if (_Count == 0)
1870 {
1871 *p = 0;
1872 }
1873 _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
1874 return 0;
1875}
1876
1877#endif
1878
1879/* _mbsnbset_s */
1880#if _SAFECRT_DEFINE_MBS_FUNCTIONS
1881
1882_SAFECRT__EXTERN_C
1883errno_t __cdecl _mbsnbset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInBytes);
1884
1885#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1886template <size_t _SizeInBytes>
1887inline
1888errno_t __cdecl _mbsnbset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value, size_t _CountInBytes)
1889{
1890 return _mbsnbset_s(_Dst, _SizeInBytes, _Value, _CountInBytes);
1891}
1892#endif
1893
1894#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
1895
1896_SAFECRT__INLINE
1897errno_t __cdecl _mbsnbset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInBytes)
1898{
1899 int mbcs_error = 0;
1900 unsigned char *p;
1901 size_t available;
1902 unsigned char highval, lowval;
1903
1904 /* validation section */
1905 if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0)
1906 {
1907 /* this case is allowed; nothing to do */
1908 return 0;
1909 }
1910 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
1911
1912 p = _Dst;
1913 available = _SizeInBytes;
1914 highval = (unsigned char)(_Value >> 8);
1915 lowval = (unsigned char)(_Value & 0x00ff);
1916 if (highval != 0)
1917 {
1918 if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0)
1919 {
1920 while (*p != 0 && _CountInBytes > 0 && --available > 0)
1921 {
1922 if (_CountInBytes == 1 || p[1] == 0)
1923 {
1924 /* do not orphan leadbyte */
1925 *p++ = ' ';
1926 --_CountInBytes;
1927 break;
1928 }
1929 *p++ = highval;
1930 if (--available == 0)
1931 {
1932 break;
1933 }
1934 *p++ = lowval;
1935 _CountInBytes -= 2;
1936 }
1937 }
1938 else
1939 {
1940 mbcs_error = 1;
1941 highval = 0;
1942 lowval = ' ';
1943 }
1944 }
1945 else
1946 {
1947 if (_SAFECRT__ISMBBLEAD(lowval))
1948 {
1949 mbcs_error = 1;
1950 lowval = ' ';
1951 }
1952 }
1953 if (highval == 0)
1954 {
1955 while (*p != 0 && available > 0 && _CountInBytes > 0)
1956 {
1957 *p++ = lowval;
1958 --available;
1959 --_CountInBytes;
1960 }
1961 }
1962 if (available == 0)
1963 {
1964 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
1965 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
1966 }
1967 if (_CountInBytes == 0)
1968 {
1969 *p = 0;
1970 }
1971 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
1972 if (mbcs_error)
1973 {
1974 _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ;
1975 }
1976 else
1977 {
1978 return 0;
1979 }
1980}
1981
1982#endif
1983
1984#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
1985
1986/* _mbsnset_s */
1987#if _SAFECRT_DEFINE_MBS_FUNCTIONS
1988
1989_SAFECRT__EXTERN_C
1990errno_t __cdecl _mbsnset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInChars);
1991
1992#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
1993template <size_t _SizeInBytes>
1994inline
1995errno_t __cdecl _mbsnset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value, size_t _CountInChars)
1996{
1997 return _mbsnset_s(_Dst, _SizeInBytes, _Value, _CountInChars);
1998}
1999#endif
2000
2001#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2002
2003_SAFECRT__INLINE
2004errno_t __cdecl _mbsnset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInChars)
2005{
2006 int mbcs_error = 0;
2007 unsigned char *p;
2008 size_t available;
2009 unsigned char highval, lowval;
2010
2011 /* validation section */
2012 if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0)
2013 {
2014 /* this case is allowed; nothing to do */
2015 return 0;
2016 }
2017 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
2018
2019 p = _Dst;
2020 available = _SizeInBytes;
2021 highval = (unsigned char)(_Value >> 8);
2022 lowval = (unsigned char)(_Value & 0x00ff);
2023 if (highval != 0)
2024 {
2025 if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0)
2026 {
2027 while (*p != 0 && _CountInChars > 0 && --available > 0)
2028 {
2029 if (p[1] == 0)
2030 {
2031 /* do not orphan leadbyte */
2032 *p++ = ' ';
2033 break;
2034 }
2035 *p++ = highval;
2036 if (--available == 0)
2037 {
2038 break;
2039 }
2040 *p++ = lowval;
2041 --_CountInChars;
2042 }
2043 }
2044 else
2045 {
2046 mbcs_error = 1;
2047 highval = 0;
2048 lowval = ' ';
2049 }
2050 }
2051 else
2052 {
2053 if (_SAFECRT__ISMBBLEAD(lowval))
2054 {
2055 mbcs_error = 1;
2056 lowval = ' ';
2057 }
2058 }
2059 if (highval == 0)
2060 {
2061 while (*p != 0 && available > 0 && _CountInChars > 0)
2062 {
2063 *p++ = lowval;
2064 --available;
2065 --_CountInChars;
2066 }
2067 }
2068 if (available == 0)
2069 {
2070 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
2071 _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
2072 }
2073 if (_CountInChars == 0)
2074 {
2075 *p = 0;
2076 }
2077 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
2078 if (mbcs_error)
2079 {
2080 _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ;
2081 }
2082 else
2083 {
2084 return 0;
2085 }
2086}
2087
2088#endif
2089
2090#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
2091
2092/* _mbccpy_s */
2093#if _SAFECRT_DEFINE_MBS_FUNCTIONS
2094
2095_SAFECRT__EXTERN_C
2096errno_t __cdecl _mbccpy_s(unsigned char *_Dst, size_t _SizeInBytes, int *_PCopied, const unsigned char *_Src);
2097
2098#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
2099template <size_t _SizeInBytes>
2100inline
2101errno_t __cdecl _mbccpy_s(unsigned char (&_Dst)[_SizeInBytes], int *_PCopied, const unsigned char *_Src)
2102{
2103 return _mbccpy_s(_Dst, _SizeInBytes, _PCopied, _Src);
2104}
2105#endif
2106
2107#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2108
2109_SAFECRT__INLINE
2110errno_t __cdecl _mbccpy_s(unsigned char *_Dst, size_t _SizeInBytes, int *_PCopied, const unsigned char *_Src)
2111{
2112 /* validation section */
2113 if (_PCopied != nullptr) { *_PCopied = 0; };
2114 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
2115 if (_Src == nullptr)
2116 {
2117 *_Dst = '\0';
2118 _SAFECRT__RETURN_EINVAL;
2119 }
2120
2121 /* copy */
2122 if (_SAFECRT__ISMBBLEAD(*_Src))
2123 {
2124 if (_Src[1] == '\0')
2125 {
2126 /* the source string contained a lead byte followed by the null terminator:
2127 we copy only the null terminator and return EILSEQ to indicate the
2128 malformed char */
2129 *_Dst = '\0';
2130 if (_PCopied != nullptr) { *_PCopied = 1; };
2131 _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ;
2132 }
2133 if (_SizeInBytes < 2)
2134 {
2135 *_Dst = '\0';
2136 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
2137 }
2138 *_Dst++ = *_Src++;
2139 *_Dst = *_Src;
2140 if (_PCopied != nullptr) { *_PCopied = 2; };
2141 }
2142 else
2143 {
2144 *_Dst = *_Src;
2145 if (_PCopied != nullptr) { *_PCopied = 1; };
2146 }
2147
2148 return 0;
2149}
2150#endif
2151
2152#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
2153
2154/* strtok_s */
2155/*
2156 * strtok_s, wcstok_s ;
2157 * uses _Context to keep track of the position in the string.
2158 */
2159_SAFECRT__EXTERN_C
2160char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context);
2161
2162#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2163
2164_SAFECRT__INLINE
2165char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context)
2166{
2167 unsigned char *str;
2168 const unsigned char *ctl = (const unsigned char *)_Control;
2169 unsigned char map[32];
2170 int count;
2171
2172 /* validation section */
2173 _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr);
2174 _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr);
2175 _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr);
2176
2177 /* Clear control map */
2178 for (count = 0; count < 32; count++)
2179 {
2180 map[count] = 0;
2181 }
2182
2183 /* Set bits in delimiter table */
2184 do {
2185 map[*ctl >> 3] |= (1 << (*ctl & 7));
2186 } while (*ctl++);
2187
2188 /* If string is nullptr, set str to the saved
2189 * pointer (i.e., continue breaking tokens out of the string
2190 * from the last strtok call) */
2191 if (_String != nullptr)
2192 {
2193 str = (unsigned char *)_String;
2194 }
2195 else
2196 {
2197 str = (unsigned char *)*_Context;
2198 }
2199
2200 /* Find beginning of token (skip over leading delimiters). Note that
2201 * there is no token iff this loop sets str to point to the terminal
2202 * null (*str == 0) */
2203 while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0)
2204 {
2205 str++;
2206 }
2207
2208 _String = (char *)str;
2209
2210 /* Find the end of the token. If it is not the end of the string,
2211 * put a null there. */
2212 for ( ; *str != 0 ; str++ )
2213 {
2214 if (map[*str >> 3] & (1 << (*str & 7)))
2215 {
2216 *str++ = 0;
2217 break;
2218 }
2219 }
2220
2221 /* Update context */
2222 *_Context = (char *)str;
2223
2224 /* Determine if a token has been found. */
2225 if (_String == (char *)str)
2226 {
2227 return nullptr;
2228 }
2229 else
2230 {
2231 return _String;
2232 }
2233}
2234#endif
2235
2236/* wcstok_s */
2237_SAFECRT__EXTERN_C
2238WCHAR * __cdecl wcstok_s(WCHAR *_String, const WCHAR *_Control, WCHAR **_Context);
2239
2240#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2241
2242_SAFECRT__INLINE
2243WCHAR * __cdecl wcstok_s(WCHAR *_String, const WCHAR *_Control, WCHAR **_Context)
2244{
2245 WCHAR *token;
2246 const WCHAR *ctl;
2247
2248 /* validation section */
2249 _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr);
2250 _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr);
2251 _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr);
2252
2253 /* If string==nullptr, continue with previous string */
2254 if (!_String)
2255 {
2256 _String = *_Context;
2257 }
2258
2259 /* Find beginning of token (skip over leading delimiters). Note that
2260 * there is no token iff this loop sets string to point to the terminal null. */
2261 for ( ; *_String != 0 ; _String++)
2262 {
2263 for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
2264 ;
2265 if (*ctl == 0)
2266 {
2267 break;
2268 }
2269 }
2270
2271 token = _String;
2272
2273 /* Find the end of the token. If it is not the end of the string,
2274 * put a null there. */
2275 for ( ; *_String != 0 ; _String++)
2276 {
2277 for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
2278 ;
2279 if (*ctl != 0)
2280 {
2281 *_String++ = 0;
2282 break;
2283 }
2284 }
2285
2286 /* Update the context */
2287 *_Context = _String;
2288
2289 /* Determine if a token has been found. */
2290 if (token == _String)
2291 {
2292 return nullptr;
2293 }
2294 else
2295 {
2296 return token;
2297 }
2298}
2299#endif
2300
2301/* _mbstok_s */
2302#if _SAFECRT_DEFINE_MBS_FUNCTIONS
2303
2304_SAFECRT__EXTERN_C
2305unsigned char * __cdecl _mbstok_s(unsigned char *_String, const unsigned char *_Control, unsigned char **_Context);
2306
2307#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2308
2309_SAFECRT__INLINE
2310unsigned char * __cdecl _mbstok_s(unsigned char *_String, const unsigned char *_Control, unsigned char **_Context)
2311{
2312 unsigned char *token;
2313 const unsigned char *ctl;
2314 int dbc;
2315
2316 /* validation section */
2317 _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr);
2318 _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr);
2319 _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr);
2320
2321 /* If string==nullptr, continue with previous string */
2322 if (!_String)
2323 {
2324 _String = *_Context;
2325 }
2326
2327 /* Find beginning of token (skip over leading delimiters). Note that
2328 * there is no token iff this loop sets string to point to the terminal null. */
2329 for ( ; *_String != 0; _String++)
2330 {
2331 for (ctl = _Control; *ctl != 0; ctl++)
2332 {
2333 if (_SAFECRT__ISMBBLEAD(*ctl))
2334 {
2335 if (*ctl == *_String && (ctl[1] == 0 || ctl[1] == _String[1]))
2336 {
2337 break;
2338 }
2339 ctl++;
2340 }
2341 else
2342 {
2343 if (*ctl == *_String)
2344 {
2345 break;
2346 }
2347 }
2348 }
2349 if (*ctl == 0)
2350 {
2351 break;
2352 }
2353 if (_SAFECRT__ISMBBLEAD(*_String))
2354 {
2355 _String++;
2356 if (*_String == 0)
2357 {
2358 break;
2359 }
2360 }
2361 }
2362
2363 token = _String;
2364
2365 /* Find the end of the token. If it is not the end of the string,
2366 * put a null there. */
2367 for ( ; *_String != 0; _String++)
2368 {
2369 for (ctl = _Control, dbc = 0; *ctl != 0; ctl++)
2370 {
2371 if (_SAFECRT__ISMBBLEAD(*ctl))
2372 {
2373 if (*ctl == *_String && (ctl[1] == 0 || ctl[1] == _String[1]))
2374 {
2375 dbc = 1;
2376 break;
2377 }
2378 ctl++;
2379 }
2380 else
2381 {
2382 if (*ctl == *_String)
2383 {
2384 break;
2385 }
2386 }
2387 }
2388 if (*ctl != 0)
2389 {
2390 *_String++ = 0;
2391 if (dbc && ctl[1] != 0)
2392 {
2393 *_String++ = 0;
2394 }
2395 break;
2396 }
2397 if (_SAFECRT__ISMBBLEAD(*_String))
2398 {
2399 _String++;
2400 if (*_String == 0)
2401 {
2402 break;
2403 }
2404 }
2405 }
2406
2407 /* Update the context */
2408 *_Context = _String;
2409
2410 /* Determine if a token has been found. */
2411 if (token == _String)
2412 {
2413 return nullptr;
2414 }
2415 else
2416 {
2417 return token;
2418 }
2419}
2420#endif
2421
2422#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
2423
2424#ifndef PAL_STDCPP_COMPAT
2425/* strnlen */
2426/*
2427 * strnlen, wcsnlen ;
2428 * returns inMaxSize if the null character is not found.
2429 */
2430_SAFECRT__EXTERN_C
2431size_t __cdecl strnlen(const char* inString, size_t inMaxSize);
2432
2433#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2434
2435_SAFECRT__INLINE
2436size_t __cdecl strnlen(const char* inString, size_t inMaxSize)
2437{
2438 size_t n;
2439
2440 /* Note that we do not check if s == nullptr, because we do not
2441 * return errno_t...
2442 */
2443
2444 for (n = 0; n < inMaxSize && *inString; n++, inString++)
2445 ;
2446
2447 return n;
2448}
2449
2450#endif
2451
2452/* wcsnlen */
2453_SAFECRT__EXTERN_C
2454size_t __cdecl wcsnlen(const WCHAR *inString, size_t inMaxSize);
2455
2456#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2457
2458_SAFECRT__INLINE
2459size_t __cdecl wcsnlen(const WCHAR *inString, size_t inMaxSize)
2460{
2461 size_t n;
2462
2463 /* Note that we do not check if s == nullptr, because we do not
2464 * return errno_t...
2465 */
2466
2467 for (n = 0; n < inMaxSize && *inString; n++, inString++)
2468 ;
2469
2470 return n;
2471}
2472
2473#endif
2474#endif // PAL_STDCPP_COMPAT
2475
2476/* _makepath_s */
2477/*
2478 * _makepath_s, _wmakepath_s build up a path starting from the specified components;
2479 * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
2480 * any of _Drive, _Dir, _Filename and _Ext can be nullptr
2481 */
2482_SAFECRT__EXTERN_C
2483errno_t __cdecl _makepath_s(char *_Dst, size_t _SizeInBytes, const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext);
2484
2485#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
2486template <size_t _SizeInBytes>
2487inline
2488errno_t __cdecl _makepath_s(char (&_Dst)[_SizeInBytes], const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext)
2489{
2490 return _makepath_s(_Dst, _SizeInBytes, _Drive, _Dir, _Filename, _Ext);
2491}
2492#endif
2493
2494#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2495
2496_SAFECRT__INLINE
2497errno_t __cdecl _makepath_s(char *_Dst, size_t _SizeInBytes, const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext)
2498{
2499 size_t written;
2500 const char *p;
2501 char *d;
2502
2503 /* validation section */
2504 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
2505
2506 /* copy drive */
2507 written = 0;
2508 d = _Dst;
2509 if (_Drive != nullptr && *_Drive != 0)
2510 {
2511 written += 2;
2512 if(written >= _SizeInBytes)
2513 {
2514 goto error_return;
2515 }
2516 *d++ = *_Drive;
2517 *d++ = ':';
2518 }
2519
2520 /* copy dir */
2521 p = _Dir;
2522 if (p != nullptr && *p != 0)
2523 {
2524 do {
2525 if(++written >= _SizeInBytes)
2526 {
2527 goto error_return;
2528 }
2529 *d++ = *p++;
2530 } while (*p != 0);
2531
2532 p = (const char *)_SAFECRT__MBSDEC((const unsigned char *)_Dir, (const unsigned char *)p);
2533 if (*p != '/' && *p != '\\')
2534 {
2535 if(++written >= _SizeInBytes)
2536 {
2537 goto error_return;
2538 }
2539 *d++ = '\\';
2540 }
2541 }
2542
2543 /* copy fname */
2544 p = _Filename;
2545 if (p != nullptr)
2546 {
2547 while (*p != 0)
2548 {
2549 if(++written >= _SizeInBytes)
2550 {
2551 goto error_return;
2552 }
2553 *d++ = *p++;
2554 }
2555 }
2556
2557 /* copy extension; check to see if a '.' needs to be inserted */
2558 p = _Ext;
2559 if (p != nullptr)
2560 {
2561 if (*p != 0 && *p != '.')
2562 {
2563 if(++written >= _SizeInBytes)
2564 {
2565 goto error_return;
2566 }
2567 *d++ = '.';
2568 }
2569 while (*p != 0)
2570 {
2571 if(++written >= _SizeInBytes)
2572 {
2573 goto error_return;
2574 }
2575 *d++ = *p++;
2576 }
2577 }
2578
2579 if(++written > _SizeInBytes)
2580 {
2581 goto error_return;
2582 }
2583 *d = 0;
2584 _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, written);
2585 return 0;
2586
2587error_return:
2588 _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
2589 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
2590 /* should never happen, but compiler can't tell */
2591 return EINVAL;
2592}
2593#endif
2594
2595/* _wmakepath_s */
2596_SAFECRT__EXTERN_C
2597errno_t __cdecl _wmakepath_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext);
2598
2599#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
2600template <size_t _SizeInWords>
2601inline
2602errno_t __cdecl _wmakepath_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext)
2603{
2604 return _wmakepath_s(_Dst, _SizeInWords, _Drive, _Dir, _Filename, _Ext);
2605}
2606#endif
2607
2608#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2609
2610_SAFECRT__INLINE
2611errno_t __cdecl _wmakepath_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext)
2612{
2613 size_t written;
2614 const WCHAR *p;
2615 WCHAR *d;
2616
2617 /* validation section */
2618 _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
2619
2620 /* copy drive */
2621 written = 0;
2622 d = _Dst;
2623 if (_Drive != nullptr && *_Drive != 0)
2624 {
2625 written += 2;
2626 if(written >= _SizeInWords)
2627 {
2628 goto error_return;
2629 }
2630 *d++ = *_Drive;
2631 *d++ = L':';
2632 }
2633
2634 /* copy dir */
2635 p = _Dir;
2636 if (p != nullptr && *p != 0)
2637 {
2638 do {
2639 if(++written >= _SizeInWords)
2640 {
2641 goto error_return;
2642 }
2643 *d++ = *p++;
2644 } while (*p != 0);
2645
2646 p = p - 1;
2647 if (*p != L'/' && *p != L'\\')
2648 {
2649 if(++written >= _SizeInWords)
2650 {
2651 goto error_return;
2652 }
2653 *d++ = L'\\';
2654 }
2655 }
2656
2657 /* copy fname */
2658 p = _Filename;
2659 if (p != nullptr)
2660 {
2661 while (*p != 0)
2662 {
2663 if(++written >= _SizeInWords)
2664 {
2665 goto error_return;
2666 }
2667 *d++ = *p++;
2668 }
2669 }
2670
2671 /* copy extension; check to see if a '.' needs to be inserted */
2672 p = _Ext;
2673 if (p != nullptr)
2674 {
2675 if (*p != 0 && *p != L'.')
2676 {
2677 if(++written >= _SizeInWords)
2678 {
2679 goto error_return;
2680 }
2681 *d++ = L'.';
2682 }
2683 while (*p != 0)
2684 {
2685 if(++written >= _SizeInWords)
2686 {
2687 goto error_return;
2688 }
2689 *d++ = *p++;
2690 }
2691 }
2692
2693 if(++written > _SizeInWords)
2694 {
2695 goto error_return;
2696 }
2697 *d = 0;
2698 _SAFECRT__FILL_STRING(_Dst, _SizeInWords, written);
2699 return 0;
2700
2701error_return:
2702 _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
2703 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
2704 /* should never happen, but compiler can't tell */
2705 return EINVAL;
2706}
2707#endif
2708
2709/* _splitpath_s */
2710/*
2711 * _splitpath_s, _wsplitpath_s decompose a path into the specified components;
2712 * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in
2713 * any of _Drive, _Dir, _Filename and _Ext;
2714 * any of _Drive, _Dir, _Filename and _Ext can be nullptr, but the correspondent size must
2715 * be set to 0, e.g. (_Drive == nullptr && _DriveSize == 0) is allowed, but
2716 * (_Drive == nullptr && _DriveSize != 0) is considered an invalid parameter
2717 */
2718_SAFECRT__EXTERN_C
2719errno_t __cdecl _splitpath_s(
2720 const char *_Path,
2721 char *_Drive, size_t _DriveSize,
2722 char *_Dir, size_t _DirSize,
2723 char *_Filename, size_t _FilenameSize,
2724 char *_Ext, size_t _ExtSize
2725);
2726
2727/* no C++ overload for _splitpath_s */
2728
2729#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2730
2731_SAFECRT__INLINE
2732errno_t __cdecl _splitpath_s(
2733 const char *_Path,
2734 char *_Drive, size_t _DriveSize,
2735 char *_Dir, size_t _DirSize,
2736 char *_Filename, size_t _FilenameSize,
2737 char *_Ext, size_t _ExtSize
2738)
2739{
2740 const char *tmp;
2741 const char *last_slash;
2742 const char *dot;
2743 int drive_set = 0;
2744 size_t length = 0;
2745 int bEinval = 0;
2746
2747 /* validation section */
2748 _SAFECRT__VALIDATE_POINTER(_Path);
2749 if ((_Drive == nullptr && _DriveSize != 0) || (_Drive != nullptr && _DriveSize == 0))
2750 {
2751 goto error_einval;
2752 }
2753 if ((_Dir == nullptr && _DirSize != 0) || (_Dir != nullptr && _DirSize == 0))
2754 {
2755 goto error_einval;
2756 }
2757 if ((_Filename == nullptr && _FilenameSize != 0) || (_Filename != nullptr && _FilenameSize == 0))
2758 {
2759 goto error_einval;
2760 }
2761 if ((_Ext == nullptr && _ExtSize != 0) || (_Ext != nullptr && _ExtSize == 0))
2762 {
2763 goto error_einval;
2764 }
2765
2766 /* check if _Path begins with the longpath prefix */
2767 if (_Path[0] == '\\' && _Path[1] == '\\' && _Path[2] == '?' && _Path[3] == '\\')
2768 {
2769 _Path += 4;
2770 }
2771
2772 /* extract drive letter and ':', if any */
2773 if (!drive_set)
2774 {
2775 size_t skip = _MAX_DRIVE - 2;
2776 tmp = _Path;
2777 while (skip > 0 && *tmp != 0)
2778 {
2779 skip--;
2780 tmp++;
2781 }
2782 if (*tmp == ':')
2783 {
2784 if (_Drive != nullptr)
2785 {
2786 if (_DriveSize < _MAX_DRIVE)
2787 {
2788 goto error_erange;
2789 }
2790 strncpy_s(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1);
2791 }
2792 _Path = tmp + 1;
2793 }
2794 else
2795 {
2796 if (_Drive != nullptr)
2797 {
2798 _SAFECRT__RESET_STRING(_Drive, _DriveSize);
2799 }
2800 }
2801 }
2802
2803 /* extract path string, if any. _Path now points to the first character
2804 * of the path, if any, or the filename or extension, if no path was
2805 * specified. Scan ahead for the last occurence, if any, of a '/' or
2806 * '\' path separator character. If none is found, there is no path.
2807 * We will also note the last '.' character found, if any, to aid in
2808 * handling the extension.
2809 */
2810 last_slash = nullptr;
2811 dot = nullptr;
2812 tmp = _Path;
2813 for (; *tmp != 0; ++tmp)
2814 {
2815#if _SAFECRT_DEFINE_MBS_FUNCTIONS
2816#pragma warning(push)
2817#pragma warning(disable:4127)
2818 if (_SAFECRT__ISMBBLEAD(*tmp))
2819#pragma warning(pop)
2820#else
2821 if (0)
2822#endif
2823 {
2824 tmp++;
2825 }
2826 else
2827 {
2828 if (*tmp == '/' || *tmp == '\\')
2829 {
2830 /* point to one beyond for later copy */
2831 last_slash = tmp + 1;
2832 }
2833 else if (*tmp == '.')
2834 {
2835 dot = tmp;
2836 }
2837 }
2838 }
2839
2840 if (last_slash != nullptr)
2841 {
2842 /* found a path - copy up through last_slash or max characters
2843 * allowed, whichever is smaller
2844 */
2845 if (_Dir != nullptr) {
2846 length = (size_t)(last_slash - _Path);
2847 if (_DirSize <= length)
2848 {
2849 goto error_erange;
2850 }
2851 strncpy_s(_Dir, _DirSize, _Path, length);
2852 }
2853 _Path = last_slash;
2854 }
2855 else
2856 {
2857 /* there is no path */
2858 if (_Dir != nullptr)
2859 {
2860 _SAFECRT__RESET_STRING(_Dir, _DirSize);
2861 }
2862 }
2863
2864 /* extract file name and extension, if any. Path now points to the
2865 * first character of the file name, if any, or the extension if no
2866 * file name was given. Dot points to the '.' beginning the extension,
2867 * if any.
2868 */
2869 if (dot != nullptr && (dot >= _Path))
2870 {
2871 /* found the marker for an extension - copy the file name up to the '.' */
2872 if (_Filename)
2873 {
2874 length = (size_t)(dot - _Path);
2875 if (_FilenameSize <= length)
2876 {
2877 goto error_erange;
2878 }
2879 strncpy_s(_Filename, _FilenameSize, _Path, length);
2880 }
2881 /* now we can get the extension - remember that tmp still points
2882 * to the terminating nullptr character of path.
2883 */
2884 if (_Ext)
2885 {
2886 length = (size_t)(tmp - dot);
2887 if (_ExtSize <= length)
2888 {
2889 goto error_erange;
2890 }
2891 strncpy_s(_Ext, _ExtSize, dot, length);
2892 }
2893 }
2894 else
2895 {
2896 /* found no extension, give empty extension and copy rest of
2897 * string into fname.
2898 */
2899 if (_Filename)
2900 {
2901 length = (size_t)(tmp - _Path);
2902 if (_FilenameSize <= length)
2903 {
2904 goto error_erange;
2905 }
2906 strncpy_s(_Filename, _FilenameSize, _Path, length);
2907 }
2908 if (_Ext)
2909 {
2910 _SAFECRT__RESET_STRING(_Ext, _ExtSize);
2911 }
2912 }
2913
2914 return 0;
2915
2916error_einval:
2917 bEinval = 1;
2918
2919error_erange:
2920 if (_Drive != nullptr && _DriveSize > 0)
2921 {
2922 _SAFECRT__RESET_STRING(_Drive, _DriveSize);
2923 }
2924 if (_Dir != nullptr && _DirSize > 0)
2925 {
2926 _SAFECRT__RESET_STRING(_Dir, _DirSize);
2927 }
2928 if (_Filename != nullptr && _FilenameSize > 0)
2929 {
2930 _SAFECRT__RESET_STRING(_Filename, _FilenameSize);
2931 }
2932 if (_Ext != nullptr && _ExtSize > 0)
2933 {
2934 _SAFECRT__RESET_STRING(_Ext, _ExtSize);
2935 }
2936
2937 if (bEinval)
2938 {
2939 _SAFECRT__RETURN_EINVAL;
2940 }
2941
2942 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Strings, _StringSizes);
2943 /* should never happen, but compiler can't tell */
2944 return EINVAL;
2945}
2946#endif
2947
2948/* _wsplitpath_s */
2949_SAFECRT__EXTERN_C
2950errno_t __cdecl _wsplitpath_s(
2951 const WCHAR *_Path,
2952 WCHAR *_Drive, size_t _DriveSize,
2953 WCHAR *_Dir, size_t _DirSize,
2954 WCHAR *_Filename, size_t _FilenameSize,
2955 WCHAR *_Ext, size_t _ExtSize
2956);
2957
2958/* no C++ overload for _wsplitpath_s */
2959
2960#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
2961
2962_SAFECRT__INLINE
2963errno_t __cdecl _wsplitpath_s(
2964 const WCHAR *_Path,
2965 WCHAR *_Drive, size_t _DriveSize,
2966 WCHAR *_Dir, size_t _DirSize,
2967 WCHAR *_Filename, size_t _FilenameSize,
2968 WCHAR *_Ext, size_t _ExtSize
2969)
2970{
2971 const WCHAR *tmp;
2972 const WCHAR *last_slash;
2973 const WCHAR *dot;
2974 int drive_set = 0;
2975 size_t length = 0;
2976 int bEinval = 0;
2977
2978 /* validation section */
2979 _SAFECRT__VALIDATE_POINTER(_Path);
2980 if ((_Drive == nullptr && _DriveSize != 0) || (_Drive != nullptr && _DriveSize == 0))
2981 {
2982 goto error_einval;
2983 }
2984 if ((_Dir == nullptr && _DirSize != 0) || (_Dir != nullptr && _DirSize == 0))
2985 {
2986 goto error_einval;
2987 }
2988 if ((_Filename == nullptr && _FilenameSize != 0) || (_Filename != nullptr && _FilenameSize == 0))
2989 {
2990 goto error_einval;
2991 }
2992 if ((_Ext == nullptr && _ExtSize != 0) || (_Ext != nullptr && _ExtSize == 0))
2993 {
2994 goto error_einval;
2995 }
2996
2997 /* check if _Path begins with the longpath prefix */
2998 if (_Path[0] == L'\\' && _Path[1] == L'\\' && _Path[2] == L'?' && _Path[3] == L'\\')
2999 {
3000 _Path += 4;
3001 }
3002
3003 /* extract drive letter and ':', if any */
3004 if (!drive_set)
3005 {
3006 size_t skip = _MAX_DRIVE - 2;
3007 tmp = _Path;
3008 while (skip > 0 && *tmp != 0)
3009 {
3010 skip--;
3011 tmp++;
3012 }
3013 if (*tmp == L':')
3014 {
3015 if (_Drive != nullptr)
3016 {
3017 if (_DriveSize < _MAX_DRIVE)
3018 {
3019 goto error_erange;
3020 }
3021 wcsncpy_s(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1);
3022 }
3023 _Path = tmp + 1;
3024 }
3025 else
3026 {
3027 if (_Drive != nullptr)
3028 {
3029 _SAFECRT__RESET_STRING(_Drive, _DriveSize);
3030 }
3031 }
3032 }
3033
3034 /* extract path string, if any. _Path now points to the first character
3035 * of the path, if any, or the filename or extension, if no path was
3036 * specified. Scan ahead for the last occurence, if any, of a '/' or
3037 * '\' path separator character. If none is found, there is no path.
3038 * We will also note the last '.' character found, if any, to aid in
3039 * handling the extension.
3040 */
3041 last_slash = nullptr;
3042 dot = nullptr;
3043 tmp = _Path;
3044 for (; *tmp != 0; ++tmp)
3045 {
3046 {
3047 if (*tmp == L'/' || *tmp == L'\\')
3048 {
3049 /* point to one beyond for later copy */
3050 last_slash = tmp + 1;
3051 }
3052 else if (*tmp == L'.')
3053 {
3054 dot = tmp;
3055 }
3056 }
3057 }
3058
3059 if (last_slash != nullptr)
3060 {
3061 /* found a path - copy up through last_slash or max characters
3062 * allowed, whichever is smaller
3063 */
3064 if (_Dir != nullptr) {
3065 length = (size_t)(last_slash - _Path);
3066 if (_DirSize <= length)
3067 {
3068 goto error_erange;
3069 }
3070 wcsncpy_s(_Dir, _DirSize, _Path, length);
3071 }
3072 _Path = last_slash;
3073 }
3074 else
3075 {
3076 /* there is no path */
3077 if (_Dir != nullptr)
3078 {
3079 _SAFECRT__RESET_STRING(_Dir, _DirSize);
3080 }
3081 }
3082
3083 /* extract file name and extension, if any. Path now points to the
3084 * first character of the file name, if any, or the extension if no
3085 * file name was given. Dot points to the '.' beginning the extension,
3086 * if any.
3087 */
3088 if (dot != nullptr && (dot >= _Path))
3089 {
3090 /* found the marker for an extension - copy the file name up to the '.' */
3091 if (_Filename)
3092 {
3093 length = (size_t)(dot - _Path);
3094 if (_FilenameSize <= length)
3095 {
3096 goto error_erange;
3097 }
3098 wcsncpy_s(_Filename, _FilenameSize, _Path, length);
3099 }
3100 /* now we can get the extension - remember that tmp still points
3101 * to the terminating nullptr character of path.
3102 */
3103 if (_Ext)
3104 {
3105 length = (size_t)(tmp - dot);
3106 if (_ExtSize <= length)
3107 {
3108 goto error_erange;
3109 }
3110 wcsncpy_s(_Ext, _ExtSize, dot, length);
3111 }
3112 }
3113 else
3114 {
3115 /* found no extension, give empty extension and copy rest of
3116 * string into fname.
3117 */
3118 if (_Filename)
3119 {
3120 length = (size_t)(tmp - _Path);
3121 if (_FilenameSize <= length)
3122 {
3123 goto error_erange;
3124 }
3125 wcsncpy_s(_Filename, _FilenameSize, _Path, length);
3126 }
3127 if (_Ext)
3128 {
3129 _SAFECRT__RESET_STRING(_Ext, _ExtSize);
3130 }
3131 }
3132
3133 return 0;
3134
3135error_einval:
3136 bEinval = 1;
3137
3138error_erange:
3139 if (_Drive != nullptr && _DriveSize > 0)
3140 {
3141 _SAFECRT__RESET_STRING(_Drive, _DriveSize);
3142 }
3143 if (_Dir != nullptr && _DirSize > 0)
3144 {
3145 _SAFECRT__RESET_STRING(_Dir, _DirSize);
3146 }
3147 if (_Filename != nullptr && _FilenameSize > 0)
3148 {
3149 _SAFECRT__RESET_STRING(_Filename, _FilenameSize);
3150 }
3151 if (_Ext != nullptr && _ExtSize > 0)
3152 {
3153 _SAFECRT__RESET_STRING(_Ext, _ExtSize);
3154 }
3155
3156 if (bEinval)
3157 {
3158 _SAFECRT__RETURN_EINVAL;
3159 }
3160
3161 _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Strings, _StringSizes);
3162 /* should never happen, but compiler can't tell */
3163 return EINVAL;
3164}
3165#endif
3166
3167/* sprintf_s, vsprintf_s */
3168/*
3169 * sprintf_s, swprintf_s, vsprintf_s, vswprintf_s format a string and copy it into _Dst;
3170 * need safecrt.lib and msvcrt.dll;
3171 * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
3172 * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed;
3173 * the %n format type is not allowed;
3174 * return the length of string _Dst;
3175 * return a negative number if something goes wrong with mbcs conversions (we will not call _SAFECRT_INVALID_PARAMETER);
3176 * _SizeInBytes/_SizeInWords must be <= (INT_MAX / sizeof(char/WCHAR));
3177 * cannot be used without safecrt.lib
3178 */
3179_SAFECRT__EXTERN_C
3180int __cdecl sprintf_s(char *_Dst, size_t _SizeInBytes, const char *_Format, ...);
3181_SAFECRT__EXTERN_C
3182int __cdecl vsprintf_s(char *_Dst, size_t _SizeInBytes, const char *_Format, va_list _ArgList);
3183
3184#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
3185template <size_t _SizeInBytes>
3186inline
3187int __cdecl sprintf_s(char (&_Dst)[_SizeInBytes], const char *_Format, ...)
3188{
3189 int ret;
3190 va_list _ArgList;
3191 va_start(_ArgList, _Format);
3192 ret = vsprintf_s(_Dst, _SizeInBytes, _Format, _ArgList);
3193 va_end(_ArgList);
3194 return ret;
3195}
3196
3197template <size_t _SizeInBytes>
3198inline
3199int __cdecl vsprintf_s(char (&_Dst)[_SizeInBytes], const char *_Format, va_list _ArgList)
3200{
3201 return vsprintf_s(_Dst, _SizeInBytes, _Format, _ArgList);
3202}
3203#endif
3204
3205/* no inline version of sprintf_s, vsprintf_s */
3206
3207/* swprintf_s, vswprintf_s */
3208_SAFECRT__EXTERN_C
3209int __cdecl swprintf_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Format, ...);
3210_SAFECRT__EXTERN_C
3211int __cdecl vswprintf_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Format, va_list _ArgList);
3212
3213#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
3214template <size_t _SizeInWords>
3215inline
3216int __cdecl swprintf_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Format, ...)
3217{
3218 int ret;
3219 va_list _ArgList;
3220 va_start(_ArgList, _Format);
3221 ret = vswprintf_s(_Dst, _SizeInWords, _Format, _ArgList);
3222 va_end(_ArgList);
3223 return ret;
3224}
3225
3226template <size_t _SizeInWords>
3227inline
3228int __cdecl vswprintf_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Format, va_list _ArgList)
3229{
3230 return vswprintf_s(_Dst, _SizeInWords, _Format, _ArgList);
3231}
3232#endif
3233
3234/* no inline version of swprintf_s, vswprintf_s */
3235
3236/* _snprintf_s, _vsnprintf_s */
3237/*
3238 * _snprintf_s, _snwprintf_s, _vsnprintf_s, _vsnwprintf_s format a string and copy at max _Count characters into _Dst;
3239 * need safecrt.lib and msvcrt.dll;
3240 * string _Dst will always be null-terminated;
3241 * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
3242 * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed;
3243 * the %n format type is not allowed;
3244 * return the length of string _Dst;
3245 * return a negative number if something goes wrong with mbcs conversions (we will not call _SAFECRT_INVALID_PARAMETER);
3246 * _SizeInBytes/_SizeInWords must be <= (INT_MAX / sizeof(char/WCHAR));
3247 * cannot be used without safecrt.lib;
3248 * if _Count == _TRUNCATE, we will copy into _Dst as many characters as we can, and
3249 * return -1 if the formatted string does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER);
3250 * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed
3251 */
3252
3253#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
3254template <size_t _SizeInBytes>
3255inline
3256int __cdecl _snprintf_s(char (&_Dst)[_SizeInBytes], size_t _Count, const char *_Format, ...)
3257{
3258 int ret;
3259 va_list _ArgList;
3260 va_start(_ArgList, _Format);
3261 ret = _vsnprintf_s(_Dst, _SizeInBytes, _Count, _Format, _ArgList);
3262 va_end(_ArgList);
3263 return ret;
3264}
3265
3266template <size_t _SizeInBytes>
3267inline
3268int __cdecl _vsnprintf_s(char (&_Dst)[_SizeInBytes], size_t _Count, const char *_Format, va_list _ArgList)
3269{
3270 return _vsnprintf_s(_Dst, _SizeInBytes, _Count, _Format, _ArgList);
3271}
3272#endif
3273
3274/* no inline version of _snprintf_s, _vsnprintf_s */
3275
3276/* _snwprintf_s, _vsnwprintf_s */
3277_SAFECRT__EXTERN_C
3278int __cdecl _vsnwprintf_s(WCHAR *_Dst, size_t _SizeInWords, size_t _Count, const WCHAR *_Format, va_list _ArgList);
3279
3280#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
3281template <size_t _SizeInWords>
3282inline
3283int __cdecl _snwprintf_s(WCHAR (&_Dst)[_SizeInWords], size_t _Count, const WCHAR *_Format, ...)
3284{
3285 int ret;
3286 va_list _ArgList;
3287 va_start(_ArgList, _Format);
3288 ret = _vsnwprintf_s(_Dst, _SizeInWords, _Count, _Format, _ArgList);
3289 va_end(_ArgList);
3290 return ret;
3291}
3292
3293template <size_t _SizeInWords>
3294inline
3295int __cdecl _vsnwprintf_s(char (&_Dst)[_SizeInWords], size_t _Count, const char *_Format, va_list _ArgList)
3296{
3297 return _vsnwprintf_s(_Dst, _SizeInWords, _Count, _Format, _ArgList);
3298}
3299#endif
3300
3301/* no inline version of _snwprintf_s, _vsnwprintf_s */
3302
3303/* scanf_s */
3304/*
3305 * read formatted data from the standard input stream;
3306 * need safecrt.lib and msvcrt.dll;
3307 * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed;
3308 * for format types %s, %S, %[, %c and %C, in the argument list the buffer pointer
3309 * need to be followed by the size of the buffer, e.g.:
3310 * #define BUFFSIZE 100
3311 * char buff[BUFFSIZE];
3312 * scanf_s("%s", buff, BUFFSIZE);
3313 * as scanf, returns the number of fields successfully converted and assigned;
3314 * if a buffer field is too small, scanf set the buffer to the empty string and returns.
3315 * do not support floating-point, for now
3316 */
3317_SAFECRT__EXTERN_C
3318int __cdecl scanf_s(const char *_Format, ...);
3319
3320/* no C++ overload for scanf_s */
3321
3322/* no inline version of scanf_s */
3323
3324/* wscanf_s */
3325_SAFECRT__EXTERN_C
3326int __cdecl wscanf_s(const WCHAR *_Format, ...);
3327
3328/* no C++ overload for wscanf_s */
3329
3330/* no inline version of wscanf_s */
3331
3332/* sscanf_s */
3333_SAFECRT__EXTERN_C
3334int __cdecl sscanf_s(const char *_String, const char *_Format, ...);
3335
3336/* no C++ overload for sscanf_s */
3337
3338/* no inline version of sscanf_s */
3339
3340/* swscanf_s */
3341_SAFECRT__EXTERN_C
3342int __cdecl swscanf_s(const WCHAR *_String, const WCHAR *_Format, ...);
3343
3344/* no C++ overload for swscanf_s */
3345
3346/* no inline version of swscanf_s */
3347
3348/* _snscanf_s */
3349_SAFECRT__EXTERN_C
3350int __cdecl _snscanf_s(const char *_String, size_t _Count, const char *_Format, ...);
3351
3352/* no C++ overload for snscanf_s */
3353
3354/* no inline version of snscanf_s */
3355
3356/* _swnscanf_s */
3357_SAFECRT__EXTERN_C
3358int __cdecl _swnscanf_s(const WCHAR *_String, size_t _Count, const WCHAR *_Format, ...);
3359
3360/* no C++ overload for _swnscanf_s */
3361
3362/* no inline version of _swnscanf_s */
3363
3364//#endif /* ndef _SAFECRT_IMPL */
3365
3366#endif /* _INC_SAFECRT */
3367