diff options
author | Jiyoung Yun <jy910.yun@samsung.com> | 2016-11-23 19:09:09 +0900 |
---|---|---|
committer | Jiyoung Yun <jy910.yun@samsung.com> | 2016-11-23 19:09:09 +0900 |
commit | 4b4aad7217d3292650e77eec2cf4c198ea9c3b4b (patch) | |
tree | 98110734c91668dfdbb126fcc0e15ddbd93738ca /src/pal/src/safecrt | |
parent | fa45f57ed55137c75ac870356a1b8f76c84b229c (diff) | |
download | coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.gz coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.tar.bz2 coreclr-4b4aad7217d3292650e77eec2cf4c198ea9c3b4b.zip |
Imported Upstream version 1.1.0upstream/1.1.0
Diffstat (limited to 'src/pal/src/safecrt')
46 files changed, 9395 insertions, 0 deletions
diff --git a/src/pal/src/safecrt/cruntime.h b/src/pal/src/safecrt/cruntime.h new file mode 100644 index 0000000000..cdad474e53 --- /dev/null +++ b/src/pal/src/safecrt/cruntime.h @@ -0,0 +1,98 @@ +// 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. + +/*** +*cruntime.h - definitions specific to the target operating system and hardware +* + +* +*Purpose: +* This header file contains widely used definitions specific to the +* host operating system and hardware. It is included by every C source +* and most every other header file. +* +* [Internal] +* +****/ + +#if _MSC_VER > 1000 +#pragma once +#endif /* _MSC_VER > 1000 */ + +#ifndef _INC_CRUNTIME +#define _INC_CRUNTIME + +#ifndef _CRTBLD +/* + * This is an internal C runtime header file. It is used when building + * the C runtimes only. It is not to be used as a public header file. + */ +#error ERROR: Use of C runtime library internal header file. +#endif /* _CRTBLD */ + +#if defined (_SYSCRT) && defined (_WIN64) +#define _USE_OLD_STDCPP 1 +#endif /* defined (_SYSCRT) && defined (_WIN64) */ + +#if !defined (UNALIGNED) +#if defined (_M_IA64) || defined (_M_AMD64) +#define UNALIGNED __unaligned +#else /* defined (_M_IA64) || defined (_M_AMD64) */ +#define UNALIGNED +#endif /* defined (_M_IA64) || defined (_M_AMD64) */ +#endif /* !defined (UNALIGNED) */ + +#ifdef _M_IX86 +/* + * 386/486 + */ +#define REG1 register +#define REG2 register +#define REG3 register +#define REG4 +#define REG5 +#define REG6 +#define REG7 +#define REG8 +#define REG9 + +#elif defined (_M_IA64) || defined (_M_AMD64) +/* + * IA64 + */ +#define REG1 register +#define REG2 register +#define REG3 register +#define REG4 register +#define REG5 register +#define REG6 register +#define REG7 register +#define REG8 register +#define REG9 register + +#else /* defined (_M_IA64) || defined (_M_AMD64) */ + +#pragma message ("Machine register set not defined") + +/* + * Unknown machine + */ + +#define REG1 +#define REG2 +#define REG3 +#define REG4 +#define REG5 +#define REG6 +#define REG7 +#define REG8 +#define REG9 + +#endif /* defined (_M_IA64) || defined (_M_AMD64) */ + +/* + * Are the macro definitions below still needed in this file? + */ + +#endif /* _INC_CRUNTIME */ diff --git a/src/pal/src/safecrt/input.inl b/src/pal/src/safecrt/input.inl new file mode 100644 index 0000000000..eaad174ff5 --- /dev/null +++ b/src/pal/src/safecrt/input.inl @@ -0,0 +1,1314 @@ +// 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. + +/*** +*input.c - C formatted input, used by scanf, etc. +* + +* +*Purpose: +* defines _input() to do formatted input; called from scanf(), +* etc. functions. This module defines _cscanf() instead when +* CPRFLAG is defined. The file cscanf.c defines that symbol +* and then includes this file in order to implement _cscanf(). +* +*Note: +* this file is included in safecrt.lib build directly, plese refer +* to safecrt_[w]input_s.c +* +*******************************************************************************/ + + +#define ALLOW_RANGE /* enable "%[a-z]"-style scansets */ + + +/* temporary work-around for compiler without 64-bit support */ + +#ifndef _INTEGRAL_MAX_BITS +#define _INTEGRAL_MAX_BITS 64 +#endif /* _INTEGRAL_MAX_BITS */ + +// typedef __int64_t __int64; + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#define UNALIGNED + +#define _BEGIN_SECURE_CRT_DEPRECATION_DISABLE +#define _END_SECURE_CRT_DEPRECATION_DISABLE + +#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */ + +//#include <cruntime.h> +//#include <stdio.h> +//#include <ctype.h> +//#include <cvt.h> +//#include <conio.h> +//#include <stdarg.h> +//#include <string.h> +//#include <internal.h> +//#include <fltintrn.h> +//#include <malloc.h> +//#include <locale.h> +//#include <mtdll.h> +//#include <stdlib.h> +//#include <setlocal.h> +//#include <dbgint.h> + +//#ifndef _INC_INTERNAL_SAFECRT +//#include <internal_securecrt.h> +//#endif /* _INC_INTERNAL_SAFECRT */ + +//#ifdef _MBCS +//#undef _MBCS +//#endif /* _MBCS */ +//#include <tchar.h> + +#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y ) + +#define _istspace(x) isspace((unsigned char)x) + +#define _malloc_crt PAL_malloc +#define _realloc_crt PAL_realloc +#define _free_crt PAL_free + +#define _FASSIGN(flag, argument, number, dec_point, locale) _safecrt_fassign((flag), (argument), (number)) +#define _WFASSIGN(flag, argument, number, dec_point, locale) _safecrt_wfassign((flag), (argument), (number)) + +#if defined (UNICODE) +#define ALLOC_TABLE 1 +#else /* defined (UNICODE) */ +#define ALLOC_TABLE 0 +#endif /* defined (UNICODE) */ + +#define HEXTODEC(chr) _hextodec(chr) + +#define LEFT_BRACKET ('[' | ('a' - 'A')) /* 'lowercase' version */ + +static int __cdecl _hextodec(_TCHAR); +#ifdef CPRFLAG + +#define INC() (++charcount, _inc()) +#define UN_INC(chr) (--charcount, _un_inc(chr)) +#define EAT_WHITE() _whiteout(&charcount) + +static int __cdecl _inc(void); +static void __cdecl _un_inc(int); +static int __cdecl _whiteout(int *); + +#else /* CPRFLAG */ + +#define INC() (++charcount, _inc(stream)) +#define UN_INC(chr) (--charcount, _un_inc(chr, stream)) +#define EAT_WHITE() _whiteout(&charcount, stream) + +static int __cdecl _inc(miniFILE *); +static void __cdecl _un_inc(int, miniFILE *); +static int __cdecl _whiteout(int *, miniFILE *); + +#endif /* CPRFLAG */ + +#ifndef _UNICODE +#define _ISDIGIT(chr) isdigit((unsigned char)chr) +#define _ISXDIGIT(chr) isxdigit((unsigned char)chr) +#else /* _UNICODE */ +#define _ISDIGIT(chr) ( !(chr & 0xff00) && isdigit( ((chr) & 0x00ff) ) ) +#define _ISXDIGIT(chr) ( !(chr & 0xff00) && isxdigit( ((chr) & 0x00ff) ) ) +#endif /* _UNICODE */ + +#define MUL10(x) ( (((x)<<2) + (x))<<1 ) + + +#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 + 0 means long long is same as long */ + +/*** +* int __check_float_string(size_t,size_t *, _TCHAR**, _TCHAR*, int*) +* +* Purpose: +* Check if there is enough space insert onemore character in the given +* block, if not then allocate more memory. +* +* Return: +* FALSE if more memory needed and the reallocation failed. +* +*******************************************************************************/ + +static int __check_float_string(size_t nFloatStrUsed, + size_t *pnFloatStrSz, + _TCHAR **pFloatStr, + _TCHAR *floatstring, + int *pmalloc_FloatStrFlag) +{ + void *tmpPointer; + _ASSERTE(nFloatStrUsed<=(*pnFloatStrSz)); + if (nFloatStrUsed==(*pnFloatStrSz)) + { + size_t newSize; + + // Will (*pnFloatStrSz) * 2 * sizeof(_TCHAR) overflow? + if ( *pnFloatStrSz > (SIZE_T_MAX / 2 / sizeof(_TCHAR))) + { + return FALSE; + } + + newSize = *pnFloatStrSz * 2 * sizeof(_TCHAR); + + if ((*pFloatStr)==floatstring) + { + if (((*pFloatStr)=(_TCHAR *)_malloc_crt(newSize))==NULL) + { + return FALSE; + } + + (*pmalloc_FloatStrFlag)=1; + + memcpy((*pFloatStr),floatstring,(*pnFloatStrSz)*sizeof(_TCHAR)); + (*pnFloatStrSz)*=2; + } + else + { + if ((tmpPointer=(_TCHAR *)_realloc_crt((*pFloatStr), newSize))==NULL) + { + return FALSE; + } + (*pFloatStr)=(_TCHAR *)(tmpPointer); + (*pnFloatStrSz)*=2; + } + } + return TRUE; +} + + +#define ASCII 32 /* # of bytes needed to hold 256 bits */ + +#define SCAN_SHORT 0 /* also for FLOAT */ +#define SCAN_LONG 1 /* also for DOUBLE */ +#define SCAN_L_DOUBLE 2 /* only for LONG DOUBLE */ + +#define SCAN_NEAR 0 +#define SCAN_FAR 1 + +#ifndef _UNICODE +#define TABLESIZE ASCII +#else /* _UNICODE */ +#define TABLESIZE (ASCII * 256) +#endif /* _UNICODE */ + + +/*** +*int _input(stream, format, arglist), static int input(format, arglist) +* +*Purpose: +* get input items (data items or literal matches) from the input stream +* and assign them if appropriate to the items thru the arglist. this +* function is intended for internal library use only, not for the user +* +* The _input entry point is for the normal scanf() functions +* The input entry point is used when compiling for _cscanf() [CPRFLAF +* defined] and is a static function called only by _cscanf() -- reads from +* console. +* +* This code also defines _input_s, which works differently for %c, %s & %[. +* For these, _input_s first picks up the next argument from the variable +* argument list & uses it as the maximum size of the character array pointed +* to by the next argument in the list. +* +*Entry: +* FILE *stream - file to read from +* char *format - format string to determine the data to read +* arglist - list of pointer to data items +* +*Exit: +* returns number of items assigned and fills in data items +* returns EOF if error or EOF found on stream before 1st data item matched +* +*Exceptions: +* +*******************************************************************************/ + + #define _INTRN_LOCALE_CONV( x ) localeconv() + +#ifndef _UNICODE + int __cdecl __tinput_s (miniFILE* stream, const _TUCHAR* format, va_list arglist) +#else + int __cdecl __twinput_s (miniFILE* stream, const _TUCHAR* format, va_list arglist) +#endif /* _UNICODE */ +{ + _TCHAR floatstring[_CVTBUFSIZE + 1]; + _TCHAR *pFloatStr=floatstring; + size_t nFloatStrUsed=0; + size_t nFloatStrSz=sizeof(floatstring)/sizeof(floatstring[0]); + int malloc_FloatStrFlag=0; + + unsigned long number; /* temp hold-value */ +#if ALLOC_TABLE + char *table = NULL; /* which chars allowed for %[] */ + int malloc_flag = 0; /* is "table" allocated on the heap? */ +#else /* ALLOC_TABLE */ + char AsciiTable[TABLESIZE]; + char *table = AsciiTable; +#endif /* ALLOC_TABLE */ + +#if _INTEGRAL_MAX_BITS >= 64 + uint64_t num64 = 0LL; /* temp for 64-bit integers */ +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + void *pointer=NULL; /* points to user data receptacle */ + void *start; /* indicate non-empty string */ + + +#ifndef _UNICODE + wchar_t wctemp=L'\0'; +#endif /* _UNICODE */ + _TUCHAR *scanptr; /* for building "table" data */ + int ch = 0; + int charcount; /* total number of chars read */ + int comchr; /* holds designator type */ + int count; /* return value. # of assignments */ + + int started; /* indicate good number */ + int width; /* width of field */ + int widthset; /* user has specified width */ +#ifdef _SECURE_SCANF + size_t array_width = 0; + size_t original_array_width = 0; + int enomem = 0; + int format_error = FALSE; +#endif /* _SECURE_SCANF */ + +/* Neither coerceshort nor farone are need for the 386 */ + + + char done_flag; /* general purpose loop monitor */ + char longone; /* 0 = SHORT, 1 = LONG, 2 = L_DOUBLE */ +#if _INTEGRAL_MAX_BITS >= 64 + int integer64; /* 1 for 64-bit integer, 0 otherwise */ +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + signed char widechar; /* -1 = char, 0 = ????, 1 = wchar_t */ + char reject; /* %[^ABC] instead of %[ABC] */ + char negative; /* flag for '-' detected */ + char suppress; /* don't assign anything */ + char match; /* flag: !0 if any fields matched */ + va_list arglistsave; /* save arglist value */ + + char fl_wchar_arg; /* flags wide char/string argument */ + + _TCHAR decimal; + + + _TUCHAR rngch; + _TUCHAR last; + _TUCHAR prevchar; + _TCHAR tch; + + _VALIDATE_RETURN( (format != NULL), EINVAL, EOF); + +#ifndef CPRFLAG + _VALIDATE_RETURN( (stream != NULL), EINVAL, EOF); +#endif /* CPRFLAG */ + + /* + count = # fields assigned + charcount = # chars read + match = flag indicating if any fields were matched + + [Note that we need both count and match. For example, a field + may match a format but have assignments suppressed. In this case, + match will get set, but 'count' will still equal 0. We need to + distinguish 'match vs no-match' when terminating due to EOF.] + */ + + count = charcount = match = 0; + + while (*format) { + + if (_istspace((_TUCHAR)*format)) { + + UN_INC(EAT_WHITE()); /* put first non-space char back */ + + do { + tch = *++format; + } while (_istspace((_TUCHAR)tch)); + + continue; + + } + + if (_T('%') == *format) { + + number = 0; + prevchar = 0; + width = widthset = started = 0; +#ifdef _SECURE_SCANF + original_array_width = array_width = 0; + enomem = 0; +#endif /* _SECURE_SCANF */ + fl_wchar_arg = done_flag = suppress = negative = reject = 0; + widechar = 0; + + longone = 1; + +#if _INTEGRAL_MAX_BITS >= 64 + integer64 = 0; +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + + while (!done_flag) { + + comchr = *++format; + if (_ISDIGIT((_TUCHAR)comchr)) { + ++widthset; + width = MUL10(width) + (comchr - _T('0')); + } else + switch (comchr) { + case _T('F') : + case _T('N') : /* no way to push NEAR in large model */ + break; /* NEAR is default in small model */ + case _T('h') : + /* set longone to 0 */ + --longone; + --widechar; /* set widechar = -1 */ + break; + +#if _INTEGRAL_MAX_BITS >= 64 + case _T('I'): + if ( (*(format + 1) == _T('6')) && + (*(format + 2) == _T('4')) ) + { + format += 2; + ++integer64; + num64 = 0; + break; + } + else if ( (*(format + 1) == _T('3')) && + (*(format + 2) == _T('2')) ) + { + format += 2; + break; + } + else if ( (*(format + 1) == _T('d')) || + (*(format + 1) == _T('i')) || + (*(format + 1) == _T('o')) || + (*(format + 1) == _T('x')) || + (*(format + 1) == _T('X')) ) + { + if (sizeof(void*) == sizeof(__int64)) + { + ++integer64; + num64 = 0; + } + break; + } + if (sizeof(void*) == sizeof(__int64)) + { + ++integer64; + num64 = 0; + } + goto DEFAULT_LABEL; +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + + case _T('L') : + /* ++longone; */ + ++longone; + break; + + case _T('q'): + ++integer64; + num64 = 0; + break; + + case _T('l') : + if (*(format + 1) == _T('l')) + { + ++format; +#ifdef LONGLONG_IS_INT64 + ++integer64; + num64 = 0; + break; +#else /* LONGLONG_IS_INT64 */ + ++longone; + /* NOBREAK */ +#endif /* LONGLONG_IS_INT64 */ + } + else + { + ++longone; + /* NOBREAK */ + } + case _T('w') : + ++widechar; /* set widechar = 1 */ + break; + + case _T('*') : + ++suppress; + break; + + default: +DEFAULT_LABEL: + ++done_flag; + break; + } + } + + if (!suppress) { + va_copy(arglistsave, arglist); + pointer = va_arg(arglist,void *); + } else { + pointer = NULL; // doesn't matter what value we use here - we're only using it as a flag + } + + done_flag = 0; + + if (!widechar) { /* use case if not explicitly specified */ + if ((*format == _T('S')) || (*format == _T('C'))) +#ifdef _UNICODE + --widechar; + else + ++widechar; +#else /* _UNICODE */ + ++widechar; + else + --widechar; +#endif /* _UNICODE */ + } + + /* switch to lowercase to allow %E,%G, and to + keep the switch table small */ + + comchr = *format | (_T('a') - _T('A')); + + if (_T('n') != comchr) + { + if (_T('c') != comchr && LEFT_BRACKET != comchr) + ch = EAT_WHITE(); + else + ch = INC(); + } + + if (_T('n') != comchr) + { + if (_TEOF == ch) + goto error_return; + } + + if (!widthset || width) { + +#ifdef _SECURE_SCANF + if(!suppress && (comchr == _T('c') || comchr == _T('s') || comchr == LEFT_BRACKET)) { + + va_copy(arglist, arglistsave); + + /* Reinitialize pointer to point to the array to which we write the input */ + pointer = va_arg(arglist, void*); + + va_copy(arglistsave, arglist); + + /* Get the next argument - size of the array in characters */ +#ifdef _WIN64 + original_array_width = array_width = (size_t)(va_arg(arglist, unsigned int)); +#else /* _WIN64 */ + original_array_width = array_width = va_arg(arglist, size_t); +#endif /* _WIN64 */ + + if(array_width < 1) { + if (widechar > 0) + *(wchar_t UNALIGNED *)pointer = L'\0'; + else + *(char *)pointer = '\0'; + + errno = ENOMEM; + + goto error_return; + } + } +#endif /* _SECURE_SCANF */ + switch(comchr) { + + case _T('c'): + /* case _T('C'): */ + if (!widthset) { + ++widthset; + ++width; + } + if (widechar > 0) + fl_wchar_arg++; + goto scanit; + + + case _T('s'): + /* case _T('S'): */ + if(widechar > 0) + fl_wchar_arg++; + goto scanit; + + + case LEFT_BRACKET : /* scanset */ + if (widechar>0) + fl_wchar_arg++; + scanptr = (_TUCHAR *)(++format); + + if (_T('^') == *scanptr) { + ++scanptr; + --reject; /* set reject to 255 */ + } + + /* Allocate "table" on first %[] spec */ +#if ALLOC_TABLE + if (table == NULL) { + table = (char*)_malloc_crt(TABLESIZE); + if ( table == NULL) + goto error_return; + malloc_flag = 1; + } +#endif /* ALLOC_TABLE */ + memset(table, 0, TABLESIZE); + + + if (LEFT_BRACKET == comchr) + if (_T(']') == *scanptr) { + prevchar = _T(']'); + ++scanptr; + + table[ _T(']') >> 3] = 1 << (_T(']') & 7); + + } + + while (_T(']') != *scanptr) { + + rngch = *scanptr++; + + if (_T('-') != rngch || + !prevchar || /* first char */ + _T(']') == *scanptr) /* last char */ + + table[(prevchar = rngch) >> 3] |= 1 << (rngch & 7); + + else { /* handle a-z type set */ + + rngch = *scanptr++; /* get end of range */ + + if (prevchar < rngch) /* %[a-z] */ + last = rngch; + else { /* %[z-a] */ + last = prevchar; + prevchar = rngch; + } + for (rngch = prevchar; rngch <= last; ++rngch) + table[rngch >> 3] |= 1 << (rngch & 7); + + prevchar = 0; + + } + } + + + if (!*scanptr) + goto error_return; /* trunc'd format string */ + + /* scanset completed. Now read string */ + + if (LEFT_BRACKET == comchr) + format = scanptr; + +scanit: + start = pointer; + + /* + * execute the format directive. that is, scan input + * characters until the directive is fulfilled, eof + * is reached, or a non-matching character is + * encountered. + * + * it is important not to get the next character + * unless that character needs to be tested! other- + * wise, reads from line-buffered devices (e.g., + * scanf()) would require an extra, spurious, newline + * if the first newline completes the current format + * directive. + */ + UN_INC(ch); + +#ifdef _SECURE_SCANF + /* One element is needed for '\0' for %s & %[ */ + if(comchr != _T('c')) { + --array_width; + } +#endif /* _SECURE_SCANF */ + while ( !widthset || width-- ) { + + ch = INC(); + if ( +#ifndef CPRFLAG + (_TEOF != ch) && +#endif /* CPRFLAG */ + // char conditions + ( ( comchr == _T('c')) || + // string conditions !isspace() + ( ( comchr == _T('s') && + (!(ch >= _T('\t') && ch <= _T('\r')) && + ch != _T(' ')))) || + // BRACKET conditions + ( (comchr == LEFT_BRACKET) && + ((table[ch >> 3] ^ reject) & (1 << (ch & 7))) + ) + ) + ) + { + if (!suppress) { +#ifdef _SECURE_SCANF + if(!array_width) { + /* We have exhausted the user's buffer */ + + enomem = 1; + break; + } +#endif /* _SECURE_SCANF */ +#ifndef _UNICODE + if (fl_wchar_arg) { + wctemp = L'?'; + char temp[2]; + temp[0] = (char) ch; +#if 0 // we are not supporting multibyte input strings + if (isleadbyte((unsigned char)ch)) + { + temp[1] = (char) INC(); + } +#endif /* 0 */ + _MBTOWC(&wctemp, temp, MB_CUR_MAX); + *(wchar_t UNALIGNED *)pointer = wctemp; + /* just copy L'?' if mbtowc fails, errno is set by mbtowc */ + pointer = (wchar_t *)pointer + 1; +#ifdef _SECURE_SCANF + --array_width; +#endif /* _SECURE_SCANF */ + } else +#else /* _UNICODE */ + if (fl_wchar_arg) { + *(wchar_t UNALIGNED *)pointer = ch; + pointer = (wchar_t *)pointer + 1; +#ifdef _SECURE_SCANF + --array_width; +#endif /* _SECURE_SCANF */ + } else +#endif /* _UNICODE */ + { +#ifndef _UNICODE + *(char *)pointer = (char)ch; + pointer = (char *)pointer + 1; +#ifdef _SECURE_SCANF + --array_width; +#endif /* _SECURE_SCANF */ +#else /* _UNICODE */ + int temp = 0; +#ifndef _SECURE_SCANF + /* convert wide to multibyte */ + if (_ERRCHECK_EINVAL_ERANGE(wctomb_s(&temp, (char *)pointer, MB_LEN_MAX, ch)) == 0) + { + /* do nothing if wctomb fails, errno will be set to EILSEQ */ + pointer = (char *)pointer + temp; + } +#else /* _SECURE_SCANF */ + /* convert wide to multibyte */ + if (array_width >= ((size_t)MB_CUR_MAX)) + { +_BEGIN_SECURE_CRT_DEPRECATION_DISABLE + temp = wctomb((char *)pointer, ch); +_END_SECURE_CRT_DEPRECATION_DISABLE + } + else + { + char tmpbuf[MB_LEN_MAX]; +_BEGIN_SECURE_CRT_DEPRECATION_DISABLE + temp = wctomb(tmpbuf, ch); +_END_SECURE_CRT_DEPRECATION_DISABLE + if (temp > 0 && ((size_t)temp) > array_width) + { + /* We have exhausted the user's buffer */ + enomem = 1; + break; + } + memcpy(pointer, tmpbuf, temp); + } + if (temp > 0) + { + /* do nothing if wctomb fails, errno will be set to EILSEQ */ + pointer = (char *)pointer + temp; + array_width -= temp; + } +#endif /* _SECURE_SCANF */ +#endif /* _UNICODE */ + } + } /* suppress */ + else { + /* just indicate a match */ + start = (_TCHAR *)start + 1; + } + } + else { + UN_INC(ch); + break; + } + } + + /* make sure something has been matched and, if + assignment is not suppressed, null-terminate + output string if comchr != c */ + +#ifdef _SECURE_SCANF + if(enomem) { + errno = ENOMEM; + /* In case of error, blank out the input buffer */ + if (fl_wchar_arg) + { + _RESET_STRING(((wchar_t UNALIGNED *)start), original_array_width); + } + else + { + _RESET_STRING(((char *)start), original_array_width); + } + + goto error_return; + } +#endif /* _SECURE_SCANF */ + + if (start != pointer) { + if (!suppress) { + ++count; + if ('c' != comchr) /* null-terminate strings */ + { + if (fl_wchar_arg) + { + *(wchar_t UNALIGNED *)pointer = L'\0'; +#ifdef _SECURE_SCANF + _FILL_STRING(((wchar_t UNALIGNED *)start), original_array_width, + ((wchar_t UNALIGNED *)pointer - (wchar_t UNALIGNED *)start + 1)) +#endif /* _SECURE_SCANF */ + } + else + { + *(char *)pointer = '\0'; +#ifdef _SECURE_SCANF + _FILL_STRING(((char *)start), original_array_width, + ((char *)pointer - (char *)start + 1)) +#endif /* _SECURE_SCANF */ + } + } + } + else + { + // supress set, do nothing + } + } + else + goto error_return; + + break; + + case _T('i') : /* could be d, o, or x */ + + comchr = _T('d'); /* use as default */ + + case _T('x'): + + if (_T('-') == ch) { + ++negative; + + goto x_incwidth; + + } else if (_T('+') == ch) { +x_incwidth: + if (!--width && widthset) + ++done_flag; + else + ch = INC(); + } + + if (_T('0') == ch) { + + if (_T('x') == (_TCHAR)(ch = INC()) || _T('X') == (_TCHAR)ch) { + ch = INC(); + if (widthset) { + width -= 2; + if (width < 1) + ++done_flag; + } + comchr = _T('x'); + } else { + ++started; + if (_T('x') != comchr) { + if (widthset && !--width) + ++done_flag; + comchr = _T('o'); + } + else { + /* scanning a hex number that starts */ + /* with a 0. push back the character */ + /* currently in ch and restore the 0 */ + UN_INC(ch); + ch = _T('0'); + } + } + } + goto getnum; + + /* NOTREACHED */ + + case _T('p') : + /* force %hp to be treated as %p */ + longone = 1; +#ifdef _WIN64 + /* force %p to be 64 bit in WIN64 */ + ++integer64; + num64 = 0; +#endif /* _WIN64 */ + case _T('o') : + case _T('u') : + case _T('d') : + + if (_T('-') == ch) { + ++negative; + + goto d_incwidth; + + } else if (_T('+') == ch) { +d_incwidth: + if (!--width && widthset) + ++done_flag; + else + ch = INC(); + } + +getnum: +#if _INTEGRAL_MAX_BITS >= 64 + if ( integer64 ) { + + while (!done_flag) { + + if (_T('x') == comchr || _T('p') == comchr) + + if (_ISXDIGIT(ch)) { + num64 <<= 4; + ch = _hextodec(ch); + } + else + ++done_flag; + + else if (_ISDIGIT(ch)) + + if (_T('o') == comchr) + if (_T('8') > ch) + num64 <<= 3; + else { + ++done_flag; + } + else /* _T('d') == comchr */ + num64 = MUL10(num64); + + else + ++done_flag; + + if (!done_flag) { + ++started; + num64 += ch - _T('0'); + + if (widthset && !--width) + ++done_flag; + else + ch = INC(); + } else + UN_INC(ch); + + } /* end of WHILE loop */ + + if (negative) + num64 = (uint64_t )(-(__int64)num64); + } + else { +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + while (!done_flag) { + + if (_T('x') == comchr || _T('p') == comchr) + + if (_ISXDIGIT(ch)) { + number = (number << 4); + ch = _hextodec(ch); + } + else + ++done_flag; + + else if (_ISDIGIT(ch)) + + if (_T('o') == comchr) + if (_T('8') > ch) + number = (number << 3); + else { + ++done_flag; + } + else /* _T('d') == comchr */ + number = MUL10(number); + + else + ++done_flag; + + if (!done_flag) { + ++started; + number += ch - _T('0'); + + if (widthset && !--width) + ++done_flag; + else + ch = INC(); + } else + UN_INC(ch); + + } /* end of WHILE loop */ + + if (negative) + number = (unsigned long)(-(long)number); +#if _INTEGRAL_MAX_BITS >= 64 + } +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + if (_T('F')==comchr) /* expected ':' in long pointer */ + started = 0; + + if (started) + if (!suppress) { + + ++count; +assign_num: +#if _INTEGRAL_MAX_BITS >= 64 + if ( integer64 ) + *(__int64 UNALIGNED *)pointer = ( uint64_t )num64; + else +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + if (longone) + *(int UNALIGNED *)pointer = (unsigned int)number; + else + *(short UNALIGNED *)pointer = (unsigned short)number; + + } else /*NULL*/; + else + goto error_return; + + break; + + case _T('n') : /* char count, don't inc return value */ + number = charcount; + if(!suppress) + goto assign_num; /* found in number code above */ + break; + + + case _T('e') : + /* case _T('E') : */ + case _T('f') : + case _T('g') : /* scan a float */ + /* case _T('G') : */ + nFloatStrUsed=0; + + if (_T('-') == ch) { + pFloatStr[nFloatStrUsed++] = _T('-'); + goto f_incwidth; + + } else if (_T('+') == ch) { +f_incwidth: + --width; + ch = INC(); + } + + if (!widthset) /* must watch width */ + width = -1; + + + /* now get integral part */ + + while (_ISDIGIT(ch) && width--) { + ++started; + pFloatStr[nFloatStrUsed++] = (char)ch; + if (__check_float_string(nFloatStrUsed, + &nFloatStrSz, + &pFloatStr, + floatstring, + &malloc_FloatStrFlag + )==FALSE) { + goto error_return; + } + ch = INC(); + } + +#ifdef _UNICODE + /* convert decimal point to wide-char */ + /* if mbtowc fails (should never happen), we use L'.' */ + decimal = L'.'; + _MBTOWC(&decimal, _INTRN_LOCALE_CONV(_loc_update)->decimal_point, MB_CUR_MAX); +#else /* _UNICODE */ + + decimal=*((_INTRN_LOCALE_CONV(_loc_update))->decimal_point); +#endif /* _UNICODE */ + + /* now check for decimal */ + if (decimal == (char)ch && width--) { + ch = INC(); + pFloatStr[nFloatStrUsed++] = decimal; + if (__check_float_string(nFloatStrUsed, + &nFloatStrSz, + &pFloatStr, + floatstring, + &malloc_FloatStrFlag + )==FALSE) { + goto error_return; + } + + while (_ISDIGIT(ch) && width--) { + ++started; + pFloatStr[nFloatStrUsed++] = (_TCHAR)ch; + if (__check_float_string(nFloatStrUsed, + &nFloatStrSz, + &pFloatStr, + floatstring, + &malloc_FloatStrFlag + )==FALSE) { + goto error_return; + } + ch = INC(); + } + } + + /* now check for exponent */ + + if (started && (_T('e') == ch || _T('E') == ch) && width--) { + pFloatStr[nFloatStrUsed++] = _T('e'); + if (__check_float_string(nFloatStrUsed, + &nFloatStrSz, + &pFloatStr, + floatstring, + &malloc_FloatStrFlag + )==FALSE) { + goto error_return; + } + + if (_T('-') == (ch = INC())) { + + pFloatStr[nFloatStrUsed++] = _T('-'); + if (__check_float_string(nFloatStrUsed, + &nFloatStrSz, + &pFloatStr, + floatstring, + &malloc_FloatStrFlag + )==FALSE) { + goto error_return; + } + goto f_incwidth2; + + } else if (_T('+') == ch) { +f_incwidth2: + if (!width--) + ++width; + else + ch = INC(); + } + + + while (_ISDIGIT(ch) && width--) { + ++started; + pFloatStr[nFloatStrUsed++] = (_TCHAR)ch; + if (__check_float_string(nFloatStrUsed, + &nFloatStrSz, + &pFloatStr, + floatstring, + &malloc_FloatStrFlag + )==FALSE) { + goto error_return; + } + ch = INC(); + } + + } + + UN_INC(ch); + + if (started) + if (!suppress) { + ++count; + pFloatStr[nFloatStrUsed]= _T('\0'); +#ifdef _UNICODE + _WFASSIGN( longone-1, pointer, pFloatStr, (char)decimal, _loc_update.GetLocaleT()); +#else /* _UNICODE */ + _FASSIGN( longone-1, pointer, pFloatStr, (char)decimal, _loc_update.GetLocaleT()); +#endif /* _UNICODE */ + } else /*NULL */; + else + goto error_return; + + break; + + + default: /* either found '%' or something else */ + + if ((int)*format != (int)ch) { + UN_INC(ch); +#ifdef _SECURE_SCANF + /* error_return ASSERT's if format_error is true */ + format_error = TRUE; +#endif /* _SECURE_SCANF */ + goto error_return; + } + else + match--; /* % found, compensate for inc below */ + + if (!suppress) + va_copy(arglist, arglistsave); + + } /* SWITCH */ + + match++; /* matched a format field - set flag */ + + } /* WHILE (width) */ + + else { /* zero-width field in format string */ + UN_INC(ch); /* check for input error */ + goto error_return; + } + + ++format; /* skip to next char */ + + } else /* ('%' != *format) */ + { + + if ((int)*format++ != (int)(ch = INC())) + { + UN_INC(ch); + goto error_return; + } +#if 0 // we are not supporting multibyte input strings +#ifndef _UNICODE + if (isleadbyte((unsigned char)ch)) + { + int ch2; + if ((int)*format++ != (ch2=INC())) + { + UN_INC(ch2); + UN_INC(ch); + goto error_return; + } + + --charcount; /* only count as one character read */ + } +#endif /* _UNICODE */ +#endif + } + +#ifndef CPRFLAG + if ( (_TEOF == ch) && ((*format != _T('%')) || (*(format + 1) != _T('n'))) ) + break; +#endif /* CPRFLAG */ + + } /* WHILE (*format) */ + +error_return: +#if ALLOC_TABLE + if (malloc_flag == 1) + { + _free_crt(table); + } +#endif /* ALLOC_TABLE */ + if (malloc_FloatStrFlag == 1) + { + _free_crt(pFloatStr); + } + +#ifndef CPRFLAG + if (_TEOF == ch) + /* If any fields were matched or assigned, return count */ + return ( (count || match) ? count : EOF); + else +#endif /* CPRFLAG */ +#ifdef _SECURE_SCANF + if(format_error == TRUE) { + _VALIDATE_RETURN( ("Invalid Input Format" && 0), EINVAL, count); + } +#endif /* _SECURE_SCANF */ + return count; + +} + +/* _hextodec() returns a value of 0-15 and expects a char 0-9, a-f, A-F */ +/* _inc() is the one place where we put the actual getc code. */ +/* _whiteout() returns the first non-blank character, as defined by isspace() */ + +static int __cdecl _hextodec ( _TCHAR chr) +{ + return _ISDIGIT(chr) ? chr : (chr & ~(_T('a') - _T('A'))) - _T('A') + 10 + _T('0'); +} + +#ifdef CPRFLAG + +static int __cdecl _inc(void) +{ + return (_gettche_nolock()); +} + +static void __cdecl _un_inc(int chr) +{ + if (_TEOF != chr) { + _ungettch_nolock(chr); + } +} + +static int __cdecl _whiteout(REG1 int* counter) +{ + REG2 int ch; + + do + { + ++*counter; + ch = _inc(); + + if (ch == _TEOF) + { + break; + } + } + while(_istspace((_TUCHAR)ch)); + return ch; +} + +#else /* CPRFLAG */ + +static int __cdecl _inc(miniFILE* fileptr) +{ + return (_gettc_nolock(fileptr)); +} + +static void __cdecl _un_inc(int chr, miniFILE* fileptr) +{ + if (_TEOF != chr) { + _ungettc_nolock(chr,fileptr); + } +} + +static int __cdecl _whiteout(int* counter, miniFILE* fileptr) +{ + int ch; + + do + { + ++*counter; + ch = _inc(fileptr); + + if (ch == _TEOF) + { + break; + } + } + while(_istspace((_TUCHAR)ch)); + return ch; +} + +#endif /* CPRFLAG */ diff --git a/src/pal/src/safecrt/internal.h b/src/pal/src/safecrt/internal.h new file mode 100644 index 0000000000..f4220c2b68 --- /dev/null +++ b/src/pal/src/safecrt/internal.h @@ -0,0 +1,1097 @@ +// 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. + +/*** +*internal.h - contains declarations of internal routines and variables +* + +* +*Purpose: +* Declares routines and variables used internally by the C run-time. +* +* [Internal] +* +****/ + +#if _MSC_VER > 1000 +#pragma once +#endif /* _MSC_VER > 1000 */ + +#ifndef _INC_INTERNAL +#define _INC_INTERNAL + +#include <crtdefs.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <cruntime.h> +#include <limits.h> + +/* + * Conditionally include windows.h to pick up the definition of + * CRITICAL_SECTION. + */ +#include <windows.h> + +#ifdef _MSC_VER +#pragma pack(push,_CRT_PACKING) +#endif /* _MSC_VER */ + +/* Define function types used in several startup sources */ + +typedef void (__cdecl *_PVFV)(void); +typedef int (__cdecl *_PIFV)(void); +typedef void (__cdecl *_PVFI)(int); + +#if _MSC_VER >= 1400 && defined(_M_CEE) +typedef const void* (__clrcall *_PVFVM)(void); +typedef int (__clrcall *_PIFVM)(void); +typedef void (__clrcall *_CPVFV)(void); +#endif /* _MSC_VER >= 1400 && defined(_M_CEE) */ + +#if defined (_M_CEE_PURE) || (defined (_DLL) && defined (_M_IX86)) +/* Retained for compatibility with VC++ 5.0 and earlier versions */ +_CRTIMP int * __cdecl __p__commode(void); +#endif /* defined (_M_CEE_PURE) || (defined (_DLL) && defined (_M_IX86)) */ +#if defined (SPECIAL_CRTEXE) && defined (_DLL) + extern int _commode; +#else /* defined (SPECIAL_CRTEXE) && defined (_DLL) */ +#ifndef _M_CEE_PURE +_CRTIMP extern int _commode; +#else /* _M_CEE_PURE */ +#define _commode (*__p___commode()) +#endif /* _M_CEE_PURE */ +#endif /* defined (SPECIAL_CRTEXE) && defined (_DLL) */ + +#define __IOINFO_TM_ANSI 0 /* Regular Text */ +#define __IOINFO_TM_UTF8 1 /* UTF8 Encoded */ +#define __IOINFO_TM_UTF16LE 2 /* UTF16 Little Endian Encoded */ + +/* + * Control structure for lowio file handles + */ +typedef struct { + intptr_t osfhnd; /* underlying OS file HANDLE */ + char osfile; /* attributes of file (e.g., open in text mode?) */ + char pipech; /* one char buffer for handles opened on pipes */ + int lockinitflag; + CRITICAL_SECTION lock; +#ifndef _SAFECRT_IMPL + /* Not used in the safecrt downlevel. We do not define them, so we cannot use them accidentally */ + char textmode : 7; /* __IOINFO_TM_ANSI or __IOINFO_TM_UTF8 or __IOINFO_TM_UTF16LE */ + char unicode : 1; /* Was the file opened as unicode? */ + char pipech2[2]; /* 2 more peak ahead chars for UNICODE mode */ +#endif /* _SAFECRT_IMPL */ + } ioinfo; + +/* + * Definition of IOINFO_L2E, the log base 2 of the number of elements in each + * array of ioinfo structs. + */ +#define IOINFO_L2E 5 + +/* + * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array + */ +#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) + +/* + * Definition of IOINFO_ARRAYS, maximum number of supported ioinfo arrays. + */ +#define IOINFO_ARRAYS 64 + +#define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS) + +#define _TZ_STRINGS_SIZE 64 + +/* + * Access macros for getting at an ioinfo struct and its fields from a + * file handle + */ +#define _pioinfo(i) ( __pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - \ + 1)) ) +#define _osfhnd(i) ( _pioinfo(i)->osfhnd ) + +#define _osfile(i) ( _pioinfo(i)->osfile ) + +#define _pipech(i) ( _pioinfo(i)->pipech ) + +#define _pipech2(i) ( _pioinfo(i)->pipech2 ) + +#define _textmode(i) ( _pioinfo(i)->textmode ) + +#define _tm_unicode(i) ( _pioinfo(i)->unicode ) + +/* + * Safer versions of the above macros. Currently, only _osfile_safe is + * used. + */ +#define _pioinfo_safe(i) ( (((i) != -1) && ((i) != -2)) ? _pioinfo(i) : &__badioinfo ) + +#define _osfhnd_safe(i) ( _pioinfo_safe(i)->osfhnd ) + +#define _osfile_safe(i) ( _pioinfo_safe(i)->osfile ) + +#define _pipech_safe(i) ( _pioinfo_safe(i)->pipech ) + +#define _pipech2_safe(i) ( _pioinfo_safe(i)->pipech2 ) + +#ifdef _SAFECRT_IMPL +/* safecrt does not have support for textmode, so we always return __IOINFO_TM_ANSI */ +#define _textmode_safe(i) __IOINFO_TM_ANSI +#define _tm_unicode_safe(i) 0 +#else /* _SAFECRT_IMPL */ +#define _textmode_safe(i) ( _pioinfo_safe(i)->textmode ) +#define _tm_unicode_safe(i) ( _pioinfo_safe(i)->unicode ) +#endif /* _SAFECRT_IMPL */ + +#ifndef _M_CEE_PURE +#ifdef _SAFECRT_IMPL +/* We need to get this from the downlevel DLL, even when we build safecrt.lib */ +extern __declspec(dllimport) ioinfo __badioinfo; +extern __declspec(dllimport) ioinfo * __pioinfo[]; +#else /* _SAFECRT_IMPL */ +/* + * Special, static ioinfo structure used only for more graceful handling + * of a C file handle value of -1 (results from common errors at the stdio + * level). + */ +extern _CRTIMP ioinfo __badioinfo; + +/* + * Array of arrays of control structures for lowio files. + */ +extern _CRTIMP ioinfo * __pioinfo[]; +#endif /* _SAFECRT_IMPL */ +#endif /* _M_CEE_PURE */ + +/* + * Current number of allocated ioinfo structures (_NHANDLE_ is the upper + * limit). + */ +extern int _nhandle; + +int __cdecl _alloc_osfhnd(void); +int __cdecl _free_osfhnd(int); +int __cdecl _set_osfhnd(int, intptr_t); + +/* + fileno for stdout, stdin & stderr when there is no console +*/ +#define _NO_CONSOLE_FILENO (intptr_t)-2 + + +extern const char __dnames[]; +extern const char __mnames[]; + +extern int _days[]; +extern int _lpdays[]; + +extern __time32_t __cdecl __loctotime32_t(int, int, int, int, int, int, int); +extern __time64_t __cdecl __loctotime64_t(int, int, int, int, int, int, int); + +#ifdef _TM_DEFINED +extern int __cdecl _isindst(__in struct tm * _Time); +#endif /* _TM_DEFINED */ + +extern void __cdecl __tzset(void); + +extern int __cdecl _validdrive(unsigned); + +/* + * If we are only interested in years between 1901 and 2099, we could use this: + * + * #define IS_LEAP_YEAR(y) (y % 4 == 0) + */ + +#define IS_LEAP_YEAR(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) + +/* + * get the buffer used by gmtime + */ +struct tm * __cdecl __getgmtimebuf (); + +/* + * This variable is in the C start-up; the length must be kept synchronized + * It is used by the *cenvarg.c modules + */ + +extern char _acfinfo[]; /* "_C_FILE_INFO=" */ + +#define CFI_LENGTH 12 /* "_C_FILE_INFO" is 12 bytes long */ + + +/* + * stdio internals + */ +#ifndef _FILE_DEFINED +struct _iobuf { + char *_ptr; + int _cnt; + char *_base; + int _flag; + int _file; + int _charbuf; + int _bufsiz; + char *_tmpfname; + }; +typedef struct _iobuf FILE; +#define _FILE_DEFINED +#endif /* _FILE_DEFINED */ + +#if !defined (_FILEX_DEFINED) && defined (_WINDOWS_) + +/* + * Variation of FILE type used for the dynamically allocated portion of + * __piob[]. For single thread, _FILEX is the same as FILE. For multithread + * models, _FILEX has two fields: the FILE struct and the CRITICAL_SECTION + * struct used to serialize access to the FILE. + */ + +typedef struct { + FILE f; + CRITICAL_SECTION lock; + } _FILEX; + + +#define _FILEX_DEFINED +#endif /* !defined (_FILEX_DEFINED) && defined (_WINDOWS_) */ + +/* + * Number of entries supported in the array pointed to by __piob[]. That is, + * the number of stdio-level files which may be open simultaneously. This + * is normally set to _NSTREAM_ by the stdio initialization code. + */ +extern int _nstream; + +/* + * Pointer to the array of pointers to FILE/_FILEX structures that are used + * to manage stdio-level files. + */ +extern void **__piob; + +FILE * __cdecl _getstream(void); +FILE * __cdecl _openfile(__in_z const char * _Filename, __in_z const char * _Mode, __in int _ShFlag, __out FILE * _File); +FILE * __cdecl _wopenfile(__in_z const wchar_t * _Filename, __in_z const wchar_t * _Mode, __in int _ShFlag, __out FILE * _File); +void __cdecl _getbuf(__out FILE * _File); +int __cdecl _filwbuf (__inout FILE * _File); +int __cdecl _flswbuf(__in int _Ch, __inout FILE * _File); +void __cdecl _freebuf(__inout FILE * _File); +int __cdecl _stbuf(__inout FILE * _File); +void __cdecl _ftbuf(int _Flag, __inout FILE * _File); + +#ifdef _SAFECRT_IMPL + +int __cdecl _output(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList); +int __cdecl _woutput(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList); +int __cdecl _output_s(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList); +int __cdecl _output_p(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList); +int __cdecl _woutput_s(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList); +int __cdecl _woutput_p(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList); +typedef int (*OUTPUTFN)(FILE *, const char *, va_list); +typedef int (*WOUTPUTFN)(FILE *, const wchar_t *, va_list); + +#else /* _SAFECRT_IMPL */ + +int __cdecl _output_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList); +int __cdecl _woutput_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList); +int __cdecl _output_s_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList); +int __cdecl _output_p_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList); +int __cdecl _woutput_s_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList); +int __cdecl _woutput_p_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList); +typedef int (*OUTPUTFN)(__inout FILE * _File, const char *, _locale_t, va_list); +typedef int (*WOUTPUTFN)(__inout FILE * _File, const wchar_t *, _locale_t, va_list); + +#endif /* _SAFECRT_IMPL */ + +#ifdef _SAFECRT_IMPL + +int __cdecl _input(__in FILE * _File, __in_z __format_string const unsigned char * _Format, va_list _ArgList); +int __cdecl _winput(__in FILE * _File, __in_z __format_string const wchar_t * _Format, va_list _ArgList); +int __cdecl _input_s(__in FILE * _File, __in_z __format_string const unsigned char * _Format, va_list _ArgList); +int __cdecl _winput_s(__in FILE * _File, __in_z __format_string const wchar_t * _Format, va_list _ArgList); +typedef int (*INPUTFN)(FILE *, const unsigned char *, va_list); +typedef int (*WINPUTFN)(FILE *, const wchar_t *, va_list); + +#else /* _SAFECRT_IMPL */ + +int __cdecl _input_l(__inout FILE * _File, __in_z __format_string const unsigned char *, __in_opt _locale_t _Locale, va_list _ArgList); +int __cdecl _winput_l(__inout FILE * _File, __in_z __format_string const wchar_t *, __in_opt _locale_t _Locale, va_list _ArgList); +int __cdecl _input_s_l(__inout FILE * _File, __in_z __format_string const unsigned char *, __in_opt _locale_t _Locale, va_list _ArgList); +int __cdecl _winput_s_l(__inout FILE * _File, __in_z __format_string const wchar_t *, __in_opt _locale_t _Locale, va_list _ArgList); +typedef int (*INPUTFN)(FILE *, const unsigned char *, _locale_t, va_list); +typedef int (*WINPUTFN)(FILE *, const wchar_t *, _locale_t, va_list); + +#ifdef _UNICODE +#define TINPUTFN WINPUTFN +#else /* _UNICODE */ +#define TINPUTFN INPUTFN +#endif /* _UNICODE */ + +#endif /* _SAFECRT_IMPL */ + +int __cdecl _flush(__inout FILE * _File); +void __cdecl _endstdio(void); + +errno_t __cdecl _sopen_helper(__in_z const char * _Filename, + __in int _OFlag, __in int _ShFlag, __in int _PMode, + __out int * _PFileHandle, int _BSecure); +errno_t __cdecl _wsopen_helper(__in_z const wchar_t * _Filename, + __in int _OFlag, __in int _ShFlag, __in int _PMode, + __out int * _PFileHandle, int _BSecure); + +#ifndef CRTDLL +extern int _cflush; +#endif /* CRTDLL */ + +extern unsigned int _tempoff; + +extern unsigned int _old_pfxlen; + +extern int _umaskval; /* the umask value */ + +extern char _pipech[]; /* pipe lookahead */ + +extern char _exitflag; /* callable termination flag */ + +extern int _C_Termination_Done; /* termination done flag */ + +char * __cdecl _getpath(__in_z const char * _Src, __out_ecount_z(_SizeInChars) char * _Dst, __in size_t _SizeInChars); +wchar_t * __cdecl _wgetpath(__in_z const wchar_t * _Src, __out_ecount_z(_SizeInWords) wchar_t * _Dst, __in size_t _SizeInWords); + +extern int _dowildcard; /* flag to enable argv[] wildcard expansion */ + +#ifndef _PNH_DEFINED +typedef int (__cdecl * _PNH)( size_t ); +#define _PNH_DEFINED +#endif /* _PNH_DEFINED */ + +#if _MSC_VER >= 1400 && defined(_M_CEE) +#ifndef __MPNH_DEFINED +typedef int (__clrcall * __MPNH)( size_t ); +#define __MPNH_DEFINED +#endif /* __MPNH_DEFINED */ +#endif /* _MSC_VER >= 1400 && defined(_M_CEE) */ + + +/* calls the currently installed new handler */ +int __cdecl _callnewh(__in size_t _Size); + +extern int _newmode; /* malloc new() handler mode */ + +/* pointer to initial environment block that is passed to [w]main */ +#ifndef _M_CEE_PURE +extern _CRTIMP wchar_t **__winitenv; +extern _CRTIMP char **__initenv; +#endif /* _M_CEE_PURE */ + +/* _calloca helper */ +#define _calloca(count, size) ((count<=0 || size<=0 || ((((size_t)_HEAP_MAXREQ) / ((size_t)count)) < ((size_t)size)))? NULL : _malloca(count * size)) + +/* startup set values */ +extern char *_aenvptr; /* environment ptr */ +extern wchar_t *_wenvptr; /* wide environment ptr */ + +/* command line */ + +#if defined (_DLL) +_CRTIMP char ** __cdecl __p__acmdln(void); +_CRTIMP wchar_t ** __cdecl __p__wcmdln(void); +#endif /* defined (_DLL) */ +#ifndef _M_CEE_PURE +_CRTIMP extern char *_acmdln; +_CRTIMP extern wchar_t *_wcmdln; +#else /* _M_CEE_PURE */ +#define _acmdln (*__p__acmdln()) +#define _wcmdln (*__p__wcmdln()) +#endif /* _M_CEE_PURE */ + +/* + * prototypes for internal startup functions + */ +int __cdecl _cwild(void); /* wild.c */ +int __cdecl _wcwild(void); /* wwild.c */ +int __cdecl _mtinit(void); /* tidtable.c */ +void __cdecl _mtterm(void); /* tidtable.c */ +int __cdecl _mtinitlocks(void); /* mlock.c */ +void __cdecl _mtdeletelocks(void); /* mlock.c */ +int __cdecl _mtinitlocknum(int); /* mlock.c */ + +/* Wrapper for InitializeCriticalSection API, with default spin count */ +int __cdecl __crtInitCritSecAndSpinCount(PCRITICAL_SECTION, DWORD); +#define _CRT_SPINCOUNT 4000 + +/* + * C source build only!!!! + * + * more prototypes for internal startup functions + */ +void __cdecl _amsg_exit(int); /* crt0.c */ +void __cdecl __crtExitProcess(int); /* crt0dat.c */ +void __cdecl __crtCorExitProcess(int); /* crt0dat.c */ +void __cdecl __crtdll_callstaticterminators(void); /* crt0dat.c */ + +/* +_cinit now allows the caller to suppress floating point precision init +This allows the DLLs that use the CRT to not initialise FP precision, +allowing the EXE's setting to persist even when a DLL is loaded +*/ +int __cdecl _cinit(int /* initFloatingPrecision */); /* crt0dat.c */ +void __cdecl __doinits(void); /* astart.asm */ +void __cdecl __doterms(void); /* astart.asm */ +void __cdecl __dopreterms(void); /* astart.asm */ +void __cdecl _FF_MSGBANNER(void); +void __cdecl _fpmath(int /*initPrecision*/); +void __cdecl _fpclear(void); +void __cdecl _fptrap(void); /* crt0fp.c */ +int __cdecl _heap_init(int); +void __cdecl _heap_term(void); +void __cdecl _heap_abort(void); +void __cdecl __initconin(void); /* initcon.c */ +void __cdecl __initconout(void); /* initcon.c */ +int __cdecl _ioinit(void); /* crt0.c, crtlib.c */ +void __cdecl _ioterm(void); /* crt0.c, crtlib.c */ +char * __cdecl _GET_RTERRMSG(int); +void __cdecl _NMSG_WRITE(int); +int __CRTDECL _setargv(void); /* setargv.c, stdargv.c */ +int __CRTDECL __setargv(void); /* stdargv.c */ +int __CRTDECL _wsetargv(void); /* wsetargv.c, wstdargv.c */ +int __CRTDECL __wsetargv(void); /* wstdargv.c */ +int __cdecl _setenvp(void); /* stdenvp.c */ +int __cdecl _wsetenvp(void); /* wstdenvp.c */ +void __cdecl __setmbctable(unsigned int); /* mbctype.c */ + +#ifdef MRTDLL +_MRTIMP int __cdecl _onexit_process(_CPVFV); +_MRTIMP int __cdecl _onexit_app_domain(_CPVFV); +#endif /* MRTDLL */ + +#ifdef _MBCS +int __cdecl __initmbctable(void); /* mbctype.c */ +#endif /* _MBCS */ + +#ifndef _MANAGED_MAIN +int __CRTDECL main(__in int _Argc, __in_ecount_z(_Argc) char ** _Argv, __in_z char ** _Env); +int __CRTDECL wmain(__in int _Argc, __in_ecount_z(_Argc) wchar_t ** _Argv, __in_z wchar_t ** _Env); +#endif /* _MANAGED_MAIN */ + +/* helper functions for wide/multibyte environment conversion */ +int __cdecl __mbtow_environ (void); +int __cdecl __wtomb_environ (void); + +/* These two functions take a char ** for the environment option + At some point during their execution, they take ownership of the + memory block passed in using option. At this point, they + NULL out the incoming char * / wchar_t * to ensure there is no + double-free +*/ +int __cdecl __crtsetenv (__deref_inout_opt char ** _POption, __in const int _Primary); +int __cdecl __crtwsetenv (__deref_inout_opt wchar_t ** _POption, __in const int _Primary); + +#ifndef _M_CEE_PURE +_CRTIMP extern void (__cdecl * _aexit_rtn)(int); +#endif /* _M_CEE_PURE */ + +#if defined (_DLL) || defined (CRTDLL) + +#ifndef _STARTUP_INFO_DEFINED +typedef struct +{ + int newmode; +} _startupinfo; +#define _STARTUP_INFO_DEFINED +#endif /* _STARTUP_INFO_DEFINED */ + +_CRTIMP int __cdecl __getmainargs(__out int * _Argc, __deref_out_ecount(*_Argc) char *** _Argv, + __deref_out_opt char *** _Env, __in int _DoWildCard, + __in _startupinfo * _StartInfo); + +_CRTIMP int __cdecl __wgetmainargs(__out int * _Argc, __deref_out_ecount(*_Argc)wchar_t *** _Argv, + __deref_out_opt wchar_t *** _Env, __in int _DoWildCard, + __in _startupinfo * _StartInfo); + +#endif /* defined (_DLL) || defined (CRTDLL) */ + +/* + * Prototype, variables and constants which determine how error messages are + * written out. + */ +#define _UNKNOWN_APP 0 +#define _CONSOLE_APP 1 +#define _GUI_APP 2 + +extern int __app_type; + +#if !defined (_M_CEE_PURE) + +extern Volatile<void*> __native_startup_lock; + +#define __NO_REASON UINT_MAX +extern Volatile<unsigned int> __native_dllmain_reason; +extern Volatile<unsigned int> __native_vcclrit_reason; + +#if defined (__cplusplus) + +#pragma warning(push) +#pragma warning(disable: 4483) +#if _MSC_FULL_VER >= 140050415 +#define _NATIVE_STARTUP_NAMESPACE __identifier("<CrtImplementationDetails>") +#else /* _MSC_FULL_VER >= 140050415 */ +#define _NATIVE_STARTUP_NAMESPACE __CrtImplementationDetails +#endif /* _MSC_FULL_VER >= 140050415 */ + +namespace _NATIVE_STARTUP_NAMESPACE +{ + class NativeDll + { + private: + static const unsigned int ProcessDetach = 0; + static const unsigned int ProcessAttach = 1; + static const unsigned int ThreadAttach = 2; + static const unsigned int ThreadDetach = 3; + static const unsigned int ProcessVerifier = 4; + + public: + + inline static bool IsInDllMain() + { + return (__native_dllmain_reason != __NO_REASON); + } + + inline static bool IsInProcessAttach() + { + return (__native_dllmain_reason == ProcessAttach); + } + + inline static bool IsInProcessDetach() + { + return (__native_dllmain_reason == ProcessDetach); + } + + inline static bool IsInVcclrit() + { + return (__native_vcclrit_reason != __NO_REASON); + } + + inline static bool IsSafeForManagedCode() + { + if (!IsInDllMain()) + { + return true; + } + + if (IsInVcclrit()) + { + return true; + } + + return !IsInProcessAttach() && !IsInProcessDetach(); + } + }; +} +#pragma warning(pop) + +#endif /* defined (__cplusplus) */ + +#endif /* !defined (_M_CEE_PURE) */ + +extern int __error_mode; + +_CRTIMP void __cdecl __set_app_type(int); +#if defined (CRTDLL) && !defined (_SYSCRT) +/* + * All these function pointer are used for creating global state of CRT + * functions. Either all of them will be set or all of them will be NULL + */ +typedef void (__cdecl *_set_app_type_function)(int); +typedef int (__cdecl *_get_app_type_function)(); +extern _set_app_type_function __set_app_type_server; +extern _get_app_type_function __get_app_type_server; +#endif /* defined (CRTDLL) && !defined (_SYSCRT) */ + +/* + * C source build only!!!! + * + * map Win32 errors into Xenix errno values -- for modules written in C + */ +_CRTIMP void __cdecl _dosmaperr(unsigned long); +extern int __cdecl _get_errno_from_oserr(unsigned long); + +/* + * internal routines used by the exec/spawn functions + */ + +extern intptr_t __cdecl _dospawn(__in int _Mode, __in_z_opt const char * _Name, __inout_z char * _Cmd, __in_z_opt char * _Env); +extern intptr_t __cdecl _wdospawn(__in int _Mode, __in_z_opt const wchar_t * _Name, __inout_z wchar_t * _Cmd, __in_z_opt wchar_t * _Env); +extern int __cdecl _cenvarg(__in_z const char * const * _Argv, __in_z_opt const char * const * _Env, + __deref_out_opt char ** _ArgBlk, __deref_out_opt char ** _EnvBlk, __in_z const char *_Name); +extern int __cdecl _wcenvarg(__in_z const wchar_t * const * _Argv, __in_z_opt const wchar_t * const * _Env, + __deref_out_opt wchar_t ** _ArgBlk, __deref_out_opt wchar_t ** _EnvBlk, __in_z const wchar_t * _Name); +#ifndef _M_IX86 +extern char ** _capture_argv(__in va_list *, __in_z const char * _FirstArg, __out_ecount_z(_MaxCount) char ** _Static_argv, __in size_t _MaxCount); +extern wchar_t ** _wcapture_argv(__in va_list *, __in_z const wchar_t * _FirstArg, __out_ecount_z(_MaxCount) wchar_t ** _Static_argv, __in size_t _MaxCount); +#endif /* _M_IX86 */ + +/* + * internal routine used by the abort + */ + +extern _PHNDLR __cdecl __get_sigabrt(void); + +/* + * Type from ntdef.h + */ + +typedef LONG NTSTATUS; + +/* + * Exception code used in _invalid_parameter + */ + +#ifndef STATUS_INVALID_PARAMETER +#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL) +#endif /* STATUS_INVALID_PARAMETER */ + +/* + * Exception code used for abort and _CALL_REPORTFAULT + */ + +#ifndef STATUS_FATAL_APP_EXIT +#define STATUS_FATAL_APP_EXIT ((NTSTATUS)0x40000015L) +#endif /* STATUS_FATAL_APP_EXIT */ + +/* + * Validate functions + */ +#include <crtdbg.h> /* _ASSERTE */ +#include <errno.h> + +#define __STR2WSTR(str) L##str + +#define _STR2WSTR(str) __STR2WSTR(str) + +#define __FILEW__ _STR2WSTR(__FILE__) +#define __FUNCTIONW__ _STR2WSTR(__FUNCTION__) + +/* We completely fill the buffer only in debug (see _SECURECRT__FILL_STRING + * and _SECURECRT__FILL_BYTE macros). + */ +#if !defined (_SECURECRT_FILL_BUFFER) +#ifdef _DEBUG +#define _SECURECRT_FILL_BUFFER 1 +#else /* _DEBUG */ +#define _SECURECRT_FILL_BUFFER 0 +#endif /* _DEBUG */ +#endif /* !defined (_SECURECRT_FILL_BUFFER) */ + +#ifndef _SAFECRT_IMPL +/* _invalid_parameter is already defined in safecrt.h and safecrt.lib */ +#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) +extern "C++" +#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */ +_CRTIMP +#endif /* _SAFECRT_IMPL */ +void __cdecl _invalid_parameter(__in_z_opt const wchar_t *, __in_z_opt const wchar_t *, __in_z_opt const wchar_t *, unsigned int, uintptr_t); + +#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) +extern "C++" +#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */ +_CRTIMP +void __cdecl _invoke_watson(__in_z_opt const wchar_t *, __in_z_opt const wchar_t *, __in_z_opt const wchar_t *, unsigned int, uintptr_t); + +#ifndef _DEBUG +#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) +extern "C++" +#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */ +_CRTIMP +void __cdecl _invalid_parameter_noinfo(void); +#endif /* _DEBUG */ + +/* Invoke Watson if _ExpressionError is not 0; otherwise simply return _EspressionError */ +__forceinline +void _invoke_watson_if_error( + errno_t _ExpressionError, + const wchar_t *_Expression, + const wchar_t *_Function, + const wchar_t *_File, + unsigned int _Line, + uintptr_t _Reserved + ) +{ + if (_ExpressionError == 0) + { + return; + } + _invoke_watson(_Expression, _Function, _File, _Line, _Reserved); +} + +/* Invoke Watson if _ExpressionError is not 0 and equal to _ErrorValue1 or _ErrorValue2; otherwise simply return _EspressionError */ +__forceinline +errno_t _invoke_watson_if_oneof( + errno_t _ExpressionError, + errno_t _ErrorValue1, + errno_t _ErrorValue2, + const wchar_t *_Expression, + const wchar_t *_Function, + const wchar_t *_File, + unsigned int _Line, + uintptr_t _Reserved + ) +{ + if (_ExpressionError == 0 || (_ExpressionError != _ErrorValue1 && _ExpressionError != _ErrorValue2)) + { + return _ExpressionError; + } + _invoke_watson(_Expression, _Function, _File, _Line, _Reserved); + return _ExpressionError; +} + +/* + * Assert in debug builds. + * set errno and return + * + */ +#ifdef _DEBUG +#define _CALL_INVALID_PARAMETER_FUNC(funcname, expr) funcname(expr, __FUNCTIONW__, __FILEW__, __LINE__, 0) +#define _INVOKE_WATSON_IF_ERROR(expr) _invoke_watson_if_error((expr), __STR2WSTR(#expr), __FUNCTIONW__, __FILEW__, __LINE__, 0) +#define _INVOKE_WATSON_IF_ONEOF(expr, errvalue1, errvalue2) _invoke_watson_if_oneof(expr, (errvalue1), (errvalue2), __STR2WSTR(#expr), __FUNCTIONW__, __FILEW__, __LINE__, 0) +#else /* _DEBUG */ +#define _CALL_INVALID_PARAMETER_FUNC(funcname, expr) funcname(NULL, NULL, NULL, 0, 0) +#define _INVOKE_WATSON_IF_ERROR(expr) _invoke_watson_if_error(expr, NULL, NULL, NULL, 0, 0) +#define _INVOKE_WATSON_IF_ONEOF(expr, errvalue1, errvalue2) _invoke_watson_if_oneof((expr), (errvalue1), (errvalue2), NULL, NULL, NULL, 0, 0) +#endif /* _DEBUG */ + +#define _INVALID_PARAMETER(expr) _CALL_INVALID_PARAMETER_FUNC(_invalid_parameter, expr) + +#define _VALIDATE_RETURN_VOID( expr, errorcode ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \ + if ( !( _Expr_val ) ) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return; \ + } \ + } + +/* + * Assert in debug builds. + * set errno and return value + */ + +#ifndef _VALIDATE_RETURN +#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \ + if ( !( _Expr_val ) ) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr) ); \ + return ( retexpr ); \ + } \ + } +#endif /* _VALIDATE_RETURN */ + +#ifndef _VALIDATE_RETURN_NOEXC +#define _VALIDATE_RETURN_NOEXC( expr, errorcode, retexpr ) \ + { \ + if ( !(expr) ) \ + { \ + errno = errorcode; \ + return ( retexpr ); \ + } \ + } +#endif /* _VALIDATE_RETURN_NOEXC */ + +/* + * Assert in debug builds. + * set errno and set retval for later usage + */ + +#define _VALIDATE_SETRET( expr, errorcode, retval, retexpr ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \ + if ( !( _Expr_val ) ) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + retval=( retexpr ); \ + } \ + } + +#define _CHECK_FH_RETURN( handle, errorcode, retexpr ) \ + { \ + if(handle == _NO_CONSOLE_FILENO) \ + { \ + errno = errorcode; \ + return ( retexpr ); \ + } \ + } + +/* + We use _VALIDATE_STREAM_ANSI_RETURN to ensure that ANSI file operations( + fprintf etc) aren't called on files opened as UNICODE. We do this check + only if it's an actual FILE pointer & not a string +*/ + +#define _VALIDATE_STREAM_ANSI_RETURN( stream, errorcode, retexpr ) \ + { \ + FILE *_Stream=stream; \ + _VALIDATE_RETURN(( (_Stream->_flag & _IOSTRG) || \ + ( (_textmode_safe(_fileno(_Stream)) == __IOINFO_TM_ANSI) && \ + !_tm_unicode_safe(_fileno(_Stream)))), \ + errorcode, retexpr) \ + } + +/* + We use _VALIDATE_STREAM_ANSI_SETRET to ensure that ANSI file operations( + fprintf etc) aren't called on files opened as UNICODE. We do this check + only if it's an actual FILE pointer & not a string. It doesn't actually return + immediately +*/ + +#define _VALIDATE_STREAM_ANSI_SETRET( stream, errorcode, retval, retexpr) \ + { \ + FILE *_Stream=stream; \ + _VALIDATE_SETRET(( (_Stream->_flag & _IOSTRG) || \ + ( (_textmode_safe(_fileno(_Stream)) == __IOINFO_TM_ANSI) && \ + !_tm_unicode_safe(_fileno(_Stream)))), \ + errorcode, retval, retexpr) \ + } + +/* + * Assert in debug builds. + * Return value (do not set errno) + */ + +#define _VALIDATE_RETURN_NOERRNO( expr, retexpr ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \ + if ( !( _Expr_val ) ) \ + { \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return ( retexpr ); \ + } \ + } + +/* + * Assert in debug builds. + * set errno and return errorcode + */ + +#define _VALIDATE_RETURN_ERRCODE( expr, errorcode ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \ + if ( !( _Expr_val ) ) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return ( errorcode ); \ + } \ + } + +#define _VALIDATE_RETURN_ERRCODE_NOEXC( expr, errorcode ) \ + { \ + if (!(expr)) \ + { \ + errno = errorcode; \ + return ( errorcode ); \ + } \ + } + +#define _VALIDATE_CLEAR_OSSERR_RETURN( expr, errorcode, retexpr ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \ + if ( !( _Expr_val ) ) \ + { \ + _doserrno = 0L; \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr) ); \ + return ( retexpr ); \ + } \ + } + +#define _CHECK_FH_CLEAR_OSSERR_RETURN( handle, errorcode, retexpr ) \ + { \ + if(handle == _NO_CONSOLE_FILENO) \ + { \ + _doserrno = 0L; \ + errno = errorcode; \ + return ( retexpr ); \ + } \ + } + +#define _VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE( expr, errorcode ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \ + if ( !( _Expr_val ) ) \ + { \ + _doserrno = 0L; \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return ( errorcode ); \ + } \ + } + +#define _CHECK_FH_CLEAR_OSSERR_RETURN_ERRCODE( handle, retexpr ) \ + { \ + if(handle == _NO_CONSOLE_FILENO) \ + { \ + _doserrno = 0L; \ + return ( retexpr ); \ + } \ + } + +#ifdef _DEBUG +extern size_t __crtDebugFillThreshold; +#endif /* _DEBUG */ + +#if !defined (_SECURECRT_FILL_BUFFER_THRESHOLD) +#ifdef _DEBUG +#define _SECURECRT_FILL_BUFFER_THRESHOLD __crtDebugFillThreshold +#else /* _DEBUG */ +#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)0) +#endif /* _DEBUG */ +#endif /* !defined (_SECURECRT_FILL_BUFFER_THRESHOLD) */ + +#if _SECURECRT_FILL_BUFFER +#define _SECURECRT__FILL_STRING(_String, _Size, _Offset) \ + if ((_Size) != ((size_t)-1) && (_Size) != INT_MAX && \ + ((size_t)(_Offset)) < (_Size)) \ + { \ + memset((_String) + (_Offset), \ + _SECURECRT_FILL_BUFFER_PATTERN, \ + (_SECURECRT_FILL_BUFFER_THRESHOLD < ((size_t)((_Size) - (_Offset))) ? \ + _SECURECRT_FILL_BUFFER_THRESHOLD : \ + ((_Size) - (_Offset))) * sizeof(*(_String))); \ + } +#else /* _SECURECRT_FILL_BUFFER */ +#define _SECURECRT__FILL_STRING(_String, _Size, _Offset) +#endif /* _SECURECRT_FILL_BUFFER */ + +#if _SECURECRT_FILL_BUFFER +#define _SECURECRT__FILL_BYTE(_Position) \ + if (_SECURECRT_FILL_BUFFER_THRESHOLD > 0) \ + { \ + (_Position) = _SECURECRT_FILL_BUFFER_PATTERN; \ + } +#else /* _SECURECRT_FILL_BUFFER */ +#define _SECURECRT__FILL_BYTE(_Position) +#endif /* _SECURECRT_FILL_BUFFER */ + +#ifdef __cplusplus +#define _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE extern "C" +#else /* __cplusplus */ +#define _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE +#endif /* __cplusplus */ + +/* helper macros to redirect an mbs function to the corresponding _l version */ +#define _REDIRECT_TO_L_VERSION_1(_ReturnType, _FunctionName, _Type1) \ + _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \ + _ReturnType __cdecl _FunctionName(_Type1 _Arg1) \ + { \ + return _FunctionName##_l(_Arg1, NULL); \ + } + +#define _REDIRECT_TO_L_VERSION_2(_ReturnType, _FunctionName, _Type1, _Type2) \ + _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \ + _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2) \ + { \ + return _FunctionName##_l(_Arg1, _Arg2, NULL); \ + } + +#define _REDIRECT_TO_L_VERSION_3(_ReturnType, _FunctionName, _Type1, _Type2, _Type3) \ + _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \ + _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3) \ + { \ + return _FunctionName##_l(_Arg1, _Arg2, _Arg3, NULL); \ + } + +#define _REDIRECT_TO_L_VERSION_4(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4) \ + _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \ + _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4) \ + { \ + return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, NULL); \ + } + +#define _REDIRECT_TO_L_VERSION_5(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4, _Type5) \ + _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \ + _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4, _Type5 _Arg5) \ + { \ + return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, _Arg5, NULL); \ + } + +#define _REDIRECT_TO_L_VERSION_6(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4, _Type5, _Type6) \ + _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \ + _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4, _Type5 _Arg5, _Type6 _Arg6) \ + { \ + return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, _Arg5, _Arg6, NULL); \ + } + +/* internal helper functions for encoding and decoding pointers */ +void __cdecl _init_pointers(); +_CRTIMP void * __cdecl _encode_pointer(void *); +_CRTIMP void * __cdecl _encoded_null(); +_CRTIMP void * __cdecl _decode_pointer(void *); + +/* internal helper function for communicating with the debugger */ +BOOL DebuggerKnownHandle(); + +/* Macros to simplify the use of Secure CRT in the CRT itself. + * We should use [_BEGIN/_END]_SECURE_CRT_DEPRECATION_DISABLE sparingly. + */ +#define _BEGIN_SECURE_CRT_DEPRECATION_DISABLE \ + __pragma(warning(push)) \ + __pragma(warning(disable:4996)) + +#define _END_SECURE_CRT_DEPRECATION_DISABLE \ + __pragma(warning(pop)) + +#define _ERRCHECK(e) \ + _INVOKE_WATSON_IF_ERROR(e) + +#define _ERRCHECK_EINVAL(e) \ + _INVOKE_WATSON_IF_ONEOF(e, EINVAL, EINVAL) + +#define _ERRCHECK_EINVAL_ERANGE(e) \ + _INVOKE_WATSON_IF_ONEOF(e, EINVAL, ERANGE) + +#define _ERRCHECK_SPRINTF(_PrintfCall) \ + { \ + errno_t _SaveErrno = errno; \ + errno = 0; \ + if ( ( _PrintfCall ) < 0) \ + { \ + _ERRCHECK_EINVAL_ERANGE(errno); \ + } \ + errno = _SaveErrno; \ + } + +/* internal helper function to access environment variable in read-only mode */ +const wchar_t * __cdecl _wgetenv_helper_nolock(const wchar_t *); +const char * __cdecl _getenv_helper_nolock(const char *); + +/* internal helper routines used to query a PE image header. */ +BOOL __cdecl _ValidateImageBase(PBYTE pImageBase); +PIMAGE_SECTION_HEADER __cdecl _FindPESection(PBYTE pImageBase, DWORD_PTR rva); +BOOL __cdecl _IsNonwritableInCurrentImage(PBYTE pTarget); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +#endif /* _INC_INTERNAL */ diff --git a/src/pal/src/safecrt/internal_securecrt.h b/src/pal/src/safecrt/internal_securecrt.h new file mode 100644 index 0000000000..c38bc4613b --- /dev/null +++ b/src/pal/src/safecrt/internal_securecrt.h @@ -0,0 +1,292 @@ +// 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. + +/*** +*internal_securecrt.h - contains declarations of internal routines and variables for securecrt +* + +* +*Purpose: +* Declares routines and variables used internally in the SecureCRT implementation. +* In this include file we define the macros needed to implement the secure functions +* inlined in the *.inl files like tcscpy_s.inl, etc. +* Note that this file is used for the CRT implementation, while internal_safecrt is used +* to build the downlevel library safecrt.lib. +* +* [Internal] +* +****/ + +#pragma once + +#ifndef _INC_INTERNAL_SECURECRT +#define _INC_INTERNAL_SECURECRT + +/* more VS specific goodness */ +#define __out_ecount_z( x ) +#define __out_ecount( x ) +#define __in_opt +#define __in_z_opt +#define __out_ecount_z_opt( x ) +#define __in_z +#define __in + +/* + * The original SafeCRT implemention allows runtine control over buffer checking. + * For now we'll key this off the debug flag. + */ +#ifdef _DEBUG + #define _CrtGetCheckCount() ((int)1) +#else + #define _CrtGetCheckCount() ((int)0) +#endif + +/* Assert message and Invalid parameter */ +#ifdef _DEBUG + #define _ASSERT_EXPR( val, exp ) \ + { \ + if ( ( val ) == 0 ) \ + { \ + if ( sMBUSafeCRTAssertFunc != NULL ) \ + { \ + ( *sMBUSafeCRTAssertFunc )( #exp, "SafeCRT assert failed", __FILE__, __LINE__ ); \ + } \ + } \ + } + #define _INVALID_PARAMETER( exp ) _ASSERT_EXPR( 0, exp ) + #define _ASSERTE( exp ) _ASSERT_EXPR( exp, exp ) +#else + #define _ASSERT_EXPR( val, expr ) + #define _INVALID_PARAMETER( exp ) + #define _ASSERTE( exp ) +#endif + +/* _TRUNCATE */ +#if !defined (_TRUNCATE) +#define _TRUNCATE ((size_t)-1) +#endif /* !defined (_TRUNCATE) */ + +/* #include <internal.h> */ + +#define _VALIDATE_RETURN_VOID( expr, errorcode ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), #expr ); \ + if ( !( _Expr_val ) ) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(#expr); \ + return; \ + } \ + } + +/* + * Assert in debug builds. + * set errno and return value + */ + +#ifndef _VALIDATE_RETURN +#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), #expr ); \ + if ( !( _Expr_val ) ) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(#expr ); \ + return ( retexpr ); \ + } \ + } +#endif /* _VALIDATE_RETURN */ + +#ifndef _VALIDATE_RETURN_NOEXC +#define _VALIDATE_RETURN_NOEXC( expr, errorcode, retexpr ) \ + { \ + if ( !(expr) ) \ + { \ + errno = errorcode; \ + return ( retexpr ); \ + } \ + } +#endif /* _VALIDATE_RETURN_NOEXC */ + +/* + * Assert in debug builds. + * set errno and return errorcode + */ + +#define _VALIDATE_RETURN_ERRCODE( expr, errorcode ) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \ + if ( !( _Expr_val ) ) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return ( errorcode ); \ + } \ + } + +/* We completely fill the buffer only in debug (see _SECURECRT__FILL_STRING + * and _SECURECRT__FILL_BYTE macros). + */ +#if !defined (_SECURECRT_FILL_BUFFER) +#ifdef _DEBUG +#define _SECURECRT_FILL_BUFFER 1 +#else /* _DEBUG */ +#define _SECURECRT_FILL_BUFFER 0 +#endif /* _DEBUG */ +#endif /* !defined (_SECURECRT_FILL_BUFFER) */ + +/* _SECURECRT_FILL_BUFFER_PATTERN is the same as _bNoMansLandFill */ +#define _SECURECRT_FILL_BUFFER_PATTERN 0xFD + +#if !defined (_SECURECRT_FILL_BUFFER_THRESHOLD) +#ifdef _DEBUG +#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8) +#else /* _DEBUG */ +#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)0) +#endif /* _DEBUG */ +#endif /* !defined (_SECURECRT_FILL_BUFFER_THRESHOLD) */ + +#if _SECURECRT_FILL_BUFFER +#define _SECURECRT__FILL_STRING(_String, _Size, _Offset) \ + if ((_Size) != ((size_t)-1) && (_Size) != INT_MAX && \ + ((size_t)(_Offset)) < (_Size)) \ + { \ + memset((_String) + (_Offset), \ + _SECURECRT_FILL_BUFFER_PATTERN, \ + (_SECURECRT_FILL_BUFFER_THRESHOLD < ((size_t)((_Size) - (_Offset))) ? \ + _SECURECRT_FILL_BUFFER_THRESHOLD : \ + ((_Size) - (_Offset))) * sizeof(*(_String))); \ + } +#else /* _SECURECRT_FILL_BUFFER */ +#define _SECURECRT__FILL_STRING(_String, _Size, _Offset) +#endif /* _SECURECRT_FILL_BUFFER */ + +#if _SECURECRT_FILL_BUFFER +#define _SECURECRT__FILL_BYTE(_Position) \ + if (_SECURECRT_FILL_BUFFER_THRESHOLD > 0) \ + { \ + (_Position) = _SECURECRT_FILL_BUFFER_PATTERN; \ + } +#else /* _SECURECRT_FILL_BUFFER */ +#define _SECURECRT__FILL_BYTE(_Position) +#endif /* _SECURECRT_FILL_BUFFER */ + +/* string resetting */ +#define _FILL_STRING _SECURECRT__FILL_STRING + +#define _FILL_BYTE _SECURECRT__FILL_BYTE + +#define _RESET_STRING(_String, _Size) \ + { \ + *(_String) = 0; \ + _FILL_STRING((_String), (_Size), 1); \ + } + +/* validations */ +#define _VALIDATE_STRING_ERROR(_String, _Size, _Ret) \ + _VALIDATE_RETURN((_String) != NULL && (_Size) > 0, EINVAL, (_Ret)) + +#define _VALIDATE_STRING(_String, _Size) \ + _VALIDATE_STRING_ERROR((_String), (_Size), EINVAL) + +#define _VALIDATE_POINTER_ERROR_RETURN(_Pointer, _ErrorCode, _Ret) \ + _VALIDATE_RETURN((_Pointer) != NULL, (_ErrorCode), (_Ret)) + +#define _VALIDATE_POINTER_ERROR(_Pointer, _Ret) \ + _VALIDATE_POINTER_ERROR_RETURN((_Pointer), EINVAL, (_Ret)) + +#define _VALIDATE_POINTER(_Pointer) \ + _VALIDATE_POINTER_ERROR((_Pointer), EINVAL) + +#define _VALIDATE_CONDITION_ERROR_RETURN(_Condition, _ErrorCode, _Ret) \ + _VALIDATE_RETURN((_Condition), (_ErrorCode), (_Ret)) + +#define _VALIDATE_CONDITION_ERROR(_Condition, _Ret) \ + _VALIDATE_CONDITION_ERROR_RETURN((_Condition), EINVAL, (_Ret)) + +#define _VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, _Ret) \ + if ((_Pointer) == NULL) \ + { \ + _RESET_STRING((_String), (_Size)); \ + _VALIDATE_POINTER_ERROR_RETURN((_Pointer), EINVAL, (_Ret)) \ + } + +#define _VALIDATE_POINTER_RESET_STRING(_Pointer, _String, _Size) \ + _VALIDATE_POINTER_RESET_STRING_ERROR((_Pointer), (_String), (_Size), EINVAL) + +#define _RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, _Ret) \ + _VALIDATE_RETURN(("Buffer is too small" && 0), ERANGE, _Ret) + +#define _RETURN_BUFFER_TOO_SMALL(_String, _Size) \ + _RETURN_BUFFER_TOO_SMALL_ERROR((_String), (_Size), ERANGE) + +#define _RETURN_DEST_NOT_NULL_TERMINATED(_String, _Size) \ + _VALIDATE_RETURN(("String is not null terminated" && 0), EINVAL, EINVAL) + +#define _RETURN_EINVAL \ + _VALIDATE_RETURN(("Invalid parameter" && 0), EINVAL, EINVAL) + +#define _RETURN_ERROR(_Msg, _Ret) \ + _VALIDATE_RETURN(((_Msg), 0), EINVAL, _Ret) + +/* returns without calling _invalid_parameter */ +#define _RETURN_NO_ERROR \ + return 0 + +/* Note that _RETURN_TRUNCATE does not set errno */ +#define _RETURN_TRUNCATE \ + return STRUNCATE + +#define _SET_MBCS_ERROR \ + (errno = EILSEQ) + +#define _RETURN_MBCS_ERROR \ + return _SET_MBCS_ERROR + +/* locale dependent */ +#define _LOCALE_ARG \ + _LocInfo + +#define _LOCALE_ARG_DECL \ + _locale_t _LOCALE_ARG + +#define _LOCALE_UPDATE \ + _LocaleUpdate _LocUpdate(_LOCALE_ARG) + +#define _ISMBBLEAD(_Character) \ + _ismbblead_l((_Character), _LocUpdate.GetLocaleT()) + +#define _MBSDEC(_String, _Current) \ + _mbsdec((_String), (_Current)) + +#define _ISMBBLEADPREFIX(_Result, _StringStart, _BytePtr) \ + { \ + unsigned char *_Tmp_VAR, *_StringStart_VAR, *_BytePtr_VAR; \ + \ + _StringStart_VAR = (_StringStart); \ + _BytePtr_VAR = (_BytePtr); \ + _Tmp_VAR = _BytePtr_VAR; \ + while ((_Tmp_VAR >= _StringStart_VAR) && _ISMBBLEAD(*_Tmp_VAR)) \ + { \ + _Tmp_VAR--; \ + } \ + (_Result) = ((_BytePtr_VAR - _Tmp_VAR) & 1) != 0; \ + } + +#define _LOCALE_SHORTCUT_TEST \ + _LocUpdate.GetLocaleT()->mbcinfo->ismbcodepage == 0 + +#define _USE_LOCALE_ARG 1 + +/* misc */ +#define _ASSIGN_IF_NOT_NULL(_Pointer, _Value) \ + if ((_Pointer) != NULL) \ + { \ + *(_Pointer) = (_Value); \ + } + +#endif /* _INC_INTERNAL_SECURECRT */ diff --git a/src/pal/src/safecrt/makepath_s.c b/src/pal/src/safecrt/makepath_s.c new file mode 100644 index 0000000000..4342685b9c --- /dev/null +++ b/src/pal/src/safecrt/makepath_s.c @@ -0,0 +1,31 @@ +// 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. + +/*** +*makepath_s.c - create path name from components +* + +* +*Purpose: +* To provide support for creation of full path names from components +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME _makepath_s +#define _CHAR char +#define _DEST _Dst +#define _SIZE _SizeInBytes +#define _T(_Character) _Character + +#define _MBS_SUPPORT 0 + +#include "tmakepath_s.inl" diff --git a/src/pal/src/safecrt/mbusafecrt.c b/src/pal/src/safecrt/mbusafecrt.c new file mode 100644 index 0000000000..ca853d9269 --- /dev/null +++ b/src/pal/src/safecrt/mbusafecrt.c @@ -0,0 +1,254 @@ +// 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. + +/*** +* mbusafecrt.c - implementaion of support functions and data for MBUSafeCRT +* + +* +* Purpose: +* This file contains the implementation of support functions and +* data for MBUSafeCRT declared in mbusafecrt.h and mbusafecrt_internal.h. +****/ + +#include "pal/palinternal.h" +#include <string.h> +#include <errno.h> +#include <limits.h> + +#include "mbusafecrt_internal.h" + +/* global data */ +tSafeCRT_AssertFuncPtr sMBUSafeCRTAssertFunc = NULL; + +/*** +* MBUSafeCRTSetAssertFunc - Set the function called when an assert fails. +****/ + +void MBUSafeCRTSetAssertFunc( tSafeCRT_AssertFuncPtr inAssertFuncPtr ) +{ + /* set it */ + sMBUSafeCRTAssertFunc = inAssertFuncPtr; +} + +/*** +* _putc_nolock - putc for the miniFILE stream. +****/ + +int _putc_nolock( char inChar, miniFILE* inStream ) +{ + int returnValue = EOF; + + inStream->_cnt -= sizeof( char ); + + if ( ( inStream->_cnt ) >= 0 ) + { + *( inStream->_ptr ) = inChar; + inStream->_ptr += sizeof( char ); + returnValue = ( int )inChar; + } + + return returnValue; +} + +/*** +* _putwc_nolock - putwc for the miniFILE stream. +****/ + +int _putwc_nolock( wchar_t inChar, miniFILE* inStream ) +{ + int returnValue = WEOF; + + inStream->_cnt -= sizeof( wchar_t ); + + if ( ( inStream->_cnt ) >= 0 ) + { + *( ( wchar_t* )( inStream->_ptr ) ) = inChar; + inStream->_ptr += sizeof( wchar_t ); + returnValue = ( int )inChar; + } + + return returnValue; +} + +/*** +* _getc_nolock - getc for the miniFILE stream. +****/ + +int _getc_nolock( miniFILE* inStream ) +{ + int returnValue = EOF; + + if ( ( inStream->_cnt ) >= ( int )( sizeof( char ) ) ) + { + inStream->_cnt -= sizeof( char ); + returnValue = ( int )( *( inStream->_ptr ) ); + inStream->_ptr += sizeof( char ); + } + + return returnValue; +} + +/*** +* _getwc_nolock - getc for the miniFILE stream. +****/ + +int _getwc_nolock( miniFILE* inStream ) +{ + int returnValue = EOF; + + if ( ( inStream->_cnt ) >= ( int )( sizeof( wchar_t ) ) ) + { + inStream->_cnt -= sizeof( wchar_t ); + returnValue = ( int )( *( ( wchar_t* )( inStream->_ptr ) ) ); + inStream->_ptr += sizeof( wchar_t ); + } + + return returnValue; +} + +/*** +* _ungetc_nolock - ungetc for the miniFILE stream. +****/ + +int _ungetc_nolock( char inChar, miniFILE* inStream ) +{ + int returnValue = EOF; + + if ( ( size_t )( ( inStream->_ptr ) - ( inStream->_base ) ) >= ( sizeof( char ) ) ) + { + inStream->_cnt += sizeof( char ); + inStream->_ptr -= sizeof( char ); + return ( int )inChar; + } + + return returnValue; +} + +/*** +* _ungetwc_nolock - ungetwc for the miniFILE stream. +****/ + +int _ungetwc_nolock( wchar_t inChar, miniFILE* inStream ) +{ + int returnValue = WEOF; + + if ( ( size_t )( ( inStream->_ptr ) - ( inStream->_base ) ) >= ( sizeof( wchar_t ) ) ) + { + inStream->_cnt += sizeof( wchar_t ); + inStream->_ptr -= sizeof( wchar_t ); + returnValue = ( unsigned short )inChar; + } + + return returnValue; +} + + +/*** +* _safecrt_cfltcvt - convert a float to an ascii string. +* Uses sprintf - this usage is OK. +****/ + +/* routine used for floating-point output */ +#define FORMATSIZE 30 + +#define _snprintf snprintf + +// taken from output.inl +#define FL_ALTERNATE 0x00080 /* alternate form requested */ + +errno_t _safecrt_cfltcvt(double *arg, char *buffer, size_t sizeInBytes, int type, int precision, int flags) +{ + char format[FORMATSIZE]; + size_t formatlen = 0; + int retvalue; + + if (flags & 1) + { + type -= 'a' - 'A'; + } + formatlen = 0; + format[formatlen++] = '%'; + if (flags & FL_ALTERNATE) + { + format[formatlen++] = '#'; + } + format[formatlen++] = '.'; + _itoa_s(precision, format + formatlen, FORMATSIZE - formatlen, 10); + formatlen = strlen(format); + format[formatlen++] = (char)type; + format[formatlen] = 0; + + buffer[sizeInBytes - 1] = 0; + retvalue = _snprintf(buffer, sizeInBytes, format, *arg); + if (buffer[sizeInBytes - 1] != 0 || retvalue <= 0) + { + buffer[0] = 0; + return EINVAL; + } + return 0; +} + + +/*** +* _safecrt_fassign - convert a string into a float or double. +****/ + +void _safecrt_fassign(int flag, void* argument, char* number ) +{ + if ( flag != 0 ) // double + { + double dblValue = 0.0; + (void)sscanf( number, "%lf", &dblValue ); + *( ( double* )argument ) = dblValue; + } + else // float + { + float fltValue = 0.0; + (void)sscanf( number, "%f", &fltValue ); + *( ( float* )argument ) = fltValue; + } +} + + +/*** +* _safecrt_wfassign - convert a wchar_t string into a float or double. +****/ + +void _safecrt_wfassign(int flag, void* argument, wchar_t* number ) +{ + // We cannot use system functions for this - they + // assume that wchar_t is four bytes, while we assume + // two. So, we need to convert to a regular char string + // without using any system functions. To do this, + // we'll assume that the numbers are in the 0-9 range and + // do a simple conversion. + + char* numberAsChars = ( char* )number; + int position = 0; + + // do the convert + while ( number[ position ] != 0 ) + { + numberAsChars[ position ] = ( char )( number[ position ] & 0x00FF ); + position++; + } + numberAsChars[ position ] = ( char )( number[ position ] & 0x00FF ); + + // call the normal char version + _safecrt_fassign( flag, argument, numberAsChars ); +} + + +/*** +* _minimal_chartowchar - do a simple char to wchar conversion. +****/ + +int _minimal_chartowchar( wchar_t* outWChar, const char* inChar ) +{ + *outWChar = ( wchar_t )( ( unsigned short )( ( unsigned char )( *inChar ) ) ); + return 1; +} + + diff --git a/src/pal/src/safecrt/mbusafecrt_internal.h b/src/pal/src/safecrt/mbusafecrt_internal.h new file mode 100644 index 0000000000..9a3aa1ca90 --- /dev/null +++ b/src/pal/src/safecrt/mbusafecrt_internal.h @@ -0,0 +1,88 @@ +// 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. + +/*** +* mbusafecrt_internal.h - internal declarations for SafeCRT functions +* + +* +* Purpose: +* This file contains the internal declarations SafeCRT +* functions ported to MacOS. These are the safe versions of +* functions standard functions banned by SWI +****/ + +/* shields! */ + +#ifndef MBUSAFECRT_INTERNAL_H +#define MBUSAFECRT_INTERNAL_H + +#include "pal_char16.h" +#include "pal_mstypes.h" + +typedef __builtin_va_list va_list; + +// The ifdef below are to accommodate Unix build +// that complains about them being declared in stdarg.h already. +#ifndef va_start +#define va_start __builtin_va_start +#endif +#ifndef va_end +#define va_end __builtin_va_end +#endif + +#include "mbusafecrt.h" + +#ifdef EOF +#undef EOF +#endif +#define EOF -1 + +#ifdef WEOF +#undef WEOF +#endif +#define WEOF -1 + +#define CASSERT(p) extern int sanity_check_dummy[1+((!(p))*(-2))]; + +extern tSafeCRT_AssertFuncPtr sMBUSafeCRTAssertFunc; + +typedef struct miniFILE_struct +{ + char* _ptr; + int _cnt; + char* _base; + int _flag; +} miniFILE; + +#define _IOSTRG 1 +#define _IOWRT 2 +#define _IOREAD 4 +#define _IOMYBUF 8 + +int _putc_nolock( char inChar, miniFILE* inStream ); +int _putwc_nolock( wchar_t inChar, miniFILE* inStream ); +int _getc_nolock( miniFILE* inStream ); +int _getwc_nolock( miniFILE* inStream ); +int _ungetc_nolock( char inChar, miniFILE* inStream ); +int _ungetwc_nolock( wchar_t inChar, miniFILE* inStream ); + +errno_t _safecrt_cfltcvt(double *arg, char *buffer, size_t sizeInBytes, int type, int precision, int flags); + +void _safecrt_fassign(int flag, void* argument, char * number ); +void _safecrt_wfassign(int flag, void* argument, wchar_t * number ); + +int _minimal_chartowchar( wchar_t* outWChar, const char* inChar ); + +int _output_s( miniFILE* outfile, const char* _Format, va_list _ArgList); +int _woutput_s( miniFILE* outfile, const wchar_t* _Format, va_list _ArgList); +int _output( miniFILE *outfile, const char* _Format, va_list _ArgList); + +int _soutput_s( char *_Dst, size_t _Size, const char *_Format, va_list _ArgList ); +int _swoutput_s( wchar_t *_Dst, size_t _Size, const wchar_t *_Format, va_list _ArgList ); + +int __tinput_s( miniFILE* inFile, const unsigned char * inFormat, va_list inArgList ); +int __twinput_s( miniFILE* inFile, const wchar_t * inFormat, va_list inArgList ); + +#endif /* MBUSAFECRT_INTERNAL_H */ diff --git a/src/pal/src/safecrt/memcpy_s.c b/src/pal/src/safecrt/memcpy_s.c new file mode 100644 index 0000000000..27aeb79665 --- /dev/null +++ b/src/pal/src/safecrt/memcpy_s.c @@ -0,0 +1,82 @@ +// 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. + +/*** +*memcpy_s.c - contains memcpy_s routine +* + +* +*Purpose: +* memcpy_s() copies a source memory buffer to a destination buffer. +* Overlapping buffers are not treated specially, so propagation may occur. +* +*Revision History: +* 10-07-03 AC Module created. +* 03-10-04 AC Return ERANGE when buffer is too small +* 01-14-05 AC Prefast (espx) fixes +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <assert.h> +#include "internal_securecrt.h" +#include "mbusafecrt_internal.h" + +/*** +*memcpy_s - Copy source buffer to destination buffer +* +*Purpose: +* memcpy_s() copies a source memory buffer to a destination memory buffer. +* This routine does NOT recognize overlapping buffers, and thus can lead +* to propagation. +* +* For cases where propagation must be avoided, memmove_s() must be used. +* +*Entry: +* void *dst = pointer to destination buffer +* size_t sizeInBytes = size in bytes of the destination buffer +* const void *src = pointer to source buffer +* size_t count = number of bytes to copy +* +*Exit: +* Returns 0 if everything is ok, else return the error code. +* +*Exceptions: +* Input parameters are validated. Refer to the validation section of the function. +* On error, the error code is returned and the destination buffer is zeroed. +* +*******************************************************************************/ + +errno_t __cdecl memcpy_s( + void * dst, + size_t sizeInBytes, + const void * src, + size_t count +) +{ + if (count == 0) + { + /* nothing to do */ + return 0; + } + + /* validation section */ + _VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL); + if (src == NULL || sizeInBytes < count) + { + /* zeroes the destination buffer */ + memset(dst, 0, sizeInBytes); + + _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL); + _VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE); + /* useless, but prefast is confused */ + return EINVAL; + } + + UINT_PTR x = (UINT_PTR)dst, y = (UINT_PTR)src; + assert((x + count <= y) || (y + count <= x)); + memcpy(dst, src, count); + return 0; +} diff --git a/src/pal/src/safecrt/memmove_s.c b/src/pal/src/safecrt/memmove_s.c new file mode 100644 index 0000000000..a0ae5f7ea6 --- /dev/null +++ b/src/pal/src/safecrt/memmove_s.c @@ -0,0 +1,69 @@ +// 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. + +/*** +*memmove_s.c - contains memmove_s routine +* + +* +*Purpose: +* memmove_s() copies a source memory buffer to a destination buffer. +* Overlapping buffers are treated specially, to avoid propagation. +* +*Revision History: +* 10-07-03 AC Module created. +* 03-10-04 AC Return ERANGE when buffer is too small +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include "internal_securecrt.h" +#include "mbusafecrt_internal.h" + +/*** +*memmove - Copy source buffer to destination buffer +* +*Purpose: +* memmove() copies a source memory buffer to a destination memory buffer. +* This routine recognize overlapping buffers to avoid propagation. +* +* For cases where propagation is not a problem, memcpy_s() can be used. +* +*Entry: +* void *dst = pointer to destination buffer +* size_t sizeInBytes = size in bytes of the destination buffer +* const void *src = pointer to source buffer +* size_t count = number of bytes to copy +* +*Exit: +* Returns 0 if everything is ok, else return the error code. +* +*Exceptions: +* Input parameters are validated. Refer to the validation section of the function. +* On error, the error code is returned. Nothing is written to the destination buffer. +* +*******************************************************************************/ + +errno_t __cdecl memmove_s( + void * dst, + size_t sizeInBytes, + const void * src, + size_t count +) +{ + if (count == 0) + { + /* nothing to do */ + return 0; + } + + /* validation section */ + _VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL); + _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL); + _VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE); + + memmove(dst, src, count); + return 0; +} diff --git a/src/pal/src/safecrt/output.inl b/src/pal/src/safecrt/output.inl new file mode 100644 index 0000000000..ae0692efc5 --- /dev/null +++ b/src/pal/src/safecrt/output.inl @@ -0,0 +1,1624 @@ +// 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. + +/*** +*output.c - printf style output to a FILE +* + +* +*Purpose: +* This file contains the code that does all the work for the +* printf family of functions. It should not be called directly, only +* by the *printf functions. We don't make any assumtions about the +* sizes of ints, longs, shorts, or long doubles, but if types do overlap, +* we also try to be efficient. We do assume that pointers are the same +* size as either ints or longs. +* If CPRFLAG is defined, defines _cprintf instead. +* **** DOESN'T CURRENTLY DO MTHREAD LOCKING **** +* +*Note: +* this file is included in safecrt.lib build directly, plese refer +* to safecrt_[w]output_s.c +* +*******************************************************************************/ + + +//typedef __int64_t __int64; + + +#define FORMAT_VALIDATIONS + +typedef double _CRT_DOUBLE; + +//typedef int* intptr_t; + +/* +Buffer size required to be passed to _gcvt, fcvt and other fp conversion routines +*/ +#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */ + +/* temporary work-around for compiler without 64-bit support */ +#ifndef _INTEGRAL_MAX_BITS +#define _INTEGRAL_MAX_BITS 64 +#endif /* _INTEGRAL_MAX_BITS */ + +//#include <mtdll.h> +//#include <cruntime.h> +//#include <limits.h> +//#include <string.h> +//#include <stddef.h> +//#include <crtdefs.h> +//#include <stdio.h> +//#include <stdarg.h> +//#include <cvt.h> +//#include <conio.h> +//#include <internal.h> +//#include <fltintrn.h> +//#include <stdlib.h> +//#include <ctype.h> +//#include <dbgint.h> +//#include <setlocal.h> + +#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y ) + +#ifndef _WCTOMB_S +#define _WCTOMB_S wctomb_s +#endif /* _WCTOMB_S */ + +#undef _malloc_crt +#define _malloc_crt malloc + +#undef _free_crt +#define _free_crt free + +/* Wrapper for _output_s so that we do not expose FILE in the _output_s signature. + * Always ensure null-termination. Returns the number of written chars, not including the terminating null. + * Returns -1 if something went wrong during the formatting (in _output_s), e.g. mbcs conversions. + * Returns -2 if the string has been truncated. + * _output_s calls _invalid_parameter (and returns -1, possibly) if the format string is malformed. + */ +#ifndef _UNICODE +int __cdecl _soutput_s(char *_Dst, size_t _Size, const char *_Format, va_list _ArgList) +#else /* _UNICODE */ +int __cdecl _swoutput_s(wchar_t *_Dst, size_t _Size, const wchar_t *_Format, va_list _ArgList) +#endif /* _UNICODE */ +{ + miniFILE stream; + miniFILE *outfile = &stream; + int written = -1; + + /* validation section */ +#ifndef _UNICODE + if(_Size==SIZE_MAX) + { + /* user is attempting to make us unbounded, but we don't fit that much */ + outfile->_cnt = INT_MAX; + } + else + { + _VALIDATE_RETURN(_Size <= INT_MAX, EINVAL, -1); + outfile->_cnt = (int)_Size; + } + outfile->_ptr = outfile->_base = _Dst; +#else /* _UNICODE */ + if(_Size==SIZE_MAX) + { + /* user is attempting to make us unbounded, but we don't fit that much */ + outfile->_cnt = INT_MAX; + } + else if(_Size>(INT_MAX/sizeof(wchar_t))) + { + /* we can't represent the amount of output the user asked for */ + _VALIDATE_RETURN( 0 /* FALSE */, EINVAL, -1 ); + } + else + { + outfile->_cnt = (int)(_Size*sizeof(wchar_t)); + } + outfile->_ptr = outfile->_base = (char*)_Dst; +#endif /* _UNICODE */ + outfile->_flag = _IOWRT | _IOSTRG; + +#ifndef _UNICODE + written = _output_s(outfile, _Format, _ArgList); +#else /* _UNICODE */ + written = _woutput_s(outfile, _Format, _ArgList); +#endif /* _UNICODE */ + _Dst[_Size - 1] = 0; + if (written < 0) + { + if (outfile->_cnt < 0) + { + /* the buffer was too small; we return -2 to indicate truncation */ + return -2; + } + /* otherwise, something else failed: we reset the string and we return */ + if (_Dst != NULL && _Size > 0) + { + *_Dst = 0; + } + return written; + } + +#ifndef _UNICODE + if ((_putc_nolock('\0', outfile) != EOF)) +#else /* _UNICODE */ + if ((_putc_nolock('\0', outfile) != EOF) && (_putc_nolock('\0', outfile) != EOF)) +#endif /* _UNICODE */ + { + return written; + } + /* the last putc failed, so it means there is not enough space in the buffer */ + return -2; +} + + +#ifndef _CFLTCVT +#define _CFLTCVT _cfltcvt +#endif /* _CFLTCVT */ + +#ifndef _CLDCVT +#define _CLDCVT _cldcvt +#endif /* _CLDCVT */ + +#ifdef _MBCS +#undef _MBCS +#endif /* _MBCS */ +//#include <tchar.h> + +/* this macro defines a function which is private and as fast as possible: */ +/* for example, in C 6.0, it might be static _fastcall <type> near. */ +#define LOCAL(x) static x __cdecl + +/* int/long/short/pointer sizes */ + +/* the following should be set depending on the sizes of various types */ +#if __LP64__ + #define LONG_IS_INT 0 + CASSERT(sizeof(long) > sizeof(int)); +#else + #define LONG_IS_INT 1 /* 1 means long is same size as int */ + CASSERT(sizeof(long) == sizeof(int)); +#endif + +#define SHORT_IS_INT 0 /* 1 means short is same size as int */ +#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 */ +#if defined (_WIN64) + #define PTR_IS_INT 0 /* 1 means ptr is same size as int */ + CASSERT(sizeof(void *) != sizeof(int)); + #if __LP64__ + #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */ + CASSERT(sizeof(void *) == sizeof(long)); + #else + #define PTR_IS_LONG 0 /* 1 means ptr is same size as long */ + CASSERT(sizeof(void *) != sizeof(long)); + #endif + #define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */ + CASSERT(sizeof(void *) == sizeof(int64_t)); +#else /* defined (_WIN64) */ + #define PTR_IS_INT 1 /* 1 means ptr is same size as int */ + CASSERT(sizeof(void *) == sizeof(int)); + #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */ + CASSERT(sizeof(void *) == sizeof(long)); + #define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */ + CASSERT(sizeof(void *) != sizeof(int64_t)); +#endif /* defined (_WIN64) */ + +/* CONSTANTS */ + +/* size of conversion buffer (ANSI-specified minimum is 509) */ + +#define BUFFERSIZE 512 +#define MAXPRECISION BUFFERSIZE + +#if BUFFERSIZE < _CVTBUFSIZE + 6 +/* + * Buffer needs to be big enough for default minimum precision + * when converting floating point needs bigger buffer, and malloc + * fails + */ +#error Conversion buffer too small for max double. +#endif /* BUFFERSIZE < _CVTBUFSIZE + 6 */ + +/* flag definitions */ +#define FL_SIGN 0x00001 /* put plus or minus in front */ +#define FL_SIGNSP 0x00002 /* put space or minus in front */ +#define FL_LEFT 0x00004 /* left justify */ +#define FL_LEADZERO 0x00008 /* pad with leading zeros */ +#define FL_LONG 0x00010 /* long value given */ +#define FL_SHORT 0x00020 /* short value given */ +#define FL_SIGNED 0x00040 /* signed data given */ +#define FL_ALTERNATE 0x00080 /* alternate form requested */ +#define FL_NEGATIVE 0x00100 /* value is negative */ +#define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */ +#define FL_LONGDOUBLE 0x00400 /* long double value given */ +#define FL_WIDECHAR 0x00800 /* wide characters */ +#define FL_LONGLONG 0x01000 /* long long value given */ +#define FL_I64 0x08000 /* __int64 value given */ + +/* state definitions */ +enum STATE { + ST_NORMAL, /* normal state; outputting literal chars */ + ST_PERCENT, /* just read '%' */ + ST_FLAG, /* just read flag character */ + ST_WIDTH, /* just read width specifier */ + ST_DOT, /* just read '.' */ + ST_PRECIS, /* just read precision specifier */ + ST_SIZE, /* just read size specifier */ + ST_TYPE /* just read type specifier */ +#ifdef FORMAT_VALIDATIONS + ,ST_INVALID /* Invalid format */ +#endif /* FORMAT_VALIDATIONS */ + +}; + +#ifdef FORMAT_VALIDATIONS +#define NUMSTATES (ST_INVALID + 1) +#else /* FORMAT_VALIDATIONS */ +#define NUMSTATES (ST_TYPE + 1) +#endif /* FORMAT_VALIDATIONS */ + +/* character type values */ +enum CHARTYPE { + CH_OTHER, /* character with no special meaning */ + CH_PERCENT, /* '%' */ + CH_DOT, /* '.' */ + CH_STAR, /* '*' */ + CH_ZERO, /* '0' */ + CH_DIGIT, /* '1'..'9' */ + CH_FLAG, /* ' ', '+', '-', '#' */ + CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */ + CH_TYPE /* type specifying character */ +}; + +/* static data (read only, since we are re-entrant) */ +//#if defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) +//extern const char __nullstring[]; /* string to print on null ptr */ +//extern const wchar_t __wnullstring[]; /* string to print on null ptr */ +//#else /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */ +static const char __nullstring[] = "(null)"; /* string to print on null ptr */ +static const wchar_t __wnullstring[] = {'(', 'n', 'u', 'l', 'l', ')', '\0'};/* string to print on null ptr */ +//#endif /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */ + +/* The state table. This table is actually two tables combined into one. */ +/* The lower nybble of each byte gives the character class of any */ +/* character; while the uper nybble of the byte gives the next state */ +/* to enter. See the macros below the table for details. */ +/* */ +/* The table is generated by maketabc.c -- use this program to make */ +/* changes. */ + +#ifndef FORMAT_VALIDATIONS + +//#if defined (_UNICODE) || defined (CPRFLAG) +//extern const char __lookuptable[]; +//#else /* defined (_UNICODE) || defined (CPRFLAG) */ +extern const char __lookuptable[] = { + /* ' ' */ 0x06, + /* '!' */ 0x00, + /* '"' */ 0x00, + /* '#' */ 0x06, + /* '$' */ 0x00, + /* '%' */ 0x01, + /* '&' */ 0x00, + /* ''' */ 0x00, + /* '(' */ 0x10, + /* ')' */ 0x00, + /* '*' */ 0x03, + /* '+' */ 0x06, + /* ',' */ 0x00, + /* '-' */ 0x06, + /* '.' */ 0x02, + /* '/' */ 0x10, + /* '0' */ 0x04, + /* '1' */ 0x45, + /* '2' */ 0x45, + /* '3' */ 0x45, + /* '4' */ 0x05, + /* '5' */ 0x05, + /* '6' */ 0x05, + /* '7' */ 0x05, + /* '8' */ 0x05, + /* '9' */ 0x35, + /* ':' */ 0x30, + /* ';' */ 0x00, + /* '<' */ 0x50, + /* '=' */ 0x00, + /* '>' */ 0x00, + /* '?' */ 0x00, + /* '@' */ 0x00, + /* 'A' */ 0x20, // Disable %A format + /* 'B' */ 0x20, + /* 'C' */ 0x38, + /* 'D' */ 0x50, + /* 'E' */ 0x58, + /* 'F' */ 0x07, + /* 'G' */ 0x08, + /* 'H' */ 0x00, + /* 'I' */ 0x37, + /* 'J' */ 0x30, + /* 'K' */ 0x30, + /* 'L' */ 0x57, + /* 'M' */ 0x50, + /* 'N' */ 0x07, + /* 'O' */ 0x00, + /* 'P' */ 0x00, + /* 'Q' */ 0x20, + /* 'R' */ 0x20, + /* 'S' */ 0x08, + /* 'T' */ 0x00, + /* 'U' */ 0x00, + /* 'V' */ 0x00, + /* 'W' */ 0x00, + /* 'X' */ 0x08, + /* 'Y' */ 0x60, + /* 'Z' */ 0x68, + /* '[' */ 0x60, + /* '\' */ 0x60, + /* ']' */ 0x60, + /* '^' */ 0x60, + /* '_' */ 0x00, + /* '`' */ 0x00, + /* 'a' */ 0x70, // Disable %a format + /* 'b' */ 0x70, + /* 'c' */ 0x78, + /* 'd' */ 0x78, + /* 'e' */ 0x78, + /* 'f' */ 0x78, + /* 'g' */ 0x08, + /* 'h' */ 0x07, + /* 'i' */ 0x08, + /* 'j' */ 0x00, + /* 'k' */ 0x00, + /* 'l' */ 0x07, + /* 'm' */ 0x00, + /* 'n' */ 0x00, // Disable %n format + /* 'o' */ 0x08, + /* 'p' */ 0x08, + /* 'q' */ 0x00, + /* 'r' */ 0x00, + /* 's' */ 0x08, + /* 't' */ 0x00, + /* 'u' */ 0x08, + /* 'v' */ 0x00, + /* 'w' */ 0x07, + /* 'x' */ 0x08 +}; + +//#endif /* defined (_UNICODE) || defined (CPRFLAG) */ + +#else /* FORMAT_VALIDATIONS */ + +//#if defined (_UNICODE) || defined (CPRFLAG) +//extern const unsigned char __lookuptable_s[]; +//#else /* defined (_UNICODE) || defined (CPRFLAG) */ +static const unsigned char __lookuptable_s[] = { + /* ' ' */ 0x06, + /* '!' */ 0x80, + /* '"' */ 0x80, + /* '#' */ 0x86, + /* '$' */ 0x80, + /* '%' */ 0x81, + /* '&' */ 0x80, + /* ''' */ 0x00, + /* '(' */ 0x00, + /* ')' */ 0x10, + /* '*' */ 0x03, + /* '+' */ 0x86, + /* ',' */ 0x80, + /* '-' */ 0x86, + /* '.' */ 0x82, + /* '/' */ 0x80, + /* '0' */ 0x14, + /* '1' */ 0x05, + /* '2' */ 0x05, + /* '3' */ 0x45, + /* '4' */ 0x45, + /* '5' */ 0x45, + /* '6' */ 0x85, + /* '7' */ 0x85, + /* '8' */ 0x85, + /* '9' */ 0x05, + /* ':' */ 0x00, + /* ';' */ 0x00, + /* '<' */ 0x30, + /* '=' */ 0x30, + /* '>' */ 0x80, + /* '?' */ 0x50, + /* '@' */ 0x80, + /* 'A' */ 0x80, // Disable %A format + /* 'B' */ 0x00, + /* 'C' */ 0x08, + /* 'D' */ 0x00, + /* 'E' */ 0x28, + /* 'F' */ 0x27, + /* 'G' */ 0x38, + /* 'H' */ 0x50, + /* 'I' */ 0x57, + /* 'J' */ 0x80, + /* 'K' */ 0x00, + /* 'L' */ 0x07, + /* 'M' */ 0x00, + /* 'N' */ 0x37, + /* 'O' */ 0x30, + /* 'P' */ 0x30, + /* 'Q' */ 0x50, + /* 'R' */ 0x50, + /* 'S' */ 0x88, + /* 'T' */ 0x00, + /* 'U' */ 0x00, + /* 'V' */ 0x00, + /* 'W' */ 0x20, + /* 'X' */ 0x28, + /* 'Y' */ 0x80, + /* 'Z' */ 0x88, + /* '[' */ 0x80, + /* '\' */ 0x80, + /* ']' */ 0x00, + /* '^' */ 0x00, + /* '_' */ 0x00, + /* '`' */ 0x60, + /* 'a' */ 0x60, // Disable %a format + /* 'b' */ 0x60, + /* 'c' */ 0x68, + /* 'd' */ 0x68, + /* 'e' */ 0x68, + /* 'f' */ 0x08, + /* 'g' */ 0x08, + /* 'h' */ 0x07, + /* 'i' */ 0x78, + /* 'j' */ 0x70, + /* 'k' */ 0x70, + /* 'l' */ 0x77, + /* 'm' */ 0x70, + /* 'n' */ 0x70, + /* 'o' */ 0x08, + /* 'p' */ 0x08, + /* 'q' */ 0x00, + /* 'r' */ 0x00, + /* 's' */ 0x08, + /* 't' */ 0x00, + /* 'u' */ 0x08, + /* 'v' */ 0x00, + /* 'w' */ 0x07, + /* 'x' */ 0x08 +}; +//#endif /* defined (_UNICODE) || defined (CPRFLAG) */ + +#endif /* FORMAT_VALIDATIONS */ + +#define FIND_CHAR_CLASS(lookuptbl, c) \ + ((c) < _T(' ') || (c) > _T('x') ? \ + CH_OTHER \ + : \ + (enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF)) + +#define FIND_NEXT_STATE(lookuptbl, class, state) \ + (enum STATE)(lookuptbl[(class) * NUMSTATES + (state)] >> 4) + +/* + * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive. + */ + +/* prototypes */ + +#ifdef CPRFLAG + +#define WRITE_CHAR(ch, pnw) write_char(ch, pnw) +#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw) +#define WRITE_STRING(s, len, pnw) write_string(s, len, pnw) + +LOCAL(void) write_char(_TCHAR ch, int *pnumwritten); +LOCAL(void) write_multi_char(_TCHAR ch, int num, int *pnumwritten); +LOCAL(void) write_string(const _TCHAR *string, int len, int *numwritten); + +#else /* CPRFLAG */ + +#define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw) +#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw) +#define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw) + +LOCAL(void) write_char(_TCHAR ch, miniFILE *f, int *pnumwritten); +LOCAL(void) write_multi_char(_TCHAR ch, int num, miniFILE *f, int *pnumwritten); +LOCAL(void) write_string(const _TCHAR *string, int len, miniFILE *f, int *numwritten); + +#endif /* CPRFLAG */ + +#define get_int_arg(list) va_arg(*list, int) +#define get_long_arg(list) va_arg(*list, long) +#define get_long_long_arg(list) va_arg(*list, long long) +#define get_int64_arg(list) va_arg(*list, __int64) +#define get_crtdouble_arg(list) va_arg(*list, _CRT_DOUBLE) +#define get_ptr_arg(list) va_arg(*list, void *) + +#ifdef CPRFLAG +LOCAL(int) output(const _TCHAR *, _locale_t , va_list); +_CRTIMP int __cdecl _vtcprintf_l (const _TCHAR *, _locale_t, va_list); +_CRTIMP int __cdecl _vtcprintf_s_l (const _TCHAR *, _locale_t, va_list); +_CRTIMP int __cdecl _vtcprintf_p_l (const _TCHAR *, _locale_t, va_list); + + +/*** +*int _cprintf(format, arglist) - write formatted output directly to console +* +*Purpose: +* Writes formatted data like printf, but uses console I/O functions. +* +*Entry: +* char *format - format string to determine data formats +* arglist - list of POINTERS to where to put data +* +*Exit: +* returns number of characters written +* +*Exceptions: +* +*******************************************************************************/ +#ifndef FORMAT_VALIDATIONS +_CRTIMP int __cdecl _tcprintf_l ( + const _TCHAR * format, + _locale_t plocinfo, + ... + ) +#else /* FORMAT_VALIDATIONS */ +_CRTIMP int __cdecl _tcprintf_s_l ( + const _TCHAR * format, + _locale_t plocinfo, + ... + ) +#endif /* FORMAT_VALIDATIONS */ + +{ + int ret; + va_list arglist; + va_start(arglist, plocinfo); + +#ifndef FORMAT_VALIDATIONS + ret = _vtcprintf_l(format, plocinfo, arglist); +#else /* FORMAT_VALIDATIONS */ + ret = _vtcprintf_s_l(format, plocinfo, arglist); + +#endif /* FORMAT_VALIDATIONS */ + + va_end(arglist); + + return ret; +} + +#ifndef FORMAT_VALIDATIONS +_CRTIMP int __cdecl _tcprintf ( + const _TCHAR * format, + ... + ) +#else /* FORMAT_VALIDATIONS */ +_CRTIMP int __cdecl _tcprintf_s ( + const _TCHAR * format, + ... + ) +#endif /* FORMAT_VALIDATIONS */ + +{ + int ret; + va_list arglist; + + va_start(arglist, format); + +#ifndef FORMAT_VALIDATIONS + ret = _vtcprintf_l(format, NULL, arglist); +#else /* FORMAT_VALIDATIONS */ + ret = _vtcprintf_s_l(format, NULL, arglist); + +#endif /* FORMAT_VALIDATIONS */ + + va_end(arglist); + + return ret; +} + +#endif /* CPRFLAG */ + + +/*** +*int _output(stream, format, argptr), static int output(format, argptr) +* +*Purpose: +* Output performs printf style output onto a stream. It is called by +* printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty +* work. In multi-thread situations, _output assumes that the given +* stream is already locked. +* +* Algorithm: +* The format string is parsed by using a finite state automaton +* based on the current state and the current character read from +* the format string. Thus, looping is on a per-character basis, +* not a per conversion specifier basis. Once the format specififying +* character is read, output is performed. +* +*Entry: +* FILE *stream - stream for output +* char *format - printf style format string +* va_list argptr - pointer to list of subsidiary arguments +* +*Exit: +* Returns the number of characters written, or -1 if an output error +* occurs. +*ifdef _UNICODE +* The wide-character flavour returns the number of wide-characters written. +*endif +* +*Exceptions: +* +*******************************************************************************/ +#ifdef CPRFLAG +#ifndef FORMAT_VALIDATIONS +_CRTIMP int __cdecl _vtcprintf ( + const _TCHAR *format, + va_list argptr + ) +{ + return _vtcprintf_l(format, NULL, argptr); +} + +#else /* FORMAT_VALIDATIONS */ +_CRTIMP int __cdecl _vtcprintf_s ( + const _TCHAR *format, + va_list argptr + ) +{ + return _vtcprintf_s_l(format, NULL, argptr); +} + +#endif /* FORMAT_VALIDATIONS */ +#endif /* CPRFLAG */ + +#ifdef CPRFLAG +#ifndef FORMAT_VALIDATIONS +_CRTIMP int __cdecl _vtcprintf_l ( +#else /* FORMAT_VALIDATIONS */ +_CRTIMP int __cdecl _vtcprintf_s_l ( +#endif /* FORMAT_VALIDATIONS */ +#else /* CPRFLAG */ + +#ifdef _UNICODE +#ifndef FORMAT_VALIDATIONS +int __cdecl _woutput ( + miniFILE *stream, +#else /* FORMAT_VALIDATIONS */ +int __cdecl _woutput_s ( + miniFILE *stream, +#endif /* FORMAT_VALIDATIONS */ +#else /* _UNICODE */ +#ifndef FORMAT_VALIDATIONS +int __cdecl _output ( + miniFILE *stream, +#else /* FORMAT_VALIDATIONS */ + int __cdecl _output_s ( + miniFILE *stream, + +#endif /* FORMAT_VALIDATIONS */ +#endif /* _UNICODE */ + +#endif /* CPRFLAG */ + const _TCHAR *format, + va_list argptr + ) +{ + int hexadd=0; /* offset to add to number to get 'a'..'f' */ + TCHAR ch; /* character just read */ + int flags=0; /* flag word -- see #defines above for flag values */ + enum STATE state; /* current state */ + enum CHARTYPE chclass; /* class of current character */ + int radix; /* current conversion radix */ + int charsout; /* characters currently written so far, -1 = IO error */ + int fldwidth = 0; /* selected field width -- 0 means default */ + int precision = 0; /* selected precision -- -1 means default */ + TCHAR prefix[2]; /* numeric prefix -- up to two characters */ + int prefixlen=0; /* length of prefix -- 0 means no prefix */ + int capexp = 0; /* non-zero = 'E' exponent signifient, zero = 'e' */ + int no_output=0; /* non-zero = prodcue no output for this specifier */ + union { + const char *sz; /* pointer text to be printed, not zero terminated */ + const wchar_t *wz; + } text; + + int textlen; /* length of the text in bytes/wchars to be printed. + textlen is in multibyte or wide chars if _UNICODE */ + union { + char sz[BUFFERSIZE]; +#ifdef _UNICODE + wchar_t wz[BUFFERSIZE]; +#endif /* _UNICODE */ + } buffer; + wchar_t wchar; /* temp wchar_t */ + int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */ + int bufferiswide=0; /* non-zero = buffer contains wide chars already */ + +#ifndef CPRFLAG + _VALIDATE_RETURN( (stream != NULL), EINVAL, -1); +#endif /* CPRFLAG */ + _VALIDATE_RETURN( (format != NULL), EINVAL, -1); + + charsout = 0; /* no characters written yet */ + textlen = 0; /* no text yet */ + state = ST_NORMAL; /* starting state */ + buffersize = 0; + + /* main loop -- loop while format character exist and no I/O errors */ + while ((ch = *format++) != _T('\0') && charsout >= 0) { +#ifndef FORMAT_VALIDATIONS + chclass = FIND_CHAR_CLASS(__lookuptable, ch); /* find character class */ + state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */ +#else /* FORMAT_VALIDATIONS */ + chclass = FIND_CHAR_CLASS(__lookuptable_s, ch); /* find character class */ + state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */ + + _VALIDATE_RETURN((state != ST_INVALID), EINVAL, -1); + +#endif /* FORMAT_VALIDATIONS */ + + /* execute code for each state */ + switch (state) { + + case ST_NORMAL: + + NORMAL_STATE: + + /* normal state -- just write character */ +#ifdef _UNICODE + bufferiswide = 1; +#else /* _UNICODE */ + bufferiswide = 0; +#endif /* _UNICODE */ + WRITE_CHAR(ch, &charsout); + break; + + case ST_PERCENT: + /* set default value of conversion parameters */ + prefixlen = fldwidth = no_output = capexp = 0; + flags = 0; + precision = -1; + bufferiswide = 0; /* default */ + break; + + case ST_FLAG: + /* set flag based on which flag character */ + switch (ch) { + case _T('-'): + flags |= FL_LEFT; /* '-' => left justify */ + break; + case _T('+'): + flags |= FL_SIGN; /* '+' => force sign indicator */ + break; + case _T(' '): + flags |= FL_SIGNSP; /* ' ' => force sign or space */ + break; + case _T('#'): + flags |= FL_ALTERNATE; /* '#' => alternate form */ + break; + case _T('0'): + flags |= FL_LEADZERO; /* '0' => pad with leading zeros */ + break; + } + break; + + case ST_WIDTH: + /* update width value */ + if (ch == _T('*')) { + /* get width from arg list */ + fldwidth = get_int_arg(&argptr); + if (fldwidth < 0) { + /* ANSI says neg fld width means '-' flag and pos width */ + flags |= FL_LEFT; + fldwidth = -fldwidth; + } + } + else { + /* add digit to current field width */ + fldwidth = fldwidth * 10 + (ch - _T('0')); + } + break; + + case ST_DOT: + /* zero the precision, since dot with no number means 0 + not default, according to ANSI */ + precision = 0; + break; + + case ST_PRECIS: + /* update precison value */ + if (ch == _T('*')) { + /* get precision from arg list */ + precision = get_int_arg(&argptr); + if (precision < 0) + precision = -1; /* neg precision means default */ + } + else { + /* add digit to current precision */ + precision = precision * 10 + (ch - _T('0')); + } + break; + + case ST_SIZE: + /* just read a size specifier, set the flags based on it */ + switch (ch) { + case _T('l'): + /* + * In order to handle the ll case, we depart from the + * simple deterministic state machine. + */ + if (*format == _T('l')) + { + ++format; + flags |= FL_LONGLONG; /* 'll' => long long */ + } + else + { + flags |= FL_LONG; /* 'l' => long int or wchar_t */ + } + break; + + case _T('I'): + /* + * In order to handle the I, I32, and I64 size modifiers, we + * depart from the simple deterministic state machine. The + * code below scans for characters following the 'I', + * and defaults to 64 bit on WIN64 and 32 bit on WIN32 + */ +#if PTR_IS_INT64 + flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */ +#endif /* PTR_IS_INT64 */ + if ( (*format == _T('6')) && (*(format + 1) == _T('4')) ) + { + format += 2; + flags |= FL_I64; /* I64 => __int64 */ + } + else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) ) + { + format += 2; + flags &= ~FL_I64; /* I32 => __int32 */ + } + else if ( (*format == _T('d')) || + (*format == _T('i')) || + (*format == _T('o')) || + (*format == _T('u')) || + (*format == _T('x')) || + (*format == _T('X')) ) + { + /* + * Nothing further needed. %Id (et al) is + * handled just like %d, except that it defaults to 64 bits + * on WIN64. Fall through to the next iteration. + */ + } + else { + state = ST_NORMAL; + goto NORMAL_STATE; + } + break; + + case _T('h'): + flags |= FL_SHORT; /* 'h' => short int or char */ + break; + + case _T('w'): + flags |= FL_WIDECHAR; /* 'w' => wide character */ + break; + + } + break; + + case ST_TYPE: + /* we have finally read the actual type character, so we */ + /* now format and "print" the output. We use a big switch */ + /* statement that sets 'text' to point to the text that should */ + /* be printed, and 'textlen' to the length of this text. */ + /* Common code later on takes care of justifying it and */ + /* other miscellaneous chores. Note that cases share code, */ + /* in particular, all integer formatting is done in one place. */ + /* Look at those funky goto statements! */ + + switch (ch) { + + case _T('C'): /* ISO wide character */ + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) +#ifdef _UNICODE + flags |= FL_SHORT; +#else /* _UNICODE */ + flags |= FL_WIDECHAR; /* ISO std. */ +#endif /* _UNICODE */ + /* fall into 'c' case */ + + case _T('c'): { + /* print a single character specified by int argument */ +#ifdef _UNICODE + bufferiswide = 1; + wchar = (wchar_t) get_int_arg(&argptr); + if (flags & FL_SHORT) { + /* format multibyte character */ + /* this is an extension of ANSI */ + char tempchar[2]; + { + tempchar[0] = (char)(wchar & 0x00ff); + tempchar[1] = '\0'; + } + + if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0) + { + /* ignore if conversion was unsuccessful */ + no_output = 1; + } + } else { + buffer.wz[0] = wchar; + } + text.wz = buffer.wz; + textlen = 1; /* print just a single character */ +#else /* _UNICODE */ + if (flags & (FL_LONG|FL_WIDECHAR)) { + wchar = (wchar_t) get_int_arg(&argptr); + no_output = 1; + } else { + /* format multibyte character */ + /* this is an extension of ANSI */ + unsigned short temp; + wchar = (wchar_t)get_int_arg(&argptr); + temp = (unsigned short)wchar; + { + buffer.sz[0] = (char) temp; + textlen = 1; + } + } + text.sz = buffer.sz; +#endif /* _UNICODE */ + } + break; + + case _T('Z'): { + /* print a Counted String */ + struct _count_string { + short Length; + short MaximumLength; + char *Buffer; + } *pstr; + + pstr = (struct _count_string *)get_ptr_arg(&argptr); + if (pstr == NULL || pstr->Buffer == NULL) { + /* null ptr passed, use special string */ + text.sz = __nullstring; + textlen = (int)strlen(text.sz); + } else { + if (flags & FL_WIDECHAR) { + text.wz = (wchar_t *)pstr->Buffer; + textlen = pstr->Length / (int)sizeof(wchar_t); + bufferiswide = 1; + } else { + bufferiswide = 0; + text.sz = pstr->Buffer; + textlen = pstr->Length; + } + } + } + break; + + case _T('S'): /* ISO wide character string */ +#ifndef _UNICODE + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) + flags |= FL_WIDECHAR; +#else /* _UNICODE */ + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) + flags |= FL_SHORT; +#endif /* _UNICODE */ + + case _T('s'): { + /* print a string -- */ + /* ANSI rules on how much of string to print: */ + /* all if precision is default, */ + /* min(precision, length) if precision given. */ + /* prints '(null)' if a null string is passed */ + + int i; + const char *p; /* temps */ + const wchar_t *pwch; + + /* At this point it is tempting to use strlen(), but */ + /* if a precision is specified, we're not allowed to */ + /* scan past there, because there might be no null */ + /* at all. Thus, we must do our own scan. */ + + i = (precision == -1) ? INT_MAX : precision; + text.sz = (char *)get_ptr_arg(&argptr); + + /* scan for null upto i characters */ +#ifdef _UNICODE + if (flags & FL_SHORT) { + if (text.sz == NULL) /* NULL passed, use special string */ + text.sz = __nullstring; + p = text.sz; + for (textlen=0; textlen<i && *p; textlen++) { + ++p; + } + /* textlen now contains length in multibyte chars */ + } else { + if (text.wz == NULL) /* NULL passed, use special string */ + text.wz = __wnullstring; + bufferiswide = 1; + pwch = text.wz; + while (i-- && *pwch) + ++pwch; + textlen = (int)(pwch - text.wz); /* in wchar_ts */ + /* textlen now contains length in wide chars */ + } +#else /* _UNICODE */ + if (flags & (FL_LONG|FL_WIDECHAR)) { + if (text.wz == NULL) /* NULL passed, use special string */ + text.wz = __wnullstring; + bufferiswide = 1; + pwch = text.wz; + while ( i-- && *pwch ) + ++pwch; + textlen = (int)(pwch - text.wz); + /* textlen now contains length in wide chars */ + } else { + if (text.sz == NULL) /* NULL passed, use special string */ + text.sz = __nullstring; + p = text.sz; + while (i-- && *p) + ++p; + textlen = (int)(p - text.sz); /* length of the string */ + } + +#endif /* _UNICODE */ + } + break; + + + case _T('n'): { + /* write count of characters seen so far into */ + /* short/int/long thru ptr read from args */ + + void *p; /* temp */ + + p = get_ptr_arg(&argptr); + + /* %n is disabled */ + _VALIDATE_RETURN(("'n' format specifier disabled" && 0), EINVAL, -1); + break; + + /* store chars out into short/long/int depending on flags */ +#if !LONG_IS_INT + if (flags & FL_LONG) + *(long *)p = charsout; + else +#endif /* !LONG_IS_INT */ + +#if !SHORT_IS_INT + if (flags & FL_SHORT) + *(short *)p = (short) charsout; + else +#endif /* !SHORT_IS_INT */ + *(int *)p = charsout; + + no_output = 1; /* force no output */ + } + break; + + case _T('E'): + case _T('G'): + case _T('A'): + capexp = 1; /* capitalize exponent */ + ch += _T('a') - _T('A'); /* convert format char to lower */ + /* DROP THROUGH */ + case _T('e'): + case _T('f'): + case _T('g'): + case _T('a'): { + /* floating point conversion -- we call cfltcvt routines */ + /* to do the work for us. */ + flags |= FL_SIGNED; /* floating point is signed conversion */ + text.sz = buffer.sz; /* put result in buffer */ + buffersize = BUFFERSIZE; + + /* compute the precision value */ + if (precision < 0) + precision = 6; /* default precision: 6 */ + else if (precision == 0 && ch == _T('g')) + precision = 1; /* ANSI specified */ + else if (precision > MAXPRECISION) + precision = MAXPRECISION; + + if (precision > BUFFERSIZE - _CVTBUFSIZE) { + /* cap precision further */ + precision = BUFFERSIZE - _CVTBUFSIZE; + } + + /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */ + if (flags & FL_ALTERNATE) + { + capexp |= FL_ALTERNATE; + } + + _CRT_DOUBLE tmp; + tmp=va_arg(argptr, _CRT_DOUBLE); + /* Note: assumes ch is in ASCII range */ + /* In safecrt, we provide a special version of _cfltcvt which internally calls printf (see safecrt_output_s.c) */ + _CFLTCVT(&tmp, buffer.sz, buffersize, (char)ch, precision, capexp); + + /* check if result was negative, save '-' for later */ + /* and point to positive part (this is for '0' padding) */ + if (*text.sz == '-') { + flags |= FL_NEGATIVE; + ++text.sz; + } + + textlen = (int)strlen(text.sz); /* compute length of text */ + } + break; + + case _T('d'): + case _T('i'): + /* signed decimal output */ + flags |= FL_SIGNED; + radix = 10; + goto COMMON_INT; + + case _T('u'): + radix = 10; + goto COMMON_INT; + + case _T('p'): + /* write a pointer -- this is like an integer or long */ + /* except we force precision to pad with zeros and */ + /* output in big hex. */ + + precision = 2 * sizeof(void *); /* number of hex digits needed */ +#if PTR_IS_INT64 + flags |= FL_I64; /* assume we're converting an int64 */ +#elif !PTR_IS_INT + flags |= FL_LONG; /* assume we're converting a long */ +#endif /* !PTR_IS_INT */ + /* DROP THROUGH to hex formatting */ + + case _T('X'): + /* unsigned upper hex output */ + hexadd = _T('A') - _T('9') - 1; /* set hexadd for uppercase hex */ + goto COMMON_HEX; + + case _T('x'): + /* unsigned lower hex output */ + hexadd = _T('a') - _T('9') - 1; /* set hexadd for lowercase hex */ + /* DROP THROUGH TO COMMON_HEX */ + + COMMON_HEX: + radix = 16; + if (flags & FL_ALTERNATE) { + /* alternate form means '0x' prefix */ + prefix[0] = _T('0'); + prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd); /* 'x' or 'X' */ + prefixlen = 2; + } + goto COMMON_INT; + + case _T('o'): + /* unsigned octal output */ + radix = 8; + if (flags & FL_ALTERNATE) { + /* alternate form means force a leading 0 */ + flags |= FL_FORCEOCTAL; + } + /* DROP THROUGH to COMMON_INT */ + + COMMON_INT: { + /* This is the general integer formatting routine. */ + /* Basically, we get an argument, make it positive */ + /* if necessary, and convert it according to the */ + /* correct radix, setting text and textlen */ + /* appropriately. */ + +#if _INTEGRAL_MAX_BITS >= 64 + uint64_t number; /* number to convert */ + int digit; /* ascii value of digit */ + __int64 l; /* temp long value */ +#else /* _INTEGRAL_MAX_BITS >= 64 */ + unsigned long number; /* number to convert */ + int digit; /* ascii value of digit */ + long l; /* temp long value */ +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + + /* 1. read argument into l, sign extend as needed */ +#if _INTEGRAL_MAX_BITS >= 64 + if (flags & FL_I64) + l = get_int64_arg(&argptr); + else +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + + if (flags & FL_LONGLONG) + l = get_long_long_arg(&argptr); + + else + +#if !LONG_IS_INT + if (flags & FL_LONG) + l = get_long_arg(&argptr); + else +#endif /* !LONG_IS_INT */ + +#if !SHORT_IS_INT + if (flags & FL_SHORT) { + if (flags & FL_SIGNED) + l = (short) get_int_arg(&argptr); /* sign extend */ + else + l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/ + + } else +#endif /* !SHORT_IS_INT */ + { + if (flags & FL_SIGNED) + l = get_int_arg(&argptr); /* sign extend */ + else + l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/ + } + + /* 2. check for negative; copy into number */ + if ( (flags & FL_SIGNED) && l < 0) { + number = -l; + flags |= FL_NEGATIVE; /* remember negative sign */ + } else { + number = l; + } + +#if _INTEGRAL_MAX_BITS >= 64 + if ( (flags & FL_I64) == 0 && (flags & FL_LONGLONG) == 0 ) { + /* + * Unless printing a full 64-bit value, insure values + * here are not in cananical longword format to prevent + * the sign extended upper 32-bits from being printed. + */ + number &= 0xffffffff; + } +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + + /* 3. check precision value for default; non-default */ + /* turns off 0 flag, according to ANSI. */ + if (precision < 0) + precision = 1; /* default precision */ + else { + flags &= ~FL_LEADZERO; + if (precision > MAXPRECISION) + precision = MAXPRECISION; + } + + /* 4. Check if data is 0; if so, turn off hex prefix */ + if (number == 0) + prefixlen = 0; + + /* 5. Convert data to ASCII -- note if precision is zero */ + /* and number is zero, we get no digits at all. */ + + char *sz; + sz = &buffer.sz[BUFFERSIZE-1]; /* last digit at end of buffer */ + + while (precision-- > 0 || number != 0) { + digit = (int)(number % radix) + '0'; + number /= radix; /* reduce number */ + if (digit > '9') { + /* a hex digit, make it a letter */ + digit += hexadd; + } + *sz-- = (char)digit; /* store the digit */ + } + + textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - sz); /* compute length of number */ + ++sz; /* text points to first digit now */ + + + /* 6. Force a leading zero if FORCEOCTAL flag set */ + if ((flags & FL_FORCEOCTAL) && (textlen == 0 || sz[0] != '0')) { + *--sz = '0'; + ++textlen; /* add a zero */ + } + + text.sz = sz; + } + break; + } + + + /* At this point, we have done the specific conversion, and */ + /* 'text' points to text to print; 'textlen' is length. Now we */ + /* justify it, put on prefixes, leading zeros, and then */ + /* print it. */ + + if (!no_output) { + int padding; /* amount of padding, negative means zero */ + + if (flags & FL_SIGNED) { + if (flags & FL_NEGATIVE) { + /* prefix is a '-' */ + prefix[0] = _T('-'); + prefixlen = 1; + } + else if (flags & FL_SIGN) { + /* prefix is '+' */ + prefix[0] = _T('+'); + prefixlen = 1; + } + else if (flags & FL_SIGNSP) { + /* prefix is ' ' */ + prefix[0] = _T(' '); + prefixlen = 1; + } + } + + /* calculate amount of padding -- might be negative, */ + /* but this will just mean zero */ + padding = fldwidth - textlen - prefixlen; + + /* put out the padding, prefix, and text, in the correct order */ + + if (!(flags & (FL_LEFT | FL_LEADZERO))) { + /* pad on left with blanks */ + WRITE_MULTI_CHAR(_T(' '), padding, &charsout); + } + + /* write prefix */ + WRITE_STRING(prefix, prefixlen, &charsout); + + if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) { + /* write leading zeros */ + WRITE_MULTI_CHAR(_T('0'), padding, &charsout); + } + + /* write text */ +#ifndef _UNICODE + if (bufferiswide && (textlen > 0)) { + charsout = -1; + } else { + WRITE_STRING(text.sz, textlen, &charsout); + } +#else /* _UNICODE */ + if (!bufferiswide && textlen > 0) { + const char *p; + int retval = 0; + int count; + + p = text.sz; + count = textlen; + while (count-- > 0) { + retval = _MBTOWC(&wchar, p, MB_CUR_MAX); + if (retval <= 0) { + charsout = -1; + break; + } + WRITE_CHAR(wchar, &charsout); + p += retval; + } + } else { + WRITE_STRING(text.wz, textlen, &charsout); + } +#endif /* _UNICODE */ + + if (charsout >= 0 && (flags & FL_LEFT)) { + /* pad on right with blanks */ + WRITE_MULTI_CHAR(_T(' '), padding, &charsout); + } + + /* we're done! */ + } + break; + case ST_INVALID: + _VALIDATE_RETURN(0 /* FALSE */, EINVAL, -1); + break; + } + } + +#ifdef FORMAT_VALIDATIONS + /* The format string shouldn't be incomplete - i.e. when we are finished + with the format string, the last thing we should have encountered + should have been a regular char to be output or a type specifier. Else + the format string was incomplete */ + _VALIDATE_RETURN(((state == ST_NORMAL) || (state == ST_TYPE)), EINVAL, -1); +#endif /* FORMAT_VALIDATIONS */ + + return charsout; /* return value = number of characters written */ +} + +/* + * Future Optimizations for swprintf: + * - Don't free the memory used for converting the buffer to wide chars. + * Use realloc if the memory is not sufficient. Free it at the end. + */ + +/*** +*void write_char(char ch, int *pnumwritten) +*ifdef _UNICODE +*void write_char(wchar_t ch, FILE *f, int *pnumwritten) +*endif +*void write_char(char ch, FILE *f, int *pnumwritten) +* +*Purpose: +* Writes a single character to the given file/console. If no error occurs, +* then *pnumwritten is incremented; otherwise, *pnumwritten is set +* to -1. +* +*Entry: +* _TCHAR ch - character to write +* FILE *f - file to write to +* int *pnumwritten - pointer to integer to update with total chars written +* +*Exit: +* No return value. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef CPRFLAG + +LOCAL(void) write_char ( + _TCHAR ch, + int *pnumwritten + ) +{ +#ifdef _UNICODE + if (_putwch_nolock(ch) == WEOF) +#else /* _UNICODE */ + if (_putch_nolock(ch) == EOF) +#endif /* _UNICODE */ + *pnumwritten = -1; + else + ++(*pnumwritten); +} + +#else /* CPRFLAG */ + +LOCAL(void) write_char ( + _TCHAR ch, + miniFILE *f, + int *pnumwritten + ) +{ + if ( (f->_flag & _IOSTRG) && f->_base == NULL) + { + ++(*pnumwritten); + return; + } +#ifdef _UNICODE + if (_putwc_nolock(ch, f) == WEOF) +#else /* _UNICODE */ + if (_putc_nolock(ch, f) == EOF) +#endif /* _UNICODE */ + *pnumwritten = -1; + else + ++(*pnumwritten); +} + +#endif /* CPRFLAG */ + +/*** +*void write_multi_char(char ch, int num, int *pnumwritten) +*ifdef _UNICODE +*void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten) +*endif +*void write_multi_char(char ch, int num, FILE *f, int *pnumwritten) +* +*Purpose: +* Writes num copies of a character to the given file/console. If no error occurs, +* then *pnumwritten is incremented by num; otherwise, *pnumwritten is set +* to -1. If num is negative, it is treated as zero. +* +*Entry: +* _TCHAR ch - character to write +* int num - number of times to write the characters +* FILE *f - file to write to +* int *pnumwritten - pointer to integer to update with total chars written +* +*Exit: +* No return value. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef CPRFLAG +LOCAL(void) write_multi_char ( + _TCHAR ch, + int num, + int *pnumwritten + ) +{ + while (num-- > 0) { + write_char(ch, pnumwritten); + if (*pnumwritten == -1) + break; + } +} + +#else /* CPRFLAG */ + +LOCAL(void) write_multi_char ( + _TCHAR ch, + int num, + miniFILE *f, + int *pnumwritten + ) +{ + while (num-- > 0) { + write_char(ch, f, pnumwritten); + if (*pnumwritten == -1) + break; + } +} + +#endif /* CPRFLAG */ + +/*** +*void write_string(const char *string, int len, int *pnumwritten) +*void write_string(const char *string, int len, FILE *f, int *pnumwritten) +*ifdef _UNICODE +*void write_string(const wchar_t *string, int len, FILE *f, int *pnumwritten) +*endif +* +*Purpose: +* Writes a string of the given length to the given file. If no error occurs, +* then *pnumwritten is incremented by len; otherwise, *pnumwritten is set +* to -1. If len is negative, it is treated as zero. +* +*Entry: +* _TCHAR *string - string to write (NOT null-terminated) +* int len - length of string +* FILE *f - file to write to +* int *pnumwritten - pointer to integer to update with total chars written +* +*Exit: +* No return value. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef CPRFLAG + +LOCAL(void) write_string ( + const _TCHAR *string, + int len, + int *pnumwritten + ) +{ + while (len-- > 0) { + write_char(*string++, pnumwritten); + if (*pnumwritten == -1) + { + if (errno == EILSEQ) + write_char(_T('?'), pnumwritten); + else + break; + } + } +} + +#else /* CPRFLAG */ + +LOCAL(void) write_string ( + const _TCHAR *string, + int len, + miniFILE *f, + int *pnumwritten + ) +{ + if ( (f->_flag & _IOSTRG) && f->_base == NULL) + { + (*pnumwritten) += len; + return; + } + while (len-- > 0) { + write_char(*string++, f, pnumwritten); + if (*pnumwritten == -1) + { + if (errno == EILSEQ) + write_char(_T('?'), f, pnumwritten); + else + break; + } + } +} +#endif /* CPRFLAG */ diff --git a/src/pal/src/safecrt/safecrt_input_s.c b/src/pal/src/safecrt/safecrt_input_s.c new file mode 100644 index 0000000000..6ba607c669 --- /dev/null +++ b/src/pal/src/safecrt/safecrt_input_s.c @@ -0,0 +1,46 @@ +// 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_input_s.c - implementation of the _input family for safecrt.lib +* + +* +*Purpose: +* This file contains the implementation of the _input family for safecrt.lib. +* +*Revision History: +* 07/19/04 AC Created +* +****/ + +#define _SAFECRT_IMPL +#define _SECURE_SCANF + +#include "pal/palinternal.h" +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <locale.h> +#include <stdarg.h> +#include <inttypes.h> + +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _TCHAR CRT_TCHAR +#define TCHAR CRTTCHAR + +typedef char _TCHAR; +typedef char TCHAR; +typedef unsigned char _TUCHAR; +#define _T(x) x +#define _TEOF EOF + +#define _gettc_nolock(x) _getc_nolock(x) +#define _ungettc_nolock(x,y) _ungetc_nolock(x,y) + +#include "input.inl" diff --git a/src/pal/src/safecrt/safecrt_output_l.c b/src/pal/src/safecrt/safecrt_output_l.c new file mode 100644 index 0000000000..d6844f4f8b --- /dev/null +++ b/src/pal/src/safecrt/safecrt_output_l.c @@ -0,0 +1,1467 @@ +// 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_output_l.c - implementation of the _output family for safercrt.lib +* + +* +*Purpose: +* This file contains the implementation of the _output family for safercrt.lib. +* +*Revision History: +* 07-08-04 SJ Stub module created. +* 07-13-04 AC Added support for floating-point types. +* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll +* based on the _NTSUBSET_ #define +* 09-24-04 MSL Prefix disallow NULL deref +* +****/ + +#define _SAFECRT_IMPL + +#define __STDC_LIMIT_MACROS +#include "pal/palinternal.h" +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <inttypes.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _CFLTCVT _safecrt_cfltcvt + +//typedef __int64_t __int64; +typedef double _CRT_DOUBLE; +typedef char _TCHAR; +typedef char TCHAR; +#define _T(x) x +/* +Buffer size required to be passed to _gcvt, fcvt and other fp conversion routines +*/ +#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */ + +//------------------------------------------------------------------------------ +// This code was taken from the 'ouput.c' file located in Visual Studio 8 (i.e. 2005) +// in the '\Microsoft Visual Studio 8\VC\crt\src' directory. It was moved into +// this file to support only the '_output' function used by _vscprintf() in vsprintf.c +// UNUSED / NON-RELEVANT PORTIONS OF THE CODE HAVE BEEN REMOVED - do not try and +// use it to generate any other safecrt 'output' functions +// +// Noteable modifications +// - changed FILE to miniFILE (defined in mbusafecrt_internal.h) +// - removed _soutput_s - it was unused in this case and conflicted with output.inl +// - changed #define SHORT_IS_INT to true varargs promotes shorts to ints in GCC +// - removed definition of __lookuptable_s when using FORMAT_VALIDATIONS, we don't use them + +// 7/03/07 - Created by Stephen Shaw (steshaw) +//------------------------------------------------------------------------------ + + +/* temporary work-around for compiler without 64-bit support */ +#ifndef _INTEGRAL_MAX_BITS +#define _INTEGRAL_MAX_BITS 64 +#endif /* _INTEGRAL_MAX_BITS */ + +#include <limits.h> +#include <string.h> +#include <stddef.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> + +#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y ) + +#undef _malloc_crt +#define _malloc_crt malloc + +#undef _free_crt +#define _free_crt free + +// SNIP -srs 7/3/07 + +#ifndef _CFLTCVT +#define _CFLTCVT _cfltcvt +#endif /* _CFLTCVT */ + +#ifndef _CLDCVT +#define _CLDCVT _cldcvt +#endif /* _CLDCVT */ + +#ifdef _MBCS +#undef _MBCS +#endif /* _MBCS */ +//#include <tchar.h> + +/* this macro defines a function which is private and as fast as possible: */ +/* for example, in C 6.0, it might be static _fastcall <type> near. */ +#define LOCAL(x) static x __cdecl + +/* int/long/short/pointer sizes */ + +/* the following should be set depending on the sizes of various types */ +#if __LP64__ + #define LONG_IS_INT 0 + CASSERT(sizeof(long) > sizeof(int)); +#else + #define LONG_IS_INT 1 /* 1 means long is same size as int */ + CASSERT(sizeof(long) == sizeof(int)); +#endif + +// GCC: short is not int, but GCC promotes va_arg to int +#define SHORT_IS_INT 1 + +#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 */ + CASSERT(sizeof(long long) == sizeof(int64_t)); + +#if defined (_WIN64) + #define PTR_IS_INT 0 /* 1 means ptr is same size as int */ + CASSERT(sizeof(void *) != sizeof(int)); + #if __LP64__ + #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */ + CASSERT(sizeof(void *) == sizeof(long)); + #else + #define PTR_IS_LONG 0 /* 1 means ptr is same size as long */ + CASSERT(sizeof(void *) != sizeof(long)); + #endif + #define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */ + CASSERT(sizeof(void *) == sizeof(int64_t)); +#else /* defined (_WIN64) */ + #define PTR_IS_INT 1 /* 1 means ptr is same size as int */ + CASSERT(sizeof(void *) == sizeof(int)); + #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */ + CASSERT(sizeof(void *) == sizeof(long)); + #define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */ + CASSERT(sizeof(void *) != sizeof(int64_t)); +#endif /* defined (_WIN64) */ + +/* CONSTANTS */ + +/* size of conversion buffer (ANSI-specified minimum is 509) */ + +#define BUFFERSIZE 512 +#define MAXPRECISION BUFFERSIZE + +#if BUFFERSIZE < _CVTBUFSIZE + 6 +/* + * Buffer needs to be big enough for default minimum precision + * when converting floating point needs bigger buffer, and malloc + * fails + */ +#error Conversion buffer too small for max double. +#endif /* BUFFERSIZE < _CVTBUFSIZE + 6 */ + +/* flag definitions */ +#define FL_SIGN 0x00001 /* put plus or minus in front */ +#define FL_SIGNSP 0x00002 /* put space or minus in front */ +#define FL_LEFT 0x00004 /* left justify */ +#define FL_LEADZERO 0x00008 /* pad with leading zeros */ +#define FL_LONG 0x00010 /* long value given */ +#define FL_SHORT 0x00020 /* short value given */ +#define FL_SIGNED 0x00040 /* signed data given */ +#define FL_ALTERNATE 0x00080 /* alternate form requested */ +#define FL_NEGATIVE 0x00100 /* value is negative */ +#define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */ +#define FL_LONGDOUBLE 0x00400 /* long double value given */ +#define FL_WIDECHAR 0x00800 /* wide characters */ +#define FL_LONGLONG 0x01000 /* long long value given */ +#define FL_I64 0x08000 /* __int64 value given */ + +/* state definitions */ +enum STATE { + ST_NORMAL, /* normal state; outputting literal chars */ + ST_PERCENT, /* just read '%' */ + ST_FLAG, /* just read flag character */ + ST_WIDTH, /* just read width specifier */ + ST_DOT, /* just read '.' */ + ST_PRECIS, /* just read precision specifier */ + ST_SIZE, /* just read size specifier */ + ST_TYPE /* just read type specifier */ +#ifdef FORMAT_VALIDATIONS + ,ST_INVALID /* Invalid format */ +#endif /* FORMAT_VALIDATIONS */ + +}; + +#ifdef FORMAT_VALIDATIONS +#define NUMSTATES (ST_INVALID + 1) +#else /* FORMAT_VALIDATIONS */ +#define NUMSTATES (ST_TYPE + 1) +#endif /* FORMAT_VALIDATIONS */ + +/* character type values */ +enum CHARTYPE { + CH_OTHER, /* character with no special meaning */ + CH_PERCENT, /* '%' */ + CH_DOT, /* '.' */ + CH_STAR, /* '*' */ + CH_ZERO, /* '0' */ + CH_DIGIT, /* '1'..'9' */ + CH_FLAG, /* ' ', '+', '-', '#' */ + CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */ + CH_TYPE /* type specifying character */ +}; + +/* static data (read only, since we are re-entrant) */ +#if defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) +extern const char __nullstring[]; /* string to print on null ptr */ +extern const wchar_t __wnullstring[]; /* string to print on null ptr */ +#else /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */ +static const char __nullstring[] = "(null)"; /* string to print on null ptr */ +static const wchar_t __wnullstring[] = { '(', 'n', 'u', 'l', 'l', ')', '\0' };/* string to print on null ptr */ +#endif /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */ + +/* The state table. This table is actually two tables combined into one. */ +/* The lower nybble of each byte gives the character class of any */ +/* character; while the uper nybble of the byte gives the next state */ +/* to enter. See the macros below the table for details. */ +/* */ +/* The table is generated by maketabc.c -- use this program to make */ +/* changes. */ + +#ifndef FORMAT_VALIDATIONS +#if defined (_UNICODE) || defined (CPRFLAG) +extern const char __lookuptable[]; +#else /* defined (_UNICODE) || defined (CPRFLAG) */ +//extern const char __lookuptable[] = { +const char __lookuptable[] = { + /* ' ' */ 0x06, + /* '!' */ 0x00, + /* '"' */ 0x00, + /* '#' */ 0x06, + /* '$' */ 0x00, + /* '%' */ 0x01, + /* '&' */ 0x00, + /* ''' */ 0x00, + /* '(' */ 0x10, + /* ')' */ 0x00, + /* '*' */ 0x03, + /* '+' */ 0x06, + /* ',' */ 0x00, + /* '-' */ 0x06, + /* '.' */ 0x02, + /* '/' */ 0x10, + /* '0' */ 0x04, + /* '1' */ 0x45, + /* '2' */ 0x45, + /* '3' */ 0x45, + /* '4' */ 0x05, + /* '5' */ 0x05, + /* '6' */ 0x05, + /* '7' */ 0x05, + /* '8' */ 0x05, + /* '9' */ 0x35, + /* ':' */ 0x30, + /* ';' */ 0x00, + /* '<' */ 0x50, + /* '=' */ 0x00, + /* '>' */ 0x00, + /* '?' */ 0x00, + /* '@' */ 0x00, + /* 'A' */ 0x20, // Disable %A format + /* 'B' */ 0x20, + /* 'C' */ 0x38, + /* 'D' */ 0x50, + /* 'E' */ 0x58, + /* 'F' */ 0x07, + /* 'G' */ 0x08, + /* 'H' */ 0x00, + /* 'I' */ 0x37, + /* 'J' */ 0x30, + /* 'K' */ 0x30, + /* 'L' */ 0x57, + /* 'M' */ 0x50, + /* 'N' */ 0x07, + /* 'O' */ 0x00, + /* 'P' */ 0x00, + /* 'Q' */ 0x20, + /* 'R' */ 0x20, + /* 'S' */ 0x08, + /* 'T' */ 0x00, + /* 'U' */ 0x00, + /* 'V' */ 0x00, + /* 'W' */ 0x00, + /* 'X' */ 0x08, + /* 'Y' */ 0x60, + /* 'Z' */ 0x68, + /* '[' */ 0x60, + /* '\' */ 0x60, + /* ']' */ 0x60, + /* '^' */ 0x60, + /* '_' */ 0x00, + /* '`' */ 0x00, + /* 'a' */ 0x70, // Disable %a format + /* 'b' */ 0x70, + /* 'c' */ 0x78, + /* 'd' */ 0x78, + /* 'e' */ 0x78, + /* 'f' */ 0x78, + /* 'g' */ 0x08, + /* 'h' */ 0x07, + /* 'i' */ 0x08, + /* 'j' */ 0x00, + /* 'k' */ 0x00, + /* 'l' */ 0x07, + /* 'm' */ 0x00, + /* 'n' */ 0x00, // Disable %n format + /* 'o' */ 0x08, + /* 'p' */ 0x08, + /* 'q' */ 0x00, + /* 'r' */ 0x00, + /* 's' */ 0x08, + /* 't' */ 0x00, + /* 'u' */ 0x08, + /* 'v' */ 0x00, + /* 'w' */ 0x07, + /* 'x' */ 0x08 +}; + +#endif /* defined (_UNICODE) || defined (CPRFLAG) */ + +#else /* FORMAT_VALIDATIONS */ +// SNIP -srs 7/3/07 +#error code has been removed +#endif /* FORMAT_VALIDATIONS */ + +#define FIND_CHAR_CLASS(lookuptbl, c) \ + ((c) < _T(' ') || (c) > _T('x') ? \ + CH_OTHER \ + : \ + (enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF)) + +#define FIND_NEXT_STATE(lookuptbl, class, state) \ + (enum STATE)(lookuptbl[(class) * NUMSTATES + (state)] >> 4) + +/* + * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive. + */ + +/* prototypes */ + +#ifdef CPRFLAG + +#define WRITE_CHAR(ch, pnw) write_char(ch, pnw) +#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw) +#define WRITE_STRING(s, len, pnw) write_string(s, len, pnw) +#define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, pnw) + +LOCAL(void) write_char(_TCHAR ch, int *pnumwritten); +LOCAL(void) write_multi_char(_TCHAR ch, int num, int *pnumwritten); +LOCAL(void) write_string(const _TCHAR *string, int len, int *numwritten); +LOCAL(void) write_wstring(const wchar_t *string, int len, int *numwritten); + +#else /* CPRFLAG */ + +#define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw) +#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw) +#define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw) +#define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, stream, pnw) + +LOCAL(void) write_char(_TCHAR ch, miniFILE *f, int *pnumwritten); +LOCAL(void) write_multi_char(_TCHAR ch, int num, miniFILE *f, int *pnumwritten); +LOCAL(void) write_string(const _TCHAR *string, int len, miniFILE *f, int *numwritten); +//LOCAL(void) write_wstring(const wchar_t *string, int len, miniFILE *f, int *numwritten); + +#endif /* CPRFLAG */ + +#define get_short_arg(list) va_arg(*list, int) // GCC promotes va_arg shorts into int values +#define get_int_arg(list) va_arg(*list, int) +#define get_long_arg(list) va_arg(*list, long) +#define get_long_long_arg(list) va_arg(*list, long long) +#define get_int64_arg(list) va_arg(*list, __int64) +#define get_crtdouble_arg(list) va_arg(*list, _CRT_DOUBLE) +#define get_ptr_arg(list) va_arg(*list, void *) + +#ifdef CPRFLAG +LOCAL(int) output(const _TCHAR *, _locale_t , va_list); +_CRTIMP int __cdecl _vtcprintf_l (const _TCHAR *, _locale_t, va_list); +_CRTIMP int __cdecl _vtcprintf_s_l (const _TCHAR *, _locale_t, va_list); +_CRTIMP int __cdecl _vtcprintf_p_l (const _TCHAR *, _locale_t, va_list); + + +/*** +*int _cprintf(format, arglist) - write formatted output directly to console +* +*Purpose: +* Writes formatted data like printf, but uses console I/O functions. +* +*Entry: +* char *format - format string to determine data formats +* arglist - list of POINTERS to where to put data +* +*Exit: +* returns number of characters written +* +*Exceptions: +* +*******************************************************************************/ +#ifndef FORMAT_VALIDATIONS +_CRTIMP int __cdecl _tcprintf_l ( + const _TCHAR * format, + _locale_t plocinfo, + ... + ) +#else /* FORMAT_VALIDATIONS */ +_CRTIMP int __cdecl _tcprintf_s_l ( + const _TCHAR * format, + _locale_t plocinfo, + ... + ) +#endif /* FORMAT_VALIDATIONS */ + +{ + int ret; + va_list arglist; + va_start(arglist, plocinfo); + +#ifndef FORMAT_VALIDATIONS + ret = _vtcprintf_l(format, plocinfo, arglist); +#else /* FORMAT_VALIDATIONS */ + ret = _vtcprintf_s_l(format, plocinfo, arglist); + +#endif /* FORMAT_VALIDATIONS */ + + va_end(arglist); + + return ret; +} + +#ifndef FORMAT_VALIDATIONS +_CRTIMP int __cdecl _tcprintf ( + const _TCHAR * format, + ... + ) +#else /* FORMAT_VALIDATIONS */ +_CRTIMP int __cdecl _tcprintf_s ( + const _TCHAR * format, + ... + ) +#endif /* FORMAT_VALIDATIONS */ + +{ + int ret; + va_list arglist; + + va_start(arglist, format); + +#ifndef FORMAT_VALIDATIONS + ret = _vtcprintf_l(format, NULL, arglist); +#else /* FORMAT_VALIDATIONS */ + ret = _vtcprintf_s_l(format, NULL, arglist); + +#endif /* FORMAT_VALIDATIONS */ + + va_end(arglist); + + return ret; +} + +#endif /* CPRFLAG */ + + +/*** +*int _output(stream, format, argptr), static int output(format, argptr) +* +*Purpose: +* Output performs printf style output onto a stream. It is called by +* printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty +* work. In multi-thread situations, _output assumes that the given +* stream is already locked. +* +* Algorithm: +* The format string is parsed by using a finite state automaton +* based on the current state and the current character read from +* the format string. Thus, looping is on a per-character basis, +* not a per conversion specifier basis. Once the format specififying +* character is read, output is performed. +* +*Entry: +* FILE *stream - stream for output +* char *format - printf style format string +* va_list argptr - pointer to list of subsidiary arguments +* +*Exit: +* Returns the number of characters written, or -1 if an output error +* occurs. +*ifdef _UNICODE +* The wide-character flavour returns the number of wide-characters written. +*endif +* +*Exceptions: +* +*******************************************************************************/ +#ifdef CPRFLAG +#ifndef FORMAT_VALIDATIONS +_CRTIMP int __cdecl _vtcprintf ( + const _TCHAR *format, + va_list argptr + ) +{ + return _vtcprintf_l(format, NULL, argptr); +} + +#else /* FORMAT_VALIDATIONS */ +_CRTIMP int __cdecl _vtcprintf_s ( + const _TCHAR *format, + va_list argptr + ) +{ + return _vtcprintf_s_l(format, NULL, argptr); +} + +#endif /* FORMAT_VALIDATIONS */ +#endif /* CPRFLAG */ + +#ifdef CPRFLAG +#ifndef FORMAT_VALIDATIONS +_CRTIMP int __cdecl _vtcprintf_l ( +#else /* FORMAT_VALIDATIONS */ +_CRTIMP int __cdecl _vtcprintf_s_l ( +#endif /* FORMAT_VALIDATIONS */ +#else /* CPRFLAG */ + +#ifdef _UNICODE +#ifndef FORMAT_VALIDATIONS +int __cdecl _woutput ( + miniFILE *stream, +#else /* FORMAT_VALIDATIONS */ +int __cdecl _woutput_s ( + miniFILE *stream, +#endif /* FORMAT_VALIDATIONS */ +#else /* _UNICODE */ +#ifndef FORMAT_VALIDATIONS +int __cdecl _output ( + miniFILE *stream, +#else /* FORMAT_VALIDATIONS */ + int __cdecl _output_s ( + miniFILE *stream, + +#endif /* FORMAT_VALIDATIONS */ +#endif /* _UNICODE */ + +#endif /* CPRFLAG */ + const _TCHAR *format, + va_list argptr + ) +{ + int hexadd=0; /* offset to add to number to get 'a'..'f' */ + TCHAR ch; /* character just read */ + int flags=0; /* flag word -- see #defines above for flag values */ + enum STATE state; /* current state */ + enum CHARTYPE chclass; /* class of current character */ + int radix; /* current conversion radix */ + int charsout; /* characters currently written so far, -1 = IO error */ + int fldwidth = 0; /* selected field width -- 0 means default */ + int precision = 0; /* selected precision -- -1 means default */ + TCHAR prefix[2]; /* numeric prefix -- up to two characters */ + int prefixlen=0; /* length of prefix -- 0 means no prefix */ + int capexp = 0; /* non-zero = 'E' exponent signifient, zero = 'e' */ + int no_output=0; /* non-zero = prodcue no output for this specifier */ + union { + const char *sz; /* pointer text to be printed, not zero terminated */ + const wchar_t *wz; + } text; + + int textlen; /* length of the text in bytes/wchars to be printed. + textlen is in multibyte or wide chars if _UNICODE */ + union { + char sz[BUFFERSIZE]; +#ifdef _UNICODE + wchar_t wz[BUFFERSIZE]; +#endif /* _UNICODE */ + } buffer; + wchar_t wchar; /* temp wchar_t */ + int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */ + int bufferiswide=0; /* non-zero = buffer contains wide chars already */ + +#ifndef CPRFLAG + _VALIDATE_RETURN( (stream != NULL), EINVAL, -1); +#endif /* CPRFLAG */ + _VALIDATE_RETURN( (format != NULL), EINVAL, -1); + + charsout = 0; /* no characters written yet */ + textlen = 0; /* no text yet */ + state = ST_NORMAL; /* starting state */ + buffersize = 0; + + /* main loop -- loop while format character exist and no I/O errors */ + while ((ch = *format++) != _T('\0') && charsout >= 0) { +#ifndef FORMAT_VALIDATIONS + chclass = FIND_CHAR_CLASS(__lookuptable, ch); /* find character class */ + state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */ +#else /* FORMAT_VALIDATIONS */ + chclass = FIND_CHAR_CLASS(__lookuptable_s, ch); /* find character class */ + state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */ + + _VALIDATE_RETURN((state != ST_INVALID), EINVAL, -1); + +#endif /* FORMAT_VALIDATIONS */ + + /* execute code for each state */ + switch (state) { + + case ST_NORMAL: + + NORMAL_STATE: + + /* normal state -- just write character */ +#ifdef _UNICODE + bufferiswide = 1; +#else /* _UNICODE */ + bufferiswide = 0; +#endif /* _UNICODE */ + WRITE_CHAR(ch, &charsout); + break; + + case ST_PERCENT: + /* set default value of conversion parameters */ + prefixlen = fldwidth = no_output = capexp = 0; + flags = 0; + precision = -1; + bufferiswide = 0; /* default */ + break; + + case ST_FLAG: + /* set flag based on which flag character */ + switch (ch) { + case _T('-'): + flags |= FL_LEFT; /* '-' => left justify */ + break; + case _T('+'): + flags |= FL_SIGN; /* '+' => force sign indicator */ + break; + case _T(' '): + flags |= FL_SIGNSP; /* ' ' => force sign or space */ + break; + case _T('#'): + flags |= FL_ALTERNATE; /* '#' => alternate form */ + break; + case _T('0'): + flags |= FL_LEADZERO; /* '0' => pad with leading zeros */ + break; + } + break; + + case ST_WIDTH: + /* update width value */ + if (ch == _T('*')) { + /* get width from arg list */ + fldwidth = get_int_arg(&argptr); + if (fldwidth < 0) { + /* ANSI says neg fld width means '-' flag and pos width */ + flags |= FL_LEFT; + fldwidth = -fldwidth; + } + } + else { + /* add digit to current field width */ + fldwidth = fldwidth * 10 + (ch - _T('0')); + } + break; + + case ST_DOT: + /* zero the precision, since dot with no number means 0 + not default, according to ANSI */ + precision = 0; + break; + + case ST_PRECIS: + /* update precison value */ + if (ch == _T('*')) { + /* get precision from arg list */ + precision = get_int_arg(&argptr); + if (precision < 0) + precision = -1; /* neg precision means default */ + } + else { + /* add digit to current precision */ + precision = precision * 10 + (ch - _T('0')); + } + break; + + case ST_SIZE: + /* just read a size specifier, set the flags based on it */ + switch (ch) { + case _T('l'): + /* + * In order to handle the ll case, we depart from the + * simple deterministic state machine. + */ + if (*format == _T('l')) + { + ++format; + flags |= FL_LONGLONG; /* 'll' => long long */ + } + else + { + flags |= FL_LONG; /* 'l' => long int or wchar_t */ + } + break; + + case _T('I'): + /* + * In order to handle the I, I32, and I64 size modifiers, we + * depart from the simple deterministic state machine. The + * code below scans for characters following the 'I', + * and defaults to 64 bit on WIN64 and 32 bit on WIN32 + */ +#if PTR_IS_INT64 + flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */ +#endif /* PTR_IS_INT64 */ + if ( (*format == _T('6')) && (*(format + 1) == _T('4')) ) + { + format += 2; + flags |= FL_I64; /* I64 => __int64 */ + } + else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) ) + { + format += 2; + flags &= ~FL_I64; /* I32 => __int32 */ + } + else if ( (*format == _T('d')) || + (*format == _T('i')) || + (*format == _T('o')) || + (*format == _T('u')) || + (*format == _T('x')) || + (*format == _T('X')) ) + { + /* + * Nothing further needed. %Id (et al) is + * handled just like %d, except that it defaults to 64 bits + * on WIN64. Fall through to the next iteration. + */ + } + else { + state = ST_NORMAL; + goto NORMAL_STATE; + } + break; + + case _T('h'): + flags |= FL_SHORT; /* 'h' => short int or char */ + break; + + case _T('w'): + flags |= FL_WIDECHAR; /* 'w' => wide character */ + break; + + } + break; + + case ST_TYPE: + /* we have finally read the actual type character, so we */ + /* now format and "print" the output. We use a big switch */ + /* statement that sets 'text' to point to the text that should */ + /* be printed, and 'textlen' to the length of this text. */ + /* Common code later on takes care of justifying it and */ + /* other miscellaneous chores. Note that cases share code, */ + /* in particular, all integer formatting is done in one place. */ + /* Look at those funky goto statements! */ + + switch (ch) { + + case _T('C'): /* ISO wide character */ + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) +#ifdef _UNICODE + flags |= FL_SHORT; +#else /* _UNICODE */ + flags |= FL_WIDECHAR; /* ISO std. */ +#endif /* _UNICODE */ + /* fall into 'c' case */ + + case _T('c'): { + /* print a single character specified by int argument */ +#ifdef _UNICODE + bufferiswide = 1; + wchar = (wchar_t) get_int_arg(&argptr); + if (flags & FL_SHORT) { + /* format multibyte character */ + /* this is an extension of ANSI */ + char tempchar[2]; + { + tempchar[0] = (char)(wchar & 0x00ff); + tempchar[1] = '\0'; + } + + if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0) + { + /* ignore if conversion was unsuccessful */ + no_output = 1; + } + } else { + buffer.wz[0] = wchar; + } + text.wz = buffer.wz; + textlen = 1; /* print just a single character */ +#else /* _UNICODE */ + if (flags & (FL_LONG|FL_WIDECHAR)) { + wchar = (wchar_t) get_short_arg(&argptr); + no_output = 1; + } else { + /* format multibyte character */ + /* this is an extension of ANSI */ + unsigned short temp; + wchar = (wchar_t)get_int_arg(&argptr); + temp = (unsigned short)wchar; + { + buffer.sz[0] = (char) temp; + textlen = 1; + } + } + text.sz = buffer.sz; +#endif /* _UNICODE */ + } + break; + + case _T('Z'): { + /* print a Counted String */ + struct _count_string { + short Length; + short MaximumLength; + char *Buffer; + } *pstr; + + pstr = (struct _count_string *)get_ptr_arg(&argptr); + if (pstr == NULL || pstr->Buffer == NULL) { + /* null ptr passed, use special string */ + text.sz = __nullstring; + textlen = (int)strlen(text.sz); + } else { + if (flags & FL_WIDECHAR) { + text.wz = (wchar_t *)pstr->Buffer; + textlen = pstr->Length / (int)sizeof(wchar_t); + bufferiswide = 1; + } else { + bufferiswide = 0; + text.sz = pstr->Buffer; + textlen = pstr->Length; + } + } + } + break; + + case _T('S'): /* ISO wide character string */ +#ifndef _UNICODE + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) + flags |= FL_WIDECHAR; +#else /* _UNICODE */ + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) + flags |= FL_SHORT; +#endif /* _UNICODE */ + + case _T('s'): { + /* print a string -- */ + /* ANSI rules on how much of string to print: */ + /* all if precision is default, */ + /* min(precision, length) if precision given. */ + /* prints '(null)' if a null string is passed */ + + int i; + const char *p; /* temps */ + const wchar_t *pwch; + + /* At this point it is tempting to use strlen(), but */ + /* if a precision is specified, we're not allowed to */ + /* scan past there, because there might be no null */ + /* at all. Thus, we must do our own scan. */ + + i = (precision == -1) ? INT_MAX : precision; + text.sz = (char *)get_ptr_arg(&argptr); + + /* scan for null upto i characters */ +#ifdef _UNICODE + if (flags & FL_SHORT) { + if (text.sz == NULL) /* NULL passed, use special string */ + text.sz = __nullstring; + p = text.sz; + for (textlen=0; textlen<i && *p; textlen++) { + ++p; + } + /* textlen now contains length in multibyte chars */ + } else { + if (text.wz == NULL) /* NULL passed, use special string */ + text.wz = __wnullstring; + bufferiswide = 1; + pwch = text.wz; + while (i-- && *pwch) + ++pwch; + textlen = (int)(pwch - text.wz); /* in wchar_ts */ + /* textlen now contains length in wide chars */ + } +#else /* _UNICODE */ + if (flags & (FL_LONG|FL_WIDECHAR)) { + if (text.wz == NULL) /* NULL passed, use special string */ + text.wz = __wnullstring; + bufferiswide = 1; + pwch = text.wz; + while ( i-- && *pwch ) + ++pwch; + textlen = (int)(pwch - text.wz); + /* textlen now contains length in wide chars */ + } else { + if (text.sz == NULL) /* NULL passed, use special string */ + text.sz = __nullstring; + p = text.sz; + while (i-- && *p) + ++p; + textlen = (int)(p - text.sz); /* length of the string */ + } + +#endif /* _UNICODE */ + } + break; + + + case _T('n'): { + /* write count of characters seen so far into */ + /* short/int/long thru ptr read from args */ + + void *p; /* temp */ + + p = get_ptr_arg(&argptr); + + /* %n is disabled */ + _VALIDATE_RETURN(("'n' format specifier disabled" && 0), EINVAL, -1); + break; + + /* store chars out into short/long/int depending on flags */ +#if !LONG_IS_INT + if (flags & FL_LONG) + *(long *)p = charsout; + else +#endif /* !LONG_IS_INT */ + +#if !SHORT_IS_INT + if (flags & FL_SHORT) + *(short *)p = (short) charsout; + else +#endif /* !SHORT_IS_INT */ + *(int *)p = charsout; + + no_output = 1; /* force no output */ + } + break; + + case _T('E'): + case _T('G'): + case _T('A'): + capexp = 1; /* capitalize exponent */ + ch += _T('a') - _T('A'); /* convert format char to lower */ + /* DROP THROUGH */ + case _T('e'): + case _T('f'): + case _T('g'): + case _T('a'): { + /* floating point conversion -- we call cfltcvt routines */ + /* to do the work for us. */ + flags |= FL_SIGNED; /* floating point is signed conversion */ + text.sz = buffer.sz; /* put result in buffer */ + buffersize = BUFFERSIZE; + + /* compute the precision value */ + if (precision < 0) + precision = 6; /* default precision: 6 */ + else if (precision == 0 && ch == _T('g')) + precision = 1; /* ANSI specified */ + else if (precision > MAXPRECISION) + precision = MAXPRECISION; + + if (precision > BUFFERSIZE - _CVTBUFSIZE) { + precision = BUFFERSIZE - _CVTBUFSIZE; + } + + /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */ + if (flags & FL_ALTERNATE) + { + capexp |= FL_ALTERNATE; + } + + _CRT_DOUBLE tmp; + tmp=va_arg(argptr, _CRT_DOUBLE); + /* Note: assumes ch is in ASCII range */ + /* In safecrt, we provide a special version of _cfltcvt which internally calls printf (see safecrt_output_s.c) */ + _CFLTCVT(&tmp, buffer.sz, buffersize, (char)ch, precision, capexp); + + /* check if result was negative, save '-' for later */ + /* and point to positive part (this is for '0' padding) */ + if (*text.sz == '-') { + flags |= FL_NEGATIVE; + ++text.sz; + } + + textlen = (int)strlen(text.sz); /* compute length of text */ + } + break; + + case _T('d'): + case _T('i'): + /* signed decimal output */ + flags |= FL_SIGNED; + radix = 10; + goto COMMON_INT; + + case _T('u'): + radix = 10; + goto COMMON_INT; + + case _T('p'): + /* write a pointer -- this is like an integer or long */ + /* except we force precision to pad with zeros and */ + /* output in big hex. */ + + precision = 2 * sizeof(void *); /* number of hex digits needed */ +#if PTR_IS_INT64 + flags |= FL_I64; /* assume we're converting an int64 */ +#elif !PTR_IS_INT + flags |= FL_LONG; /* assume we're converting a long */ +#endif /* !PTR_IS_INT */ + /* DROP THROUGH to hex formatting */ + + case _T('X'): + /* unsigned upper hex output */ + hexadd = _T('A') - _T('9') - 1; /* set hexadd for uppercase hex */ + goto COMMON_HEX; + + case _T('x'): + /* unsigned lower hex output */ + hexadd = _T('a') - _T('9') - 1; /* set hexadd for lowercase hex */ + /* DROP THROUGH TO COMMON_HEX */ + + COMMON_HEX: + radix = 16; + if (flags & FL_ALTERNATE) { + /* alternate form means '0x' prefix */ + prefix[0] = _T('0'); + prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd); /* 'x' or 'X' */ + prefixlen = 2; + } + goto COMMON_INT; + + case _T('o'): + /* unsigned octal output */ + radix = 8; + if (flags & FL_ALTERNATE) { + /* alternate form means force a leading 0 */ + flags |= FL_FORCEOCTAL; + } + /* DROP THROUGH to COMMON_INT */ + + COMMON_INT: { + /* This is the general integer formatting routine. */ + /* Basically, we get an argument, make it positive */ + /* if necessary, and convert it according to the */ + /* correct radix, setting text and textlen */ + /* appropriately. */ + +#if _INTEGRAL_MAX_BITS >= 64 +// unsigned __int64 number; /* number to convert */ + uint64_t number; /* number to convert */ + int digit; /* ascii value of digit */ + __int64 l; /* temp long value */ +#else /* _INTEGRAL_MAX_BITS >= 64 */ + unsigned long number; /* number to convert */ + int digit; /* ascii value of digit */ + long l; /* temp long value */ +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + + /* 1. read argument into l, sign extend as needed */ +#if _INTEGRAL_MAX_BITS >= 64 + if (flags & FL_I64) + l = get_int64_arg(&argptr); + else +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + + if (flags & FL_LONGLONG) + l = get_long_long_arg(&argptr); + else + +#if !LONG_IS_INT + if (flags & FL_LONG) + l = get_long_arg(&argptr); + else +#endif /* !LONG_IS_INT */ + +#if !SHORT_IS_INT + if (flags & FL_SHORT) { + if (flags & FL_SIGNED) + l = (short) get_int_arg(&argptr); /* sign extend */ + else + l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/ + + } else +#endif /* !SHORT_IS_INT */ + { + if (flags & FL_SIGNED) + l = get_int_arg(&argptr); /* sign extend */ + else + l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/ + + } + + /* 2. check for negative; copy into number */ + if ( (flags & FL_SIGNED) && l < 0) { + number = -l; + flags |= FL_NEGATIVE; /* remember negative sign */ + } else { + number = l; + } + +#if _INTEGRAL_MAX_BITS >= 64 + if ( (flags & FL_I64) == 0 && (flags & FL_LONGLONG) == 0 ) { + /* + * Unless printing a full 64-bit value, insure values + * here are not in cananical longword format to prevent + * the sign extended upper 32-bits from being printed. + */ + number &= 0xffffffff; + } +#endif /* _INTEGRAL_MAX_BITS >= 64 */ + + /* 3. check precision value for default; non-default */ + /* turns off 0 flag, according to ANSI. */ + if (precision < 0) + precision = 1; /* default precision */ + else { + flags &= ~FL_LEADZERO; + if (precision > MAXPRECISION) + precision = MAXPRECISION; + } + + /* 4. Check if data is 0; if so, turn off hex prefix */ + if (number == 0) + prefixlen = 0; + + /* 5. Convert data to ASCII -- note if precision is zero */ + /* and number is zero, we get no digits at all. */ + + char *sz; + sz = &buffer.sz[BUFFERSIZE-1]; /* last digit at end of buffer */ + + while (precision-- > 0 || number != 0) { + digit = (int)(number % radix) + '0'; + number /= radix; /* reduce number */ + if (digit > '9') { + /* a hex digit, make it a letter */ + digit += hexadd; + } + *sz-- = (char)digit; /* store the digit */ + } + + textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - sz); /* compute length of number */ + ++sz; /* text points to first digit now */ + + + /* 6. Force a leading zero if FORCEOCTAL flag set */ + if ((flags & FL_FORCEOCTAL) && (textlen == 0 || sz[0] != '0')) { + *--sz = '0'; + ++textlen; /* add a zero */ + } + + text.sz = sz; + } + break; + } + + + /* At this point, we have done the specific conversion, and */ + /* 'text' points to text to print; 'textlen' is length. Now we */ + /* justify it, put on prefixes, leading zeros, and then */ + /* print it. */ + + if (!no_output) { + int padding; /* amount of padding, negative means zero */ + + if (flags & FL_SIGNED) { + if (flags & FL_NEGATIVE) { + /* prefix is a '-' */ + prefix[0] = _T('-'); + prefixlen = 1; + } + else if (flags & FL_SIGN) { + /* prefix is '+' */ + prefix[0] = _T('+'); + prefixlen = 1; + } + else if (flags & FL_SIGNSP) { + /* prefix is ' ' */ + prefix[0] = _T(' '); + prefixlen = 1; + } + } + + /* calculate amount of padding -- might be negative, */ + /* but this will just mean zero */ + padding = fldwidth - textlen - prefixlen; + + /* put out the padding, prefix, and text, in the correct order */ + + if (!(flags & (FL_LEFT | FL_LEADZERO))) { + /* pad on left with blanks */ + WRITE_MULTI_CHAR(_T(' '), padding, &charsout); + } + + /* write prefix */ + WRITE_STRING(prefix, prefixlen, &charsout); + + if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) { + /* write leading zeros */ + WRITE_MULTI_CHAR(_T('0'), padding, &charsout); + } + + /* write text */ +#ifndef _UNICODE + if (bufferiswide && (textlen > 0)) { + charsout = -1; + } else { + WRITE_STRING(text.sz, textlen, &charsout); + } +#else /* _UNICODE */ + if (!bufferiswide && textlen > 0) { + char *p; + int retval = 0 + int count; + + p = text.sz; + count = textlen; + while (count-- > 0) { + retval = _MBTOWC(&wchar, p, MB_CUR_MAX); + if (retval <= 0) { + charsout = -1; + break; + } + WRITE_CHAR(wchar, &charsout); + p += retval; + } + } else { + WRITE_STRING(text.wz, textlen, &charsout); + } +#endif /* _UNICODE */ + + if (charsout >= 0 && (flags & FL_LEFT)) { + /* pad on right with blanks */ + WRITE_MULTI_CHAR(_T(' '), padding, &charsout); + } + + /* we're done! */ + } + break; + } + } + +#ifdef FORMAT_VALIDATIONS + /* The format string shouldn't be incomplete - i.e. when we are finished + with the format string, the last thing we should have encountered + should have been a regular char to be output or a type specifier. Else + the format string was incomplete */ + _VALIDATE_RETURN(((state == ST_NORMAL) || (state == ST_TYPE)), EINVAL, -1); +#endif /* FORMAT_VALIDATIONS */ + + return charsout; /* return value = number of characters written */ +} + +/* + * Future Optimizations for swprintf: + * - Don't free the memory used for converting the buffer to wide chars. + * Use realloc if the memory is not sufficient. Free it at the end. + */ + +/*** +*void write_char(char ch, int *pnumwritten) +*ifdef _UNICODE +*void write_char(wchar_t ch, FILE *f, int *pnumwritten) +*endif +*void write_char(char ch, FILE *f, int *pnumwritten) +* +*Purpose: +* Writes a single character to the given file/console. If no error occurs, +* then *pnumwritten is incremented; otherwise, *pnumwritten is set +* to -1. +* +*Entry: +* _TCHAR ch - character to write +* FILE *f - file to write to +* int *pnumwritten - pointer to integer to update with total chars written +* +*Exit: +* No return value. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef CPRFLAG + +LOCAL(void) write_char ( + _TCHAR ch, + int *pnumwritten + ) +{ +#ifdef _UNICODE + if (_putwch_nolock(ch) == WEOF) +#else /* _UNICODE */ + if (_putch_nolock(ch) == EOF) +#endif /* _UNICODE */ + *pnumwritten = -1; + else + ++(*pnumwritten); +} + +#else /* CPRFLAG */ + +LOCAL(void) write_char ( + _TCHAR ch, + miniFILE *f, + int *pnumwritten + ) +{ + if ( (f->_flag & _IOSTRG) && f->_base == NULL) + { + ++(*pnumwritten); + return; + } +#ifdef _UNICODE + if (_putwc_nolock(ch, f) == WEOF) +#else /* _UNICODE */ + if (_putc_nolock(ch, f) == EOF) +#endif /* _UNICODE */ + *pnumwritten = -1; + else + ++(*pnumwritten); +} + +#endif /* CPRFLAG */ + +/*** +*void write_multi_char(char ch, int num, int *pnumwritten) +*ifdef _UNICODE +*void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten) +*endif +*void write_multi_char(char ch, int num, FILE *f, int *pnumwritten) +* +*Purpose: +* Writes num copies of a character to the given file/console. If no error occurs, +* then *pnumwritten is incremented by num; otherwise, *pnumwritten is set +* to -1. If num is negative, it is treated as zero. +* +*Entry: +* _TCHAR ch - character to write +* int num - number of times to write the characters +* FILE *f - file to write to +* int *pnumwritten - pointer to integer to update with total chars written +* +*Exit: +* No return value. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef CPRFLAG +LOCAL(void) write_multi_char ( + _TCHAR ch, + int num, + int *pnumwritten + ) +{ + while (num-- > 0) { + write_char(ch, pnumwritten); + if (*pnumwritten == -1) + break; + } +} + +#else /* CPRFLAG */ + +LOCAL(void) write_multi_char ( + _TCHAR ch, + int num, + miniFILE *f, + int *pnumwritten + ) +{ + while (num-- > 0) { + write_char(ch, f, pnumwritten); + if (*pnumwritten == -1) + break; + } +} + +#endif /* CPRFLAG */ + +/*** +*void write_string(const char *string, int len, int *pnumwritten) +*void write_string(const char *string, int len, FILE *f, int *pnumwritten) +*ifdef _UNICODE +*void write_string(const wchar_t *string, int len, FILE *f, int *pnumwritten) +*endif +*void write_wstring(const wchar_t *string, int len, int *pnumwritten) +*void write_wstring(const wchar_t *string, int len, FILE *f, int *pnumwritten) +* +*Purpose: +* Writes a string of the given length to the given file. If no error occurs, +* then *pnumwritten is incremented by len; otherwise, *pnumwritten is set +* to -1. If len is negative, it is treated as zero. +* +*Entry: +* _TCHAR *string - string to write (NOT null-terminated) +* int len - length of string +* FILE *f - file to write to +* int *pnumwritten - pointer to integer to update with total chars written +* +*Exit: +* No return value. +* +*Exceptions: +* +*******************************************************************************/ + +#ifdef CPRFLAG + +LOCAL(void) write_string ( + const _TCHAR *string, + int len, + int *pnumwritten + ) +{ + while (len-- > 0) { + write_char(*string++, pnumwritten); + if (*pnumwritten == -1) + { + if (errno == EILSEQ) + write_char(_T('?'), pnumwritten); + else + break; + } + } +} + +#else /* CPRFLAG */ + +LOCAL(void) write_string ( + const _TCHAR *string, + int len, + miniFILE *f, + int *pnumwritten + ) +{ + if ( (f->_flag & _IOSTRG) && f->_base == NULL) + { + (*pnumwritten) += len; + return; + } + while (len-- > 0) { + write_char(*string++, f, pnumwritten); + if (*pnumwritten == -1) + { + if (errno == EILSEQ) + write_char(_T('?'), f, pnumwritten); + else + break; + } + } +} +#endif /* CPRFLAG */ diff --git a/src/pal/src/safecrt/safecrt_output_s.c b/src/pal/src/safecrt/safecrt_output_s.c new file mode 100644 index 0000000000..c3e7f91404 --- /dev/null +++ b/src/pal/src/safecrt/safecrt_output_s.c @@ -0,0 +1,46 @@ +// 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_output_s.c - implementation of the _output family for safercrt.lib +* + +* +*Purpose: +* This file contains the implementation of the _output family for safercrt.lib. +* +*Revision History: +* 07-08-04 SJ Stub module created. +* 07-13-04 AC Added support for floating-point types. +* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll +* based on the _NTSUBSET_ #define +* 09-24-04 MSL Prefix disallow NULL deref +* +****/ + +#define _SAFECRT_IMPL + +#define __STDC_LIMIT_MACROS +#include "pal/palinternal.h" +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <stdarg.h> +#include <inttypes.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define FORMAT_VALIDATIONS +#define _CFLTCVT _safecrt_cfltcvt + +#define _TCHAR CRT_TCHAR +#define TCHAR CRTTCHAR + +typedef char _TCHAR; +typedef char TCHAR; +#define _T(x) x + +#include "output.inl" diff --git a/src/pal/src/safecrt/safecrt_winput_s.c b/src/pal/src/safecrt/safecrt_winput_s.c new file mode 100644 index 0000000000..17a621781b --- /dev/null +++ b/src/pal/src/safecrt/safecrt_winput_s.c @@ -0,0 +1,55 @@ +// 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_winput_s.c - implementation of the _winput family for safecrt.lib +* + +* +*Purpose: +* This file contains the implementation of the _winput family for safecrt.lib. +* +*Revision History: +* 07/19/04 AC Created +* +****/ + + +#ifndef _UNICODE /* CRT flag */ +#define _UNICODE 1 +#endif + +#ifndef UNICODE /* NT flag */ +#define UNICODE 1 +#endif + +#define _SAFECRT_IMPL +#define _SECURE_SCANF + +#include "pal/palinternal.h" +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <locale.h> +#include <stdarg.h> +#include <inttypes.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _TCHAR CRT_TCHAR +#define TCHAR CRTTCHAR + +typedef wchar_t _TCHAR; +typedef wchar_t TCHAR; +typedef wchar_t _TUCHAR; +#define _T(x) x +#define _TEOF WEOF + +#define _gettc_nolock(x) _getwc_nolock(x) +#define _ungettc_nolock(x,y) _ungetwc_nolock(x,y) + +#include "input.inl" + diff --git a/src/pal/src/safecrt/safecrt_woutput_s.c b/src/pal/src/safecrt/safecrt_woutput_s.c new file mode 100644 index 0000000000..52fe9400d5 --- /dev/null +++ b/src/pal/src/safecrt/safecrt_woutput_s.c @@ -0,0 +1,59 @@ +// 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_woutput_s.c - implementation of the _woutput family for safercrt.lib +* + +* +*Purpose: +* This file contains the implementation of the _woutput family for safercrt.lib. +* +*Revision History: +* 07-08-04 SJ Stub module created. +* 07-13-04 AC Added support for floating-point types. +* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll +* based on the _NTSUBSET_ #define +* +****/ + +#define _SAFECRT_IMPL + +#define __STDC_LIMIT_MACROS + +#include "pal/palinternal.h" +#include <string.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <stdarg.h> +#include <inttypes.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#ifndef _UNICODE /* CRT flag */ +#define _UNICODE 1 +#endif + +#ifndef UNICODE /* NT flag */ +#define UNICODE 1 +#endif + +#define FORMAT_VALIDATIONS +#if defined(_NTSUBSET_) +#define _MBTOWC _safecrt_mbtowc +#endif +#define _WCTOMB_S _safecrt_wctomb_s +#define _CFLTCVT _safecrt_cfltcvt +#define _CLDCVT _safecrt_cldcvt + +#define _TCHAR CRT_TCHAR +#define TCHAR CRTTCHAR + +typedef wchar_t _TCHAR; +typedef wchar_t TCHAR; +#define _T(x) L##x + +#include "output.inl" diff --git a/src/pal/src/safecrt/snprintf.c b/src/pal/src/safecrt/snprintf.c new file mode 100644 index 0000000000..c892d1a9b6 --- /dev/null +++ b/src/pal/src/safecrt/snprintf.c @@ -0,0 +1,18 @@ +// 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. + +/*** +*snprintf.c - "Count" version of sprintf +* + +* +*Purpose: +* The _snprintf() flavor takes a count argument that is +* the max number of bytes that should be written to the +* user's buffer. +* +*******************************************************************************/ + +#define _COUNT_ 1 +#include "sprintf.c" diff --git a/src/pal/src/safecrt/splitpath_s.c b/src/pal/src/safecrt/splitpath_s.c new file mode 100644 index 0000000000..cb8a364550 --- /dev/null +++ b/src/pal/src/safecrt/splitpath_s.c @@ -0,0 +1,31 @@ +// 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. + +/*** +*splitpath_s.c - break down path name into components +* + +* +*Purpose: +* To provide support for accessing the individual components of an +* arbitrary path name +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME _splitpath_s +#define _CHAR char +#define _TCSNCPY_S strncpy_s +#define _T(_Character) _Character + +#define _MBS_SUPPORT 0 + +#include "tsplitpath_s.inl" diff --git a/src/pal/src/safecrt/sprintf.c b/src/pal/src/safecrt/sprintf.c new file mode 100644 index 0000000000..5454179f8d --- /dev/null +++ b/src/pal/src/safecrt/sprintf.c @@ -0,0 +1,98 @@ +// 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. + +/*** +*sprintf.c - print formatted to string +* + +* +*Purpose: +* defines sprintf() and _snprintf() - print formatted data to string +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + + +/*** +*ifndef _COUNT_ +*int sprintf(string, format, ...) - print formatted data to string +*else +*int _snprintf(string, cnt, format, ...) - print formatted data to string +*endif +* +*Purpose: +* Prints formatted data to the using the format string to +* format data and getting as many arguments as called for +* Sets up a FILE so file i/o operations can be used, make +* string look like a huge buffer to it, but _flsbuf will +* refuse to flush it if it fills up. Appends '\0' to make +* it a true string. _output does the real work here +* +* Allocate the 'fake' _iob[] entry statically instead of on +* the stack so that other routines can assume that _iob[] +* entries are in are in DGROUP and, thus, are near. +* +*ifdef _COUNT_ +* The _snprintf() flavor takes a count argument that is +* the max number of bytes that should be written to the +* user's buffer. +*endif +* +* Multi-thread: (1) Since there is no stream, this routine must +* never try to get the stream lock (i.e., there is no stream +* lock either). (2) Also, since there is only one statically +* allocated 'fake' iob, we must lock/unlock to prevent collisions. +* +*Entry: +* char *string - pointer to place to put output +*ifdef _COUNT_ +* size_t count - max number of bytes to put in buffer +*endif +* char *format - format string to control data format/number +* of arguments followed by list of arguments, number and type +* controlled by format string +* +*Exit: +* returns number of characters printed +* +*Exceptions: +* +*******************************************************************************/ + +int sprintf_s ( + char *string, + size_t sizeInBytes, + const char *format, + ... + ) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = _vsprintf_s(string, sizeInBytes, format, arglist); + va_end(arglist); + return ret; +} + +int _snprintf_s ( + char *string, + size_t sizeInBytes, + size_t count, + const char *format, + ... + ) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = _vsnprintf_s(string, sizeInBytes, count, format, arglist); + va_end(arglist); + return ret; +} diff --git a/src/pal/src/safecrt/sscanf.c b/src/pal/src/safecrt/sscanf.c new file mode 100644 index 0000000000..94b5148875 --- /dev/null +++ b/src/pal/src/safecrt/sscanf.c @@ -0,0 +1,249 @@ +// 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. + +/*** +*sscanf.c - read formatted data from string +* + +* +*Purpose: +* defines scanf() - reads formatted data from string +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +typedef int (*INPUTFN)(miniFILE *, const unsigned char*, va_list); +typedef int (*WINPUTFN)(miniFILE *, const unsigned short*, va_list); + + +/*** +*static int v[nw]scan_fn([w]inputfn, string, [count], format, ...) +* +*Purpose: +* this is a helper function which is called by the other functions +* in this file - sscanf/swscanf/snscanf etc. It calls either _(w)input or +* _(w)input_s depending on the first parameter. +* +*******************************************************************************/ + +static int __cdecl vscan_fn ( + INPUTFN inputfn, + const char *string, + const char *format, + va_list arglist + ) +{ + miniFILE str; + miniFILE *infile = &str; + int retval; + size_t count = strlen(string); + + _VALIDATE_RETURN( (string != NULL), EINVAL, EOF); + _VALIDATE_RETURN( (format != NULL), EINVAL, EOF); + + infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF; + infile->_ptr = infile->_base = (char *) string; + + if(count>(INT_MAX/sizeof(char))) + { + /* old-style functions allow any large value to mean unbounded */ + infile->_cnt = INT_MAX; + } + else + { + infile->_cnt = (int)count*sizeof(char); + } + + retval = (inputfn(infile, ( const unsigned char* )format, arglist)); + + return(retval); +} + +static int __cdecl vnscan_fn ( + INPUTFN inputfn, + const char *string, + size_t count, + const char *format, + va_list arglist + ) +{ + miniFILE str; + miniFILE *infile = &str; + int retval; + size_t length = strlen(string); + + _VALIDATE_RETURN( (string != NULL), EINVAL, EOF); + _VALIDATE_RETURN( (format != NULL), EINVAL, EOF); + + infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF; + infile->_ptr = infile->_base = (char *) string; + + if ( count > length ) + { + count = length; + } + + if(count>(INT_MAX/sizeof(char))) + { + /* old-style functions allow any large value to mean unbounded */ + infile->_cnt = INT_MAX; + } + else + { + infile->_cnt = (int)count*sizeof(char); + } + + retval = (inputfn(infile, ( const unsigned char* )format, arglist)); + + return(retval); +} + +static int __cdecl vwscan_fn ( + WINPUTFN inputfn, + const wchar_t *string, + const wchar_t *format, + va_list arglist + ) +{ + miniFILE str; + miniFILE *infile = &str; + int retval; + size_t count = wcsnlen(string, INT_MAX); + + _VALIDATE_RETURN( (string != NULL), EINVAL, EOF); + _VALIDATE_RETURN( (format != NULL), EINVAL, EOF); + + infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF; + infile->_ptr = infile->_base = (char *) string; + + if(count>(INT_MAX/sizeof(wchar_t))) + { + /* old-style functions allow any large value to mean unbounded */ + infile->_cnt = INT_MAX; + } + else + { + infile->_cnt = (int)count*sizeof(wchar_t); + } + + retval = (inputfn(infile, format, arglist)); + + return(retval); +} + +static int __cdecl vnwscan_fn ( + WINPUTFN inputfn, + const wchar_t *string, + size_t count, + const wchar_t *format, + va_list arglist + ) +{ + miniFILE str; + miniFILE *infile = &str; + int retval; + size_t length = wcsnlen(string, INT_MAX); + + _VALIDATE_RETURN( (string != NULL), EINVAL, EOF); + _VALIDATE_RETURN( (format != NULL), EINVAL, EOF); + + infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF; + infile->_ptr = infile->_base = (char *) string; + + if ( count > length ) + { + count = length; + } + + if(count>(INT_MAX/sizeof(wchar_t))) + { + /* old-style functions allow any large value to mean unbounded */ + infile->_cnt = INT_MAX; + } + else + { + infile->_cnt = (int)count*sizeof(wchar_t); + } + + retval = (inputfn(infile, format, arglist)); + + return(retval); +} + + +/*** +*int sscanf_s(string, format, ...) +* Same as sscanf above except that it calls _input_s to do the real work. +* +*int snscanf_s(string, size, format, ...) +* Same as snscanf above except that it calls _input_s to do the real work. +* +* _input_s has a size check for array parameters. +* +*******************************************************************************/ + +int __cdecl sscanf_s ( + const char *string, + const char *format, + ... + ) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = vscan_fn(__tinput_s, string, format, arglist); + va_end(arglist); + return ret; +} + +int __cdecl _snscanf_s ( + const char *string, + size_t count, + const char *format, + ... + ) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = vnscan_fn(__tinput_s, string, count, format, arglist); + va_end(arglist); + return ret; +} + +int __cdecl swscanf_s ( + const wchar_t *string, + const wchar_t *format, + ... + ) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = vwscan_fn(__twinput_s, string, format, arglist); + va_end(arglist); + return ret; +} + +int __cdecl _snwscanf_s ( + const wchar_t *string, + size_t count, + const wchar_t *format, + ... + ) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = vnwscan_fn(__twinput_s, string, count, format, arglist); + va_end(arglist); + return ret; +} + diff --git a/src/pal/src/safecrt/strcat_s.c b/src/pal/src/safecrt/strcat_s.c new file mode 100644 index 0000000000..4dc2332006 --- /dev/null +++ b/src/pal/src/safecrt/strcat_s.c @@ -0,0 +1,33 @@ +// 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. + +/*** +*strcat_s.c - contains strcat_s() +* + +* +*Purpose: +* strcat_s() concatenates (appends) a copy of the source string to the +* end of the destination string. +* +*******************************************************************************/ + +#define _SECURECRT_FILL_BUFFER 1 +#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8) + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME strcat_s +#define _CHAR char +#define _DEST _Dst +#define _SIZE _SizeInBytes +#define _SRC _Src + +#include "tcscat_s.inl" diff --git a/src/pal/src/safecrt/strcpy_s.c b/src/pal/src/safecrt/strcpy_s.c new file mode 100644 index 0000000000..821dbe85f6 --- /dev/null +++ b/src/pal/src/safecrt/strcpy_s.c @@ -0,0 +1,29 @@ +// 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. + +/*** +*strcpy_s.c - contains strcpy_s() +* + +* +*Purpose: +* strcpy_s() copies one string onto another. +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME strcpy_s +#define _CHAR char +#define _DEST _Dst +#define _SIZE _SizeInBytes +#define _SRC _Src + +#include "tcscpy_s.inl" diff --git a/src/pal/src/safecrt/strlen_s.c b/src/pal/src/safecrt/strlen_s.c new file mode 100644 index 0000000000..34c1308d5c --- /dev/null +++ b/src/pal/src/safecrt/strlen_s.c @@ -0,0 +1,58 @@ +// 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. + +/*** +*strlen_s.c - contains strnlen() routine +* + +* +*Purpose: +* strnlen returns the length of a null-terminated string, +* not including the null byte itself, up to the specified max size +* +*******************************************************************************/ + + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +/*** +*strnlen - return the length of a null-terminated string +* +*Purpose: +* Finds the length in bytes of the given string, not including +* the final null character. Only the first maxsize characters +* are inspected: if the null character is not found, maxsize is +* returned. +* +*Entry: +* const char * str - string whose length is to be computed +* size_t maxsize +* +*Exit: +* Length of the string "str", exclusive of the final null byte, or +* maxsize if the null character is not found. +* +*Exceptions: +* +*******************************************************************************/ + +size_t __cdecl strnlen(const char *str, size_t maxsize) +{ + size_t n; + + /* Note that we do not check if str == NULL, because we do not + * return errno_t... + */ + + for (n = 0; n < maxsize && *str; n++, str++) + ; + + return n; +} + diff --git a/src/pal/src/safecrt/strncat_s.c b/src/pal/src/safecrt/strncat_s.c new file mode 100644 index 0000000000..ef8c6cfc7f --- /dev/null +++ b/src/pal/src/safecrt/strncat_s.c @@ -0,0 +1,31 @@ +// 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. + +/*** +*strncat_s.c - append n chars of string to new string +* + +* +*Purpose: +* defines strncat_s() - appends n characters of string onto +* end of other string +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME strncat_s +#define _CHAR char +#define _DEST _Dst +#define _SIZE _SizeInBytes +#define _SRC _Src +#define _COUNT _Count + +#include "tcsncat_s.inl" diff --git a/src/pal/src/safecrt/strncpy_s.c b/src/pal/src/safecrt/strncpy_s.c new file mode 100644 index 0000000000..f819ebb6bb --- /dev/null +++ b/src/pal/src/safecrt/strncpy_s.c @@ -0,0 +1,30 @@ +// 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. + +/*** +*strncpy_s.c - copy at most n characters of string +* + +* +*Purpose: +* defines strncpy_s() - copy at most n characters of string +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME strncpy_s +#define _CHAR char +#define _DEST _Dst +#define _SIZE _SizeInBytes +#define _SRC _Src +#define _COUNT _Count + +#include "tcsncpy_s.inl" diff --git a/src/pal/src/safecrt/strtok_s.c b/src/pal/src/safecrt/strtok_s.c new file mode 100644 index 0000000000..6f1c80633f --- /dev/null +++ b/src/pal/src/safecrt/strtok_s.c @@ -0,0 +1,27 @@ +// 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. + +/*** +*strtok_s.c - tokenize a string with given delimiters +* + +* +*Purpose: +* defines strtok_s() - breaks string into series of token +* via repeated calls. +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME strtok_s +#define _CHAR char + +#include "tcstok_s.inl" diff --git a/src/pal/src/safecrt/swprintf.c b/src/pal/src/safecrt/swprintf.c new file mode 100644 index 0000000000..75004eafe2 --- /dev/null +++ b/src/pal/src/safecrt/swprintf.c @@ -0,0 +1,120 @@ +// 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. + +/*** +*swprintf.c - print formatted to string +* +*Purpose: +* defines _swprintf(), _swprintf_c and _snwprintf() - print formatted data +* to string +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +/*** +*ifndef _COUNT_ +*int _swprintf(string, format, ...) - print formatted data to string +*else +*ifndef _SWPRINTFS_ERROR_RETURN_FIX +*int _snwprintf(string, cnt, format, ...) - print formatted data to string +*else +*int _swprintf_c(string, cnt, format, ...) - print formatted data to string +*endif +*endif +* +*Purpose: +* Prints formatted data to the using the format string to +* format data and getting as many arguments as called for +* Sets up a FILE so file i/o operations can be used, make +* string look like a huge buffer to it, but _flsbuf will +* refuse to flush it if it fills up. Appends '\0' to make +* it a true string. _output does the real work here +* +* Allocate the 'fake' _iob[] entry statically instead of on +* the stack so that other routines can assume that _iob[] +* entries are in are in DGROUP and, thus, are near. +* +* We alias swprintf to _swprintf +* +*ifdef _COUNT_ +*ifndef _SWPRINTFS_ERROR_RETURN_FIX +* The _snwprintf() flavor takes a count argument that is +* the max number of wide characters that should be written to the +* user's buffer. +* We don't expose this function directly in the headers. +*else +* The _swprintf_c() flavor does the same thing as the _snwprintf +* above, but, it also fixes a issue in the return value in the case +* when there isn't enough space to write the null terminator +* We don't fix this issue in _snwprintf because of backward +* compatibility. In new code, however, _snwprintf is #defined to +* _swprintf_c so users get the fix. +* +*endif +* +* Multi-thread: (1) Since there is no stream, this routine must +* never try to get the stream lock (i.e., there is no stream +* lock either). (2) Also, since there is only one statically +* allocated 'fake' iob, we must lock/unlock to prevent collisions. +* +*Entry: +* wchar_t *string - pointer to place to put output +*ifdef _COUNT_ +* size_t count - max number of wide characters to put in buffer +*endif +* wchar_t *format - format string to control data format/number +* of arguments followed by list of arguments, number and type +* controlled by format string +* +*Exit: +* returns number of wide characters printed +* +*Exceptions: +* +*******************************************************************************/ + +int __cdecl swprintf_s ( + wchar_t *string, + size_t sizeInWords, + const wchar_t *format, + ... + ) +{ + int ret; + va_list arglist; + + va_start(arglist, format); + + ret = _vswprintf_s(string, sizeInWords, format, arglist); + + va_end(arglist); + + return ret; +} + +int __cdecl _snwprintf_s ( + wchar_t *string, + size_t sizeInWords, + size_t count, + const wchar_t *format, + ... + ) +{ + int ret; + va_list arglist; + + va_start(arglist, format); + + ret = _vsnwprintf_s(string, sizeInWords, count, format, arglist); + + va_end(arglist); + + return ret; +} diff --git a/src/pal/src/safecrt/tcscat_s.inl b/src/pal/src/safecrt/tcscat_s.inl new file mode 100644 index 0000000000..b6fefdc0ae --- /dev/null +++ b/src/pal/src/safecrt/tcscat_s.inl @@ -0,0 +1,51 @@ +// 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. + +/*** +*tcscat_s.inl - general implementation of _tcscpy_s +* + +* +*Purpose: +* This file contains the general algorithm for strcat_s and its variants. +* +****/ + +_FUNC_PROLOGUE +errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC) +{ + _CHAR *p; + size_t available; + + /* validation section */ + _VALIDATE_STRING(_DEST, _SIZE); + _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE); + + p = _DEST; + available = _SIZE; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + _RESET_STRING(_DEST, _SIZE); + _RETURN_DEST_NOT_NULL_TERMINATED(_DEST, _SIZE); + } + + while ((*p++ = *_SRC++) != 0 && --available > 0) + { + } + + if (available == 0) + { + _RESET_STRING(_DEST, _SIZE); + _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE); + } + _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1); + _RETURN_NO_ERROR; +} + diff --git a/src/pal/src/safecrt/tcscpy_s.inl b/src/pal/src/safecrt/tcscpy_s.inl new file mode 100644 index 0000000000..b1192d8ee7 --- /dev/null +++ b/src/pal/src/safecrt/tcscpy_s.inl @@ -0,0 +1,39 @@ +// 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. + +/*** +*tcscpy_s.inl - general implementation of _tcscpy_s +* + +* +*Purpose: +* This file contains the general algorithm for strcpy_s and its variants. +* +****/ + +_FUNC_PROLOGUE +errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC) +{ + _CHAR *p; + size_t available; + + /* validation section */ + _VALIDATE_STRING(_DEST, _SIZE); + _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE); + + p = _DEST; + available = _SIZE; + while ((*p++ = *_SRC++) != 0 && --available > 0) + { + } + + if (available == 0) + { + _RESET_STRING(_DEST, _SIZE); + _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE); + } + _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1); + _RETURN_NO_ERROR; +} + diff --git a/src/pal/src/safecrt/tcsncat_s.inl b/src/pal/src/safecrt/tcsncat_s.inl new file mode 100644 index 0000000000..6de501767d --- /dev/null +++ b/src/pal/src/safecrt/tcsncat_s.inl @@ -0,0 +1,81 @@ +// 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. + +/*** +*tcsncat_s.inl - general implementation of _tcscpy_s +* + +* +*Purpose: +* This file contains the general algorithm for strncat_s and its variants. +* +****/ + +_FUNC_PROLOGUE +errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC, size_t _COUNT) +{ + _CHAR *p; + size_t available; + + if (_COUNT == 0 && _DEST == NULL && _SIZE == 0) + { + /* this case is allowed; nothing to do */ + _RETURN_NO_ERROR; + } + + /* validation section */ + _VALIDATE_STRING(_DEST, _SIZE); + if (_COUNT != 0) + { + _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE); + } + + p = _DEST; + available = _SIZE; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + _RESET_STRING(_DEST, _SIZE); + _RETURN_DEST_NOT_NULL_TERMINATED(_DEST, _SIZE); + } + + if (_COUNT == _TRUNCATE) + { + while ((*p++ = *_SRC++) != 0 && --available > 0) + { + } + } + else + { + _ASSERT_EXPR((!_CrtGetCheckCount() || _COUNT < available), "Buffer is too small"); + + while (_COUNT > 0 && (*p++ = *_SRC++) != 0 && --available > 0) + { + _COUNT--; + } + if (_COUNT == 0) + { + *p = 0; + } + } + + if (available == 0) + { + if (_COUNT == _TRUNCATE) + { + _DEST[_SIZE - 1] = 0; + _RETURN_TRUNCATE; + } + _RESET_STRING(_DEST, _SIZE); + _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE); + } + _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1); + _RETURN_NO_ERROR; +} + diff --git a/src/pal/src/safecrt/tcsncpy_s.inl b/src/pal/src/safecrt/tcsncpy_s.inl new file mode 100644 index 0000000000..54a79a03e7 --- /dev/null +++ b/src/pal/src/safecrt/tcsncpy_s.inl @@ -0,0 +1,71 @@ +// 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. + +/*** +*tcsncpy_s.inl - general implementation of _tcsncpy_s +* + +* +*Purpose: +* This file contains the general algorithm for strncpy_s and its variants. +* +****/ + +_FUNC_PROLOGUE +errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC, size_t _COUNT) +{ + _CHAR *p; + size_t available; + + if (_COUNT == 0 && _DEST == NULL && _SIZE == 0) + { + /* this case is allowed; nothing to do */ + _RETURN_NO_ERROR; + } + + /* validation section */ + _VALIDATE_STRING(_DEST, _SIZE); + if (_COUNT == 0) + { + /* notice that the source string pointer can be NULL in this case */ + _RESET_STRING(_DEST, _SIZE); + _RETURN_NO_ERROR; + } + _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE); + + p = _DEST; + available = _SIZE; + if (_COUNT == _TRUNCATE) + { + while ((*p++ = *_SRC++) != 0 && --available > 0) + { + } + } + else + { + _ASSERT_EXPR((!_CrtGetCheckCount() || _COUNT < _SIZE), "Buffer is too small"); + + while ((*p++ = *_SRC++) != 0 && --available > 0 && --_COUNT > 0) + { + } + if (_COUNT == 0) + { + *p = 0; + } + } + + if (available == 0) + { + if (_COUNT == _TRUNCATE) + { + _DEST[_SIZE - 1] = 0; + _RETURN_TRUNCATE; + } + _RESET_STRING(_DEST, _SIZE); + _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE); + } + _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1); + _RETURN_NO_ERROR; +} + diff --git a/src/pal/src/safecrt/tcstok_s.inl b/src/pal/src/safecrt/tcstok_s.inl new file mode 100644 index 0000000000..29ca5c6858 --- /dev/null +++ b/src/pal/src/safecrt/tcstok_s.inl @@ -0,0 +1,71 @@ +// 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. + +/*** +*tcstok_s.inl - general implementation of _tcstok_s +* + +* +*Purpose: +* This file contains the general algorithm for strtok_s and its variants. +* +****/ + +_FUNC_PROLOGUE +_CHAR * __cdecl _FUNC_NAME(_CHAR *_String, const _CHAR *_Control, _CHAR **_Context) +{ + _CHAR *token; + const _CHAR *ctl; + + /* validation section */ + _VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, NULL); + _VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, NULL); + _VALIDATE_CONDITION_ERROR_RETURN(_String != NULL || *_Context != NULL, EINVAL, NULL); + + /* If string==NULL, 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 NULL; + } + else + { + return token; + } +} diff --git a/src/pal/src/safecrt/tmakepath_s.inl b/src/pal/src/safecrt/tmakepath_s.inl new file mode 100644 index 0000000000..34c4842c61 --- /dev/null +++ b/src/pal/src/safecrt/tmakepath_s.inl @@ -0,0 +1,116 @@ +// 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. + +/*** +*tmakepath_s.inl - general implementation of _tmakepath_s +* + +* +*Purpose: +* This file contains the general algorithm for _makepath_s and its variants. +* +*******************************************************************************/ + +_FUNC_PROLOGUE +errno_t __cdecl _FUNC_NAME(__out_ecount_z(_SIZE) _CHAR *_DEST, __in_opt size_t _SIZE, __in_z_opt const _CHAR *_Drive, __in_z_opt const _CHAR *_Dir, __in_z_opt const _CHAR *_Filename, __in_z_opt const _CHAR *_Ext) +{ + size_t written; + const _CHAR *p; + _CHAR *d; + + /* validation section */ + _VALIDATE_STRING(_DEST, _SIZE); + + /* copy drive */ + written = 0; + d = _DEST; + if (_Drive != NULL && *_Drive != 0) + { + written += 2; + if(written >= _SIZE) + { + goto error_return; + } + *d++ = *_Drive; + *d++ = _T(':'); + } + + /* copy dir */ + p = _Dir; + if (p != NULL && *p != 0) + { + do { + if(++written >= _SIZE) + { + goto error_return; + } + *d++ = *p++; + } while (*p != 0); + +#if _MBS_SUPPORT + p = _MBSDEC(_Dir, p); +#else /* _MBS_SUPPORT */ + p = p - 1; +#endif /* _MBS_SUPPORT */ + if (*p != _T('/') && *p != _T('\\')) + { + if(++written >= _SIZE) + { + goto error_return; + } + *d++ = _T('\\'); + } + } + + /* copy fname */ + p = _Filename; + if (p != NULL) + { + while (*p != 0) + { + if(++written >= _SIZE) + { + goto error_return; + } + *d++ = *p++; + } + } + + /* copy extension; check to see if a '.' needs to be inserted */ + p = _Ext; + if (p != NULL) + { + if (*p != 0 && *p != _T('.')) + { + if(++written >= _SIZE) + { + goto error_return; + } + *d++ = _T('.'); + } + while (*p != 0) + { + if(++written >= _SIZE) + { + goto error_return; + } + *d++ = *p++; + } + } + + if(++written > _SIZE) + { + goto error_return; + } + *d = 0; + _FILL_STRING(_DEST, _SIZE, written); + _RETURN_NO_ERROR; + +error_return: + _RESET_STRING(_DEST, _SIZE); + _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE); + + /* should never happen, but compiler can't tell */ + return EINVAL; +} diff --git a/src/pal/src/safecrt/tsplitpath_s.inl b/src/pal/src/safecrt/tsplitpath_s.inl new file mode 100644 index 0000000000..3a14fa5900 --- /dev/null +++ b/src/pal/src/safecrt/tsplitpath_s.inl @@ -0,0 +1,280 @@ +// 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. + +/*** +*tsplitpath_s.inl - general implementation of _tsplitpath_s +* + +* +*Purpose: +* This file contains the general algorithm for _splitpath_s and its variants. +* +*******************************************************************************/ + +_FUNC_PROLOGUE +errno_t __cdecl _FUNC_NAME( + __in_z const _CHAR *_Path, + __out_ecount_z_opt(_DriveSize) _CHAR *_Drive, __in size_t _DriveSize, + __out_ecount_z_opt(_DirSize) _CHAR *_Dir, __in size_t _DirSize, + __out_ecount_z_opt(_FilenameSize) _CHAR *_Filename, __in size_t _FilenameSize, + __out_ecount_z_opt(_ExtSize) _CHAR *_Ext, __in 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 */ + if (_Path == NULL) + { + goto error_einval; + } + if ((_Drive == NULL && _DriveSize != 0) || (_Drive != NULL && _DriveSize == 0)) + { + goto error_einval; + } + if ((_Dir == NULL && _DirSize != 0) || (_Dir != NULL && _DirSize == 0)) + { + goto error_einval; + } + if ((_Filename == NULL && _FilenameSize != 0) || (_Filename != NULL && _FilenameSize == 0)) + { + goto error_einval; + } + if ((_Ext == NULL && _ExtSize != 0) || (_Ext != NULL && _ExtSize == 0)) + { + goto error_einval; + } + + /* check if _Path begins with the longpath prefix */ + if (_Path[0] == _T('\\') && _Path[1] == _T('\\') && _Path[2] == _T('?') && _Path[3] == _T('\\')) + { + _Path += 4; + } + + /* extract drive letter and ':', if any */ + if (!drive_set) + { +// The CorUnix PAL is never built on Windows and thus, the code below +// for the drive check is not required. +#if 0 + size_t skip = _MAX_DRIVE - 2; + tmp = _Path; + while (skip > 0 && *tmp != 0) + { + skip--; + tmp++; + } + if (*tmp == _T(':')) + { + if (_Drive != NULL) + { + if (_DriveSize < _MAX_DRIVE) + { + goto error_erange; + } + _TCSNCPY_S(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1); + } + _Path = tmp + 1; + } + else +#endif + { + if (_Drive != NULL) + { + _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 = NULL; + dot = NULL; + tmp = _Path; + for (; *tmp != 0; ++tmp) + { +#if _MBS_SUPPORT +#pragma warning(push) +#pragma warning(disable:4127) + if (_ISMBBLEAD(*tmp)) +#pragma warning(pop) + { + tmp++; + } + else +#endif /* _MBS_SUPPORT */ + { + if (*tmp == _T('/') || *tmp == _T('\\')) + { + /* point to one beyond for later copy */ + last_slash = tmp + 1; + } + else if (*tmp == _T('.')) + { + dot = tmp; + } + } + } + + if (last_slash != NULL) + { + /* found a path - copy up through last_slash or max characters + * allowed, whichever is smaller + */ + if (_Dir != NULL) { + length = (size_t)(last_slash - _Path); + if (_DirSize <= length) + { + goto error_erange; + } + _TCSNCPY_S(_Dir, _DirSize, _Path, length); + + // Normalize the path seperator + int iIndex; + for(iIndex = 0; iIndex < length; iIndex++) + { + if (_Dir[iIndex] == _T('\\')) + { + _Dir[iIndex] = _T('/'); + } + } + } + _Path = last_slash; + } + else + { + /* there is no path */ + if (_Dir != NULL) + { + _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 != NULL && (dot >= _Path)) + { + /* found the marker for an extension - copy the file name up to the '.' */ + if (_Filename) + { + length = (size_t)(dot - _Path); + if (length == 0) + { + // At this time, dot will be equal to _Path if string is something like "/." + // since _path was set to last_slash, which in turn, was set to "tmp +1" + // where "tmp" is the location where "/" was found. See code above for + // clarification. + // + // For such cases, return the "." in filename buffer. + // + // Thus, if the length is zero, we know its a string like "/." and thus, we + // set length to 1 to get the "." in filename buffer. + length = 1; + } + + if (_FilenameSize <= length) + { + goto error_erange; + } + _TCSNCPY_S(_Filename, _FilenameSize, _Path, length); + } + + /* now we can get the extension - remember that tmp still points + * to the terminating NULL character of path. + */ + if (_Ext) + { + // At this time, _Path is pointing to the character after the last slash found. + // (See comments and code above for clarification). + // + // Returns extension as empty string for strings like "/.". + if (dot > _Path) + { + length = (size_t)(tmp - dot); + if (_ExtSize <= length) + { + goto error_erange; + } + + /* Since dot pointed to the ".", make sure we actually have an extension + like ".cmd" and not just ".", OR + + Confirm that its a string like "/.." - for this, return the + second "." in the extension part. + + However, for strings like "/myfile.", return empty string + in extension buffer. + */ + int fIsDir = (*(dot-1) == _T('.'))?1:0; + if (length > 1 || (length == 1 && fIsDir == 1)) + _TCSNCPY_S(_Ext, _ExtSize, dot, length); + else + _RESET_STRING(_Ext, _ExtSize); + } + else + _RESET_STRING(_Ext, _ExtSize); + } + } + 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; + } + _TCSNCPY_S(_Filename, _FilenameSize, _Path, length); + } + if (_Ext) + { + _RESET_STRING(_Ext, _ExtSize); + } + } + + _RETURN_NO_ERROR; + +error_einval: + bEinval = 1; + +error_erange: + if (_Drive != NULL && _DriveSize > 0) + { + _RESET_STRING(_Drive, _DriveSize); + } + if (_Dir != NULL && _DirSize > 0) + { + _RESET_STRING(_Dir, _DirSize); + } + if (_Filename != NULL && _FilenameSize > 0) + { + _RESET_STRING(_Filename, _FilenameSize); + } + if (_Ext != NULL && _ExtSize > 0) + { + _RESET_STRING(_Ext, _ExtSize); + } + + _VALIDATE_POINTER(_Path); + if (bEinval) + { + _RETURN_EINVAL; + } + return (errno = ERANGE); +} diff --git a/src/pal/src/safecrt/vsprintf.c b/src/pal/src/safecrt/vsprintf.c new file mode 100644 index 0000000000..4f2bd9fdeb --- /dev/null +++ b/src/pal/src/safecrt/vsprintf.c @@ -0,0 +1,268 @@ +// 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. + +/*** +*vsprintf.c - print formatted data into a string from var arg list +* + +* +*Purpose: +* defines vsprintf(), _vsnprintf() and _vsnprintf_s() - print formatted output to +* a string, get the data from an argument ptr instead of explicit +* arguments. +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +typedef int (*OUTPUTFN)(miniFILE *, const char *, va_list); + +static int _vsnprintf_helper( OUTPUTFN outfn, char *string, size_t count, const char *format, va_list ap ); +static int _vscprintf_helper ( OUTPUTFN outfn, const char *format, va_list ap); + +/*** +*ifndef _COUNT_ +*int vsprintf(string, format, ap) - print formatted data to string from arg ptr +*else +*int _vsnprintf(string, cnt, format, ap) - print formatted data to string from arg ptr +*endif +* +*Purpose: +* Prints formatted data, but to a string and gets data from an argument +* pointer. +* Sets up a FILE so file i/o operations can be used, make string look +* like a huge buffer to it, but _flsbuf will refuse to flush it if it +* fills up. Appends '\0' to make it a true string. +* +* Allocate the 'fake' _iob[] entryit statically instead of on +* the stack so that other routines can assume that _iob[] entries are in +* are in DGROUP and, thus, are near. +* +*ifdef _COUNT_ +* The _vsnprintf() flavor takes a count argument that is +* the max number of bytes that should be written to the +* user's buffer. +*endif +* +* Multi-thread: (1) Since there is no stream, this routine must never try +* to get the stream lock (i.e., there is no stream lock either). (2) +* Also, since there is only one staticly allocated 'fake' iob, we must +* lock/unlock to prevent collisions. +* +*Entry: +* char *string - place to put destination string +*ifdef _COUNT_ +* size_t count - max number of bytes to put in buffer +*endif +* char *format - format string, describes format of data +* va_list ap - varargs argument pointer +* +*Exit: +* returns number of characters in string +* returns -2 if the string has been truncated (only in _vsnprintf_helper) +* returns -1 in other error cases +* +*Exceptions: +* +*******************************************************************************/ + +int __cdecl _vsnprintf_helper ( + OUTPUTFN outfn, + char *string, + size_t count, + const char *format, + va_list ap + ) +{ + miniFILE str; + miniFILE *outfile = &str; + int retval; + + _VALIDATE_RETURN( (format != NULL), EINVAL, -1); + + _VALIDATE_RETURN( (count == 0) || (string != NULL), EINVAL, -1 ); + + if(count>INT_MAX) + { + /* old-style functions allow any large value to mean unbounded */ + outfile->_cnt = INT_MAX; + } + else + { + outfile->_cnt = (int)count; + } + + outfile->_flag = _IOWRT|_IOSTRG; + outfile->_ptr = outfile->_base = string; + + retval = outfn(outfile, format, ap ); + + if ( string==NULL) + return(retval); + + if((retval >= 0) && (_putc_nolock('\0',outfile) != EOF)) + return(retval); + + string[count - 1] = 0; + + if (outfile->_cnt < 0) + { + /* the buffer was too small; we return -2 to indicate truncation */ + return -2; + } + return -1; +} + +int __cdecl _vsprintf_s ( + char *string, + size_t sizeInBytes, + const char *format, + va_list ap + ) +{ + int retvalue = -1; + + /* validation section */ + _VALIDATE_RETURN(format != NULL, EINVAL, -1); + _VALIDATE_RETURN(string != NULL && sizeInBytes > 0, EINVAL, -1); + + retvalue = _vsnprintf_helper(_output_s, string, sizeInBytes, format, ap); + if (retvalue < 0) + { + string[0] = 0; + _SECURECRT__FILL_STRING(string, sizeInBytes, 1); + } + if (retvalue == -2) + { + _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1); + } + if (retvalue >= 0) + { + _SECURECRT__FILL_STRING(string, sizeInBytes, retvalue + 1); + } + + return retvalue; +} + +int __cdecl _vsnprintf_s ( + char *string, + size_t sizeInBytes, + size_t count, + const char *format, + va_list ap + ) +{ + int retvalue = -1; + errno_t save_errno = 0; + + /* validation section */ + _VALIDATE_RETURN(format != NULL, EINVAL, -1); + if (count == 0 && string == NULL && sizeInBytes == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + _VALIDATE_RETURN(string != NULL && sizeInBytes > 0, EINVAL, -1); + + if (sizeInBytes > count) + { + save_errno = errno; + retvalue = _vsnprintf_helper(_output_s, string, count + 1, format, ap); + if (retvalue == -2) + { + /* the string has been truncated, return -1 */ + _SECURECRT__FILL_STRING(string, sizeInBytes, count + 1); + if (errno == ERANGE) + { + errno = save_errno; + } + return -1; + } + } + else /* sizeInBytes <= count */ + { + save_errno = errno; + retvalue = _vsnprintf_helper(_output_s, string, sizeInBytes, format, ap); + string[sizeInBytes - 1] = 0; + /* we allow truncation if count == _TRUNCATE */ + if (retvalue == -2 && count == _TRUNCATE) + { + if (errno == ERANGE) + { + errno = save_errno; + } + return -1; + } + } + + if (retvalue < 0) + { + string[0] = 0; + _SECURECRT__FILL_STRING(string, sizeInBytes, 1); + if (retvalue == -2) + { + _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1); + } + return -1; + } + + _SECURECRT__FILL_STRING(string, sizeInBytes, retvalue + 1); + + return (retvalue < 0 ? -1 : retvalue); +} + +/*** +* _vscprintf() - counts the number of character needed to print the formatted +* data +* +*Purpose: +* Counts the number of characters in the fotmatted data. +* +*Entry: +* char *format - format string, describes format of data +* va_list ap - varargs argument pointer +* +*Exit: +* returns number of characters needed to print formatted data. +* +*Exceptions: +* +*******************************************************************************/ + +#ifndef _COUNT_ + +int __cdecl _vscprintf_helper ( + OUTPUTFN outfn, + const char *format, + va_list ap + ) +{ + miniFILE str; + miniFILE *outfile = &str; + int retval; + + _VALIDATE_RETURN( (format != NULL), EINVAL, -1); + + outfile->_cnt = INT_MAX; //MAXSTR; + outfile->_flag = _IOWRT|_IOSTRG; + outfile->_ptr = outfile->_base = NULL; + + retval = outfn(outfile, format, ap); + return(retval); +} + +int __cdecl _vscprintf ( + const char *format, + va_list ap + ) +{ + return _vscprintf_helper(_output, format, ap); +} + +#endif /* _COUNT_ */ diff --git a/src/pal/src/safecrt/vswprint.c b/src/pal/src/safecrt/vswprint.c new file mode 100644 index 0000000000..77c79b8752 --- /dev/null +++ b/src/pal/src/safecrt/vswprint.c @@ -0,0 +1,282 @@ +// 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. + +/*** +*vswprint.c - print formatted data into a string from var arg list +* +*Purpose: +* defines vswprintf(), _vswprintf_c and _vsnwprintf() - print formatted output to +* a string, get the data from an argument ptr instead of explicit +* arguments. +* +*******************************************************************************/ + + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +typedef int (*WOUTPUTFN)(miniFILE *, const wchar_t *, va_list); + +static int _vswprintf_helper( WOUTPUTFN outfn, wchar_t *string, size_t count, const wchar_t *format, va_list ap ); +static int _vscwprintf_helper (WOUTPUTFN outfn, const wchar_t *format, va_list ap ); + +/*** +*ifndef _COUNT_ +*int _vswprintf(string, format, ap) - print formatted data to string from arg ptr +*else +*ifndef _SWPRINTFS_ERROR_RETURN_FIX +*int _vsnwprintf(string, cnt, format, ap) - print formatted data to string from arg ptr +*else +*int _vswprintf_c(string, cnt, format, ...) - print formatted data to string +*endif +*endif +* +*Purpose: +* Prints formatted data, but to a string and gets data from an argument +* pointer. +* Sets up a FILE so file i/o operations can be used, make string look +* like a huge buffer to it, but _flsbuf will refuse to flush it if it +* fills up. Appends '\0' to make it a true string. +* +* Allocate the 'fake' _iob[] entryit statically instead of on +* the stack so that other routines can assume that _iob[] entries are in +* are in DGROUP and, thus, are near. +* +*ifdef _COUNT_ +*ifndef _SWPRINTFS_ERROR_RETURN_FIX +* The _vsnwprintf() flavor takes a count argument that is +* the max number of bytes that should be written to the +* user's buffer. +* We don't expose this function directly in the headers. +*else +* The _vswprintf_c() flavor does the same thing as the _snwprintf +* above, but, it also fixes an issue in the return value in the case +* when there isn't enough space to write the null terminator +* We don't fix this issue in _vsnwprintf because of backward +* compatibility. In new code, however, _vsnwprintf is #defined to +* _vswprintf_c so users get the fix. +* +*endif +* +* Multi-thread: (1) Since there is no stream, this routine must never try +* to get the stream lock (i.e., there is no stream lock either). (2) +* Also, since there is only one statically allocated 'fake' iob, we must +* lock/unlock to prevent collisions. +* +*Entry: +* wchar_t *string - place to put destination string +*ifdef _COUNT_ +* size_t count - max number of bytes to put in buffer +*endif +* wchar_t *format - format string, describes format of data +* va_list ap - varargs argument pointer +* +*Exit: +* returns number of wide characters in string +* returns -2 if the string has been truncated (only in _vsnprintf_helper) +* returns -1 in other error cases +* +*Exceptions: +* +*******************************************************************************/ + +int __cdecl _vswprintf_helper ( + WOUTPUTFN woutfn, + wchar_t *string, + size_t count, + const wchar_t *format, + va_list ap + ) +{ + miniFILE str; + miniFILE *outfile = &str; + int retval; + + _VALIDATE_RETURN( (format != NULL), EINVAL, -1); + + _VALIDATE_RETURN( (count == 0) || (string != NULL), EINVAL, -1 ); + + outfile->_flag = _IOWRT|_IOSTRG; + outfile->_ptr = outfile->_base = (char *) string; + + if(count>(INT_MAX/sizeof(wchar_t))) + { + /* old-style functions allow any large value to mean unbounded */ + outfile->_cnt = INT_MAX; + } + else + { + outfile->_cnt = (int)(count*sizeof(wchar_t)); + } + + retval = woutfn(outfile, format, ap ); + + if(string==NULL) + { + return retval; + } + + if((retval >= 0) && (_putc_nolock('\0',outfile) != EOF) && (_putc_nolock('\0',outfile) != EOF)) + return(retval); + + string[count - 1] = 0; + if (outfile->_cnt < 0) + { + /* the buffer was too small; we return -2 to indicate truncation */ + return -2; + } + return -1; +} + +int __cdecl _vswprintf_s ( + wchar_t *string, + size_t sizeInWords, + const wchar_t *format, + va_list ap + ) +{ + int retvalue = -1; + + /* validation section */ + _VALIDATE_RETURN(format != NULL, EINVAL, -1); + _VALIDATE_RETURN(string != NULL && sizeInWords > 0, EINVAL, -1); + + retvalue = _vswprintf_helper(_woutput_s, string, sizeInWords, format, ap); + if (retvalue < 0) + { + string[0] = 0; + _SECURECRT__FILL_STRING(string, sizeInWords, 1); + } + if (retvalue == -2) + { + _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1); + } + if (retvalue >= 0) + { + _SECURECRT__FILL_STRING(string, sizeInWords, retvalue + 1); + } + + return retvalue; +} + +int __cdecl _vsnwprintf_s ( + wchar_t *string, + size_t sizeInWords, + size_t count, + const wchar_t *format, + va_list ap + ) +{ + int retvalue = -1; + errno_t save_errno = 0; + + /* validation section */ + _VALIDATE_RETURN(format != NULL, EINVAL, -1); + if (count == 0 && string == NULL && sizeInWords == 0) + { + /* this case is allowed; nothing to do */ + return 0; + } + _VALIDATE_RETURN(string != NULL && sizeInWords > 0, EINVAL, -1); + + if (sizeInWords > count) + { + save_errno = errno; + retvalue = _vswprintf_helper(_woutput_s, string, count + 1, format, ap); + if (retvalue == -2) + { + /* the string has been truncated, return -1 */ + _SECURECRT__FILL_STRING(string, sizeInWords, count + 1); + if (errno == ERANGE) + { + errno = save_errno; + } + return -1; + } + } + else /* sizeInWords <= count */ + { + save_errno = errno; + retvalue = _vswprintf_helper(_woutput_s, string, sizeInWords, format, ap); + string[sizeInWords - 1] = 0; + /* we allow truncation if count == _TRUNCATE */ + if (retvalue == -2 && count == _TRUNCATE) + { + if (errno == ERANGE) + { + errno = save_errno; + } + return -1; + } + } + + if (retvalue < 0) + { + string[0] = 0; + _SECURECRT__FILL_STRING(string, sizeInWords, 1); + if (retvalue == -2) + { + _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1); + } + return -1; + } + + _SECURECRT__FILL_STRING(string, sizeInWords, retvalue + 1); + + return (retvalue < 0 ? -1 : retvalue); +} + +/*** +* _vscwprintf() - counts the number of character needed to print the formatted +* data +* +*Purpose: +* Counts the number of characters in the fotmatted data. +* +*Entry: +* wchar_t *format - format string, describes format of data +* va_list ap - varargs argument pointer +* +*Exit: +* returns number of characters needed to print formatted data. +* +*Exceptions: +* +*******************************************************************************/ + +#ifndef _COUNT_ + +int __cdecl _vscwprintf_helper ( + WOUTPUTFN woutfn, + const wchar_t *format, + va_list ap + ) +{ + miniFILE str; + miniFILE *outfile = &str; + int retval; + + _VALIDATE_RETURN( (format != NULL), EINVAL, -1); + + outfile->_cnt = INT_MAX; //MAXSTR; + outfile->_flag = _IOWRT|_IOSTRG; + outfile->_ptr = outfile->_base = NULL; + + retval = woutfn(outfile, format, ap); + return(retval); +} + +int __cdecl _vscwprintf ( + const wchar_t *format, + va_list ap + ) +{ + return _vscwprintf_helper(_woutput_s, format, ap); +} + +#endif /* _COUNT_ */ diff --git a/src/pal/src/safecrt/wcscat_s.c b/src/pal/src/safecrt/wcscat_s.c new file mode 100644 index 0000000000..06179888ff --- /dev/null +++ b/src/pal/src/safecrt/wcscat_s.c @@ -0,0 +1,36 @@ +// 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. + +/*** +*wcscat_s.c - contains wcscat_s() +* + +* +*Purpose: +* wcscat_s() appends one wchar_t string onto another. +* +* wcscat() concatenates (appends) a copy of the source string to the +* end of the destination string. +* Strings are wide-character strings. +* +*******************************************************************************/ + +#define _SECURECRT_FILL_BUFFER 1 +#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8) + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME wcscat_s +#define _CHAR wchar_t +#define _DEST _Dst +#define _SIZE _SizeInBytes +#define _SRC _Src + +#include "tcscat_s.inl" diff --git a/src/pal/src/safecrt/wcscpy_s.c b/src/pal/src/safecrt/wcscpy_s.c new file mode 100644 index 0000000000..4c60a81489 --- /dev/null +++ b/src/pal/src/safecrt/wcscpy_s.c @@ -0,0 +1,33 @@ +// 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. + +/*** +*strcpy_s.c - contains wcscpy_s() +* + +* +*Purpose: +* wcscpy_s() copies one string onto another. +* +*******************************************************************************/ + +#define _SECURECRT_FILL_BUFFER 1 +#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8) + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME wcscpy_s +#define _CHAR wchar_t +#define _DEST _Dst +#define _SIZE _SizeInWords +#define _SRC _Src + +#include "tcscpy_s.inl" + diff --git a/src/pal/src/safecrt/wcslen_s.c b/src/pal/src/safecrt/wcslen_s.c new file mode 100644 index 0000000000..4fd5371035 --- /dev/null +++ b/src/pal/src/safecrt/wcslen_s.c @@ -0,0 +1,58 @@ +// 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. + +/*** +*wcslen_s.c - contains wcsnlen() routine +* + +* +*Purpose: +* wcslen returns the length of a null-terminated wide-character string, +* not including the null wchar_t itself. +* +*******************************************************************************/ + + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +/*** +*wcsnlen - return the length of a null-terminated wide-character string +* +*Purpose: +* Finds the length in bytes of the given string, not including +* the final null character. Only the first maxsize characters +* are inspected: if the null character is not found, maxsize is +* returned. +* +*Entry: +* const wchar_t * wcs - string whose length is to be computed +* size_t maxsize +* +*Exit: +* Length of the string "wcs", exclusive of the final null byte, or +* maxsize if the null character is not found. +* +*Exceptions: +* +*******************************************************************************/ + +size_t __cdecl wcsnlen(const wchar_t *wcs, size_t maxsize) +{ + size_t n; + + /* Note that we do not check if s == NULL, because we do not + * return errno_t... + */ + + for (n = 0; n < maxsize && *wcs; n++, wcs++) + ; + + return n; +} + diff --git a/src/pal/src/safecrt/wcsncat_s.c b/src/pal/src/safecrt/wcsncat_s.c new file mode 100644 index 0000000000..1ff39d55f3 --- /dev/null +++ b/src/pal/src/safecrt/wcsncat_s.c @@ -0,0 +1,35 @@ +// 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. + +/*** +*wcsncat_s.c - append n chars of string to new string +* + +* +*Purpose: +* defines wcsncat_s() - appends n characters of string onto +* end of other string +* +*******************************************************************************/ + +#define _SECURECRT_FILL_BUFFER 1 +#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8) + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME wcsncat_s +#define _CHAR wchar_t +#define _DEST _Dst +#define _SIZE _SizeInWords +#define _SRC _Src +#define _COUNT _Count + +#include "tcsncat_s.inl" + diff --git a/src/pal/src/safecrt/wcsncpy_s.c b/src/pal/src/safecrt/wcsncpy_s.c new file mode 100644 index 0000000000..7902ded43a --- /dev/null +++ b/src/pal/src/safecrt/wcsncpy_s.c @@ -0,0 +1,34 @@ +// 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. + +/*** +*wcsncpy_s.c - copy at most n characters of wide-character string +* + +* +*Purpose: +* defines wcsncpy_s() - copy at most n characters of wchar_t string +* +*******************************************************************************/ + +#define _SECURECRT_FILL_BUFFER 1 +#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8) + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME wcsncpy_s +#define _CHAR wchar_t +#define _DEST _Dst +#define _SIZE _SizeInWords +#define _SRC _Src +#define _COUNT _Count + +#include "tcsncpy_s.inl" + diff --git a/src/pal/src/safecrt/wcstok_s.c b/src/pal/src/safecrt/wcstok_s.c new file mode 100644 index 0000000000..c99b30c773 --- /dev/null +++ b/src/pal/src/safecrt/wcstok_s.c @@ -0,0 +1,27 @@ +// 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. + +/*** +*wcstok_s.c - tokenize a wide-character string with given delimiters +* + +* +*Purpose: +* defines wcstok_s() - breaks wide-character string into series of token +* via repeated calls. +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME wcstok_s +#define _CHAR wchar_t + +#include "tcstok_s.inl" diff --git a/src/pal/src/safecrt/wmakepath_s.c b/src/pal/src/safecrt/wmakepath_s.c new file mode 100644 index 0000000000..35ab7d386e --- /dev/null +++ b/src/pal/src/safecrt/wmakepath_s.c @@ -0,0 +1,30 @@ +// 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. + +/*** +*wmakepath_s.c - create path name from components +* + +* +*Purpose: +* To provide support for creation of full path names from components +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME _wmakepath_s +#define _CHAR wchar_t +#define _DEST _Dst +#define _SIZE _SizeInWords +#define _T(_Character) L##_Character +#define _MBS_SUPPORT 0 + +#include "tmakepath_s.inl" diff --git a/src/pal/src/safecrt/wsplitpath_s.c b/src/pal/src/safecrt/wsplitpath_s.c new file mode 100644 index 0000000000..c7fb107803 --- /dev/null +++ b/src/pal/src/safecrt/wsplitpath_s.c @@ -0,0 +1,30 @@ +// 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. + +/*** +*wsplitpath_s.c - break down path name into components +* + +* +*Purpose: +* To provide support for accessing the individual components of an +* arbitrary path name +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _FUNC_PROLOGUE +#define _FUNC_NAME _wsplitpath_s +#define _CHAR wchar_t +#define _TCSNCPY_S wcsncpy_s +#define _T(_Character) L##_Character +#define _MBS_SUPPORT 0 + +#include "tsplitpath_s.inl" diff --git a/src/pal/src/safecrt/xtoa_s.c b/src/pal/src/safecrt/xtoa_s.c new file mode 100644 index 0000000000..42cc5786d1 --- /dev/null +++ b/src/pal/src/safecrt/xtoa_s.c @@ -0,0 +1,29 @@ +// 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. + +/*** +*strtok_s.c - tokenize a string with given delimiters +* + +* +*Purpose: +* defines strtok_s() - breaks string into series of token +* via repeated calls. +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +//#define __int64 long long + +#define _SECURE_ITOA + +#define TCHAR char +#define _T(x) x +#include "xtox_s.inl" diff --git a/src/pal/src/safecrt/xtow_s.c b/src/pal/src/safecrt/xtow_s.c new file mode 100644 index 0000000000..7a02424c85 --- /dev/null +++ b/src/pal/src/safecrt/xtow_s.c @@ -0,0 +1,28 @@ +// 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. + +/*** +*strtok_s.c - tokenize a string with given delimiters +* + +* +*Purpose: +* defines strtok_s() - breaks string into series of token +* via repeated calls. +* +*******************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <limits.h> +#include "internal_securecrt.h" + +#include "mbusafecrt_internal.h" + +#define _SECURE_ITOA + +#define _UNICODE +#define TCHAR wchar_t +#define _T(x) L##x +#include "xtox_s.inl" diff --git a/src/pal/src/safecrt/xtox_s.inl b/src/pal/src/safecrt/xtox_s.inl new file mode 100644 index 0000000000..e07d87adf5 --- /dev/null +++ b/src/pal/src/safecrt/xtox_s.inl @@ -0,0 +1,450 @@ +// 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. + +/*** +*xtoa.c - convert integers/longs to ASCII string +* + +* +*Purpose: +* The module has code to convert integers/longs to ASCII strings. See +* +*******************************************************************************/ + +#ifdef _UNICODE +#define xtox_s xtow_s +#define _itox_s _itow_s +#define _ltox_s _ltow_s +#define _ultox_s _ultow_s +#define x64tox_s x64tow_s +#define _i64tox_s _i64tow_s +#define _ui64tox_s _ui64tow_s +#define xtox xtow +#define _itox _itow +#define _ltox _ltow +#define _ultox _ultow +#define x64tox x64tow +#define _i64tox _i64tow +#define _ui64tox _ui64tow +#else /* _UNICODE */ +#define xtox_s xtoa_s +#define _itox_s _itoa_s +#define _ltox_s _ltoa_s +#define _ultox_s _ultoa_s +#define x64tox_s x64toa_s +#define _i64tox_s _i64toa_s +#define _ui64tox_s _ui64toa_s +#define xtox xtoa +#define _itox _itoa +#define _ltox _ltoa +#define _ultox _ultoa +#define x64tox x64toa +#define _i64tox _i64toa +#define _ui64tox _ui64toa +#endif /* _UNICODE */ + +/*** +*char *_itoa_s, *_ltoa_s, *_ultoa_s(val, buf, sizeInTChars, radix) - convert binary int to ASCII +* string +* +*Purpose: +* Converts an int to a character string. +* +*Entry: +* val - number to be converted (int, long or unsigned long) +* char *buf - ptr to buffer to place result +* size_t sizeInTChars - size of the destination buffer +* int radix - base to convert into +* +*Exit: +* Fills in space pointed to by buf with string result. +* Returns the errno_t: err != 0 means that something went wrong, and +* an empty string (buf[0] = 0) is returned. +* +*Exceptions: +* Input parameters and buffer length are validated. +* Refer to the validation section of the function. +* +*******************************************************************************/ + +/* helper routine that does the main job. */ +#ifdef _SECURE_ITOA +static errno_t __stdcall xtox_s + ( + unsigned long val, + TCHAR *buf, + size_t sizeInTChars, + unsigned radix, + int is_neg + ) +#else /* _SECURE_ITOA */ +static void __stdcall xtox + ( + unsigned long val, + TCHAR *buf, + unsigned radix, + int is_neg + ) +#endif /* _SECURE_ITOA */ +{ + TCHAR *p; /* pointer to traverse string */ + TCHAR *firstdig; /* pointer to first digit */ + TCHAR temp; /* temp char */ + unsigned digval; /* value of digit */ +#ifdef _SECURE_ITOA + size_t length; /* current length of the string */ + + /* validation section */ + _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL); + _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL); + _RESET_STRING(buf, sizeInTChars); + _VALIDATE_RETURN_ERRCODE(sizeInTChars > (size_t)(is_neg ? 2 : 1), ERANGE); + _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL); + length = 0; + +#endif /* _SECURE_ITOA */ + p = buf; + + if (is_neg) { + /* negative, so output '-' and negate */ + *p++ = _T('-'); +#ifdef _SECURE_ITOA + length++; +#endif /* _SECURE_ITOA */ + val = (unsigned long)(-(long)val); + } + + firstdig = p; /* save pointer to first digit */ + + do { + digval = (unsigned) (val % radix); + val /= radix; /* get next digit */ + + /* convert to ascii and store */ + if (digval > 9) + *p++ = (TCHAR) (digval - 10 + _T('a')); /* a letter */ + else + *p++ = (TCHAR) (digval + _T('0')); /* a digit */ +#ifndef _SECURE_ITOA + } while (val > 0); +#else /* _SECURE_ITOA */ + length++; + } while (val > 0 && length < sizeInTChars); + + /* Check for buffer overrun */ + if (length >= sizeInTChars) + { + buf[0] = '\0'; + _VALIDATE_RETURN_ERRCODE(length < sizeInTChars, ERANGE); + } +#endif /* _SECURE_ITOA */ + /* We now have the digit of the number in the buffer, but in reverse + order. Thus we reverse them now. */ + + *p-- = _T('\0'); /* terminate string; p points to last digit */ + + do { + temp = *p; + *p = *firstdig; + *firstdig = temp; /* swap *p and *firstdig */ + --p; + ++firstdig; /* advance to next two digits */ + } while (firstdig < p); /* repeat until halfway */ +#ifdef _SECURE_ITOA + return 0; +#endif /* _SECURE_ITOA */ +} + +/* Actual functions just call conversion helper with neg flag set correctly, + and return pointer to buffer. */ + +#ifdef _SECURE_ITOA +errno_t __cdecl _itox_s ( + int val, + TCHAR *buf, + size_t sizeInTChars, + int radix + ) +{ + errno_t e = 0; + + if (radix == 10 && val < 0) + e = xtox_s((unsigned long)val, buf, sizeInTChars, radix, 1); + else + e = xtox_s((unsigned long)(unsigned int)val, buf, sizeInTChars, radix, 0); + + return e; +} + +errno_t __cdecl _ltox_s ( + long val, + TCHAR *buf, + size_t sizeInTChars, + int radix + ) +{ + return xtox_s((unsigned long)val, buf, sizeInTChars, radix, (radix == 10 && val < 0)); +} + +errno_t __cdecl _ultox_s ( + unsigned long val, + TCHAR *buf, + size_t sizeInTChars, + int radix + ) +{ + return xtox_s(val, buf, sizeInTChars, radix, 0); +} + +#else /* _SECURE_ITOA */ + +/*** +*char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII +* string +* +*Purpose: +* Converts an int to a character string. +* +*Entry: +* val - number to be converted (int, long or unsigned long) +* int radix - base to convert into +* char *buf - ptr to buffer to place result +* +*Exit: +* fills in space pointed to by buf with string result +* returns a pointer to this buffer +* +*Exceptions: +* Input parameters are validated. The buffer is assumed to be big enough to +* contain the string. Refer to the validation section of the function. +* +*******************************************************************************/ + +/* Actual functions just call conversion helper with neg flag set correctly, + and return pointer to buffer. */ + +TCHAR * __cdecl _itox ( + int val, + TCHAR *buf, + int radix + ) +{ + if (radix == 10 && val < 0) + xtox((unsigned long)val, buf, radix, 1); + else + xtox((unsigned long)(unsigned int)val, buf, radix, 0); + return buf; +} + +TCHAR * __cdecl _ltox ( + long val, + TCHAR *buf, + int radix + ) +{ + xtox((unsigned long)val, buf, radix, (radix == 10 && val < 0)); + return buf; +} + +TCHAR * __cdecl _ultox ( + unsigned long val, + TCHAR *buf, + int radix + ) +{ + xtox(val, buf, radix, 0); + return buf; +} + +#endif /* _SECURE_ITOA */ + +#ifndef _NO_INT64 + +/*** +*char *_i64toa_s(val, buf, sizeInTChars, radix) - convert binary int to ASCII +* string +* +*Purpose: +* Converts an int64 to a character string. +* +*Entry: +* val - number to be converted +* char *buf - ptr to buffer to place result +* size_t sizeInTChars - size of the destination buffer +* int radix - base to convert into +* +*Exit: +* Fills in space pointed to by buf with string result. +* Returns the errno_t: err != 0 means that something went wrong, and +* an empty string (buf[0] = 0) is returned. +* +*Exceptions: +* Input parameters and buffer length are validated. +* Refer to the validation section of the function. +* +*******************************************************************************/ + +#ifdef _SECURE_ITOA +static errno_t __fastcall x64tox_s + (/* stdcall is faster and smaller... Might as well use it for the helper. */ + unsigned __int64 val, + TCHAR *buf, + size_t sizeInTChars, + unsigned radix, + int is_neg + ) +#else /* _SECURE_ITOA */ +static void __fastcall x64tox + (/* stdcall is faster and smaller... Might as well use it for the helper. */ + unsigned __int64 val, + TCHAR *buf, + unsigned radix, + int is_neg + ) +#endif /* _SECURE_ITOA */ +{ + TCHAR *p; /* pointer to traverse string */ + TCHAR *firstdig; /* pointer to first digit */ + TCHAR temp; /* temp char */ + unsigned digval; /* value of digit */ +#ifdef _SECURE_ITOA + size_t length; /* current length of the string */ + + /* validation section */ + _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL); + _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL); + _RESET_STRING(buf, sizeInTChars); + _VALIDATE_RETURN_ERRCODE(sizeInTChars > (size_t)(is_neg ? 2 : 1), ERANGE); + _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL); + length = 0; +#endif /* _SECURE_ITOA */ + p = buf; + + if ( is_neg ) + { + *p++ = _T('-'); /* negative, so output '-' and negate */ +#ifdef _SECURE_ITOA + length++; +#endif /* _SECURE_ITOA */ + val = (unsigned __int64)(-(__int64)val); + } + + firstdig = p; /* save pointer to first digit */ + + do { + digval = (unsigned) (val % radix); + val /= radix; /* get next digit */ + + /* convert to ascii and store */ + if (digval > 9) + *p++ = (TCHAR) (digval - 10 + _T('a')); /* a letter */ + else + *p++ = (TCHAR) (digval + _T('0')); /* a digit */ + +#ifndef _SECURE_ITOA + } while (val > 0); +#else /* _SECURE_ITOA */ + length++; + } while (val > 0 && length < sizeInTChars); + + /* Check for buffer overrun */ + if (length >= sizeInTChars) + { + buf[0] = '\0'; + _VALIDATE_RETURN_ERRCODE(length < sizeInTChars, ERANGE); + } +#endif /* _SECURE_ITOA */ + /* We now have the digit of the number in the buffer, but in reverse + order. Thus we reverse them now. */ + + *p-- = _T('\0'); /* terminate string; p points to last digit */ + + do { + temp = *p; + *p = *firstdig; + *firstdig = temp; /* swap *p and *firstdig */ + --p; + ++firstdig; /* advance to next two digits */ + } while (firstdig < p); /* repeat until halfway */ + +#ifdef _SECURE_ITOA + return 0; +#endif /* _SECURE_ITOA */ +} + +#ifdef _SECURE_ITOA + +/* Actual functions just call conversion helper with neg flag set correctly, + and return pointer to buffer. */ + +errno_t __cdecl _i64tox_s ( + long long val, + TCHAR *buf, + size_t sizeInTChars, + int radix + ) +{ + return x64tox_s((unsigned __int64)val, buf, sizeInTChars, radix, (radix == 10 && val < 0)); +} + +errno_t __cdecl _ui64tox_s ( + unsigned long long val, + TCHAR *buf, + size_t sizeInTChars, + int radix + ) +{ + return x64tox_s(val, buf, sizeInTChars, radix, 0); +} + +#else /* _SECURE_ITOA */ + +/*** +*char *_i64toa(val, buf, radix) - convert binary int to ASCII +* string +* +*Purpose: +* Converts an int64 to a character string. +* +*Entry: +* val - number to be converted +* int radix - base to convert into +* char *buf - ptr to buffer to place result +* +*Exit: +* fills in space pointed to by buf with string result +* returns a pointer to this buffer +* +*Exceptions: +* Input parameters are validated. The buffer is assumed to be big enough to +* contain the string. Refer to the validation section of the function. +* +*******************************************************************************/ + +/* Actual functions just call conversion helper with neg flag set correctly, + and return pointer to buffer. */ + +TCHAR * __cdecl _i64tox ( + __int64 val, + TCHAR *buf, + int radix + ) +{ + x64tox((unsigned __int64)val, buf, radix, (radix == 10 && val < 0)); + return buf; +} + +TCHAR * __cdecl _ui64tox ( + unsigned __int64 val, + TCHAR *buf, + int radix + ) +{ + x64tox(val, buf, radix, 0); + return buf; +} + +#endif /* _SECURE_ITOA */ + +#endif /* _NO_INT64 */ |