diff --git a/source/shared/FormattedPrint.cpp b/source/shared/FormattedPrint.cpp new file mode 100644 index 00000000..b297d628 --- /dev/null +++ b/source/shared/FormattedPrint.cpp @@ -0,0 +1,2805 @@ + +//----------------------------------------------------------------------------- +// File: FormattedPrint.cpp +// +// +// Contents: Contains functions for handling Windows format strings +// and UTF-16 on non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#include +#include + +#if !defined(_MSC_VER) +#include +#endif + +#include "StringFunctions.h" + +// XPLAT_ODBC_TODO VSTS 819733 - MPlat: Reconcile std c++ usage between platforms +#ifdef MPLAT_UNIX +// #include +#elif defined(MPLAT_WWOWH) +# define _ASSERTE assert +# include +# undef _M_IX86 +# undef min +# undef max +#endif +#include +#include +#ifdef MPLAT_UNIX + #include +#endif + +#ifdef __linux__ +#define PTR_IS_INT64 1 +#else +#define PTR_IS_INT64 0 +#endif + +#ifndef _MSC_VER +// SQL Server does not have a long double type +#define LONGDOUBLE_IS_DOUBLE 1 +typedef double _LONGDOUBLE; +#endif + +// XPLAT_ODBC_TODO VSTS VSTS 718708 Localization +#define _SAFECRT_IMPL + +#if !defined(_countof) +#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) +#endif // _countof + +#ifndef _VALIDATE_RETURN +#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \ + { \ + int _Expr_val=!!(expr); \ + if ( !( _Expr_val ) ) \ + { \ + assert(false); \ + errno = errorcode; \ + return ( retexpr ); \ + } \ + } +#endif /* _VALIDATE_RETURN */ + + +static const char *__nullstring = "(null)"; /* string to print on null ptr */ +static const wchar_t *__wnullstring = L"(null)";/* string to print on null ptr */ + +#define BUFFERSIZE 512 +#define MAXPRECISION BUFFERSIZE +#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */ + + +/* 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 */ + ,ST_INVALID /* Invalid format */ + +}; + +#define NUMSTATES (ST_INVALID + 1) + +/* 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 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, +#if defined (_SAFECRT_IMPL) + /* 'A' */ 0x80, // Disable %A format +#else /* defined (_SAFECRT_IMPL) */ + /* 'A' */ 0x88, +#endif /* defined (_SAFECRT_IMPL) */ + /* '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, +#if defined (_SAFECRT_IMPL) + /* 'a' */ 0x60, // Disable %a format +#else /* defined (_SAFECRT_IMPL) */ + /* 'a' */ 0x68, +#endif /* defined (_SAFECRT_IMPL) */ + /* '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 +}; + +static inline CHARTYPE GetCharType( WCHAR wch ) +{ + return ((wch < (L' ') || wch > (L'x')) ? CH_OTHER : (enum CHARTYPE)(__lookuptable_s[wch - (L' ')] & 0xF)); +} +static inline CHARTYPE GetCharType( char ch ) +{ + return ((ch < (' ') || ch > ('x')) ? CH_OTHER : (enum CHARTYPE)(__lookuptable_s[ch - (' ')] & 0xF)); +} +static inline STATE GetState( CHARTYPE type, STATE oldState ) +{ + return (enum STATE)(__lookuptable_s[type * NUMSTATES + oldState] >> 4); +} + + +static bool isleadbyte(unsigned char ch) +{ + return (FALSE != IsDBCSLeadByte(ch) ); +} +static bool isleadwchar(WCHAR ch) +{ + return ((ch & 0xFC00) == 0xD800); +} +static bool _isleadbyte_l(unsigned char ch, _locale_t loc) +{ + // XPLAT_ODBC_TODO VSTS 718708 Localization + return ( FALSE != IsDBCSLeadByte(ch) ); +} + + + +#define _WCTOMB_S mplat_wctomb_s +errno_t mplat_wctomb_s( + int *pRetValue, + char *mbchar, + size_t sizeInBytes, + WCHAR wchar +) +{ + DWORD rc; + size_t cch = SystemLocale::FromUtf16( CP_ACP, &wchar, 1, mbchar, sizeInBytes, NULL, &rc ); + *pRetValue = (int)cch; + return (ERROR_SUCCESS == rc ? 0 : -1); +} + +#define _MBTOWC mplat_mbtowc +int mplat_mbtowc( + WCHAR * pwchar, + const char * pmb, + size_t n +) +{ + size_t cch = SystemLocale::NextChar( CP_ACP, pmb ) - pmb; + if ( 0 < cch ) + { + size_t cchActual = SystemLocale::ToUtf16( CP_ACP, pmb, cch, pwchar, 1, NULL ); + assert( cch == cchActual ); + } + return (int)cch; +} + +// Floating point print routines +void _CFLTCVT( double * dbl, char * buf, int bufSize, char fmt, int precision, int caps, _locale_t loc = NULL ) +{ + const size_t local_bufsize = 8; + char local_fmt[local_bufsize]; + + if ( 0 != caps ) + { + fmt -= ('a') - ('A'); /* convert format char to upper */ + } + int chars_printed = snprintf( local_fmt, local_bufsize, "%%.%d%c", precision-1, fmt ); + assert( 0 < chars_printed && (size_t)chars_printed < local_bufsize ); + + // We want to use the platform version of snprintf so temporarily undef. + // Formatting of floating pt values is complex so we didn't implement it here. + // Even porting the CRT code would've been difficult. Instead, we can use the + // platform's snprintf for just floating pt values. We have to undef to prevent + // recursing right back to here. +# undef snprintf +# if defined(MPLAT_WWOWH) +# undef _snprintf +# define snprintf _snprintf +# endif + chars_printed = snprintf( buf, bufSize, local_fmt, *dbl ); + assert( 0 < chars_printed && chars_printed < bufSize ); +# if defined(MPLAT_WWOWH) +# undef snprintf +# define _snprintf mplat_snprintf +# endif +# define snprintf mplat_snprintf +} + +#if !LONGDOUBLE_IS_DOUBLE +// SQL Server does not support the long double data type so this should never be called. +// It will be compiled out on Linux. +void _CLDCVT( _LONGDOUBLE * dbl, char * buf, int bufSize, char fmt, int precision, int caps ) +{ + assert(false); +} +#endif + +static enum STATE ProcessSizeA( char sizeCh, char fmt_ch, char next_fmt_ch, int * advance, int * flags ) +{ + *advance = 0; + switch (sizeCh) + { + case 'l': + /* + * In order to handle the ll case, we depart from the + * simple deterministic state machine. + */ + if ( 'l' == fmt_ch ) + { + *advance = 1; + *flags |= FL_LONGLONG; + } + else + { + *flags |= FL_LONG; + } + break; + + case '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 ( '6' == fmt_ch && '4' == next_fmt_ch ) + { + *advance = 2; + *flags |= FL_I64; /* I64 => __int64 */ + } + else if ( '3' == fmt_ch && '2' == next_fmt_ch ) + { + *advance = 2; + *flags &= ~FL_I64; /* I32 => __int32 */ + } + else if ( + (fmt_ch == 'd') || + (fmt_ch == 'i') || + (fmt_ch == 'o') || + (fmt_ch == 'u') || + (fmt_ch == 'x') || + (fmt_ch == '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 + { + return ST_NORMAL; + } + break; + + case 'h': + *flags |= FL_SHORT; + break; + + case 'w': + *flags |= FL_WIDECHAR; + } + + return ST_SIZE; +} + +static enum STATE ProcessSizeW( WCHAR sizeCh, WCHAR fmt_ch, WCHAR next_fmt_ch, int * advance, int * flags ) +{ + *advance = 0; + switch (sizeCh) + { + case L'l': + /* + * In order to handle the ll case, we depart from the + * simple deterministic state machine. + */ + if ( L'l' == fmt_ch ) + { + *advance = 1; + *flags |= FL_LONGLONG; + } + else + { + *flags |= FL_LONG; + } + break; + + case L'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 ( L'6' == fmt_ch && L'4' == next_fmt_ch ) + { + *advance = 2; + *flags |= FL_I64; /* I64 => __int64 */ + } + else if ( L'3' == fmt_ch && L'2' == next_fmt_ch ) + { + *advance = 2; + *flags &= ~FL_I64; /* I32 => __int32 */ + } + else if ( + (fmt_ch == L'd') || + (fmt_ch == L'i') || + (fmt_ch == L'o') || + (fmt_ch == L'u') || + (fmt_ch == L'x') || + (fmt_ch == L'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 + { + return ST_NORMAL; + } + break; + + case L'h': + *flags |= FL_SHORT; + break; + + case L'w': + *flags |= FL_WIDECHAR; + } + + return ST_SIZE; +} + +STATE ProcessSize( WCHAR sizeCh, const WCHAR * format, int * advance, int * flags ) +{ + WCHAR formatCh = *format; + WCHAR next_formatCh = (L'\0' == formatCh ? L'\0' : *(format+1)); + return ProcessSizeW( sizeCh, formatCh, next_formatCh, advance, flags ); +} + +STATE ProcessSize( char sizeCh, const char * format, int * advance, int * flags ) +{ + char formatCh = *format; + char next_formatCh = ('\0' == formatCh ? '\0' : *(format+1)); + return ProcessSizeA( sizeCh, formatCh, next_formatCh, advance, flags ); +} + +// Tools\vc\src\crt\amd64\output.c +int FormattedPrintA( IFormattedPrintOutput * output, const char *format, va_list argptr ) +{ + int hexadd=0; /* offset to add to number to get 'a'..'f' */ + char 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 */ + char 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' or unused */ + int no_output=0; /* non-zero = prodcue no output for this specifier */ + union { + char *sz; /* pointer text to be printed, not zero terminated */ + WCHAR *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]; + } buffer; + WCHAR 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 _SAFECRT_IMPL + _LocaleUpdate _loc_update(plocinfo); +#endif /* _SAFECRT_IMPL */ + + char *heapbuf = NULL; /* non-zero = test.sz using heap buffer to be freed */ + + int advance; /* count of how much helper fxns need format ptr incremented */ + + _VALIDATE_RETURN( ((output != NULL) && (format != NULL)), EINVAL, -1); + + charsout = 0; /* no characters written yet */ + textlen = 0; /* no text yet */ + state = ST_NORMAL; /* starting state */ + heapbuf = NULL; /* not using heap-allocated buffer */ + buffersize = 0; + + /* main loop -- loop while format character exist and no I/O errors */ + while ((ch = *format++) != '\0' && charsout >= 0) { + // Find char class and next state + chclass = GetCharType( ch ); + state = GetState( chclass, state ); + + /* execute code for each state */ + switch (state) { + + case ST_INVALID: + // "Incorrect format specifier" + assert( false ); + errno = EINVAL; + return -1; + + case ST_NORMAL: + + NORMAL_STATE: + + /* normal state -- just write character */ + bufferiswide = 0; +#ifdef _SAFECRT_IMPL + if (isleadbyte((unsigned char)ch)) { +#else /* _SAFECRT_IMPL */ + if (_isleadbyte_l((unsigned char)ch, _loc_update.GetLocaleT())) { +#endif /* _SAFECRT_IMPL */ + // XPLAT_ODBC_TODO VSTS 718708 Localization + // Deal with more than 2 storage units per character + output->WRITE_CHAR(ch, &charsout); + ch = *format++; + /* don't fall off format string */ + _VALIDATE_RETURN( (ch != '\0'), EINVAL, -1); + } + output->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 ('-'): + flags |= FL_LEFT; /* '-' => left justify */ + break; + case ('+'): + flags |= FL_SIGN; /* '+' => force sign indicator */ + break; + case (' '): + flags |= FL_SIGNSP; /* ' ' => force sign or space */ + break; + case ('#'): + flags |= FL_ALTERNATE; /* '#' => alternate form */ + break; + case ('0'): + flags |= FL_LEADZERO; /* '0' => pad with leading zeros */ + break; + } + break; + + case ST_WIDTH: + /* update width value */ + if (ch == ('*')) { + /* get width from arg list */ + fldwidth = va_arg(argptr, int); + 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 - ('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 == ('*')) { + /* get precision from arg list */ + precision = va_arg(argptr, int); + if (precision < 0) + precision = -1; /* neg precision means default */ + } + else { + /* add digit to current precision */ + precision = precision * 10 + (ch - ('0')); + } + break; + + case ST_SIZE: + /* just read a size specifier, set the flags based on it */ + state = ProcessSize( ch, format, &advance, &flags ); + format += advance; + if ( ST_NORMAL == state ) + { + goto NORMAL_STATE; + } + 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 ('C'): /* ISO wide character */ + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) + flags |= FL_WIDECHAR; /* ISO std. */ + /* fall into 'c' case */ + + case ('c'): { + /* print a single character specified by int argument */ + if (flags & (FL_LONG|FL_WIDECHAR)) { + errno_t e = 0; + wchar = (WCHAR) va_arg(argptr, int); + /* convert to multibyte character */ + e = _WCTOMB_S(&textlen, buffer.sz, _countof(buffer.sz), wchar); + + /* check that conversion was successful */ + if (e != 0) + no_output = 1; + } else { + /* format multibyte character */ + /* this is an extension of ANSI */ + unsigned short temp; + temp = (unsigned short) va_arg(argptr, int); + { + buffer.sz[0] = (char) temp; + textlen = 1; + } + } + text.sz = buffer.sz; + } + break; + + case ('Z'): { + // 'Z' format specifier disabled + _VALIDATE_RETURN(0, EINVAL, -1); + } + break; + + case ('S'): /* ISO wide character string */ + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) + flags |= FL_WIDECHAR; + + case ('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; + char *p; /* temps */ + WCHAR *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 *)va_arg(argptr, void *); + + /* scan for null upto i characters */ + if (flags & (FL_LONG|FL_WIDECHAR)) { + if (text.wz == NULL) /* NULL passed, use special string */ + text.wz = (WCHAR *)__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 = (char*) __nullstring; + p = text.sz; + while (i-- && *p) + ++p; + textlen = (int)(p - text.sz); /* length of the string */ + } + } + break; + + + case ('n'): { + // We will not support %n + _VALIDATE_RETURN(0, EINVAL, -1); + } + break; + + case ('E'): + case ('G'): + case ('A'): + capexp = 1; /* capitalize exponent */ + ch += ('a') - ('A'); /* convert format char to lower */ + /* DROP THROUGH */ + case ('e'): + case ('f'): + case ('g'): + case ('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 == ('g')) + precision = 1; /* ANSI specified */ + else if (precision > MAXPRECISION) + precision = MAXPRECISION; + + if (precision > BUFFERSIZE - _CVTBUFSIZE) { + /* conversion will potentially overflow local buffer */ + /* so we need to use a heap-allocated buffer. */ + heapbuf = (char *)malloc(_CVTBUFSIZE + precision); + if (heapbuf != NULL) + { + text.sz = heapbuf; + buffersize = _CVTBUFSIZE + precision; + } + else + /* malloc failed, cap precision further */ + precision = BUFFERSIZE - _CVTBUFSIZE; + } + +#ifdef _SAFECRT_IMPL + /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */ + if (flags & FL_ALTERNATE) + { + capexp |= FL_ALTERNATE; + } +#endif /* _SAFECRT_IMPL */ + +#if !LONGDOUBLE_IS_DOUBLE + /* do the conversion */ + if (flags & FL_LONGDOUBLE) { + _LONGDOUBLE tmp; + tmp=va_arg(argptr, _LONGDOUBLE); + /* Note: assumes ch is in ASCII range */ + _CLDCVT(&tmp, text.sz, buffersize, (char)ch, precision, capexp); + } else +#endif /* !LONGDOUBLE_IS_DOUBLE */ + { + double tmp; + tmp=va_arg(argptr, 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) */ +#ifndef _SAFECRT_IMPL + _cfltcvt_l(&tmp, text.sz, buffersize, (char)ch, precision, capexp, _loc_update.GetLocaleT()); +#else /* _SAFECRT_IMPL */ + _CFLTCVT(&tmp, text.sz, buffersize, (char)ch, precision, capexp); +#endif /* _SAFECRT_IMPL */ + } + +#ifndef _SAFECRT_IMPL + /* For safecrt, this is done already in _safecrt_cfltcvt */ + + /* '#' and precision == 0 means force a decimal point */ + if ((flags & FL_ALTERNATE) && precision == 0) + { + _forcdecpt_l(text.sz, _loc_update.GetLocaleT()); + } + + /* 'g' format means crop zero unless '#' given */ + if (ch == ('g') && !(flags & FL_ALTERNATE)) + { + _cropzeros_l(text.sz, _loc_update.GetLocaleT()); + } +#endif /* _SAFECRT_IMPL */ + + /* 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 ('d'): + case ('i'): + /* signed decimal output */ + flags |= FL_SIGNED; + radix = 10; + goto COMMON_INT; + + case ('u'): + radix = 10; + goto COMMON_INT; + + case ('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 */ +#endif /* !PTR_IS_INT */ + /* DROP THROUGH to hex formatting */ + + case ('X'): + /* unsigned upper hex output */ + hexadd = ('A') - ('9') - 1; /* set hexadd for uppercase hex */ + goto COMMON_HEX; + + case ('x'): + /* unsigned lower hex output */ + hexadd = ('a') - ('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] = ('0'); + prefix[1] = (char)(('x') - ('a') + ('9') + 1 + hexadd); /* 'x' or 'X' */ + prefixlen = 2; + } + goto COMMON_INT; + + case ('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. */ + + ULONGLONG number; /* number to convert */ + int digit; /* ascii value of digit */ + LONGLONG l; /* temp long value */ + + /* 1. read argument into l, sign extend as needed */ + if (flags & FL_I64) + l = va_arg(argptr, LONGLONG); + else if (flags & FL_LONGLONG) + l = va_arg(argptr, LONGLONG); + else + + if (flags & FL_SHORT) { + if (flags & FL_SIGNED) + l = (short) va_arg(argptr, int); /* sign extend */ + else + l = (unsigned short) va_arg(argptr, int); /* zero-extend*/ + + } else + { + if (flags & FL_SIGNED) + l = (int)va_arg(argptr, int); /* sign extend */ + else + l = (unsigned int) va_arg(argptr, int); /* 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 ( (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; + } + + /* 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. */ + + text.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; + } + *text.sz-- = (char)digit; /* store the digit */ + } + + textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - text.sz); /* compute length of number */ + ++text.sz; /* text points to first digit now */ + + + /* 6. Force a leading zero if FORCEOCTAL flag set */ + if ((flags & FL_FORCEOCTAL) && (textlen == 0 || text.sz[0] != '0')) { + *--text.sz = '0'; + ++textlen; /* add a zero */ + } + } + 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] = ('-'); + prefixlen = 1; + } + else if (flags & FL_SIGN) { + /* prefix is '+' */ + prefix[0] = ('+'); + prefixlen = 1; + } + else if (flags & FL_SIGNSP) { + /* prefix is ' ' */ + prefix[0] = (' '); + 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 */ + output->WRITE_MULTI_CHAR((' '), padding, &charsout); + } + + /* write prefix */ + output->WRITE_STRING(prefix, prefixlen, &charsout); + + if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) { + /* write leading zeros */ + output->WRITE_MULTI_CHAR(('0'), padding, &charsout); + } + + /* write text */ + if (bufferiswide && (textlen > 0)) { + WCHAR *p; + int retval, count; + errno_t e = 0; + char L_buffer[MB_LEN_MAX+1]; + + p = text.wz; + count = textlen; + while (count--) { + e = _WCTOMB_S(&retval, L_buffer, _countof(L_buffer), *p++); + if (e != 0 || retval == 0) { + charsout = -1; + break; + } + output->WRITE_STRING(L_buffer, retval, &charsout); + } + } else { + output->WRITE_STRING(text.sz, textlen, &charsout); + } + + if (charsout >= 0 && (flags & FL_LEFT)) { + /* pad on right with blanks */ + output->WRITE_MULTI_CHAR((' '), padding, &charsout); + } + + /* we're done! */ + } + if (heapbuf) { + free(heapbuf); + heapbuf = NULL; + } + break; + } + } + + /* 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); + + return charsout; /* return value = number of characters written */ +} + +// Tools\vc\src\crt\amd64\output.c +int FormattedPrintW( IFormattedPrintOutput * output, const WCHAR *format, va_list argptr ) +{ + int hexadd=0; /* offset to add to number to get 'a'..'f' */ + WCHAR 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 */ + WCHAR 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' or unused */ + int no_output=0; /* non-zero = prodcue no output for this specifier */ + union { + char *sz; /* pointer text to be printed, not zero terminated */ + WCHAR *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]; + WCHAR wz[BUFFERSIZE]; + } buffer; + WCHAR 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 _SAFECRT_IMPL + _LocaleUpdate _loc_update(plocinfo); +#endif /* _SAFECRT_IMPL */ + + char *heapbuf = NULL; /* non-zero = test.sz using heap buffer to be freed */ + + int advance; /* count of how much helper fxns need format ptr incremented */ + + _VALIDATE_RETURN( ((output != NULL) && (format != NULL)), EINVAL, -1); + + charsout = 0; /* no characters written yet */ + textlen = 0; /* no text yet */ + state = ST_NORMAL; /* starting state */ + heapbuf = NULL; /* not using heap-allocated buffer */ + buffersize = 0; + + /* main loop -- loop while format character exist and no I/O errors */ + while ((ch = *format++) != L'\0' && charsout >= 0) { + // Find char class and next state + chclass = GetCharType( ch ); + state = GetState( chclass, state ); + + /* execute code for each state */ + switch (state) { + + case ST_INVALID: + // "Incorrect format specifier" + assert( false ); + errno = EINVAL; + return -1; + + case ST_NORMAL: + + NORMAL_STATE: + + /* normal state -- just write character */ + bufferiswide = 1; + if (isleadwchar(ch)) { + // Deal with more than 2 storage units per character + output->WRITE_CHAR(ch, &charsout); + ch = *format++; + /* don't fall off format string */ + _VALIDATE_RETURN( (ch != L'\0'), EINVAL, -1); + } + output->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 L'-': + flags |= FL_LEFT; /* '-' => left justify */ + break; + case L'+': + flags |= FL_SIGN; /* '+' => force sign indicator */ + break; + case L' ': + flags |= FL_SIGNSP; /* ' ' => force sign or space */ + break; + case L'#': + flags |= FL_ALTERNATE; /* '#' => alternate form */ + break; + case L'0': + flags |= FL_LEADZERO; /* '0' => pad with leading zeros */ + break; + } + break; + + case ST_WIDTH: + /* update width value */ + if (ch == L'*') { + /* get width from arg list */ + fldwidth = va_arg(argptr, int); + 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 - L'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 == L'*') { + /* get precision from arg list */ + precision = va_arg(argptr, int); + if (precision < 0) + precision = -1; /* neg precision means default */ + } + else { + /* add digit to current precision */ + precision = precision * 10 + (ch - L'0'); + } + break; + + case ST_SIZE: + /* just read a size specifier, set the flags based on it */ + state = ProcessSize( ch, format, &advance, &flags ); + format += advance; + if ( ST_NORMAL == state ) + { + goto NORMAL_STATE; + } + 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 L'C': /* ISO wide character */ + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) + flags |= FL_SHORT; + /* fall into 'c' case */ + + case L'c': { + /* print a single character specified by int argument */ + bufferiswide = 1; + wchar = (WCHAR) va_arg(argptr, int); + if (flags & FL_SHORT) { + /* format multibyte character */ + /* this is an extension of ANSI */ + char tempchar[2]; + { + tempchar[0] = (char)(wchar & 0x00ff); + tempchar[1] = '\0'; + } + +#ifdef _SAFECRT_IMPL + if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0) +#else /* _SAFECRT_IMPL */ + if (_mbtowc_l(buffer.wz, + tempchar, + _loc_update.GetLocaleT()->locinfo->mb_cur_max, + _loc_update.GetLocaleT()) < 0) +#endif /* _SAFECRT_IMPL */ + { + /* ignore if conversion was unsuccessful */ + no_output = 1; + } + } else { + buffer.wz[0] = wchar; + } + text.wz = buffer.wz; + textlen = 1; /* print just a single character */ + } + break; + + case L'Z': { + // 'Z' format specifier disabled + _VALIDATE_RETURN(0, EINVAL, -1); + } + break; + + case L'S': /* ISO wide character string */ + if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR))) + flags |= FL_SHORT; + + case L'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; + char *p; /* temps */ + WCHAR *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 *)va_arg(argptr, void *); + + /* scan for null upto i characters */ + if (flags & FL_SHORT) { + if (text.sz == NULL) /* NULL passed, use special string */ + text.sz = (char*) __nullstring; + p = text.sz; + for (textlen=0; textlen MAXPRECISION) + precision = MAXPRECISION; + + if (precision > BUFFERSIZE - _CVTBUFSIZE) { + /* conversion will potentially overflow local buffer */ + /* so we need to use a heap-allocated buffer. */ + heapbuf = (char *)malloc(_CVTBUFSIZE + precision); + if (heapbuf != NULL) + { + text.sz = heapbuf; + buffersize = _CVTBUFSIZE + precision; + } + else + /* malloc failed, cap precision further */ + precision = BUFFERSIZE - _CVTBUFSIZE; + } + +#ifdef _SAFECRT_IMPL + /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */ + if (flags & FL_ALTERNATE) + { + capexp |= FL_ALTERNATE; + } +#endif /* _SAFECRT_IMPL */ + +#if !LONGDOUBLE_IS_DOUBLE + /* do the conversion */ + if (flags & FL_LONGDOUBLE) { + _LONGDOUBLE tmp; + tmp=va_arg(argptr, _LONGDOUBLE); + /* Note: assumes ch is in ASCII range */ + _CLDCVT(&tmp, text.sz, buffersize, (char)ch, precision, capexp); + } else +#endif /* !LONGDOUBLE_IS_DOUBLE */ + { + double tmp; + tmp=va_arg(argptr, 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) */ +#ifndef _SAFECRT_IMPL + _cfltcvt_l(&tmp, text.sz, buffersize, (char)ch, precision, capexp, _loc_update.GetLocaleT()); +#else /* _SAFECRT_IMPL */ + _CFLTCVT(&tmp, text.sz, buffersize, (char)ch, precision, capexp); +#endif /* _SAFECRT_IMPL */ + } + +#ifndef _SAFECRT_IMPL + /* For safecrt, this is done already in _safecrt_cfltcvt */ + + /* '#' and precision == 0 means force a decimal point */ + if ((flags & FL_ALTERNATE) && precision == 0) + { + _forcdecpt_l(text.sz, _loc_update.GetLocaleT()); + } + + /* 'g' format means crop zero unless '#' given */ + if (ch == L'g' && !(flags & FL_ALTERNATE)) + { + _cropzeros_l(text.sz, _loc_update.GetLocaleT()); + } +#endif /* _SAFECRT_IMPL */ + + /* 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 L'd': + case L'i': + /* signed decimal output */ + flags |= FL_SIGNED; + radix = 10; + goto COMMON_INT; + + case L'u': + radix = 10; + goto COMMON_INT; + + case L'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 */ +#endif /* !PTR_IS_INT */ + /* DROP THROUGH to hex formatting */ + + case L'X': + /* unsigned upper hex output */ + hexadd = L'A' - L'9' - 1; /* set hexadd for uppercase hex */ + goto COMMON_HEX; + + case L'x': + /* unsigned lower hex output */ + hexadd = L'a' - L'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] = L'0'; + prefix[1] = (WCHAR)(L'x' - L'a' + L'9' + 1 + hexadd); /* 'x' or 'X' */ + prefixlen = 2; + } + goto COMMON_INT; + + case L'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. */ + + ULONGLONG number; /* number to convert */ + int digit; /* ascii value of digit */ + LONGLONG l; /* temp long value */ + + /* 1. read argument into l, sign extend as needed */ + if (flags & FL_I64) + l = va_arg(argptr, LONGLONG); + else if (flags & FL_LONGLONG) + l = va_arg(argptr, LONGLONG); + else + + if (flags & FL_SHORT) { + if (flags & FL_SIGNED) + l = (short) va_arg(argptr, int); /* sign extend */ + else + l = (unsigned short) va_arg(argptr, int); /* zero-extend*/ + + } else + { + if (flags & FL_SIGNED) + l = (int)va_arg(argptr, int); /* sign extend */ + else + l = (unsigned int) va_arg(argptr, int); /* 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 ( (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; + } + + /* 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. */ + + text.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; + } + *text.sz-- = (char)digit; /* store the digit */ + } + + textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - text.sz); /* compute length of number */ + ++text.sz; /* text points to first digit now */ + + + /* 6. Force a leading zero if FORCEOCTAL flag set */ + if ((flags & FL_FORCEOCTAL) && (textlen == 0 || text.sz[0] != '0')) { + *--text.sz = '0'; + ++textlen; /* add a zero */ + } + } + 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] = L'-'; + prefixlen = 1; + } + else if (flags & FL_SIGN) { + /* prefix is '+' */ + prefix[0] = L'+'; + prefixlen = 1; + } + else if (flags & FL_SIGNSP) { + /* prefix is ' ' */ + prefix[0] = L' '; + 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 */ + output->WRITE_MULTI_CHAR(L' ', padding, &charsout); + } + + /* write prefix */ + output->WRITE_STRING(prefix, prefixlen, &charsout); + + if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) { + /* write leading zeros */ + output->WRITE_MULTI_CHAR(L'0', padding, &charsout); + } + + /* write text */ + if (!bufferiswide && textlen > 0) { + char *p; + int retval, count; + + p = text.sz; + count = textlen; + while (count-- > 0) { +#ifdef _SAFECRT_IMPL + retval = _MBTOWC(&wchar, p, MB_CUR_MAX); +#else /* _SAFECRT_IMPL */ + retval = _mbtowc_l(&wchar, + p, + _loc_update.GetLocaleT()->locinfo->mb_cur_max, + _loc_update.GetLocaleT()); +#endif /* _SAFECRT_IMPL */ + if (retval <= 0) { + charsout = -1; + break; + } + output->WRITE_CHAR(wchar, &charsout); + p += retval; + } + } else { + output->WRITE_STRING(text.wz, textlen, &charsout); + } + + if (charsout >= 0 && (flags & FL_LEFT)) { + /* pad on right with blanks */ + output->WRITE_MULTI_CHAR(L' ', padding, &charsout); + } + + /* we're done! */ + } + if (heapbuf) { + free(heapbuf); + heapbuf = NULL; + } + break; + } + } + + /* 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); + + return charsout; /* return value = number of characters written */ +} + + +// Used for holding the size and value of a variable argument. +// Uses INT and LONGLONG to hold all possible values. Each is just a buffer to hold the right number of bits. +struct vararg_t +{ + enum ArgType_e + { + Unknown, + Int32, + Int64, + ShouldBeInt32, + ShouldBeInt64 + }; + + vararg_t() : int64Val(0), int32Val(0), argType(vararg_t::Unknown) {} + vararg_t( INT val ) : int64Val(0), int32Val(val), argType(vararg_t::Int32) {} + vararg_t( LONGLONG ptr ) : int64Val(ptr), int32Val(0), argType(vararg_t::Int64) {} + + ArgType_e Type() const { return argType; } + INT Int32Value() const { return int32Val; } + LONGLONG Int64Value() const { return int64Val; } + void * PtrValue() const + { +#if PTR_IS_INT64 + return reinterpret_cast(int64Val); +#else + return reinterpret_cast(int32Val); +#endif + } + + void SetForInt32() + { + assert( vararg_t::Unknown == argType ); + argType = vararg_t::ShouldBeInt32; + } + void SetForInt64() + { + assert( vararg_t::Unknown == argType ); + argType = vararg_t::ShouldBeInt64; + } + void SetForPtr() + { +#if PTR_IS_INT64 + SetForInt64(); +#else + SetForInt32(); +#endif + } + + void Int32Value( INT val ) + { + assert( vararg_t::Unknown == argType || vararg_t::ShouldBeInt32 == argType ); + assert( 0 == int64Val ); + argType = vararg_t::Int32; + int32Val = val; + } + void Int64Value( LONGLONG val ) + { + assert( vararg_t::Unknown == argType || vararg_t::ShouldBeInt64 == argType ); + assert( 0 == int32Val ); + argType = vararg_t::Int64; + int64Val = val; + } + +private: + LONGLONG int64Val; + INT int32Val; + ArgType_e argType; +}; + +// Caches the var arg values in the supplied vector. Types are determined by inspecting the format string. +// On error, sets errno and returns false +static bool GetFormatMessageArgsA( const char * format, std::vector< vararg_t > * argcache, va_list * Arguments ) +{ + if ( NULL == format ) + { + errno = EINVAL; + return false; + } + + const char *p = format; + char fmt_ch; + + while( '\0' != (fmt_ch = *p++) ) + { + if ( '%' != fmt_ch ) + { + // continue to next format spec + } + else if ( '0' == *p || '\0' == *p ) + { + // %0 or null term means end formatting + break; + } + else if ( *p < '1' || '9' < *p ) + { + // Escaped char, skip and keep going + ++p; + } + else + { + // Integer must be [1..99] + size_t argPos = *p++ - '0'; + if ( '0' <= *p && *p <= '9' ) + { + argPos *= 10; + argPos += *p++ - '0'; + } + assert( 0 < argPos && argPos < 100 ); + + if ( argcache->size() < argPos ) + { + // Haven't processed this arg, yet + argcache->resize( argPos ); + } + + if ( vararg_t::Unknown == argcache->at(argPos-1).Type() ) + { + if ( '!' != *p ) + { + // Assume %s as per spec + argcache->at(argPos-1).SetForPtr(); + } + else + { + // Step over the initial '!' and process format specification + ++p; + + char ch; + int flags = 0; + int advance = 0; + enum CHARTYPE chclass; + enum STATE state = ST_PERCENT; + bool found_terminator = false; + while ( !found_terminator && ('\0' != (ch = *p++)) ) + { + chclass = GetCharType( ch ); + state = GetState( chclass, state ); + + switch ( state ) + { + case ST_DOT: + case ST_FLAG: + break; + + case ST_WIDTH: + case ST_PRECIS: + if ( '*' == ch ) + { + argcache->at(argPos-1).SetForInt32(); + ++argPos; + if ( argcache->size() < argPos ) + { + argcache->resize( argPos ); + } + } + break; + + case ST_SIZE: + state = ProcessSize( ch, p, &advance, &flags ); + p += advance; + if ( ST_SIZE != state ) + { + // Size and type flags were inconsistent + errno = EINVAL; + return false; + } + break; + + case ST_TYPE: + // Group into 32-bit and 64-bit sized args + assert( vararg_t::Unknown == argcache->at(argPos-1).Type() ); + switch ( ch ) + { + case 'C': // chars + case 'c': + argcache->at(argPos-1).SetForInt32(); + break; + + case 'd': // ints + case 'i': + case 'u': + case 'X': + case 'x': + case 'o': + // INT args + if ( (flags & FL_I64) || (flags & FL_LONGLONG) ) + argcache->at(argPos-1).SetForInt64(); + else + argcache->at(argPos-1).SetForInt32(); + break; + + case 'S': // strings + case 's': + case 'p': // pointer + argcache->at(argPos-1).SetForPtr(); + break; + + case 'E': // doubles (not supported as per spec) + case 'e': + case 'G': + case 'g': + case 'A': + case 'a': + case 'f': + default: + errno = EINVAL; + return false; + } + break; + + case ST_NORMAL: + if ( '!' == ch ) + { + found_terminator = true; + break; + } + // Fall thru to error, missing terminating '!' + + default: + errno = EINVAL; + return false; + } + } + + if ( !found_terminator ) + { + // End of string before trailing '!' was found + errno = EINVAL; + return false; + } + } + } + } + } + + if ( 0 < argcache->size() && NULL == Arguments ) + { + errno = EINVAL; + return false; + } + + // Cache var arg values now that we know the number and sizes + for ( std::vector< vararg_t >::iterator arg = argcache->begin(); arg != argcache->end(); ++arg ) + { + if ( vararg_t::Unknown == arg->Type() ) + { + // Arg not referenced in format string so assume ptr sized. + // This is a decent assumption since every arg gets ptr-size bytes to ensure alignment + // of later arg values. Verified this behavior with both Windows and Linux. + arg->SetForPtr(); + } + + vararg_t::ArgType_e argtype = arg->Type(); + assert( vararg_t::ShouldBeInt32 == argtype || vararg_t::ShouldBeInt64 == argtype ); + + if ( vararg_t::ShouldBeInt32 == argtype ) + { + arg->Int32Value( (INT)va_arg(*Arguments, INT) ); + } + else + { + arg->Int64Value( (LONGLONG)va_arg(*Arguments, LONGLONG) ); + } + } + + return true; +} + +// Caches the var arg values in the supplied vector. Types are determined by inspecting the format string. +// On error, sets errno and returns false +static bool GetFormatMessageArgsW( const WCHAR * format, std::vector< vararg_t > * argcache, va_list * Arguments ) +{ + if ( NULL == format ) + { + errno = EINVAL; + return false; + } + + const WCHAR *p = format; + WCHAR fmt_ch; + + while( L'\0' != (fmt_ch = *p++) ) + { + if ( L'%' != fmt_ch ) + { + // continue to next format spec + } + else if ( L'0' == *p || L'\0' == *p ) + { + // %0 or null term means end formatting + break; + } + else if ( *p < L'1' || L'9' < *p ) + { + // Escaped char, skip and keep going + ++p; + } + else + { + // Integer must be [1..99] + size_t argPos = *p++ - L'0'; + if ( L'0' <= *p && *p <= L'9' ) + { + argPos *= 10; + argPos += *p++ - L'0'; + } + assert( 0 < argPos && argPos < 100 ); + + if ( argcache->size() < argPos ) + { + // Haven't processed this arg, yet + argcache->resize( argPos ); + } + + if ( vararg_t::Unknown == argcache->at(argPos-1).Type() ) + { + if ( L'!' != *p ) + { + // Assume %s as per spec + argcache->at(argPos-1).SetForPtr(); + } + else + { + // Step over the initial '!' and process format specification + ++p; + + WCHAR ch; + int flags = 0; + int advance = 0; + enum CHARTYPE chclass; + enum STATE state = ST_PERCENT; + bool found_terminator = false; + while ( !found_terminator && (L'\0' != (ch = *p++)) ) + { + chclass = GetCharType( ch ); + state = GetState( chclass, state ); + + switch ( state ) + { + case ST_DOT: + case ST_FLAG: + break; + + case ST_WIDTH: + case ST_PRECIS: + if ( L'*' == ch ) + { + argcache->at(argPos-1).SetForInt32(); + ++argPos; + if ( argcache->size() < argPos ) + { + argcache->resize( argPos ); + } + } + break; + + case ST_SIZE: + state = ProcessSize( ch, p, &advance, &flags ); + p += advance; + if ( ST_SIZE != state ) + { + // Size and type flags were inconsistent + errno = EINVAL; + return false; + } + break; + + case ST_TYPE: + // Group into 32-bit and 64-bit sized args + assert( vararg_t::Unknown == argcache->at(argPos-1).Type() ); + switch ( ch ) + { + case L'C': // chars + case L'c': + argcache->at(argPos-1).SetForInt32(); + break; + + case L'd': // ints + case L'i': + case L'u': + case L'X': + case L'x': + case L'o': + // INT args + if ( (flags & FL_I64) || (flags & FL_LONGLONG) ) + argcache->at(argPos-1).SetForInt64(); + else + argcache->at(argPos-1).SetForInt32(); + break; + + case L'S': // strings + case L's': + case L'p': // pointer + argcache->at(argPos-1).SetForPtr(); + break; + + case L'E': // doubles (not supported as per spec) + case L'e': + case L'G': + case L'g': + case L'A': + case L'a': + case L'f': + default: + errno = EINVAL; + return false; + } + break; + + case ST_NORMAL: + if ( L'!' == ch ) + { + found_terminator = true; + break; + } + // Fall thru to error, missing terminating '!' + + default: + errno = EINVAL; + return false; + } + } + + if ( !found_terminator ) + { + // End of string before trailing '!' was found + errno = EINVAL; + return false; + } + } + } + } + } + + if ( 0 < argcache->size() && NULL == Arguments ) + { + errno = EINVAL; + return false; + } + + // Cache var arg values now that we know the number and sizes + for ( std::vector< vararg_t >::iterator arg = argcache->begin(); arg != argcache->end(); ++arg ) + { + if ( vararg_t::Unknown == arg->Type() ) + { + // Arg not referenced in format string so assume ptr sized. + // This is a decent assumption since every arg gets ptr-size bytes to ensure alignment + // of later arg values. Verified this behavior with both Windows and Linux. + arg->SetForPtr(); + } + + vararg_t::ArgType_e argtype = arg->Type(); + assert( vararg_t::ShouldBeInt32 == argtype || vararg_t::ShouldBeInt64 == argtype ); + + if ( vararg_t::ShouldBeInt32 == argtype ) + { + arg->Int32Value( (INT)va_arg(*Arguments, INT) ); + } + else + { + arg->Int64Value( (LONGLONG)va_arg(*Arguments, LONGLONG) ); + } + } + + return true; +} + +// On success, returns the number of chars written into the buffer excluding null terminator. +// On error, sets errno and returns zero. +static DWORD FormatMessageToBufferA( const char * format, char * buffer, DWORD bufferWCharSize, const std::vector< vararg_t > & args ) +{ + char * msg = buffer; + DWORD bufsize = std::min(bufferWCharSize, (DWORD)64000); + DWORD msg_pos = 0; + const DWORD fmtsize = 32; + char fmt[fmtsize]; + DWORD fmt_pos; + char fmt_ch; + + const char * p = format; + while( msg_pos < bufsize && '\0' != (fmt_ch = *p++) ) + { + if ( '%' != fmt_ch ) + { + msg[msg_pos++] = fmt_ch; + } + else if ( '0' == *p || '\0' == *p ) + { + // %0 or null term means end formatting + break; + } + else if ( *p < '1' || '9' < *p ) + { + // Escaped char, print and keep going + // Eg. "%n" == '\n' + switch ( *p ) + { + case 'a': msg[msg_pos++] = '\a'; break; + case 'b': msg[msg_pos++] = '\b'; break; + case 'f': msg[msg_pos++] = '\f'; break; + case 'n': msg[msg_pos++] = '\n'; break; + case 'r': msg[msg_pos++] = '\r'; break; + case 't': msg[msg_pos++] = '\t'; break; + case 'v': msg[msg_pos++] = '\v'; break; + default: msg[msg_pos++] = *p; break; + } + ++p; + } + else + { + // Integer must be [1..99] + size_t argPos = *p++ - '0'; + if ( '0' <= *p && *p <= '9' ) + { + argPos *= 10; + argPos += *p++ - '0'; + } + assert( 0 < argPos && argPos < 100 ); + + fmt_pos = 0; + fmt[fmt_pos++] = '%'; + + if ( '!' != *p ) + { + // Assume %s as per spec + fmt[fmt_pos++] = 's'; + fmt[fmt_pos] = '\0'; + int chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].PtrValue() ); + if ( chars_printed < 0 ) + { + errno = EINVAL; + return 0; + } + msg_pos += chars_printed; + } + else + { + // Skip over '!' and build format string + ++p; + char ch; + int flags = 0; + int advance = 0; + enum CHARTYPE chclass; + enum STATE state = ST_PERCENT; + bool found_terminator = false; + while ( fmt_pos < fmtsize && !found_terminator && ('\0' != (ch = *p++)) ) + { + chclass = GetCharType( ch ); + state = GetState( chclass, state ); + + switch ( state ) + { + case ST_SIZE: + state = ProcessSize( ch, p, &advance, &flags ); + fmt[fmt_pos++] = ch; + while ( fmt_pos < fmtsize && 0 < advance-- ) + { + fmt[fmt_pos++] = *p++; + } + break; + + case ST_NORMAL: + assert( '!' == ch ); + found_terminator = true; + break; + + case ST_INVALID: + case ST_PERCENT: + errno = EINVAL; + return 0; + + default: + fmt[fmt_pos++] = ch; + break; + } + } + + if ( fmtsize <= fmt_pos ) + { + // Should not have a format string longer than 31 chars + // It can happen but shouldn't (eg. a bunch of size mods like %llllllllllllllld) + errno = EINVAL; + return 0; + } + + fmt[fmt_pos] = '\0'; + + // Format string might need up to 3 args (eg. %*.*d ) + // If more than one arg, then the first ones must be 32-bit ints + // Hence, first 64-bit arg tells us the last arg we need to send. + int chars_printed = 0; + if ( vararg_t::Int64 == args[argPos-1].Type() ) + { + chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int64Value() ); + } + else if ( args.size() == argPos ) + { + // No more args so send the one Int + chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value() ); + } + else if ( vararg_t::Int64 == args[argPos].Type() ) + { + chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int64Value() ); + } + else if ( args.size() == (argPos+1) ) + { + // No more args so send the two Ints + chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos-1].Int32Value() ); + } + else if ( vararg_t::Int64 == args[argPos+1].Type() ) + { + chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int32Value(), args[argPos+1].Int64Value() ); + } + else + { + chars_printed = mplat_snprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int32Value(), args[argPos+1].Int32Value() ); + } + + if ( chars_printed < 0 ) + { + errno = EINVAL; + return 0; + } + msg_pos += chars_printed; + } + } + } + + if ( bufsize <= msg_pos ) + { + errno = ERANGE; + return 0; + } + + msg[msg_pos] = '\0'; + return msg_pos; +} + +// On success, returns the number of chars written into the buffer excluding null terminator. +// On error, sets errno and returns zero. +static DWORD FormatMessageToBufferW( const WCHAR * format, WCHAR * buffer, DWORD bufferWCharSize, const std::vector< vararg_t > & args ) +{ + WCHAR * msg = buffer; + DWORD bufsize = std::min(bufferWCharSize, (DWORD)64000); + DWORD msg_pos = 0; + const DWORD fmtsize = 32; + WCHAR fmt[fmtsize]; + DWORD fmt_pos; + WCHAR fmt_ch; + + const WCHAR * p = format; + while( msg_pos < bufsize && L'\0' != (fmt_ch = *p++) ) + { + if ( L'%' != fmt_ch ) + { + msg[msg_pos++] = fmt_ch; + } + else if ( L'0' == *p || L'\0' == *p ) + { + // %0 or null term means end formatting + break; + } + else if ( *p < L'1' || L'9' < *p ) + { + // Escaped char, print and keep going + // Eg. "%n" == '\n' + switch ( *p ) + { + case L'a': msg[msg_pos++] = L'\a'; break; + case L'b': msg[msg_pos++] = L'\b'; break; + case L'f': msg[msg_pos++] = L'\f'; break; + case L'n': msg[msg_pos++] = L'\n'; break; + case L'r': msg[msg_pos++] = L'\r'; break; + case L't': msg[msg_pos++] = L'\t'; break; + case L'v': msg[msg_pos++] = L'\v'; break; + default: msg[msg_pos++] = *p; break; + } + ++p; + } + else + { + // Integer must be [1..99] + size_t argPos = *p++ - L'0'; + if ( L'0' <= *p && *p <= L'9' ) + { + argPos *= 10; + argPos += *p++ - L'0'; + } + assert( 0 < argPos && argPos < 100 ); + + fmt_pos = 0; + fmt[fmt_pos++] = L'%'; + + if ( L'!' != *p ) + { + // Assume %s as per spec + fmt[fmt_pos++] = L's'; + fmt[fmt_pos] = L'\0'; + int chars_printed = mplat_snwprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].PtrValue() ); + if ( chars_printed < 0 ) + { + errno = EINVAL; + return 0; + } + msg_pos += chars_printed; + } + else + { + // Skip over '!' and build format string + ++p; + WCHAR ch; + int flags = 0; + int advance = 0; + enum CHARTYPE chclass; + enum STATE state = ST_PERCENT; + bool found_terminator = false; + while ( fmt_pos < fmtsize && !found_terminator && (L'\0' != (ch = *p++)) ) + { + chclass = GetCharType( ch ); + state = GetState( chclass, state ); + + switch ( state ) + { + case ST_SIZE: + state = ProcessSize( ch, p, &advance, &flags ); + fmt[fmt_pos++] = ch; + while ( fmt_pos < fmtsize && 0 < advance-- ) + { + fmt[fmt_pos++] = *p++; + } + break; + + case ST_NORMAL: + assert( L'!' == ch ); + found_terminator = true; + break; + + case ST_INVALID: + case ST_PERCENT: + errno = EINVAL; + return 0; + + default: + fmt[fmt_pos++] = ch; + break; + } + } + + if ( fmtsize <= fmt_pos ) + { + // Should not have a format string longer than 31 chars + // It can happen but shouldn't (eg. a bunch of size mods like %llllllllllllllld) + errno = EINVAL; + return 0; + } + + fmt[fmt_pos] = L'\0'; + + // Format string might need up to 3 args (eg. %*.*d ) + // If more than one arg, then the first ones must be 32-bit ints + // Hence, first 64-bit arg tells us the last arg we need to send. + int chars_printed = 0; + if ( vararg_t::Int64 == args[argPos-1].Type() ) + { + chars_printed = mplat_snwprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int64Value() ); + } + else if ( args.size() == argPos ) + { + // No more args so send the one Int + chars_printed = mplat_snwprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value() ); + } + else if ( vararg_t::Int64 == args[argPos].Type() ) + { + chars_printed = mplat_snwprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int64Value() ); + } + else if ( args.size() == (argPos+1) ) + { + // No more args so send the two Ints + chars_printed = mplat_snwprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos-1].Int32Value() ); + } + else if ( vararg_t::Int64 == args[argPos+1].Type() ) + { + chars_printed = mplat_snwprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int32Value(), args[argPos+1].Int64Value() ); + } + else + { + chars_printed = mplat_snwprintf_s( &msg[msg_pos], bufsize-msg_pos, bufsize-msg_pos, fmt, args[argPos-1].Int32Value(), args[argPos].Int32Value(), args[argPos+1].Int32Value() ); + } + + if ( chars_printed < 0 ) + { + errno = EINVAL; + return 0; + } + msg_pos += chars_printed; + } + } + } + + if ( bufsize <= msg_pos ) + { + errno = ERANGE; + return 0; + } + + msg[msg_pos] = L'\0'; + return msg_pos; +} + + +DWORD FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPTSTR lpBuffer, DWORD nSize, va_list *Arguments) +{ + DWORD chars_printed = 0; + + // XPLAT_ODBC_TODO VSTS 718708 Localization by handling FORMAT_MESSAGE_FROM_HMODULE and dwLanguageId param + if ( dwFlags & FORMAT_MESSAGE_FROM_STRING ) + { + // Format specification allows for reordering of insertions relative to var arg position + // This means we need to walk thru the format specification to find the types of the var args in var arg order + // We extract the var args in order based on the identified types + // Finally, we re-walk the format specfication and perform the insertions + + // First pass thru the format string to determine all args and their types + // This first pass also validates the format string and will return an error + // if it is invalid. This allows FormatMessageToBuffer to have less error + // checking. + std::vector< vararg_t > args; + // Based on quick scan of RC files, the largest arg count was 7 so reserve 8 slots to reduce allocations + args.reserve(8); + if ( GetFormatMessageArgsA( reinterpret_cast(lpSource), &args, Arguments ) ) + { + if ( dwFlags == (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING) ) + { + *((char**)lpBuffer) = NULL; + + const DWORD max_size = 64000; + char local_buf[max_size]; + chars_printed = FormatMessageToBufferA( reinterpret_cast(lpSource), local_buf, max_size, args ); + if ( 0 < chars_printed ) + { + size_t buf_size = std::min( max_size, std::max(nSize, (chars_printed+1)) ); + char * return_buf = (char *)LocalAlloc(0, buf_size * sizeof(char)); + if ( NULL == return_buf ) + { + errno = ENOMEM; + } + else + { + mplat_cscpy(return_buf, local_buf); + *((char**)lpBuffer) = return_buf; + } + } + } + else if ( dwFlags == FORMAT_MESSAGE_FROM_STRING ) + { + chars_printed = FormatMessageToBufferA( reinterpret_cast(lpSource), lpBuffer, std::min(nSize, (DWORD)64000), args ); + } + } + } + else if ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM ) + { + // Since we don't have the Windows system error messages available use a fixed message + // Can not use a message ID for this since this same code is used by driver and tools, + // each having their own RLL file. Don't think we should be reserving an ID across all RLLs. + const char systemMsg[] = "Error code 0x%X"; + if ( dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER ) + { + *((char**)lpBuffer) = NULL; + + // Add 9 for up to 8 hex digits plus null term (ignore removal of format specs) + const size_t msgsize = (9 + sizeof(systemMsg)/sizeof(systemMsg[0])); + char * return_buf = (char *)LocalAlloc(0, msgsize * sizeof(char)); + if ( NULL == return_buf ) + { + errno = ENOMEM; + } + else + { + chars_printed = mplat_snprintf_s( return_buf, msgsize, msgsize, systemMsg, dwMessageId ); + // Assert that we did our buffer size math right + assert( chars_printed < msgsize ); + if ( 0 < chars_printed ) + { + *((char**)lpBuffer) = return_buf; + } + else + { + LocalFree( return_buf ); + errno = EINVAL; + } + } + } + else + { + chars_printed = mplat_snprintf_s( lpBuffer, nSize, nSize, systemMsg, dwMessageId ); + } + } + + return chars_printed; +} + + +// FormatMessage implementation details (see MSDN for more info) +// +// The Windows FormatMessage API is very rich, complex. This is not an exact duplication of that function. +// Instead, the most important aspects of this function have been implemented here along with constraints to +// match how we use it within SNAC, BCP, and SQLCMD. +// +// Only these combinations of dwFlags are supported: +// FORMAT_MESSAGE_FROM_STRING +// Writes formatted message into supplied buffer +// FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING +// Allocates a buffer, writes formatted message into that buffer, returns buffer in lpBufffer +// FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS +// Writes fixed, English message into the supplied buffer (do not have Windows resources to get real message) +// FORMAT_MESSAGE_FROM_HMODULE +// SQLCMD uses this to read strings from the RLL that have not been translated to the current lang +// +// dwLanguageId is ignored for FORMAT_MESSAGE_FROM_STRING as per spec +// For FORMAT_MESSAGE_FROM_SYSTEM, we don't have Windows resources so language is irrelevant +DWORD FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, va_list *Arguments) +{ + DWORD chars_printed = 0; + + // XPLAT_ODBC_TODO VSTS 718708 Localization by handling FORMAT_MESSAGE_FROM_HMODULE and dwLanguageId param + if ( dwFlags & FORMAT_MESSAGE_FROM_STRING ) + { + // Format specification allows for reordering of insertions relative to var arg position + // This means we need to walk thru the format specification to find the types of the var args in var arg order + // We extract the var args in order based on the identified types + // Finally, we re-walk the format specfication and perform the insertions + + // First pass thru the format string to determine all args and their types + // This first pass also validates the format string and will return an error + // if it is invalid. This allows FormatMessageToBuffer to have less error + // checking. + std::vector< vararg_t > args; + // Based on quick scan of RC files, the largest arg count was 7 so reserve 8 slots to reduce allocations + args.reserve(8); + if ( GetFormatMessageArgsW( reinterpret_cast(lpSource), &args, Arguments ) ) + { + if ( dwFlags == (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING) ) + { + *((WCHAR**)lpBuffer) = NULL; + + const DWORD max_size = 64000; + WCHAR local_buf[max_size]; + chars_printed = FormatMessageToBufferW( reinterpret_cast(lpSource), local_buf, max_size, args ); + if ( 0 < chars_printed ) + { + size_t buf_size = std::min( max_size, std::max(nSize, (chars_printed+1)) ); + WCHAR * return_buf = (WCHAR *)LocalAlloc(0, buf_size * sizeof(WCHAR)); + if ( NULL == return_buf ) + { + errno = ENOMEM; + } + else + { + mplat_wcscpy(return_buf, local_buf); + *((WCHAR**)lpBuffer) = return_buf; + } + } + } + else if ( dwFlags == FORMAT_MESSAGE_FROM_STRING ) + { + chars_printed = FormatMessageToBufferW( reinterpret_cast(lpSource), lpBuffer, std::min(nSize, (DWORD)64000), args ); + } + } + } + else if ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM ) + { + // Since we don't have the Windows system error messages available use a fixed message + // Can not use a message ID for this since this same code is used by driver and tools, + // each having their own RLL file. Don't think we should be reserving an ID across all RLLs. + const wchar_t systemMsg[] = L"Error code 0x%X"; + if ( dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER ) + { + *((WCHAR**)lpBuffer) = NULL; + + // Add 9 for up to 8 hex digits plus null term (ignore removal of format specs) + const size_t msgsize = (9 + sizeof(systemMsg)/sizeof(systemMsg[0])); + WCHAR * return_buf = (WCHAR *)LocalAlloc(0, msgsize * sizeof(WCHAR)); + if ( NULL == return_buf ) + { + errno = ENOMEM; + } + else + { + chars_printed = mplat_snwprintf_s( return_buf, msgsize, msgsize, (WCHAR *)systemMsg, dwMessageId ); + // Assert that we did our buffer size math right + assert( chars_printed < msgsize ); + if ( 0 < chars_printed ) + { + *((WCHAR**)lpBuffer) = return_buf; + } + else + { + LocalFree( return_buf ); + errno = EINVAL; + } + } + } + else + { + chars_printed = mplat_snwprintf_s( lpBuffer, nSize, nSize, (WCHAR *)systemMsg, dwMessageId ); + } + } + + return chars_printed; +} + +//--------Other definitions from xplat stub sources-------------- + +BOOL IsDBCSLeadByte(__inn BYTE TestChar) +{ + // XPLAT_ODBC_TODO: This is to allow BatchParser to function + // BatchParser will single step thru utf8 code points + // BatchParser needs to become utf8-aware + // VSTS 718708 Localization + if ( CP_UTF8 == SystemLocale::Singleton().AnsiCP() ) + return FALSE; + // XPLAT_ODBC_TODO + + return IsDBCSLeadByteEx(SystemLocale::Singleton().AnsiCP(), TestChar); +} + +BOOL IsDBCSLeadByteEx( + __inn UINT CodePage, + __inn BYTE TestChar) +{ + if ( 1 == SystemLocale::MaxCharCchSize(CodePage) ) + return FALSE; + + // Lead byte ranges for code pages, inclusive: + // CP932 + // 0x81-0x9f, 0xe0-0xfc + // CP936, CP949, CP950 + // 0x81-0xfe + assert( 932 == CodePage || 936 == CodePage || 949 == CodePage || 950 == CodePage ); + if ( 932 == CodePage ) + { + if ( TestChar < (unsigned char)0x81 + || (unsigned char)0xfc < TestChar + || ((unsigned char)0x9f < TestChar && TestChar < (unsigned char)0xe0) ) + { + return FALSE; + } + } + else if ( TestChar < (unsigned char)0x81 || TestChar == (unsigned char)0xff ) + return FALSE; + + return TRUE; +} + +int mplat_vsnwprintf( WCHAR * buffer, size_t count, const WCHAR * format, va_list args ) +{ + BufferOutput output( buffer, count ); + return FormattedPrintW( &output, format, args ); +} + +int mplat_snwprintf_s( WCHAR *buffer, size_t bufsize, size_t count, const WCHAR *format, ... ) +{ + va_list args; + va_start( args, format ); + int retcode = mplat_vsnwprintf( buffer, std::min(bufsize, count), format, args ); + va_end( args ); + return retcode; +} + +int mplat_vsnprintf( char * buffer, size_t count, const char * format, va_list args ) +{ + BufferOutput output( buffer, count ); + return FormattedPrintA( &output, format, args ); +} + +int mplat_snprintf_s( char *buffer, size_t bufsize, size_t count, const char *format, ... ) +{ + va_list args; + va_start( args, format ); + int retcode = mplat_vsnprintf( buffer, std::min(bufsize, count), format, args ); + va_end( args ); + return retcode; +} + +// Tools\vc\src\crt\amd64\wcscat.c +WCHAR * mplat_wcscpy( WCHAR * dst, const WCHAR * src ) +{ + WCHAR * cp = dst; + + while( (*cp++ = *src++) ) + ; /* Copy src over dst */ + + return( dst ); +} + +char * mplat_cscpy( char * dst, const char * src ) +{ + char * cp = dst; + + while( (*cp++ = *src++) ) + ; /* Copy src over dst */ + + return( dst ); +} + +size_t mplat_wcslen( const WCHAR * str ) +{ + const WCHAR * eos = str; + while( *eos++ ) + { + } + return( (size_t)(eos - str- 1) ); +} + +HLOCAL LocalAlloc(UINT uFlags, SIZE_T uBytes) +{ + assert(uFlags == 0); // For now + return malloc(uBytes); +} + +HLOCAL LocalFree(HLOCAL hMem) +{ + assert(hMem != NULL); + + free(hMem); + return NULL; +} diff --git a/source/shared/FormattedPrint.h b/source/shared/FormattedPrint.h new file mode 100644 index 00000000..15521d5a --- /dev/null +++ b/source/shared/FormattedPrint.h @@ -0,0 +1,231 @@ +//----------------------------------------------------------------------------- +// File: FormattedPrint.h +// +// Contents: Contains functions for handling Windows format strings +// and UTF-16 on non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef _FORMATTEDPRINT_H_ +#define _FORMATTEDPRINT_H_ + +#include "winnls.h" +#include "localization.hpp" + +inline bool __ascii_iswalpha(WCHAR c) { return( ('A' <= (c) && (c) <= 'Z') || ( 'a' <= (c) && (c) <= 'z') ); } +inline WCHAR __ascii_towupper(WCHAR c) { return( (((c) >= L'a') && ((c) <= L'z')) ? (WCHAR)((c) - L'a' + L'A') : (c) ); } +inline char __ascii_toupper(char c) { return( (((c) >= 'a') && ((c) <= 'z')) ? ((c) - 'a' + 'A') : (c) ); } + + + + +template< typename T > +struct IFormattedPrintOutput +{ + /* + Method names are all CAPS to match the original code for formatted print from the Windows CRT. + + pCumulativeOutputCount + Used to track running total of output storage units. + Note that the count is the memory size in sizeof(TCHAR) and not the display char count. + For example, a UTF-8 char+diacritical mark is two chars in memory but only one for display + so pCumulativeOutputCount will be incremented by 2 after output. + If an error is encountered, then set this to -1. + If the value is -1 upon entry of any callback, simply return and don't output anything. + */ + + // Writes a single character to the output. + virtual void WRITE_CHAR( T ch , int * pCumulativeOutputCount ) = 0; + + // Repeatedly writes a single character to the output. If there isn't enough room, writes to end of buffer. + // If repeatCount is <=0, then don't output anything and leave pCumulativeOutputCount as is. + virtual void WRITE_MULTI_CHAR( T ch, int repeatCount, int * pCumulativeOutputCount ) = 0; + + // Writes the supplied string to the output. If there isn't enough room, writes to end of buffer. + // If count is <=0, then don't output anything and leave pCumulativeOutputCount as is. + virtual void WRITE_STRING( const T * pch, int count, int * pCumulativeOutputCount ) = 0; + + // Ensure dtors are virtual + virtual ~IFormattedPrintOutput() { } +}; + +template< typename T > +class FormattedOutput : public IFormattedPrintOutput +{ +protected: + bool ShouldOutput( const int * pCumulativeOutputCount, int count ) const + { + assert( NULL != pCumulativeOutputCount ); + return ( (0 <= *pCumulativeOutputCount) && (0 < count) ); + } +}; + +int FormattedPrintA( IFormattedPrintOutput * output, const char *format, va_list argptr ); +int FormattedPrintW( IFormattedPrintOutput * output, const WCHAR *format, va_list argptr ); + +template< typename T > +class BufferOutput : public FormattedOutput +{ + T * m_buffer; + size_t m_countRemainingInBuffer; + + bool CanOutput() const + { + return ( 0 < m_countRemainingInBuffer ); + } + + // Stop these from being available + BufferOutput(); + BufferOutput( const BufferOutput & ); + BufferOutput & operator=( const BufferOutput & ); + +public: + BufferOutput( T * pcb, size_t bufsize ) + : m_buffer( pcb ), + m_countRemainingInBuffer( bufsize ) + { + assert( NULL != m_buffer ); + if ( m_countRemainingInBuffer < INT_MAX ) + { + memset( m_buffer, 0, m_countRemainingInBuffer * sizeof(T) ); + } + } + + virtual void WRITE_CHAR(T ch, int * pCumulativeOutputCount) + { + if ( FormattedOutput::ShouldOutput( pCumulativeOutputCount, 1 ) ) + { + if ( CanOutput() ) + { + ++(*pCumulativeOutputCount); + --m_countRemainingInBuffer; + *m_buffer++ = ch; + } + else + { + *pCumulativeOutputCount = -1; + } + } + } + virtual void WRITE_MULTI_CHAR(T ch, int repeatCount, int * pCumulativeOutputCount) + { + if ( FormattedOutput::ShouldOutput( pCumulativeOutputCount, repeatCount ) ) + { + if ( CanOutput() ) + { + while ( 0 != m_countRemainingInBuffer && 0 != repeatCount ) + { + *m_buffer++ = ch; + --m_countRemainingInBuffer; + --repeatCount; + ++(*pCumulativeOutputCount); + } + if ( 0 != repeatCount ) + { + // Not enough room in buffer + *pCumulativeOutputCount = -1; + } + } + else + { + *pCumulativeOutputCount = -1; + } + } + } + virtual void WRITE_STRING(const T * pch, int count, int * pCumulativeOutputCount) + { + assert( NULL != pch ); + if ( FormattedOutput::ShouldOutput( pCumulativeOutputCount, count ) ) + { + if ( CanOutput() ) + { + while ( 0 != m_countRemainingInBuffer && 0 != count ) + { + *m_buffer++ = *pch++; + --m_countRemainingInBuffer; + --count; + ++(*pCumulativeOutputCount); + } + if ( 0 != count ) + { + // Not enough room in buffer + *pCumulativeOutputCount = -1; + } + } + else + { + *pCumulativeOutputCount = -1; + } + } + } +}; + + +template< typename T > +class FileOutput : public FormattedOutput +{ + FILE * m_file; + + // Stop these from being available + FileOutput(); + FileOutput( const FileOutput & ); + FileOutput & operator=( const FileOutput & ); + +public: + FileOutput( FILE * file ) + : m_file( file ) + { + assert( NULL != m_file ); + } + + virtual void WRITE_CHAR(T ch, int * pCumulativeOutputCount) + { + if ( FormattedOutput::ShouldOutput( pCumulativeOutputCount, 1 ) ) + { + ++(*pCumulativeOutputCount); + if ( fputc( ch, m_file ) != ch ) + *pCumulativeOutputCount = -1; + } + } + virtual void WRITE_MULTI_CHAR(T ch, int repeatCount, int * pCumulativeOutputCount) + { + if ( FormattedOutput::ShouldOutput( pCumulativeOutputCount, repeatCount ) ) + { + *pCumulativeOutputCount += repeatCount; + while ( 0 < repeatCount-- ) + { + if ( fputc( ch, m_file ) != ch ) + { + *pCumulativeOutputCount = -1; + return; + } + } + } + } + virtual void WRITE_STRING(const T * pch, int count, int * pCumulativeOutputCount) + { + if ( FormattedOutput::ShouldOutput( pCumulativeOutputCount, count ) ) + { + assert( NULL != pch ); + *pCumulativeOutputCount += count; + if ( (size_t)count != fwrite( pch, sizeof(T), count, m_file ) ) + *pCumulativeOutputCount = -1; + } + } +}; + + + +#endif // _FORMATTEDPRINT_H_ diff --git a/source/shared/StringFunctions.cpp b/source/shared/StringFunctions.cpp new file mode 100644 index 00000000..c3a8dfa9 --- /dev/null +++ b/source/shared/StringFunctions.cpp @@ -0,0 +1,145 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: StringFunctions.cpp +// +// Contents: Contains functions for handling UTF-16 on non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#include "StringFunctions.h" + +// Tools\vc\src\crt\amd64\memcpy_s.c +int mplat_memcpy_s( void * dest, size_t destSize, const void * src, size_t count ) +{ + if ( 0 == count ) + { + // nothing to do + return 0; + } + + // validation section + if ( NULL == dest ) + { + errno = EINVAL; + return EINVAL; + } + + if ( src == NULL || destSize < count ) + { + // zeroes the destination buffer + memset(dest, 0, destSize*sizeof(char)); + + if ( NULL == src ) + { + errno = EINVAL; + return EINVAL; + } + if ( destSize < count ) + { + errno = ERANGE; + return ERANGE; + } + + return EINVAL; + } + + memcpy(dest, src, count*sizeof(char)); + return 0; +} + +// Tools\vc\src\crt\amd64\strcpy_s.c +int mplat_strcpy_s( char * dest, size_t destSize, const char * src ) +{ + char * p; + size_t available; + + // validation section + if ( NULL == dest || 0 == destSize ) + { + errno = EINVAL; + return EINVAL; + } + if ( NULL == src ) + { + *dest = 0; + errno = EINVAL; + return EINVAL; + } + + p = dest; + available = destSize; + while ( (*p++ = *src++) != 0 && --available > 0 ) + { + } + + if ( 0 == available ) + { + *dest = 0; + errno = ERANGE; + return ERANGE; + } + return 0; +} + +// Tools\vc\src\crt\amd64\strcat_s.c +int mplat_strcat_s( char * dest, size_t destSize, const char * src ) +{ + char *p; + size_t available; + + // validation section + if ( NULL == dest || 0 == destSize ) + { + errno = EINVAL; + return EINVAL; + } + if ( NULL == src ) + { + *dest = 0; + errno = EINVAL; + return EINVAL; + } + + p = dest; + available = destSize; + while (available > 0 && *p != 0) + { + p++; + available--; + } + + if (available == 0) + { + *dest = 0; + errno = EINVAL; + return EINVAL; + } + + while ((*p++ = *src++) != 0 && --available > 0) + { + } + + if (available == 0) + { + *dest = 0; + errno = ERANGE; + return ERANGE; + } + *p = 0; + return 0; +} +// +// End copy functions +//---------------------------------------------------------------------------- + diff --git a/source/shared/StringFunctions.h b/source/shared/StringFunctions.h new file mode 100644 index 00000000..7e808645 --- /dev/null +++ b/source/shared/StringFunctions.h @@ -0,0 +1,39 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: StringFunctions.h +// +// Contents: Contains functions for handling UTF-16 on non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#if !defined(_STRINGFUNCTIONS_H_) +#define _STRINGFUNCTIONS_H_ + +#include "winnls.h" + +// --------------------------------------------------------------------------- +// Declare internal versions of string handling functions +// Only the functions implemented are declared here + +// Copy +int mplat_memcpy_s(void *_S1, size_t _N1, const void *_S2, size_t _N); +int mplat_strcat_s( char *strDestination, size_t numberOfElements, const char *strSource ); +int mplat_strcpy_s(char * _Dst, size_t _SizeInBytes, const char * _Src); + +// Copy +#define memcpy_s mplat_memcpy_s +#define strcat_s mplat_strcat_s +#define strcpy_s mplat_strcpy_s + +#endif // _STRINGFUNCTIONS_H_ diff --git a/source/shared/globalization.h b/source/shared/globalization.h new file mode 100644 index 00000000..e7765320 --- /dev/null +++ b/source/shared/globalization.h @@ -0,0 +1,517 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: Globalization.h +// +// Contents: Contains functions for handling Windows format strings +// and UTF-16 on non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#if !defined(_GLOBALIZATION_H_) +#define _GLOBALIZATION_H_ + +#include "xplat.h" +#include "typedefs_for_linux.h" +#include + +#if defined(MPLAT_UNIX) +#include + +const iconv_t INVALID_ICONV = (iconv_t)(-1); + +class IConvCache : public SLIST_ENTRY +{ + iconv_t m_iconv; + + // Prevent copying + IConvCache( const IConvCache & ); + IConvCache & operator=( const IConvCache & ); + +public: + IConvCache( int dstIdx, int srcIdx ); + ~IConvCache(); + + iconv_t GetIConv() const + { + return m_iconv; + } +}; + +#endif + + +class EncodingConverter +{ + UINT m_dstCodePage; + UINT m_srcCodePage; +#if defined(MPLAT_UNIX) + const IConvCache * m_pCvtCache; + + bool IsValidIConv() const + { + return (NULL != m_pCvtCache && INVALID_ICONV != m_pCvtCache->GetIConv()); + } + + template< typename T > + struct iconv_buffer + { + char * m_pBytes; + size_t m_nBytesLeft; + + iconv_buffer( char * buffer, size_t cchSize ) + : m_pBytes(buffer), m_nBytesLeft(sizeof(T)*cchSize) {} + ~iconv_buffer() {} + + void Reset( char * buffer, size_t cchSize ) + { + m_pBytes = buffer; + m_nBytesLeft = cchSize*sizeof(T); + } + + void SkipSingleCh() + { + assert( sizeof(T) <= m_nBytesLeft ); + m_nBytesLeft -= sizeof(T); + m_pBytes += sizeof(T); + } + void SkipDoubleCh() + { + SkipSingleCh(); + // Only skip second half if there's bytes left and it is non-NULL + if ( m_nBytesLeft && 0 != *(UNALIGNED T *)m_pBytes ) + SkipSingleCh(); + } + void SkipUtf8Ch() + { + assert( 1 == sizeof(T) ); + const char * pNext = SystemLocale::NextChar( CP_UTF8, m_pBytes, m_nBytesLeft ); + assert( m_pBytes < pNext && (size_t)(pNext-m_pBytes) <= SystemLocale::MaxCharCchSize(CP_UTF8) ); + + UINT toTrim = (UINT)(pNext - m_pBytes); + assert( toTrim <= m_nBytesLeft ); + assert( 0 < toTrim ); + + m_nBytesLeft -= toTrim; + m_pBytes += toTrim; + } + + static char DefaultChar( UINT srcDataCP ) + { + return 0x3f; + } + static WCHAR DefaultWChar( UINT srcDataCP ) + { + return (CP_UTF8 == srcDataCP ? 0xfffd // Unicode to Unicode, use Unicode default char + : (932 == srcDataCP ? 0x30fb // 932 to Unicode has special default char + : 0x003f)); // WCP source, use '?' + } + void AssignDefault( UINT srcDataCP ) + { + assert( sizeof(T) <= m_nBytesLeft ); + if ( 1 == sizeof(T) ) + { + *m_pBytes = DefaultChar( srcDataCP ); + --m_nBytesLeft; + ++m_pBytes; + } + else + { + *(UNALIGNED T *)m_pBytes = DefaultWChar( srcDataCP ); + m_nBytesLeft -= sizeof(T); + m_pBytes += sizeof(T); + } + } + bool AssignDefaultUtf8( UINT srcDataCP ) + { + // This is a utf8 buffer so T must be char + assert( 1 == sizeof(T) ); + if ( CP_UTF16 == srcDataCP ) + { + // If source codepage is UTF16 then use Unicode default char + // UTF8 default char is 3 bytes long + if ( m_nBytesLeft < 3 ) + return false; + + *m_pBytes++ = (T)0xef; + *m_pBytes++ = (T)0xbf; + *m_pBytes++ = (T)0xbd; + m_nBytesLeft -= 3; + } + else if ( 932 == srcDataCP ) + { + // If source codepage is 932 then use special default char + // UTF8 default char for 932 is 3 bytes long + if ( m_nBytesLeft < 3 ) + return false; + + *m_pBytes++ = (T)0xe3; + *m_pBytes++ = (T)0x83; + *m_pBytes++ = (T)0xbb; + m_nBytesLeft -= 3; + } + else + { + *m_pBytes = DefaultChar( srcDataCP ); + ++m_pBytes; + --m_nBytesLeft; + } + return true; + } + + // Prevent compiler from generating these + iconv_buffer(); + iconv_buffer( const iconv_buffer & other ); + iconv_buffer & operator=( const iconv_buffer & other ); + }; + + template< class DestType > + bool AddDefault( iconv_buffer * dest, bool * pHasLoss, DWORD * pErrorCode ) const + { + if ( NULL != pHasLoss ) + *pHasLoss = true; + + if ( CP_UTF8 != m_dstCodePage ) + dest->AssignDefault( m_srcCodePage ); + else if ( !dest->AssignDefaultUtf8(m_srcCodePage) ) + { + // Not enough room for the default char + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INSUFFICIENT_BUFFER; + return false; + } + return true; + } + + template< class DestType, class SrcType > + size_t Convert( + iconv_buffer & dest, + iconv_buffer & src, + bool failIfLossy = false, bool * pHasLoss = NULL, DWORD * pErrorCode = NULL ) const + { + if ( !IsValidIConv() ) + return 0; + + size_t iconv_ret; + size_t cchDest = dest.m_nBytesLeft/sizeof(DestType); + + if ( NULL != pHasLoss ) + *pHasLoss = false; + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + + while ( 0 < dest.m_nBytesLeft && 0 < src.m_nBytesLeft ) + { + // First clear any intermediate state left over from previous conversions + iconv_ret = iconv( m_pCvtCache->GetIConv(), NULL, NULL, NULL, NULL ); + assert( 0 == iconv_ret ); + + // Now attempt conversion + iconv_ret = iconv( m_pCvtCache->GetIConv(), &src.m_pBytes, &src.m_nBytesLeft, &dest.m_pBytes, &dest.m_nBytesLeft ); + if ( iconv_ret == (size_t)(-1) ) + { + // If there's no dest bytes left, then treat as E2BIG even if the error + // is EILSEQ, etc. We want E2BIG to take precedence like Windows. + int err = (0 < dest.m_nBytesLeft ? errno : E2BIG); + if ( E2BIG != err && failIfLossy ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_NO_UNICODE_TRANSLATION; + return 0; + } + + switch ( err ) + { + case EILSEQ: // Invalid multibyte sequence in input + if ( CP_UTF8 == m_srcCodePage ) + src.SkipUtf8Ch(); + else if ( 1 == sizeof(SrcType) ) + src.SkipDoubleCh(); // DBCS + else + src.SkipSingleCh(); // utf32 or incomplate utf16 surrogate + + if ( !AddDefault(&dest, pHasLoss, pErrorCode) ) + return 0; + + break; + case EINVAL: // Incomplete multibyte sequence in input + if ( CP_UTF8 == m_srcCodePage ) + src.SkipUtf8Ch(); + else + src.SkipSingleCh(); + + if ( !AddDefault(&dest, pHasLoss, pErrorCode) ) + return 0; + + break; + case E2BIG: // Output buffer is out of room + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INSUFFICIENT_BUFFER; + return 0; + default: + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + } + } + + return cchDest - (dest.m_nBytesLeft / sizeof(DestType)); + } + +#elif defined(MPLAT_WWOWH) + + size_t ReturnCchResult( int cch, DWORD * pErrorCode ) const + { + if ( cch < 0 ) + cch = 0; + + if ( NULL != pErrorCode ) + *pErrorCode = (0 == cch ? GetLastError() : ERROR_SUCCESS); + + return cch; + } + +#endif // defined(MPLAT_WWOWH) + + +public: + EncodingConverter( UINT dstCodePage, UINT srcCodePage ); + ~EncodingConverter(); + + bool Initialize(); + + // Performs an encoding conversion. + // Returns the number of dest chars written. + // Input and output buffers should not overlap. + template< class DestType, class SrcType, class AllocT > + size_t Convert( + DestType ** destBuffer, + const SrcType * srcBuffer, size_t cchSource, + bool failIfLossy = false, bool * pHasLoss = NULL, DWORD * pErrorCode = NULL ) const + { +#if defined(MPLAT_UNIX) + + if ( !IsValidIConv() ) + return 0; + + iconv_buffer src( + reinterpret_cast< char * >( const_cast< SrcType * >(srcBuffer) ), + cchSource ); + + size_t cchDest = cchSource; + AutoArray< DestType, AllocT > newDestBuffer( cchDest ); + + iconv_buffer dest( + reinterpret_cast< char * >(newDestBuffer.m_ptr), + cchDest ); + + size_t cchPrevCvt = 0; + DWORD rcCvt; + while ( true ) + { + size_t cchCvt = Convert( dest, src, failIfLossy, pHasLoss, &rcCvt ); + if ( 0 == cchCvt ) + { + if ( ERROR_INSUFFICIENT_BUFFER == rcCvt ) + { + // Alloc more and continue + cchPrevCvt = cchDest; + cchDest *= 2; + if ( !newDestBuffer.Realloc(cchDest) ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_NOT_ENOUGH_MEMORY; + return 0; + } + // Fill newly allocated part of buffer + dest.Reset( reinterpret_cast< char * >(newDestBuffer.m_ptr+cchPrevCvt), cchDest ); + } + else + { + if ( NULL != pErrorCode ) + *pErrorCode = rcCvt; + return 0; + } + } + else + { + if ( NULL != pErrorCode ) + *pErrorCode = rcCvt; + *destBuffer = newDestBuffer.Detach(); + return cchPrevCvt + cchCvt; + } + } + +#elif defined(MPLAT_WWOWH) + // WWOWH unit testing code + // Can only convert between ansi and utf16 + if ( 1 == sizeof(DestType) && 2 == sizeof(SrcType) ) + { + // utf16 to ansi + const wchar_t * srcPtr = reinterpret_cast< const wchar_t * >( srcBuffer ); + BOOL loss = FALSE; + int converted = WideCharToMultiByte( + m_dstCodePage, 0, + srcPtr, (int)cchSource, + NULL, 0, + NULL, &loss ); + + if ( 0 < converted ) + { + AutoArray< char, AllocT > newDestBuffer( converted ); + char * dstPtr = newDestBuffer.m_ptr; + converted = WideCharToMultiByte( + m_dstCodePage, 0, + srcPtr, (int)cchSource, + newDestBuffer.m_ptr, converted, + NULL, &loss ); + if ( 0 < converted ) + *destBuffer = newDestBuffer.Detach(); + if ( NULL != pHasLoss ) + *pHasLoss = (FALSE != loss); + } + return ReturnCchResult( converted, pErrorCode ); + } + else if ( 2 == sizeof(DestType) && 1 == sizeof(SrcType) ) + { + // ansi to utf16 + const char * srcPtr = reinterpret_cast< const char * >( srcBuffer ); + int converted = MultiByteToWideChar( + m_srcCodePage, (failIfLossy ? MB_ERR_INVALID_CHARS : 0), + srcPtr, (int)cchSource, + NULL, 0 ); + + if ( 0 < converted ) + { + AutoArray< WCHAR, AllocT > newDestBuffer( converted ); + converted = MultiByteToWideChar( + m_srcCodePage, (failIfLossy ? MB_ERR_INVALID_CHARS : 0), + srcPtr, (int)cchSource, + newDestBuffer.m_ptr, converted ); + if ( 0 < converted ) + *destBuffer = newDestBuffer.Detach(); + if ( NULL != pHasLoss ) + *pHasLoss = false; + } + return ReturnCchResult( converted, pErrorCode ); + } + else + { + assert( false ); + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_NOT_SUPPORTED; + return 0; + } + +#endif // defined(MPLAT_WWOWH) + } + // Performs an encoding conversion. + // Returns the number of dest chars written. + // Input and output buffers should not overlap. + template< class DestType, class SrcType > + size_t Convert( + DestType * destBuffer, size_t cchDest, + const SrcType * srcBuffer, size_t cchSource, + bool failIfLossy = false, bool * pHasLoss = NULL, DWORD * pErrorCode = NULL ) const + { +#if defined(MPLAT_UNIX) + + if ( !IsValidIConv() ) + return 0; + + iconv_buffer src( + reinterpret_cast< char * >( const_cast< SrcType * >(srcBuffer) ), + cchSource ); + if ( 0 < cchDest ) + { + iconv_buffer dest( + reinterpret_cast< char * >(destBuffer), + cchDest ); + return Convert( dest, src, failIfLossy, pHasLoss, pErrorCode ); + } + else + { + // Use fixed size buffer iteratively to determine final required length + const size_t CCH_FIXED_SIZE = 256; + char fixed_buf[ CCH_FIXED_SIZE*sizeof(DestType) ]; + iconv_buffer dest( + &fixed_buf[0], + CCH_FIXED_SIZE ); + + bool hasLoss = false; + DWORD rcCvt = ERROR_SUCCESS; + size_t cchOnce = 0; + size_t cchCumulative = 0; + + while ( 0 < src.m_nBytesLeft + && 0 == (cchOnce = Convert(dest, src, failIfLossy, &hasLoss, &rcCvt)) + && ERROR_INSUFFICIENT_BUFFER == rcCvt ) + { + cchCumulative += CCH_FIXED_SIZE; + cchCumulative -= dest.m_nBytesLeft; + dest.Reset( &fixed_buf[0], CCH_FIXED_SIZE ); + } + if ( 0 < cchOnce ) + cchCumulative += cchOnce; + if ( NULL != pErrorCode ) + *pErrorCode = (0 < cchCumulative ? ERROR_SUCCESS : rcCvt); + if ( NULL != pHasLoss ) + *pHasLoss |= hasLoss; + return cchCumulative; + } + +#elif defined(MPLAT_WWOWH) + // WWOWH unit testing code + // Can only convert between ansi and utf16 + if ( 1 == sizeof(DestType) && 2 == sizeof(SrcType) ) + { + // utf16 to ansi + char * dstPtr = reinterpret_cast< char * >( destBuffer ); + const wchar_t * srcPtr = reinterpret_cast< const wchar_t * >( srcBuffer ); + BOOL loss = FALSE; + int converted = WideCharToMultiByte( + m_dstCodePage, 0, + srcPtr, (int)cchSource, + dstPtr, (int)cchDest, + NULL, &loss ); + if ( NULL != pHasLoss ) + *pHasLoss = (FALSE != loss); + return ReturnCchResult( converted, pErrorCode ); + } + else if ( 2 == sizeof(DestType) && 1 == sizeof(SrcType) ) + { + // ansi to utf16 + wchar_t * dstPtr = reinterpret_cast< wchar_t * >( destBuffer ); + const char * srcPtr = reinterpret_cast< const char * >( srcBuffer ); + int converted = MultiByteToWideChar( + m_srcCodePage, (failIfLossy ? MB_ERR_INVALID_CHARS : 0), + srcPtr, (int)cchSource, + dstPtr, (int)cchDest ); + if ( NULL != pHasLoss ) + *pHasLoss = false; + return ReturnCchResult( converted, pErrorCode ); + } + else + { + assert( false ); + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_NOT_SUPPORTED; + return 0; + } + +#endif // defined(MPLAT_WWOWH) + } +}; + +#endif // _GLOBALIZATION_H_ diff --git a/source/shared/interlockedatomic.h b/source/shared/interlockedatomic.h new file mode 100644 index 00000000..c96603d0 --- /dev/null +++ b/source/shared/interlockedatomic.h @@ -0,0 +1,62 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: InterlockedAtomic.h +// +// Contents: Contains a portable abstraction for interlocked, atomic +// operations on int32_t and pointer types. +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef __INTERLOCKEDATOMIC_H__ +#define __INTERLOCKEDATOMIC_H__ + +// Forward references and contract specifications +// + +// Increments and returns new value +LONG InterlockedIncrement( LONG volatile * atomic ); + +// Decrements and returns new value +LONG InterlockedDecrement( LONG volatile * atomic ); + +// Always returns old value +// Sets to new value if old value equals compareTo +LONG InterlockedCompareExchange( LONG volatile * atomic, LONG newValue, LONG compareTo ); + +// Sets to new value and returns old value +LONG InterlockedExchange( LONG volatile * atomic, LONG newValue ); + +// Sets to new value and returns old value +PVOID InterlockedExchangePointer( PVOID volatile * atomic, PVOID newValue); + +// Adds the amount and returns the old value +LONG InterlockedExchangeAdd( LONG volatile * atomic, LONG add ); + +// Always returns the old value +// Sets the new value if old value equals compareTo +PVOID InterlockedCompareExchangePointer( PVOID volatile * atomic, PVOID newValue, PVOID compareTo ); + + + +// Use conditional compilation to load the implementation +// +#if defined(_MSC_VER) +#include "InterlockedAtomic_WwoWH.h" +#elif defined(__GNUC__) +#include "interlockedatomic_gcc.h" +#else +#error "Unsupported compiler" +#endif + +#endif // __INTERLOCKEDATOMIC_H__ diff --git a/source/shared/interlockedatomic_gcc.h b/source/shared/interlockedatomic_gcc.h new file mode 100644 index 00000000..d8ea921c --- /dev/null +++ b/source/shared/interlockedatomic_gcc.h @@ -0,0 +1,63 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: InterlockedAtomic_gcc.h +// +// Contents: Contains a portable abstraction for interlocked, atomic +// operations on int32_t and pointer types. +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef __INTERLOCKEDATOMIC_GCC_H__ +#define __INTERLOCKEDATOMIC_GCC_H__ + +#if !defined(__GNUC__) +#error "Incorrect compiler configuration in InterlockedAtomic.h. Was expecting GCC." +#endif + +inline LONG InterlockedIncrement( LONG volatile * atomic ) +{ + return __sync_add_and_fetch( atomic, 1 ); +} + +inline LONG InterlockedDecrement( LONG volatile * atomic ) +{ + return __sync_sub_and_fetch( atomic, 1 ); +} + +inline LONG InterlockedCompareExchange( LONG volatile * atomic, LONG newValue, LONG compareTo ) +{ + return __sync_val_compare_and_swap( atomic, compareTo, newValue ); +} + +inline LONG InterlockedExchange( LONG volatile * atomic, LONG newValue ) +{ + return __sync_lock_test_and_set( atomic, newValue ); +} + +inline PVOID InterlockedExchangePointer( PVOID volatile * atomic, PVOID newValue) +{ + return __sync_lock_test_and_set( atomic, newValue ); +} + +inline LONG InterlockedExchangeAdd( LONG volatile * atomic, LONG add ) +{ + return __sync_fetch_and_add( atomic, add ); +} + +inline PVOID InterlockedCompareExchangePointer( PVOID volatile * atomic, PVOID newValue, PVOID compareTo ) +{ + return __sync_val_compare_and_swap( atomic, compareTo, newValue ); +} + +#endif // __INTERLOCKEDATOMIC_GCC_H__ diff --git a/source/shared/interlockedslist.h b/source/shared/interlockedslist.h new file mode 100644 index 00000000..48427e12 --- /dev/null +++ b/source/shared/interlockedslist.h @@ -0,0 +1,142 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: InterlockedSList.h +// +// Contents: Contains a portable abstraction for interlocked, singly +// linked list. +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef __INTERLOCKEDSLIST_H__ +#define __INTERLOCKEDSLIST_H__ + +#include "interlockedatomic.h" + +#define SLIST_ENTRY SINGLE_LIST_ENTRY + +#define PSLIST_ENTRY PSINGLE_LIST_ENTRY + +typedef struct _SINGLE_LIST_ENTRY { + // Want a volatile pointer to non-volatile data so place after all type info + struct _SINGLE_LIST_ENTRY * volatile Next; +} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; + +typedef union _SLIST_HEADER { + // Provides 8 byte alignment for 32-bit builds. Technically, not needed for + // current implementation below but leaving for future use. + ULONGLONG Alignment; + struct { + // Want a volatile pointer to non-volatile data so place after all type info + PSLIST_ENTRY volatile Head; + volatile LONG Depth; + volatile LONG Mutex; + } List; +} SLIST_HEADER, *PSLIST_HEADER; + + +inline VOID InitializeSListHead( PSLIST_HEADER slist ) +{ + assert( NULL != slist ); + + slist->List.Head = NULL; + slist->List.Depth = 0; + slist->List.Mutex = 0; +} + +inline PSLIST_ENTRY InterlockedPopEntrySList( PSLIST_HEADER slist ) +{ + assert( NULL != slist ); + + // Exit prior to 'mutex' if we think it is empty + // Some callers (like sqlncli/msdart/dll/dynslist.h) rely on a NULL + // result from Pop to indicate the list is empty. This early exit + // is an optimization and not technically needed for correctness. + PSLIST_ENTRY oldHead = slist->List.Head; + if ( NULL == oldHead ) + { + return NULL; + } + + while ( 0 != slist->List.Mutex || 0 != InterlockedCompareExchange( &slist->List.Mutex, 1, 0 ) ) + { + // Spin until 'mutex' is free + } + + // We have the 'mutex' so proceed with update + oldHead = slist->List.Head; + if ( NULL != oldHead ) + { + slist->List.Head = oldHead->Next; + --(slist->List.Depth); + assert( 0 <= slist->List.Depth ); + } + + // Free the 'mutex' + slist->List.Mutex = 0; + + return oldHead; +} + +inline PSLIST_ENTRY InterlockedPushEntrySList( PSLIST_HEADER slist, PSLIST_ENTRY newEntry ) +{ + assert( NULL != slist ); + + while ( 0 != slist->List.Mutex || 0 != InterlockedCompareExchange( &slist->List.Mutex, 1, 0 ) ) + { + // Spin until 'mutex' is free + } + + // We have the 'mutex' so proceed with update + PSLIST_ENTRY oldHead = slist->List.Head; + newEntry->Next = oldHead; + slist->List.Head = newEntry; + ++(slist->List.Depth); + + // Free the 'mutex' + slist->List.Mutex = 0; + + return oldHead; +} + +inline PSLIST_ENTRY InterlockedFlushSList( PSLIST_HEADER slist ) +{ + assert( NULL != slist ); + + while ( 0 != slist->List.Mutex || 0 != InterlockedCompareExchange( &slist->List.Mutex, 1, 0 ) ) + { + // Spin until 'mutex' is free + } + + // We have the 'mutex' so proceed with update + PSLIST_ENTRY oldHead = slist->List.Head; + slist->List.Head = NULL; + slist->List.Depth = 0; + + // Free the 'mutex' + slist->List.Mutex = 0; + + return oldHead; +} + +// If the list has more than USHORT nodes then this method +// will not return reliable results. +inline USHORT QueryDepthSList( PSLIST_HEADER slist ) +{ + assert( NULL != slist ); + + return static_cast(slist->List.Depth); +} + + +#endif // __INTERLOCKEDSLIST_H__ diff --git a/source/shared/intsafe.h b/source/shared/intsafe.h new file mode 100644 index 00000000..dd718534 --- /dev/null +++ b/source/shared/intsafe.h @@ -0,0 +1,7635 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: intsafe.h +// +// Contents: This module defines helper functions to prevent +// integer overflow bugs. +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + + +#ifndef XPLAT_INTSAFE_H +#define XPLAT_INTSAFE_H + +#if (_MSC_VER > 1000) +#pragma once +#endif + +#if !defined(_W64) +#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && (_MSC_VER >= 1300) +#define _W64 __w64 +#else +#define _W64 +#endif +#endif + +#include "sal.h" +#include + +// +// typedefs +// +typedef char CHAR; +typedef signed char INT8; +typedef unsigned char UCHAR; +typedef unsigned char UINT8; +typedef unsigned char BYTE; +typedef short SHORT; +typedef signed short INT16; +typedef unsigned short USHORT; +typedef unsigned short UINT16; +typedef unsigned short WORD; +typedef int INT; +typedef signed int INT32; +typedef unsigned int UINT; +typedef unsigned int UINT32; +typedef windowsLong_t LONG; +typedef windowsULong_t DWORD; +typedef windowsLongLong_t LONGLONG; +typedef windowsLongLong_t LONG64; +typedef windowsLongLong_t INT64; +typedef windowsULongLong_t ULONGLONG; +typedef windowsULongLong_t DWORDLONG; +typedef windowsULongLong_t ULONG64; +typedef windowsULongLong_t DWORD64; +typedef windowsULongLong_t UINT64; + +#if (__midl > 501) +typedef [public] __int3264 INT_PTR; +typedef [public] unsigned __int3264 UINT_PTR; +typedef [public] __int3264 LONG_PTR; +typedef [public] unsigned __int3264 ULONG_PTR; +#else +#ifdef _WIN64 +typedef __int64 INT_PTR, *PINT_PTR; +typedef unsigned __int64 UINT_PTR, *PUINT_PTR; +typedef __int64 LONG_PTR, *PLONG_PTR; +typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; +#else +typedef _W64 int INT_PTR, *PINT_PTR; +typedef _W64 unsigned int UINT_PTR, *PUINT_PTR; +typedef _W64 windowsLong_t LONG_PTR, *PLONG_PTR; +typedef _W64 windowsULong_t ULONG_PTR, *PULONG_PTR; +#endif // WIN64 +#endif // (__midl > 501) + +typedef ULONG_PTR DWORD_PTR; +typedef LONG_PTR SSIZE_T; +typedef ULONG_PTR SIZE_T; + +#if defined(_AMD64_) +#ifdef __cplusplus +extern "C" { +#endif + +#define UnsignedMultiply128 _umul128 + +ULONG64 +UnsignedMultiply128 ( + __inn ULONG64 Multiplier, + __inn ULONG64 Multiplicand, + __outt __deref_out_range(==,Multiplier * Multiplicand) ULONG64 *HighProduct + ); +#pragma intrinsic(_umul128) + +#ifdef __cplusplus +} +#endif +#endif // _AMD64_ + + + +typedef __success(return >= 0) windowsLong_t HRESULT; + +#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) +#define FAILED(hr) (((HRESULT)(hr)) < 0) + +#define S_OK ((HRESULT)0L) + +#define INTSAFE_E_ARITHMETIC_OVERFLOW ((HRESULT)0x80070216L) // 0x216 = 534 = ERROR_ARITHMETIC_OVERFLOW +#ifndef SORTPP_PASS +// compiletime asserts (failure results in error C2118: negative subscript) +#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] +#else +#define C_ASSERT(e) +#endif + +// +// UInt32x32To64 macro +// +#define UInt32x32To64(a, b) ((windowsULongLong_t)(((windowsULongLong_t)(a)) * ((windowsULong_t)(b)))) + +// +// Min/Max type values +// +//#define INT8_MIN (-127 - 1) +#define SHORT_MIN (-32768) +//#define INT16_MIN (-32767 - 1) +//#define INT_MIN (-2147483647 - 1) +//#define INT32_MIN (-2147483647l - 1) +//#define LONG_MIN (-2147483647L - 1) +#define LONGLONG_MIN (-9223372036854775807ll - 1) +#define LONG64_MIN (-9223372036854775807ll - 1) +//#define INT64_MIN (-9223372036854775807ll - 1) +#define INT128_MIN (-170141183460469231731687303715884105727i128 - 1) + +#ifdef _WIN64 +#define INT_PTR_MIN (-9223372036854775807ll - 1) +#define LONG_PTR_MIN (-9223372036854775807ll - 1) +#define PTRDIFF_T_MIN (-9223372036854775807ll - 1) +#define SSIZE_T_MIN (-9223372036854775807ll - 1) +#else +#define INT_PTR_MIN (-2147483647 - 1) +#define LONG_PTR_MIN (-2147483647L - 1) +#define PTRDIFF_T_MIN (-2147483647 - 1) +#define SSIZE_T_MIN (-2147483647L - 1) +#endif + +//#define INT8_MAX 127 +//#define UINT8_MAX 0xff +#define BYTE_MAX 0xff +#define SHORT_MAX 32767 +//#define INT16_MAX 32767 +#define USHORT_MAX 0xffff +//#define UINT16_MAX 0xffff +#define WORD_MAX 0xffff +//#define INT_MAX 2147483647 +//#define INT32_MAX 2147483647l +//#define UINT_MAX 0xffffffff +//#define UINT32_MAX 0xfffffffful +//#define LONG_MAX 2147483647L +//#define ULONG_MAX 0xffffffffUL +#define DWORD_MAX 0xffffffffUL +#define LONGLONG_MAX 9223372036854775807ll +#define LONG64_MAX 9223372036854775807ll +//#define INT64_MAX 9223372036854775807ll +#define ULONGLONG_MAX 0xffffffffffffffffull +#define DWORDLONG_MAX 0xffffffffffffffffull +#define ULONG64_MAX 0xffffffffffffffffull +#define DWORD64_MAX 0xffffffffffffffffull +//#define UINT64_MAX 0xffffffffffffffffull +#define INT128_MAX 170141183460469231731687303715884105727i128 +#define UINT128_MAX 0xffffffffffffffffffffffffffffffffui128 + +#ifndef _I64_MIN +#define _I64_MIN INT64_MIN +#define _I64_MAX INT64_MAX +#define _UI64_MIN UINT64_MIN +#define _UI64_MAX UINT64_MAX +#endif + +#undef SIZE_T_MAX + +#ifdef _WIN64 +#define INT_PTR_MAX 9223372036854775807ll +#define UINT_PTR_MAX 0xffffffffffffffffull +#define LONG_PTR_MAX 9223372036854775807ll +#define ULONG_PTR_MAX 0xffffffffffffffffull +#define DWORD_PTR_MAX 0xffffffffffffffffull +#define PTRDIFF_T_MAX 9223372036854775807ll +#define SIZE_T_MAX 0xffffffffffffffffull +#define SSIZE_T_MAX 9223372036854775807ll +#define _SIZE_T_MAX 0xffffffffffffffffull +#else +#define INT_PTR_MAX 2147483647 +#define UINT_PTR_MAX 0xffffffff +#define LONG_PTR_MAX 2147483647L +#define ULONG_PTR_MAX 0xffffffffUL +#define DWORD_PTR_MAX 0xffffffffUL +#define PTRDIFF_T_MAX 2147483647 +#define SIZE_T_MAX 0xffffffff +#define SSIZE_T_MAX 2147483647L +#define _SIZE_T_MAX 0xffffffffUL +#endif + + +// +// It is common for -1 to be used as an error value +// +#define INT8_ERROR (-1) +#define UINT8_ERROR 0xff +#define BYTE_ERROR 0xff +#define SHORT_ERROR (-1) +#define INT16_ERROR (-1) +#define USHORT_ERROR 0xffff +#define UINT16_ERROR 0xffff +#define WORD_ERROR 0xffff +#define INT_ERROR (-1) +#define INT32_ERROR (-1l) +#define UINT_ERROR 0xffffffff +#define UINT32_ERROR 0xfffffffful +#define LONG_ERROR (-1L) +#define ULONG_ERROR 0xffffffffUL +#define DWORD_ERROR 0xffffffffUL +#define LONGLONG_ERROR (-1ll) +#define LONG64_ERROR (-1ll) +#define INT64_ERROR (-1ll) +#define ULONGLONG_ERROR 0xffffffffffffffffull +#define DWORDLONG_ERROR 0xffffffffffffffffull +#define ULONG64_ERROR 0xffffffffffffffffull +#define UINT64_ERROR 0xffffffffffffffffull + +#ifdef _WIN64 +#define INT_PTR_ERROR (-1ll) +#define UINT_PTR_ERROR 0xffffffffffffffffull +#define LONG_PTR_ERROR (-1ll) +#define ULONG_PTR_ERROR 0xffffffffffffffffull +#define DWORD_PTR_ERROR 0xffffffffffffffffull +#define PTRDIFF_T_ERROR (-1ll) +#define SIZE_T_ERROR 0xffffffffffffffffull +#define SSIZE_T_ERROR (-1ll) +#define _SIZE_T_ERROR 0xffffffffffffffffull +#else +#define INT_PTR_ERROR (-1) +#define UINT_PTR_ERROR 0xffffffff +#define LONG_PTR_ERROR (-1L) +#define ULONG_PTR_ERROR 0xffffffffUL +#define DWORD_PTR_ERROR 0xffffffffUL +#define PTRDIFF_T_ERROR (-1) +#define SIZE_T_ERROR 0xffffffff +#define SSIZE_T_ERROR (-1L) +#define _SIZE_T_ERROR 0xffffffffUL +#endif + + +// +// We make some assumptions about the sizes of various types. Let's be +// explicit about those assumptions and check them. +// +C_ASSERT(sizeof(USHORT) == 2); +C_ASSERT(sizeof(INT) == 4); +C_ASSERT(sizeof(UINT) == 4); +C_ASSERT(sizeof(LONG) == 4); +C_ASSERT(sizeof(ULONG) == 8); +C_ASSERT(sizeof(UINT_PTR) == sizeof(ULONG_PTR)); + + +//============================================================================= +// Conversion functions +// +// There are three reasons for having conversion functions: +// +// 1. We are converting from a signed type to an unsigned type of the same +// size, or vice-versa. +// +// Since we only have unsigned math functions, this allows people to convert +// to unsigned, do the math, and then convert back to signed. +// +// 2. We are converting to a smaller type, and we could therefore possibly +// overflow. +// +// 3. We are converting to a bigger type, and we are signed and the type we are +// converting to is unsigned. +// +//============================================================================= + + +// +// INT8 -> UCHAR conversion +// +__inline +HRESULT +Int8ToUChar( + __inn INT8 i8Operand, + __outt __deref_out_range(==,i8Operand) UCHAR* pch) +{ + HRESULT hr; + + if (i8Operand >= 0) + { + *pch = (UCHAR)i8Operand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT8 -> UINT8 conversion +// +__inline +HRESULT +Int8ToUInt8( + __inn INT8 i8Operand, + __outt __deref_out_range(==,i8Operand) UINT8* pu8Result) +{ + HRESULT hr; + + if (i8Operand >= 0) + { + *pu8Result = (UINT8)i8Operand; + hr = S_OK; + } + else + { + *pu8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT8 -> BYTE conversion +// +#define Int8ToByte Int8ToUInt8 + +// +// INT8 -> USHORT conversion +// +__inline +HRESULT +Int8ToUShort( + __inn INT8 i8Operand, + __outt __deref_out_range(==,i8Operand) USHORT* pusResult) +{ + HRESULT hr; + + if (i8Operand >= 0) + { + *pusResult = (USHORT)i8Operand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT8 -> UINT16 conversion +// +#define Int8ToUInt16 Int8ToUShort + +// +// INT8 -> WORD conversion +// +#define Int8ToWord Int8ToUShort + +// +// INT8 -> UINT conversion +// +__inline +HRESULT +Int8ToUInt( + __inn INT8 i8Operand, + __outt __deref_out_range(==,i8Operand) UINT* puResult) +{ + HRESULT hr; + + if (i8Operand >= 0) + { + *puResult = (UINT)i8Operand; + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT8 -> UINT32 conversion +// +#define Int8ToUInt32 Int8ToUInt + +// +// INT8 -> UINT_PTR conversion +// +__inline +HRESULT +Int8ToUIntPtr( + __inn INT8 i8Operand, + __outt __deref_out_range(==,i8Operand) UINT_PTR* puResult) +{ + HRESULT hr; + + if (i8Operand >= 0) + { + *puResult = (UINT_PTR)i8Operand; + hr = S_OK; + } + else + { + *puResult = UINT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT8 -> ULONG conversion +// +__inline +HRESULT +Int8ToULong( + __inn INT8 i8Operand, + __outt __deref_out_range(==,i8Operand) ULONG* pulResult) +{ + HRESULT hr; + + if (i8Operand >= 0) + { + *pulResult = (ULONG)i8Operand; + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT8 -> ULONG_PTR conversion +// +__inline +HRESULT +Int8ToULongPtr( + __inn INT8 i8Operand, + __outt __deref_out_range(==,i8Operand) ULONG_PTR* pulResult) +{ + HRESULT hr; + + if (i8Operand >= 0) + { + *pulResult = (ULONG_PTR)i8Operand; + hr = S_OK; + } + else + { + *pulResult = ULONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT8 -> DWORD conversion +// +#define Int8ToDWord Int8ToULong + +// +// INT8 -> DWORD_PTR conversion +// +#define Int8ToDWordPtr Int8ToULongPtr + +// +// INT8 -> ULONGLONG conversion +// +__inline +HRESULT +Int8ToULongLong( + __inn INT8 i8Operand, + __outt __deref_out_range(==,i8Operand) ULONGLONG* pullResult) +{ + HRESULT hr; + + if (i8Operand >= 0) + { + *pullResult = (ULONGLONG)i8Operand; + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT8 -> DWORDLONG conversion +// +#define Int8ToDWordLong Int8ToULongLong + +// +// INT8 -> ULONG64 conversion +// +#define Int8ToULong64 Int8ToULongLong + +// +// INT8 -> DWORD64 conversion +// +#define Int8ToDWord64 Int8ToULongLong + +// +// INT8 -> UINT64 conversion +// +#define Int8ToUInt64 Int8ToULongLong + +// +// INT8 -> size_t conversion +// +#define Int8ToSizeT Int8ToUIntPtr + +// +// INT8 -> SIZE_T conversion +// +#define Int8ToSIZET Int8ToULongPtr + +// +// UINT8 -> INT8 conversion +// +__inline +HRESULT +UInt8ToInt8( + __inn UINT8 u8Operand, + __outt __deref_out_range(==,u8Operand) INT8* pi8Result) +{ + HRESULT hr; + + if (u8Operand <= INT8_MAX) + { + *pi8Result = (INT8)u8Operand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT8 -> CHAR conversion +// +__forceinline +HRESULT +UInt8ToChar( + __inn UINT8 u8Operand, + __outt __deref_out_range(==,u8Operand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + *pch = (CHAR)u8Operand; + return S_OK; +#else + return UInt8ToInt8(u8Operand, (INT8*)pch); +#endif +} + +// +// BYTE -> INT8 conversion +// +__inline +HRESULT +ByteToInt8( + __inn BYTE bOperand, + __outt __deref_out_range(==,bOperand) INT8* pi8Result) +{ + HRESULT hr; + + if (bOperand <= INT8_MAX) + { + *pi8Result = (INT8)bOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// BYTE -> CHAR conversion +// +__forceinline +HRESULT +ByteToChar( + __inn BYTE bOperand, + __outt __deref_out_range(==,bOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + *pch = (CHAR)bOperand; + return S_OK; +#else + return ByteToInt8(bOperand, (INT8*)pch); +#endif +} + +// +// SHORT -> INT8 conversion +// +__inline +HRESULT +ShortToInt8( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) INT8* pi8Result) +{ + HRESULT hr; + + if ((sOperand >= INT8_MIN) && (sOperand <= INT8_MAX)) + { + *pi8Result = (INT8)sOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> UCHAR conversion +// +__inline +HRESULT +ShortToUChar( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) UCHAR* pch) +{ + HRESULT hr; + + if ((sOperand >= 0) && (sOperand <= 255)) + { + *pch = (UCHAR)sOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> CHAR conversion +// +__forceinline +HRESULT +ShortToChar( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return ShortToUChar(sOperand, (UCHAR*)pch); +#else + return ShortToInt8(sOperand, (INT8*)pch); +#endif // _CHAR_UNSIGNED +} + +// +// SHORT -> UINT8 conversion +// +__inline +HRESULT +ShortToUInt8( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if ((sOperand >= 0) && (sOperand <= UINT8_MAX)) + { + *pui8Result = (UINT8)sOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> BYTE conversion +// +#define ShortToByte ShortToUInt8 + +// +// SHORT -> USHORT conversion +// +__inline +HRESULT +ShortToUShort( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) USHORT* pusResult) +{ + HRESULT hr; + + if (sOperand >= 0) + { + *pusResult = (USHORT)sOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> UINT16 conversion +// +#define ShortToUInt16 ShortToUShort + +// +// SHORT -> WORD conversion +// +#define ShortToWord ShortToUShort + +// +// SHORT -> UINT conversion +// +__inline +HRESULT +ShortToUInt( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) UINT* puResult) +{ + HRESULT hr; + + if (sOperand >= 0) + { + *puResult = (UINT)sOperand; + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> UINT32 conversion +// +#define ShortToUInt32 ShortToUInt + +// +// SHORT -> UINT_PTR conversion +// +__inline +HRESULT +ShortToUIntPtr( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) UINT_PTR* puResult) +{ + HRESULT hr; + + if (sOperand >= 0) + { + *puResult = (UINT_PTR)sOperand; + hr = S_OK; + } + else + { + *puResult = UINT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> ULONG conversion +// +__inline +HRESULT +ShortToULong( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) ULONG* pulResult) +{ + HRESULT hr; + + if (sOperand >= 0) + { + *pulResult = (ULONG)sOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> ULONG_PTR conversion +// +__inline +HRESULT +ShortToULongPtr( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) ULONG_PTR* pulResult) +{ + HRESULT hr; + + if (sOperand >= 0) + { + *pulResult = (ULONG_PTR)sOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> DWORD conversion +// +#define ShortToDWord ShortToULong + +// +// SHORT -> DWORD_PTR conversion +// +__inline +HRESULT +ShortToDWordPtr( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) DWORD_PTR* pdwResult) +{ + HRESULT hr; + + if (sOperand >= 0) + { + *pdwResult = (DWORD_PTR)sOperand; + hr = S_OK; + } + else + { + *pdwResult = DWORD_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> ULONGLONG conversion +// +__inline +HRESULT +ShortToULongLong( + __inn SHORT sOperand, + __outt __deref_out_range(==,sOperand) ULONGLONG* pullResult) +{ + HRESULT hr; + + if (sOperand >= 0) + { + *pullResult = (ULONGLONG)sOperand; + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SHORT -> DWORDLONG conversion +// +#define ShortToDWordLong ShortToULongLong + +// +// SHORT -> ULONG64 conversion +// +#define ShortToULong64 ShortToULongLong + +// +// SHORT -> DWORD64 conversion +// +#define ShortToDWord64 ShortToULongLong + +// +// SHORT -> UINT64 conversion +// +#define ShortToUInt64 ShortToULongLong + +// +// SHORT -> size_t conversion +// +#define ShortToSizeT ShortToUIntPtr + +// +// SHORT -> SIZE_T conversion +// +#define ShortToSIZET ShortToULongPtr + +// +// INT16 -> CHAR conversion +// +#define Int16ToChar ShortToChar + +// +// INT16 -> INT8 conversion +// +#define Int16ToInt8 ShortToInt8 + +// +// INT16 -> UCHAR conversion +// +#define Int16ToUChar ShortToUChar + +// +// INT16 -> UINT8 conversion +// +#define Int16ToUInt8 ShortToUInt8 + +// +// INT16 -> BYTE conversion +// +#define Int16ToByte ShortToUInt8 + +// +// INT16 -> USHORT conversion +// +#define Int16ToUShort ShortToUShort + +// +// INT16 -> UINT16 conversion +// +#define Int16ToUInt16 ShortToUShort + +// +// INT16 -> WORD conversion +// +#define Int16ToWord ShortToUShort + +// +// INT16 -> UINT conversion +// +#define Int16ToUInt ShortToUInt + +// +// INT16 -> UINT32 conversion +// +#define Int16ToUInt32 ShortToUInt + +// +// INT16 -> UINT_PTR conversion +// +#define Int16ToUIntPtr ShortToUIntPtr + +// +// INT16 -> ULONG conversion +// +#define Int16ToULong ShortToULong + +// +// INT16 -> ULONG_PTR conversion +// +#define Int16ToULongPtr ShortToULongPtr + +// +// INT16 -> DWORD conversion +// +#define Int16ToDWord ShortToULong + +// +// INT16 -> DWORD_PTR conversion +// +#define Int16ToDWordPtr ShortToULongPtr + +// +// INT16 -> ULONGLONG conversion +// +#define Int16ToULongLong ShortToULongLong + +// +// INT16 -> DWORDLONG conversion +// +#define Int16ToDWordLong ShortToULongLong + +// +// INT16 -> ULONG64 conversion +// +#define Int16ToULong64 ShortToULongLong + +// +// INT16 -> DWORD64 conversion +// +#define Int16ToDWord64 ShortToULongLong + +// +// INT16 -> UINT64 conversion +// +#define Int16ToUInt64 ShortToULongLong + +// +// INT16 -> size_t conversion +// +#define Int16ToSizeT ShortToUIntPtr + +// +// INT16 -> SIZE_T conversion +// +#define Int16ToSIZET ShortToULongPtr + +// +// USHORT -> INT8 conversion +// +__inline +HRESULT +UShortToInt8( + __inn USHORT usOperand, + __outt __deref_out_range(==,usOperand) INT8* pi8Result) +{ + HRESULT hr; + + if (usOperand <= INT8_MAX) + { + *pi8Result = (INT8)usOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// USHORT -> UCHAR conversion +// +__inline +HRESULT +UShortToUChar( + __inn USHORT usOperand, + __outt __deref_out_range(==,usOperand) UCHAR* pch) +{ + HRESULT hr; + + if (usOperand <= 255) + { + *pch = (UCHAR)usOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// USHORT -> CHAR conversion +// +__forceinline +HRESULT +UShortToChar( + __inn USHORT usOperand, + __outt __deref_out_range(==,usOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return UShortToUChar(usOperand, (UCHAR*)pch); +#else + return UShortToInt8(usOperand, (INT8*)pch); +#endif // _CHAR_UNSIGNED +} + +// +// USHORT -> UINT8 conversion +// +__inline +HRESULT +UShortToUInt8( + __inn USHORT usOperand, + __outt __deref_out_range(==,usOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if (usOperand <= UINT8_MAX) + { + *pui8Result = (UINT8)usOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// USHORT -> BYTE conversion +// +#define UShortToByte UShortToUInt8 + +// +// USHORT -> SHORT conversion +// +__inline +HRESULT +UShortToShort( + __inn USHORT usOperand, + __outt __deref_out_range(==,usOperand) SHORT* psResult) +{ + HRESULT hr; + + if (usOperand <= SHORT_MAX) + { + *psResult = (SHORT)usOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// USHORT -> INT16 conversion +// +#define UShortToInt16 UShortToShort + +// +// UINT16 -> CHAR conversion +// +#define UInt16ToChar UShortToChar + +// +// UINT16 -> INT8 conversion +// +#define UInt16ToInt8 UShortToInt8 + +// +// UINT16 -> UCHAR conversion +// +#define UInt16ToUChar UShortToUChar + +// +// UINT16 -> UINT8 conversion +// +#define UInt16ToUInt8 UShortToUInt8 + +// +// UINT16 -> BYTE conversion +// +#define UInt16ToByte UShortToUInt8 + +// +// UINT16 -> SHORT conversion +// +#define UInt16ToShort UShortToShort + +// +// UINT16 -> INT16 conversion +// +#define UInt16ToInt16 UShortToShort + +// +// WORD -> INT8 conversion +// +#define WordToInt8 UShortToInt8 + +// +// WORD -> CHAR conversion +// +#define WordToChar UShortToChar + +// +// WORD -> UCHAR conversion +// +#define WordToUChar UShortToUChar + +// +// WORD -> UINT8 conversion +// +#define WordToUInt8 UShortToUInt8 + +// +// WORD -> BYTE conversion +// +#define WordToByte UShortToUInt8 + +// +// WORD -> SHORT conversion +// +#define WordToShort UShortToShort + +// +// WORD -> INT16 conversion +// +#define WordToInt16 UShortToShort + +// +// INT -> INT8 conversion +// +__inline +HRESULT +IntToInt8( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) INT8* pi8Result) +{ + HRESULT hr; + + if ((iOperand >= INT8_MIN) && (iOperand <= INT8_MAX)) + { + *pi8Result = (INT8)iOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT -> UCHAR conversion +// +__inline +HRESULT +IntToUChar( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) UCHAR* pch) +{ + HRESULT hr; + + if ((iOperand >= 0) && (iOperand <= 255)) + { + *pch = (UCHAR)iOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT -> CHAR conversion +// +__forceinline +HRESULT +IntToChar( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return IntToUChar(iOperand, (UCHAR*)pch); +#else + return IntToInt8(iOperand, (INT8*)pch); +#endif // _CHAR_UNSIGNED +} + +// +// INT -> BYTE conversion +// +#define IntToByte IntToUInt8 + +// +// INT -> UINT8 conversion +// +__inline +HRESULT +IntToUInt8( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if ((iOperand >= 0) && (iOperand <= UINT8_MAX)) + { + *pui8Result = (UINT8)iOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT -> SHORT conversion +// +__inline +HRESULT +IntToShort( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) SHORT* psResult) +{ + HRESULT hr; + + if ((iOperand >= SHORT_MIN) && (iOperand <= SHORT_MAX)) + { + *psResult = (SHORT)iOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT -> INT16 conversion +// +#define IntToInt16 IntToShort + +// +// INT -> USHORT conversion +// +__inline +HRESULT +IntToUShort( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) USHORT* pusResult) +{ + HRESULT hr; + + if ((iOperand >= 0) && (iOperand <= USHORT_MAX)) + { + *pusResult = (USHORT)iOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT -> UINT16 conversion +// +#define IntToUInt16 IntToUShort + +// +// INT -> WORD conversion +// +#define IntToWord IntToUShort + +// +// INT -> UINT conversion +// +__inline +HRESULT +IntToUInt( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) UINT* puResult) +{ + HRESULT hr; + + if (iOperand >= 0) + { + *puResult = (UINT)iOperand; + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT -> UINT_PTR conversion +// +#ifdef _WIN64 +#define IntToUIntPtr IntToULongLong +#else +#define IntToUIntPtr IntToUInt +#endif + +// +// INT -> ULONG conversion +// +__inline +HRESULT +IntToULong( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) ULONG* pulResult) +{ + HRESULT hr; + + if (iOperand >= 0) + { + *pulResult = (ULONG)iOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT -> ULONG_PTR conversion +// +#ifdef _WIN64 +#define IntToULongPtr IntToULongLong +#else +#define IntToULongPtr IntToULong +#endif + +// +// INT -> DWORD conversion +// +#define IntToDWord IntToULong + +// +// INT -> DWORD_PTR conversion +// +#define IntToDWordPtr IntToULongPtr + +// +// INT -> ULONGLONG conversion +// +__inline +HRESULT +IntToULongLong( + __inn INT iOperand, + __outt __deref_out_range(==,iOperand) ULONGLONG* pullResult) +{ + HRESULT hr; + + if (iOperand >= 0) + { + *pullResult = (ULONGLONG)iOperand; + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT -> DWORDLONG conversion +// +#define IntToDWordLong IntToULongLong + +// +// INT -> ULONG64 conversion +// +#define IntToULong64 IntToULongLong + +// +// INT -> DWORD64 conversion +// +#define IntToDWord64 IntToULongLong + +// +// INT -> UINT64 conversion +// +#define IntToUInt64 IntToULongLong + +// +// INT -> size_t conversion +// +#define IntToSizeT IntToUIntPtr + +// +// INT -> SIZE_T conversion +// +#define IntToSIZET IntToULongPtr + +// +// INT32 -> CHAR conversion +// +#define Int32ToChar IntToChar + +// +// INT32 -> INT328 conversion +// +#define Int32ToInt8 IntToInt8 + +// +// INT32 -> UCHAR conversion +// +#define Int32ToUChar IntToUChar + +// +// INT32 -> BYTE conversion +// +#define Int32ToByte IntToUInt8 + +// +// INT32 -> UINT8 conversion +// +#define Int32ToUInt8 IntToUInt8 + +// +// INT32 -> SHORT conversion +// +#define Int32ToShort IntToShort + +// +// INT32 -> INT16 conversion +// +#define Int32ToInt16 IntToShort + +// +// INT32 -> USHORT conversion +// +#define Int32ToUShort IntToUShort + +// +// INT32 -> UINT16 conversion +// +#define Int32ToUInt16 IntToUShort + +// +// INT32 -> WORD conversion +// +#define Int32ToWord IntToUShort + +// +// INT32 -> UINT conversion +// +#define Int32ToUInt IntToUInt + +// +// INT32 -> UINT32 conversion +// +#define Int32ToUInt32 IntToUInt + +// +// INT32 -> UINT_PTR conversion +// +#define Int32ToUIntPtr IntToUIntPtr + +// +// INT32 -> ULONG conversion +// +#define Int32ToULong IntToULong + +// +// INT32 -> ULONG_PTR conversion +// +#define Int32ToULongPtr IntToULongPtr + +// +// INT32 -> DWORD conversion +// +#define Int32ToDWord IntToULong + +// +// INT32 -> DWORD_PTR conversion +// +#define Int32ToDWordPtr IntToULongPtr + +// +// INT32 -> ULONGLONG conversion +// +#define Int32ToULongLong IntToULongLong + +// +// INT32 -> DWORDLONG conversion +// +#define Int32ToDWordLong IntToULongLong + +// +// INT32 -> ULONG64 conversion +// +#define Int32ToULong64 IntToULongLong + +// +// INT32 -> DWORD64 conversion +// +#define Int32ToDWord64 IntToULongLong + +// +// INT32 -> UINT64 conversion +// +#define Int32ToUInt64 IntToULongLong + +// +// INT32 -> size_t conversion +// +#define Int32ToSizeT IntToUIntPtr + +// +// INT32 -> SIZE_T conversion +// +#define Int32ToSIZET IntToULongPtr + +// +// INT_PTR -> INT8 conversion +// +__inline +HRESULT +IntPtrToInt8( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) INT8* pi8Result) +{ + HRESULT hr; + + if ((iOperand >= INT8_MIN) && (iOperand <= INT8_MAX)) + { + *pi8Result = (INT8)iOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT_PTR -> UCHAR conversion +// +__inline +HRESULT +IntPtrToUChar( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) UCHAR* pch) +{ + HRESULT hr; + + if ((iOperand >= 0) && (iOperand <= 255)) + { + *pch = (UCHAR)iOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT_PTR -> CHAR conversion +// +__forceinline +HRESULT +IntPtrToChar( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return IntPtrToUChar(iOperand, (UCHAR*)pch); +#else + return IntPtrToInt8(iOperand, (INT8*)pch); +#endif // _CHAR_UNSIGNED +} + +// +// INT_PTR -> UINT8 conversion +// +__inline +HRESULT +IntPtrToUInt8( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if ((iOperand >= 0) && (iOperand <= UINT8_MAX)) + { + *pui8Result = (UINT8)iOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT_PTR -> BYTE conversion +// +#define IntPtrToByte IntPtrToUInt8 + +// +// INT_PTR -> SHORT conversion +// +__inline +HRESULT +IntPtrToShort( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) SHORT* psResult) +{ + HRESULT hr; + + if ((iOperand >= SHORT_MIN) && (iOperand <= SHORT_MAX)) + { + *psResult = (SHORT)iOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT_PTR -> INT16 conversion +// +#define IntPtrToInt16 IntPtrToShort + +// +// INT_PTR -> USHORT conversion +// +__inline +HRESULT +IntPtrToUShort( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) USHORT* pusResult) +{ + HRESULT hr; + + if ((iOperand >= 0) && (iOperand <= USHORT_MAX)) + { + *pusResult = (USHORT)iOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// INT_PTR -> UINT16 conversion +// +#define IntPtrToUInt16 IntPtrToUShort + +// +// INT_PTR -> WORD conversion +// +#define IntPtrToWord IntPtrToUShort + +// +// INT_PTR -> INT conversion +// +#ifdef _WIN64 +#define IntPtrToInt LongLongToInt +#else +__inline +HRESULT +IntPtrToInt( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) INT* piResult) +{ + *piResult = (INT)iOperand; + return S_OK; +} +#endif + +// +// INT_PTR -> INT32 conversion +// +#define IntPtrToInt32 IntPtrToInt + +// +// INT_PTR -> UINT conversion +// +#ifdef _WIN64 +#define IntPtrToUInt LongLongToUInt +#else +__inline +HRESULT +IntPtrToUInt( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) UINT* puResult) +{ + HRESULT hr; + + if (iOperand >= 0) + { + *puResult = (UINT)iOperand; + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif + +// +// INT_PTR -> UINT32 conversion +// +#define IntPtrToUInt32 IntPtrToUInt + +// +// INT_PTR -> UINT_PTR conversion +// +#ifdef _WIN64 +#define IntPtrToUIntPtr LongLongToULongLong +#else +__inline +HRESULT +IntPtrToUIntPtr( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) UINT_PTR* puResult) +{ + HRESULT hr; + + if (iOperand >= 0) + { + *puResult = (UINT_PTR)iOperand; + hr = S_OK; + } + else + { + *puResult = UINT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif + +// +// INT_PTR -> LONG conversion +// +#ifdef _WIN64 +#define IntPtrToLong LongLongToLong +#else +__inline +HRESULT +IntPtrToLong( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) LONG* plResult) +{ + *plResult = (LONG)iOperand; + return S_OK; +} +#endif + +// +// INT_PTR -> LONG_PTR conversion +// +__inline +HRESULT +IntPtrToLongPtr( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) LONG_PTR* plResult) +{ + *plResult = (LONG_PTR)iOperand; + return S_OK; +} + +// +// INT_PTR -> ULONG conversion +// +#ifdef _WIN64 +#define IntPtrToULong LongLongToULong +#else +__inline +HRESULT +IntPtrToULong( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) ULONG* pulResult) +{ + HRESULT hr; + + if (iOperand >= 0) + { + *pulResult = (ULONG)iOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif + +// +// INT_PTR -> ULONG_PTR conversion +// +#ifdef _WIN64 +#define IntPtrToULongPtr LongLongToULongLong +#else +__inline +HRESULT +IntPtrToULongPtr( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) ULONG_PTR* pulResult) +{ + HRESULT hr; + + if (iOperand >= 0) + { + *pulResult = (ULONG_PTR)iOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif + +// +// INT_PTR -> DWORD conversion +// +#define IntPtrToDWord IntPtrToULong + +// +// INT_PTR -> DWORD_PTR conversion +// +#define IntPtrToDWordPtr IntPtrToULongPtr + +// +// INT_PTR -> ULONGLONG conversion +// +#ifdef _WIN64 +#define IntPtrToULongLong LongLongToULongLong +#else +__inline +HRESULT +IntPtrToULongLong( + __inn INT_PTR iOperand, + __outt __deref_out_range(==,iOperand) ULONGLONG* pullResult) +{ + HRESULT hr; + + if (iOperand >= 0) + { + *pullResult = (ULONGLONG)iOperand; + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif + +// +// INT_PTR -> DWORDLONG conversion +// +#define IntPtrToDWordLong IntPtrToULongLong + +// +// INT_PTR -> ULONG64 conversion +// +#define IntPtrToULong64 IntPtrToULongLong + +// +// INT_PTR -> DWORD64 conversion +// +#define IntPtrToDWord64 IntPtrToULongLong + +// +// INT_PTR -> UINT64 conversion +// +#define IntPtrToUInt64 IntPtrToULongLong + +// +// INT_PTR -> size_t conversion +// +#define IntPtrToSizeT IntPtrToUIntPtr + +// +// INT_PTR -> SIZE_T conversion +// +#define IntPtrToSIZET IntPtrToULongPtr + +// +// UINT -> INT8 conversion +// +__inline +HRESULT +UIntToInt8( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) INT8* pi8Result) +{ + HRESULT hr; + + if (uOperand <= INT8_MAX) + { + *pi8Result = (INT8)uOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT -> UCHAR conversion +// +__inline +HRESULT +UIntToUChar( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) UCHAR* pch) +{ + HRESULT hr; + + if (uOperand <= 255) + { + *pch = (UCHAR)uOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT -> CHAR conversion +// +__forceinline +HRESULT +UIntToChar( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return UIntToUChar(uOperand, (UCHAR*)pch); +#else + return UIntToInt8(uOperand, (INT8*)pch); +#endif +} + +// +// UINT -> UINT8 conversion +// +__inline +HRESULT +UIntToUInt8( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if (uOperand <= UINT8_MAX) + { + *pui8Result = (UINT8)uOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT -> BYTE conversion +// +#define UIntToByte UIntToUInt8 + +// +// UINT -> SHORT conversion +// +__inline +HRESULT +UIntToShort( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) SHORT* psResult) +{ + HRESULT hr; + + if (uOperand <= SHORT_MAX) + { + *psResult = (SHORT)uOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT -> INT16 conversion +// +#define UIntToInt16 UIntToShort + +// +// UINT -> USHORT conversion +// +__inline +HRESULT +UIntToUShort( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) USHORT* pusResult) +{ + HRESULT hr; + + if (uOperand <= USHORT_MAX) + { + *pusResult = (USHORT)uOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT -> UINT16 conversion +// +#define UIntToUInt16 UIntToUShort + +// +// UINT -> WORD conversion +// +#define UIntToWord UIntToUShort + +// +// UINT -> INT conversion +// +__inline +HRESULT +UIntToInt( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) INT* piResult) +{ + HRESULT hr; + + if (uOperand <= INT_MAX) + { + *piResult = (INT)uOperand; + hr = S_OK; + } + else + { + *piResult = INT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT -> INT32 conversion +// +#define UIntToInt32 UIntToInt + +// +// UINT -> INT_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +UIntToIntPtr( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) INT_PTR* piResult) +{ + *piResult = uOperand; + return S_OK; +} +#else +#define UIntToIntPtr UIntToInt +#endif + +// +// UINT -> LONG conversion +// +__inline +HRESULT +UIntToLong( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) LONG* plResult) +{ + HRESULT hr; + + if (uOperand <= INT32_MAX) + { + *plResult = (LONG)uOperand; + hr = S_OK; + } + else + { + *plResult = LONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT -> LONG_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +UIntToLongPtr( + __inn UINT uOperand, + __outt __deref_out_range(==,uOperand) LONG_PTR* plResult) +{ + *plResult = uOperand; + return S_OK; +} +#else +#define UIntToLongPtr UIntToLong +#endif + +// +// UINT -> ptrdiff_t conversion +// +#define UIntToPtrdiffT UIntToIntPtr + +// +// UINT -> SSIZE_T conversion +// +#define UIntToSSIZET UIntToLongPtr + +// +// UINT32 -> CHAR conversion +// +#define UInt32ToChar UIntToChar + +// +// UINT32 -> INT8 conversion +// +#define UInt32ToInt8 UIntToInt8 + +// +// UINT32 -> UCHAR conversion +// +#define UInt32ToUChar UIntToUChar + +// +// UINT32 -> UINT8 conversion +// +#define UInt32ToUInt8 UIntToUInt8 + +// +// UINT32 -> BYTE conversion +// +#define UInt32ToByte UInt32ToUInt8 + +// +// UINT32 -> SHORT conversion +// +#define UInt32ToShort UIntToShort + +// +// UINT32 -> INT16 conversion +// +#define UInt32ToInt16 UIntToShort + +// +// UINT32 -> USHORT conversion +// +#define UInt32ToUShort UIntToUShort + +// +// UINT32 -> UINT16 conversion +// +#define UInt32ToUInt16 UIntToUShort + +// +// UINT32 -> WORD conversion +// +#define UInt32ToWord UIntToUShort + +// +// UINT32 -> INT conversion +// +#define UInt32ToInt UIntToInt + +// +// UINT32 -> INT_PTR conversion +// +#define UInt32ToIntPtr UIntToIntPtr + +// +// UINT32 -> INT32 conversion +// +#define UInt32ToInt32 UIntToInt + +// +// UINT32 -> LONG conversion +// +#define UInt32ToLong UIntToLong + +// +// UINT32 -> LONG_PTR conversion +// +#define UInt32ToLongPtr UIntToLongPtr + +// +// UINT32 -> ptrdiff_t conversion +// +#define UInt32ToPtrdiffT UIntToPtrdiffT + +// +// UINT32 -> SSIZE_T conversion +// +#define UInt32ToSSIZET UIntToSSIZET + +// +// UINT_PTR -> INT8 conversion +// +__inline +HRESULT +UIntPtrToInt8( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) INT8* pi8Result) +{ + HRESULT hr; + + if (uOperand <= INT8_MAX) + { + *pi8Result = (INT8)uOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> UCHAR conversion +// +__inline +HRESULT +UIntPtrToUChar( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) UCHAR* pch) +{ + HRESULT hr; + + if (uOperand <= 255) + { + *pch = (UCHAR)uOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> CHAR conversion +// +__forceinline +HRESULT +UIntPtrToChar( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return UIntPtrToUChar(uOperand, (UCHAR*)pch); +#else + return UIntPtrToInt8(uOperand, (INT8*)pch); +#endif +} + +// +// UINT_PTR -> UINT8 conversion +// +__inline +HRESULT +UIntPtrToUInt8( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) UINT8* pu8Result) +{ + HRESULT hr; + + if (uOperand <= UINT8_MAX) + { + *pu8Result = (UINT8)uOperand; + hr = S_OK; + } + else + { + *pu8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> BYTE conversion +// +#define UIntPtrToByte UIntPtrToUInt8 + +// +// UINT_PTR -> SHORT conversion +// +__inline +HRESULT +UIntPtrToShort( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) SHORT* psResult) +{ + HRESULT hr; + + if (uOperand <= SHORT_MAX) + { + *psResult = (SHORT)uOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> INT16 conversion +// +__inline +HRESULT +UIntPtrToInt16( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) INT16* pi16Result) +{ + HRESULT hr; + + if (uOperand <= INT16_MAX) + { + *pi16Result = (INT16)uOperand; + hr = S_OK; + } + else + { + *pi16Result = INT16_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> USHORT conversion +// +__inline +HRESULT +UIntPtrToUShort( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) USHORT* pusResult) +{ + HRESULT hr; + + if (uOperand <= USHORT_MAX) + { + *pusResult = (USHORT)uOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> UINT16 conversion +// +__inline +HRESULT +UIntPtrToUInt16( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) UINT16* pu16Result) +{ + HRESULT hr; + + if (uOperand <= UINT16_MAX) + { + *pu16Result = (UINT16)uOperand; + hr = S_OK; + } + else + { + *pu16Result = UINT16_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> WORD conversion +// +#define UIntPtrToWord UIntPtrToUShort + +// +// UINT_PTR -> INT conversion +// +__inline +HRESULT +UIntPtrToInt( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) INT* piResult) +{ + HRESULT hr; + + if (uOperand <= INT_MAX) + { + *piResult = (INT)uOperand; + hr = S_OK; + } + else + { + *piResult = INT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> INT32 conversion +// +#define UIntPtrToInt32 UIntPtrToInt + +// +// UINT_PTR -> INT_PTR conversion +// +__inline +HRESULT +UIntPtrToIntPtr( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) INT_PTR* piResult) +{ + HRESULT hr; + + if (uOperand <= INT_PTR_MAX) + { + *piResult = (INT_PTR)uOperand; + hr = S_OK; + } + else + { + *piResult = INT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> UINT conversion +// +#ifdef _WIN64 +#define UIntPtrToUInt ULongLongToUInt +#else +__inline +HRESULT +UIntPtrToUInt( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) UINT* puResult) +{ + *puResult = (UINT)uOperand; + return S_OK; +} +#endif + +// +// UINT_PTR -> UINT32 conversion +// +#define UIntPtrToUInt32 UIntPtrToUInt + +// +// UINT_PTR -> LONG conversion +// +__inline +HRESULT +UIntPtrToLong( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) LONG* plResult) +{ + HRESULT hr; + + if (uOperand <= INT32_MAX) + { + *plResult = (LONG)uOperand; + hr = S_OK; + } + else + { + *plResult = LONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> LONG_PTR conversion +// +__inline +HRESULT +UIntPtrToLongPtr( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) LONG_PTR* plResult) +{ + HRESULT hr; + + if (uOperand <= LONG_PTR_MAX) + { + *plResult = (LONG_PTR)uOperand; + hr = S_OK; + } + else + { + *plResult = LONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT_PTR -> ULONG conversion +// +#ifdef _WIN64 +#define UIntPtrToULong ULongLongToULong +#else +__inline +HRESULT +UIntPtrToULong( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) ULONG* pulResult) +{ + *pulResult = (ULONG)uOperand; + return S_OK; +} +#endif + +// +// UINT_PTR -> DWORD conversion +// +#define UIntPtrToDWord UIntPtrToULong + +// +// UINT_PTR -> LONGLONG conversion +// +#ifdef _WIN64 +#define UIntPtrToLongLong ULongLongToLongLong +#else +__inline +HRESULT +UIntPtrToLongLong( + __inn UINT_PTR uOperand, + __outt __deref_out_range(==,uOperand) LONGLONG* pllResult) +{ + *pllResult = (LONGLONG)uOperand; + return S_OK; +} +#endif + +// +// UINT_PTR -> LONG64 conversion +// +#define UIntPtrToLong64 UIntPtrToLongLong + +// +// UINT_PTR -> INT64 conversion +// +#define UIntPtrToInt64 UIntPtrToLongLong + +// +// UINT_PTR -> ptrdiff_t conversion +// +#define UIntPtrToPtrdiffT UIntPtrToIntPtr + +// +// UINT_PTR -> SSIZE_T conversion +// +#define UIntPtrToSSIZET UIntPtrToLongPtr + +// +// LONG -> INT8 conversion +// +__inline +HRESULT +LongToInt8( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) INT8* pi8Result) +{ + HRESULT hr; + + if ((lOperand >= INT8_MIN) && (lOperand <= INT8_MAX)) + { + *pi8Result = (INT8)lOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG -> UCHAR conversion +// +__inline +HRESULT +LongToUChar( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) UCHAR* pch) +{ + HRESULT hr; + + if ((lOperand >= 0) && (lOperand <= 255)) + { + *pch = (UCHAR)lOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG -> CHAR conversion +// +__forceinline +HRESULT +LongToChar( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return LongToUChar(lOperand, (UCHAR*)pch); +#else + return LongToInt8(lOperand, (INT8*)pch); +#endif +} + +// +// LONG -> UINT8 conversion +// +__inline +HRESULT +LongToUInt8( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if ((lOperand >= 0) && (lOperand <= UINT8_MAX)) + { + *pui8Result = (UINT8)lOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG -> BYTE conversion +// +#define LongToByte LongToUInt8 + +// +// LONG -> SHORT conversion +// +__inline +HRESULT +LongToShort( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) SHORT* psResult) +{ + HRESULT hr; + + if ((lOperand >= SHORT_MIN) && (lOperand <= SHORT_MAX)) + { + *psResult = (SHORT)lOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG -> INT16 conversion +// +#define LongToInt16 LongToShort + +// +// LONG -> USHORT conversion +// +__inline +HRESULT +LongToUShort( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) USHORT* pusResult) +{ + HRESULT hr; + + if ((lOperand >= 0) && (lOperand <= USHORT_MAX)) + { + *pusResult = (USHORT)lOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG -> UINT16 conversion +// +#define LongToUInt16 LongToUShort + +// +// LONG -> WORD conversion +// +#define LongToWord LongToUShort + +// +// LONG -> INT conversion +// +__inline +HRESULT +LongToInt( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) INT* piResult) +{ + C_ASSERT(sizeof(INT) == sizeof(LONG)); + *piResult = (INT)lOperand; + return S_OK; +} + +// +// LONG -> INT32 conversion +// +#define LongToInt32 LongToInt + +// +// LONG -> INT_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +LongToIntPtr( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) INT_PTR* piResult) +{ + *piResult = lOperand; + return S_OK; +} +#else +#define LongToIntPtr LongToInt +#endif + +// +// LONG -> UINT conversion +// +__inline +HRESULT +LongToUInt( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) UINT* puResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *puResult = (UINT)lOperand; + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG -> UINT32 conversion +// +#define LongToUInt32 LongToUInt + +// +// LONG -> UINT_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +LongToUIntPtr( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) UINT_PTR* puResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *puResult = (UINT_PTR)lOperand; + hr = S_OK; + } + else + { + *puResult = UINT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#else +#define LongToUIntPtr LongToUInt +#endif + +// +// LONG -> ULONG conversion +// +__inline +HRESULT +LongToULong( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) ULONG* pulResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *pulResult = (ULONG)lOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG -> ULONG_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +LongToULongPtr( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) ULONG_PTR* pulResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *pulResult = (ULONG_PTR)lOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#else +#define LongToULongPtr LongToULong +#endif + +// +// LONG -> DWORD conversion +// +#define LongToDWord LongToULong + +// +// LONG -> DWORD_PTR conversion +// +#define LongToDWordPtr LongToULongPtr + +// +// LONG -> ULONGLONG conversion +// +__inline +HRESULT +LongToULongLong( + __inn LONG lOperand, + __outt __deref_out_range(==,lOperand) ULONGLONG* pullResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *pullResult = (ULONGLONG)lOperand; + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG -> DWORDLONG conversion +// +#define LongToDWordLong LongToULongLong + +// +// LONG -> ULONG64 conversion +// +#define LongToULong64 LongToULongLong + +// +// LONG -> DWORD64 conversion +// +#define LongToDWord64 LongToULongLong + +// +// LONG -> UINT64 conversion +// +#define LongToUInt64 LongToULongLong + +// +// LONG -> ptrdiff_t conversion +// +#define LongToPtrdiffT LongToIntPtr + +// +// LONG -> size_t conversion +// +#define LongToSizeT LongToUIntPtr + +// +// LONG -> SIZE_T conversion +// +#define LongToSIZET LongToULongPtr + +// +// LONG_PTR -> INT8 conversion +// +__inline +HRESULT +LongPtrToInt8( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) INT8* pi8Result) +{ + HRESULT hr; + + if ((lOperand >= INT8_MIN) && (lOperand <= INT8_MAX)) + { + *pi8Result = (INT8)lOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG_PTR -> UCHAR conversion +// +__inline +HRESULT +LongPtrToUChar( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) UCHAR* pch) +{ + HRESULT hr; + + if ((lOperand >= 0) && (lOperand <= 255)) + { + *pch = (UCHAR)lOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG_PTR -> CHAR conversion +// +__forceinline +HRESULT +LongPtrToChar( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return LongPtrToUChar(lOperand, (UCHAR*)pch); +#else + return LongPtrToInt8(lOperand, (INT8*)pch); +#endif +} + +// +// LONG_PTR -> UINT8 conversion +// +__inline +HRESULT +LongPtrToUInt8( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if ((lOperand >= 0) && (lOperand <= UINT8_MAX)) + { + *pui8Result = (UINT8)lOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG_PTR -> BYTE conversion +// +#define LongPtrToByte LongPtrToUInt8 + +// +// LONG_PTR -> SHORT conversion +// +__inline +HRESULT +LongPtrToShort( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) SHORT* psResult) +{ + HRESULT hr; + + if ((lOperand >= SHORT_MIN) && (lOperand <= SHORT_MAX)) + { + *psResult = (SHORT)lOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG_PTR -> INT16 conversion +// +#define LongPtrToInt16 LongPtrToShort + +// +// LONG_PTR -> USHORT conversion +// +__inline +HRESULT +LongPtrToUShort( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) USHORT* pusResult) +{ + HRESULT hr; + + if ((lOperand >= 0) && (lOperand <= USHORT_MAX)) + { + *pusResult = (USHORT)lOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG_PTR -> UINT16 conversion +// +#define LongPtrToUInt16 LongPtrToUShort + +// +// LONG_PTR -> WORD conversion +// +#define LongPtrToWord LongPtrToUShort + +// +// LONG_PTR -> INT conversion +// +#ifdef _WIN64 +#define LongPtrToInt LongLongToInt +#else +__inline +HRESULT +LongPtrToInt( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) INT* piResult) +{ + C_ASSERT(sizeof(INT) == sizeof(LONG_PTR)); + *piResult = (INT)lOperand; + return S_OK; +} +#endif + +// +// LONG_PTR -> INT32 conversion +// +#define LongPtrToInt32 LongPtrToInt + +// +// LONG_PTR -> INT_PTR conversion +// +__inline +HRESULT +LongPtrToIntPtr( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) INT_PTR* piResult) +{ + C_ASSERT(sizeof(LONG_PTR) == sizeof(INT_PTR)); + *piResult = (INT_PTR)lOperand; + return S_OK; +} + +// +// LONG_PTR -> UINT conversion +// +#ifdef _WIN64 +#define LongPtrToUInt LongLongToUInt +#else +__inline +HRESULT +LongPtrToUInt( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) UINT* puResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *puResult = (UINT)lOperand; + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif + +// +// LONG_PTR -> UINT32 conversion +// +#define LongPtrToUInt32 LongPtrToUInt + +// +// LONG_PTR -> UINT_PTR conversion +// +__inline +HRESULT +LongPtrToUIntPtr( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) UINT_PTR* puResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *puResult = (UINT_PTR)lOperand; + hr = S_OK; + } + else + { + *puResult = UINT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG_PTR -> LONG conversion +// +#ifdef _WIN64 +#define LongPtrToLong LongLongToLong +#else +__inline +HRESULT +LongPtrToLong( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) LONG* plResult) +{ + *plResult = (LONG)lOperand; + return S_OK; +} +#endif + +// +// LONG_PTR -> ULONG conversion +// +#ifdef _WIN64 +#define LongPtrToULong LongLongToULong +#else +__inline +HRESULT +LongPtrToULong( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) ULONG* pulResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *pulResult = (ULONG)lOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif + +// +// LONG_PTR -> ULONG_PTR conversion +// +__inline +HRESULT +LongPtrToULongPtr( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) ULONG_PTR* pulResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *pulResult = (ULONG_PTR)lOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG_PTR -> DWORD conversion +// +#define LongPtrToDWord LongPtrToULong + +// +// LONG_PTR -> DWORD_PTR conversion +// +#define LongPtrToDWordPtr LongPtrToULongPtr + +// +// LONG_PTR -> ULONGLONG conversion +// +__inline +HRESULT +LongPtrToULongLong( + __inn LONG_PTR lOperand, + __outt __deref_out_range(==,lOperand) ULONGLONG* pullResult) +{ + HRESULT hr; + + if (lOperand >= 0) + { + *pullResult = (ULONGLONG)lOperand; + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONG_PTR -> DWORDLONG conversion +// +#define LongPtrToDWordLong LongPtrToULongLong + +// +// LONG_PTR -> ULONG64 conversion +// +#define LongPtrToULong64 LongPtrToULongLong + +// +// LONG_PTR -> DWORD64 conversion +// +#define LongPtrToDWord64 LongPtrToULongLong + +// +// LONG_PTR -> UINT64 conversion +// +#define LongPtrToUInt64 LongPtrToULongLong + +// +// LONG_PTR -> size_t conversion +// +#define LongPtrToSizeT LongPtrToUIntPtr + +// +// LONG_PTR -> SIZE_T conversion +// +#define LongPtrToSIZET LongPtrToULongPtr + +// +// ULONG -> INT8 conversion +// +__inline +HRESULT +ULongToInt8( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) INT8* pi8Result) +{ + HRESULT hr; + + if (ulOperand <= INT8_MAX) + { + *pi8Result = (INT8)ulOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG -> UCHAR conversion +// +__inline +HRESULT +ULongToUChar( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) UCHAR* pch) +{ + HRESULT hr; + + if (ulOperand <= 255) + { + *pch = (UCHAR)ulOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG -> CHAR conversion +// +__forceinline +HRESULT +ULongToChar( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return ULongToUChar(ulOperand, (UCHAR*)pch); +#else + return ULongToInt8(ulOperand, (INT8*)pch); +#endif +} + +// +// ULONG -> UINT8 conversion +// +__inline +HRESULT +ULongToUInt8( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if (ulOperand <= UINT8_MAX) + { + *pui8Result = (UINT8)ulOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG -> BYTE conversion +// +#define ULongToByte ULongToUInt8 + +// +// ULONG -> SHORT conversion +// +__inline +HRESULT +ULongToShort( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) SHORT* psResult) +{ + HRESULT hr; + + if (ulOperand <= SHORT_MAX) + { + *psResult = (SHORT)ulOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG -> INT16 conversion +// +#define ULongToInt16 ULongToShort + +// +// ULONG -> USHORT conversion +// +__inline +HRESULT +ULongToUShort( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) USHORT* pusResult) +{ + HRESULT hr; + + if (ulOperand <= USHORT_MAX) + { + *pusResult = (USHORT)ulOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG -> UINT16 conversion +// +#define ULongToUInt16 ULongToUShort + +// +// ULONG -> WORD conversion +// +#define ULongToWord ULongToUShort + +// +// ULONG -> INT conversion +// +__inline +HRESULT +ULongToInt( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) INT* piResult) +{ + HRESULT hr; + + if (ulOperand <= INT_MAX) + { + *piResult = (INT)ulOperand; + hr = S_OK; + } + else + { + *piResult = INT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG -> INT32 conversion +// +#define ULongToInt32 ULongToInt + +// +// ULONG -> INT_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +ULongToIntPtr( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) INT_PTR* piResult) +{ + *piResult = (INT_PTR)ulOperand; + return S_OK; +} +#else +#define ULongToIntPtr ULongToInt +#endif + +// +// ULONG -> UINT conversion +// +__inline +HRESULT +ULongToUInt( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) UINT* puResult) +{ + //C_ASSERT(sizeof(ULONG) == sizeof(UINT)); + *puResult = (UINT)ulOperand; + return S_OK; +} + +// +// ULONG -> UINT32 conversion +// +#define ULongToUInt32 ULongToUInt + +// +// ULONG -> UINT_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +ULongToUIntPtr( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) UINT_PTR* puiResult) +{ + C_ASSERT(sizeof(UINT_PTR) > sizeof(ULONG)); + *puiResult = (UINT_PTR)ulOperand; + return S_OK; +} +#else +#define ULongToUIntPtr ULongToUInt +#endif + +// +// ULONG -> LONG conversion +// +__inline +HRESULT +ULongToLong( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) LONG* plResult) +{ + HRESULT hr; + + if (ulOperand <= INT32_MAX) + { + *plResult = (LONG)ulOperand; + hr = S_OK; + } + else + { + *plResult = LONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG -> LONG_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +ULongToLongPtr( + __inn ULONG ulOperand, + __outt __deref_out_range(==,ulOperand) LONG_PTR* plResult) +{ + C_ASSERT(sizeof(LONG_PTR) > sizeof(ULONG)); + *plResult = (LONG_PTR)ulOperand; + return S_OK; +} +#else +#define ULongToLongPtr ULongToLong +#endif + +// +// ULONG -> ptrdiff_t conversion +// +#define ULongToPtrdiffT ULongToIntPtr + +// +// ULONG -> SSIZE_T conversion +// +#define ULongToSSIZET ULongToLongPtr + +// +// ULONG_PTR -> INT8 conversion +// +__inline +HRESULT +ULongPtrToInt8( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) INT8* pi8Result) +{ + HRESULT hr; + + if (ulOperand <= INT8_MAX) + { + *pi8Result = (INT8)ulOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> UCHAR conversion +// +__inline +HRESULT +ULongPtrToUChar( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) UCHAR* pch) +{ + HRESULT hr; + + if (ulOperand <= 255) + { + *pch = (UCHAR)ulOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> CHAR conversion +// +__forceinline +HRESULT +ULongPtrToChar( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return ULongPtrToUChar(ulOperand, (UCHAR*)pch); +#else + return ULongPtrToInt8(ulOperand, (INT8*)pch); +#endif +} + +// +// ULONG_PTR -> UINT8 conversion +// +__inline +HRESULT +ULongPtrToUInt8( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) UINT8* pui8Result) +{ + HRESULT hr; + + if (ulOperand <= UINT8_MAX) + { + *pui8Result = (UINT8)ulOperand; + hr = S_OK; + } + else + { + *pui8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> BYTE conversion +// +#define ULongPtrToByte ULongPtrToUInt8 + +// +// ULONG_PTR -> SHORT conversion +// +__inline +HRESULT +ULongPtrToShort( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) SHORT* psResult) +{ + HRESULT hr; + + if (ulOperand <= SHORT_MAX) + { + *psResult = (SHORT)ulOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> INT16 conversion +// +#define ULongPtrToInt16 ULongPtrToShort + +// +// ULONG_PTR -> USHORT conversion +// +__inline +HRESULT +ULongPtrToUShort( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) USHORT* pusResult) +{ + HRESULT hr; + + if (ulOperand <= USHORT_MAX) + { + *pusResult = (USHORT)ulOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> UINT16 conversion +// +#define ULongPtrToUInt16 ULongPtrToUShort + +// +// ULONG_PTR -> WORD conversion +// +#define ULongPtrToWord ULongPtrToUShort + +// +// ULONG_PTR -> INT conversion +// +__inline +HRESULT +ULongPtrToInt( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) INT* piResult) +{ + HRESULT hr; + + if (ulOperand <= INT_MAX) + { + *piResult = (INT)ulOperand; + hr = S_OK; + } + else + { + *piResult = INT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> INT32 conversion +// +#define ULongPtrToInt32 ULongPtrToInt + +// +// ULONG_PTR -> INT_PTR conversion +// +__inline +HRESULT +ULongPtrToIntPtr( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) INT_PTR* piResult) +{ + HRESULT hr; + + if (ulOperand <= INT_PTR_MAX) + { + *piResult = (INT_PTR)ulOperand; + hr = S_OK; + } + else + { + *piResult = INT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> UINT conversion +// +#ifdef _WIN64 +#define ULongPtrToUInt ULongLongToUInt +#else +__inline +HRESULT +ULongPtrToUInt( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) UINT* puResult) +{ + C_ASSERT(sizeof(ULONG_PTR) == sizeof(UINT)); + *puResult = (UINT)ulOperand; + return S_OK; +} +#endif + +// +// ULONG_PTR -> UINT32 conversion +// +#define ULongPtrToUInt32 ULongPtrToUInt + +// +// ULONG_PTR -> UINT_PTR conversion +// +__inline +HRESULT +ULongPtrToUIntPtr( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) UINT_PTR* puResult) +{ + *puResult = (UINT_PTR)ulOperand; + return S_OK; +} + +// +// ULONG_PTR -> LONG conversion +// +__inline +HRESULT +ULongPtrToLong( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) LONG* plResult) +{ + HRESULT hr; + + if (ulOperand <= INT32_MAX) + { + *plResult = (LONG)ulOperand; + hr = S_OK; + } + else + { + *plResult = LONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> LONG_PTR conversion +// +__inline +HRESULT +ULongPtrToLongPtr( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) LONG_PTR* plResult) +{ + HRESULT hr; + + if (ulOperand <= LONG_PTR_MAX) + { + *plResult = (LONG_PTR)ulOperand; + hr = S_OK; + } + else + { + *plResult = LONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR -> ULONG conversion +// +#ifdef _WIN64 +#define ULongPtrToULong ULongLongToULong +#else +__inline +HRESULT +ULongPtrToULong( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) ULONG* pulResult) +{ + *pulResult = (ULONG)ulOperand; + return S_OK; +} +#endif + +// +// ULONG_PTR -> DWORD conversion +// +#define ULongPtrToDWord ULongPtrToULong + +// +// ULONG_PTR -> LONGLONG conversion +// +#ifdef _WIN64 +#define ULongPtrToLongLong ULongLongToLongLong +#else +__inline +HRESULT +ULongPtrToLongLong( + __inn ULONG_PTR ulOperand, + __outt __deref_out_range(==,ulOperand) LONGLONG* pllResult) +{ + *pllResult = (LONGLONG)ulOperand; + return S_OK; +} +#endif + +// +// ULONG_PTR -> LONG64 conversion +// +#define ULongPtrToLong64 ULongPtrToLongLong + +// +// ULONG_PTR -> INT64 +// +#define ULongPtrToInt64 ULongPtrToLongLong + +// +// ULONG_PTR -> ptrdiff_t conversion +// +#define ULongPtrToPtrdiffT ULongPtrToIntPtr + +// +// ULONG_PTR -> SSIZE_T conversion +// +#define ULongPtrToSSIZET ULongPtrToLongPtr + +// +// DWORD -> INT8 conversion +// +#define DWordToInt8 ULongToInt8 + +// +// DWORD -> CHAR conversion +// +#define DWordToChar ULongToChar + +// +// DWORD -> UCHAR conversion +// +#define DWordToUChar ULongToUChar + +// +// DWORD -> UINT8 conversion +// +#define DWordToUInt8 ULongToUInt8 + +// +// DWORD -> BYTE conversion +// +#define DWordToByte ULongToUInt8 + +// +// DWORD -> SHORT conversion +// +#define DWordToShort ULongToShort + +// +// DWORD -> INT16 conversion +// +#define DWordToInt16 ULongToShort + +// +// DWORD -> USHORT conversion +// +#define DWordToUShort ULongToUShort + +// +// DWORD -> UINT16 conversion +// +#define DWordToUInt16 ULongToUShort + +// +// DWORD -> WORD conversion +// +#define DWordToWord ULongToUShort + +// +// DWORD -> INT conversion +// +#define DWordToInt ULongToInt + +// +// DWORD -> INT32 conversion +// +#define DWordToInt32 ULongToInt + +// +// DWORD -> INT_PTR conversion +// +#define DWordToIntPtr ULongToIntPtr + +// +// DWORD -> UINT conversion +// +#define DWordToUInt ULongToUInt + +// +// DWORD -> UINT32 conversion +// +#define DWordToUInt32 ULongToUInt + +// +// DWORD -> UINT_PTR conversion +// +#define DWordToUIntPtr ULongToUIntPtr + +// +// DWORD -> LONG conversion +// +#define DWordToLong ULongToLong + +// +// DWORD -> LONG_PTR conversion +// +#define DWordToLongPtr ULongToLongPtr + +// +// DWORD -> ptrdiff_t conversion +// +#define DWordToPtrdiffT ULongToIntPtr + +// +// DWORD -> SSIZE_T conversion +// +#define DWordToSSIZET ULongToLongPtr + +// +// DWORD_PTR -> INT8 conversion +// +#define DWordPtrToInt8 ULongPtrToInt8 + +// +// DWORD_PTR -> UCHAR conversion +// +#define DWordPtrToUChar ULongPtrToUChar + +// +// DWORD_PTR -> CHAR conversion +// +#define DWordPtrToChar ULongPtrToChar + +// +// DWORD_PTR -> UINT8 conversion +// +#define DWordPtrToUInt8 ULongPtrToUInt8 + +// +// DWORD_PTR -> BYTE conversion +// +#define DWordPtrToByte ULongPtrToUInt8 + +// +// DWORD_PTR -> SHORT conversion +// +#define DWordPtrToShort ULongPtrToShort + +// +// DWORD_PTR -> INT16 conversion +// +#define DWordPtrToInt16 ULongPtrToShort + +// +// DWORD_PTR -> USHORT conversion +// +#define DWordPtrToUShort ULongPtrToUShort + +// +// DWORD_PTR -> UINT16 conversion +// +#define DWordPtrToUInt16 ULongPtrToUShort + +// +// DWORD_PTR -> WORD conversion +// +#define DWordPtrToWord ULongPtrToUShort + +// +// DWORD_PTR -> INT conversion +// +#define DWordPtrToInt ULongPtrToInt + +// +// DWORD_PTR -> INT32 conversion +// +#define DWordPtrToInt32 ULongPtrToInt + +// +// DWORD_PTR -> INT_PTR conversion +// +#define DWordPtrToIntPtr ULongPtrToIntPtr + +// +// DWORD_PTR -> UINT conversion +// +#define DWordPtrToUInt ULongPtrToUInt + +// +// DWORD_PTR -> UINT32 conversion +// +#define DWordPtrToUInt32 ULongPtrToUInt + +// +// DWODR_PTR -> UINT_PTR conversion +// +#define DWordPtrToUIntPtr ULongPtrToUIntPtr + +// +// DWORD_PTR -> LONG conversion +// +#define DWordPtrToLong ULongPtrToLong + +// +// DWORD_PTR -> LONG_PTR conversion +// +#define DWordPtrToLongPtr ULongPtrToLongPtr + +// +// DWORD_PTR -> ULONG conversion +// +#define DWordPtrToULong ULongPtrToULong + +// +// DWORD_PTR -> DWORD conversion +// +#define DWordPtrToDWord ULongPtrToULong + +// +// DWORD_PTR -> LONGLONG conversion +// +#define DWordPtrToLongLong ULongPtrToLongLong + +// +// DWORD_PTR -> LONG64 conversion +// +#define DWordPtrToLong64 ULongPtrToLongLong + +// +// DWORD_PTR -> INT64 conversion +// +#define DWordPtrToInt64 ULongPtrToLongLong + +// +// DWORD_PTR -> ptrdiff_t conversion +// +#define DWordPtrToPtrdiffT ULongPtrToIntPtr + +// +// DWORD_PTR -> SSIZE_T conversion +// +#define DWordPtrToSSIZET ULongPtrToLongPtr + +// +// LONGLONG -> INT8 conversion +// +__inline +HRESULT +LongLongToInt8( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) INT8* pi8Result) +{ + HRESULT hr; + + if ((llOperand >= INT8_MIN) && (llOperand <= INT8_MAX)) + { + *pi8Result = (INT8)llOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> UCHAR conversion +// +__inline +HRESULT +LongLongToUChar( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) UCHAR* pch) +{ + HRESULT hr; + + if ((llOperand >= 0) && (llOperand <= 255)) + { + *pch = (UCHAR)llOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> CHAR conversion +// +__forceinline +HRESULT +LongLongToChar( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return LongLongToUChar(llOperand, (UCHAR*)pch); +#else + return LongLongToInt8(llOperand, (INT8*)pch); +#endif +} + +// +// LONGLONG -> UINT8 conversion +// +__inline +HRESULT +LongLongToUInt8( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) UINT8* pu8Result) +{ + HRESULT hr; + + if ((llOperand >= 0) && (llOperand <= UINT8_MAX)) + { + *pu8Result = (UINT8)llOperand; + hr = S_OK; + } + else + { + *pu8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> BYTE conversion +// +#define LongLongToByte LongLongToUInt8 + +// +// LONGLONG -> SHORT conversion +// +__inline +HRESULT +LongLongToShort( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) SHORT* psResult) +{ + HRESULT hr; + + if ((llOperand >= SHORT_MIN) && (llOperand <= SHORT_MAX)) + { + *psResult = (SHORT)llOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> INT16 conversion +// +#define LongLongToInt16 LongLongToShort + +// +// LONGLONG -> USHORT conversion +// +__inline +HRESULT +LongLongToUShort( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) USHORT* pusResult) +{ + HRESULT hr; + + if ((llOperand >= 0) && (llOperand <= USHORT_MAX)) + { + *pusResult = (USHORT)llOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> UINT16 conversion +// +#define LongLongToUInt16 LongLongToUShort + +// +// LONGLONG -> WORD conversion +// +#define LongLongToWord LongLongToUShort + +// +// LONGLONG -> INT conversion +// +__inline +HRESULT +LongLongToInt( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) INT* piResult) +{ + HRESULT hr; + + if ((llOperand >= INT_MIN) && (llOperand <= INT_MAX)) + { + *piResult = (INT)llOperand; + hr = S_OK; + } + else + { + *piResult = INT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> INT32 conversion +// +#define LongLongToInt32 LongLongToInt + +// +// LONGLONG -> INT_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +LongLongToIntPtr( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) INT_PTR* piResult) +{ + *piResult = llOperand; + return S_OK; +} +#else +#define LongLongToIntPtr LongLongToInt +#endif + +// +// LONGLONG -> UINT conversion +// +__inline +HRESULT +LongLongToUInt( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) UINT* puResult) +{ + HRESULT hr; + + if ((llOperand >= 0) && (llOperand <= UINT_MAX)) + { + *puResult = (UINT)llOperand; + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> UINT32 conversion +// +#define LongLongToUInt32 LongLongToUInt + +// +// LONGLONG -> UINT_PTR conversion +// +#ifdef _WIN64 +#define LongLongToUIntPtr LongLongToULongLong +#else +#define LongLongToUIntPtr LongLongToUInt +#endif + +// +// LONGLONG -> LONG conversion +// +__inline +HRESULT +LongLongToLong( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) LONG* plResult) +{ + HRESULT hr; + + if ((llOperand >= INT32_MIN) && (llOperand <= INT32_MAX)) + { + *plResult = (LONG)llOperand; + hr = S_OK; + } + else + { + *plResult = LONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> LONG_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +LongLongToLongPtr( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) LONG_PTR* plResult) +{ + *plResult = (LONG_PTR)llOperand; + return S_OK; +} +#else +#define LongLongToLongPtr LongLongToLong +#endif + +// +// LONGLONG -> ULONG conversion +// +__inline +HRESULT +LongLongToULong( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) ULONG* pulResult) +{ + HRESULT hr; + + if ((llOperand >= 0) && (llOperand <= (LONGLONG)(ULONGLONG)UINT32_MAX)) + { + *pulResult = (ULONG)llOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> ULONG_PTR conversion +// +#ifdef _WIN64 +#define LongLongToULongPtr LongLongToULongLong +#else +#define LongLongToULongPtr LongLongToULong +#endif + +// +// LONGLONG -> DWORD conversion +// +#define LongLongToDWord LongLongToULong + +// +// LONGLONG -> DWORD_PTR conversion +// +#define LongLongToDWordPtr LongLongToULongPtr + +// +// LONGLONG -> ULONGLONG conversion +// +__inline +HRESULT +LongLongToULongLong( + __inn LONGLONG llOperand, + __outt __deref_out_range(==,llOperand) ULONGLONG* pullResult) +{ + HRESULT hr; + + if (llOperand >= 0) + { + *pullResult = (ULONGLONG)llOperand; + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// LONGLONG -> DWORDLONG conversion +// +#define LongLongToDWordLong LongLongToULongLong + +// +// LONGLONG -> ULONG64 conversion +// +#define LongLongToULong64 LongLongToULongLong + +// +// LONGLONG -> DWORD64 conversion +// +#define LongLongToDWord64 LongLongToULongLong + +// +// LONGLONG -> UINT64 conversion +// +#define LongLongToUInt64 LongLongToULongLong + +// +// LONGLONG -> ptrdiff_t conversion +// +#define LongLongToPtrdiffT LongLongToIntPtr + +// +// LONGLONG -> size_t conversion +// +#define LongLongToSizeT LongLongToUIntPtr + +// +// LONGLONG -> SSIZE_T conversion +// +#define LongLongToSSIZET LongLongToLongPtr + +// +// LONGLONG -> SIZE_T conversion +// +#define LongLongToSIZET LongLongToULongPtr + +// +// LONG64 -> CHAR conversion +// +#define Long64ToChar LongLongToChar + +// +// LONG64 -> INT8 conversion +// +#define Long64ToInt8 LongLongToInt8 + +// +// LONG64 -> UCHAR conversion +// +#define Long64ToUChar LongLongToUChar + +// +// LONG64 -> UINT8 conversion +// +#define Long64ToUInt8 LongLongToUInt8 + +// +// LONG64 -> BYTE conversion +// +#define Long64ToByte LongLongToUInt8 + +// +// LONG64 -> SHORT conversion +// +#define Long64ToShort LongLongToShort + +// +// LONG64 -> INT16 conversion +// +#define Long64ToInt16 LongLongToShort + +// +// LONG64 -> USHORT conversion +// +#define Long64ToUShort LongLongToUShort + +// +// LONG64 -> UINT16 conversion +// +#define Long64ToUInt16 LongLongToUShort + +// +// LONG64 -> WORD conversion +// +#define Long64ToWord LongLongToUShort + +// +// LONG64 -> INT conversion +// +#define Long64ToInt LongLongToInt + +// +// LONG64 -> INT32 conversion +// +#define Long64ToInt32 LongLongToInt + +// +// LONG64 -> INT_PTR conversion +// +#define Long64ToIntPtr LongLongToIntPtr + +// +// LONG64 -> UINT conversion +// +#define Long64ToUInt LongLongToUInt + +// +// LONG64 -> UINT32 conversion +// +#define Long64ToUInt32 LongLongToUInt + +// +// LONG64 -> UINT_PTR conversion +// +#define Long64ToUIntPtr LongLongToUIntPtr + +// +// LONG64 -> LONG conversion +// +#define Long64ToLong LongLongToLong + +// +// LONG64 -> LONG_PTR conversion +// +#define Long64ToLongPtr LongLongToLongPtr + +// +// LONG64 -> ULONG conversion +// +#define Long64ToULong LongLongToULong + +// +// LONG64 -> ULONG_PTR conversion +// +#define Long64ToULongPtr LongLongToULongPtr + +// +// LONG64 -> DWORD conversion +// +#define Long64ToDWord LongLongToULong + +// +// LONG64 -> DWORD_PTR conversion +// +#define Long64ToDWordPtr LongLongToULongPtr + +// +// LONG64 -> ULONGLONG conversion +// +#define Long64ToULongLong LongLongToULongLong + +// +// LONG64 -> ptrdiff_t conversion +// +#define Long64ToPtrdiffT LongLongToIntPtr + +// +// LONG64 -> size_t conversion +// +#define Long64ToSizeT LongLongToUIntPtr + +// +// LONG64 -> SSIZE_T conversion +// +#define Long64ToSSIZET LongLongToLongPtr + +// +// LONG64 -> SIZE_T conversion +// +#define Long64ToSIZET LongLongToULongPtr + +// +// INT64 -> CHAR conversion +// +#define Int64ToChar LongLongToChar + +// +// INT64 -> INT8 conversion +// +#define Int64ToInt8 LongLongToInt8 + +// +// INT64 -> UCHAR conversion +// +#define Int64ToUChar LongLongToUChar + +// +// INT64 -> UINT8 conversion +// +#define Int64ToUInt8 LongLongToUInt8 + +// +// INT64 -> BYTE conversion +// +#define Int64ToByte LongLongToUInt8 + +// +// INT64 -> SHORT conversion +// +#define Int64ToShort LongLongToShort + +// +// INT64 -> INT16 conversion +// +#define Int64ToInt16 LongLongToShort + +// +// INT64 -> USHORT conversion +// +#define Int64ToUShort LongLongToUShort + +// +// INT64 -> UINT16 conversion +// +#define Int64ToUInt16 LongLongToUShort + +// +// INT64 -> WORD conversion +// +#define Int64ToWord LongLongToUShort + +// +// INT64 -> INT conversion +// +#define Int64ToInt LongLongToInt + +// +// INT64 -> INT32 conversion +// +#define Int64ToInt32 LongLongToInt + +// +// INT64 -> INT_PTR conversion +// +#define Int64ToIntPtr LongLongToIntPtr + +// +// INT64 -> UINT conversion +// +#define Int64ToUInt LongLongToUInt + +// +// INT64 -> UINT32 conversion +// +#define Int64ToUInt32 LongLongToUInt + +// +// INT64 -> UINT_PTR conversion +// +#define Int64ToUIntPtr LongLongToUIntPtr + +// +// INT64 -> LONG conversion +// +#define Int64ToLong LongLongToLong + +// +// INT64 -> LONG_PTR conversion +// +#define Int64ToLongPtr LongLongToLongPtr + +// +// INT64 -> ULONG conversion +// +#define Int64ToULong LongLongToULong + +// +// INT64 -> ULONG_PTR conversion +// +#define Int64ToULongPtr LongLongToULongPtr + +// +// INT64 -> DWORD conversion +// +#define Int64ToDWord LongLongToULong + +// +// INT64 -> DWORD_PTR conversion +// +#define Int64ToDWordPtr LongLongToULongPtr + +// +// INT64 -> ULONGLONG conversion +// +#define Int64ToULongLong LongLongToULongLong + +// +// INT64 -> DWORDLONG conversion +// +#define Int64ToDWordLong LongLongToULongLong + +// +// INT64 -> ULONG64 conversion +// +#define Int64ToULong64 LongLongToULongLong + +// +// INT64 -> DWORD64 conversion +// +#define Int64ToDWord64 LongLongToULongLong + +// +// INT64 -> UINT64 conversion +// +#define Int64ToUInt64 LongLongToULongLong + +// +// INT64 -> ptrdiff_t conversion +// +#define Int64ToPtrdiffT LongLongToIntPtr + +// +// INT64 -> size_t conversion +// +#define Int64ToSizeT LongLongToUIntPtr + +// +// INT64 -> SSIZE_T conversion +// +#define Int64ToSSIZET LongLongToLongPtr + +// +// INT64 -> SIZE_T conversion +// +#define Int64ToSIZET LongLongToULongPtr + +// +// ULONGLONG -> INT8 conversion +// +__inline +HRESULT +ULongLongToInt8( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) INT8* pi8Result) +{ + HRESULT hr; + + if (ullOperand <= INT8_MAX) + { + *pi8Result = (INT8)ullOperand; + hr = S_OK; + } + else + { + *pi8Result = INT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> UCHAR conversion +// +__inline +HRESULT +ULongLongToUChar( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) UCHAR* pch) +{ + HRESULT hr; + + if (ullOperand <= 255) + { + *pch = (UCHAR)ullOperand; + hr = S_OK; + } + else + { + *pch = '\0'; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> CHAR conversion +// +__forceinline +HRESULT +ULongLongToChar( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) CHAR* pch) +{ +#ifdef _CHAR_UNSIGNED + return ULongLongToUChar(ullOperand, (UCHAR*)pch); +#else + return ULongLongToInt8(ullOperand, (INT8*)pch); +#endif +} + +// +// ULONGLONG -> UINT8 conversion +// +__inline +HRESULT +ULongLongToUInt8( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) UINT8* pu8Result) +{ + HRESULT hr; + + if (ullOperand <= UINT8_MAX) + { + *pu8Result = (UINT8)ullOperand; + hr = S_OK; + } + else + { + *pu8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> BYTE conversion +// +#define ULongLongToByte ULongLongToUInt8 + +// +// ULONGLONG -> SHORT conversion +// +__inline +HRESULT +ULongLongToShort( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) SHORT* psResult) +{ + HRESULT hr; + + if (ullOperand <= SHORT_MAX) + { + *psResult = (SHORT)ullOperand; + hr = S_OK; + } + else + { + *psResult = SHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> INT16 conversion +// +#define ULongLongToInt16 ULongLongToShort + +// +// ULONGLONG -> USHORT conversion +// +__inline +HRESULT +ULongLongToUShort( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) USHORT* pusResult) +{ + HRESULT hr; + + if (ullOperand <= USHORT_MAX) + { + *pusResult = (USHORT)ullOperand; + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> UINT16 conversion +// +#define ULongLongToUInt16 ULongLongToUShort + +// +// ULONGLONG -> WORD conversion +// +#define ULongLongToWord ULongLongToUShort + +// +// ULONGLONG -> INT conversion +// +__inline +HRESULT +ULongLongToInt( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) INT* piResult) +{ + HRESULT hr; + + if (ullOperand <= INT_MAX) + { + *piResult = (INT)ullOperand; + hr = S_OK; + } + else + { + *piResult = INT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> INT32 conversion +// +#define ULongLongToInt32 ULongLongToInt + +// +// ULONGLONG -> INT_PTR conversion +// +#ifdef _WIN64 +#define ULongLongToIntPtr ULongLongToLongLong +#else +#define ULongLongToIntPtr ULongLongToInt +#endif + +// +// ULONGLONG -> UINT conversion +// +__inline +HRESULT +ULongLongToUInt( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) UINT* puResult) +{ + HRESULT hr; + + if (ullOperand <= UINT_MAX) + { + *puResult = (UINT)ullOperand; + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> UINT32 conversion +// +#define ULongLongToUInt32 ULongLongToUInt + +// +// ULONGLONG -> UINT_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +ULongLongToUIntPtr( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) UINT_PTR* puResult) +{ + *puResult = ullOperand; + return S_OK; +} +#else +#define ULongLongToUIntPtr ULongLongToUInt +#endif + +// +// ULONGLONG -> LONG conversion +// +__inline +HRESULT +ULongLongToLong( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) LONG* plResult) +{ + HRESULT hr; + + if (ullOperand <= INT32_MAX) + { + *plResult = (LONG)ullOperand; + hr = S_OK; + } + else + { + *plResult = LONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> LONG_PTR conversion +// +__inline +HRESULT +ULongLongToLongPtr( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) LONG_PTR* plResult) +{ + HRESULT hr; + + if (ullOperand <= LONG_PTR_MAX) + { + *plResult = (LONG_PTR)ullOperand; + hr = S_OK; + } + else + { + *plResult = LONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> ULONG conversion +// +__inline +HRESULT +ULongLongToULong( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) ULONG* pulResult) +{ + HRESULT hr; + + if (ullOperand <= UINT32_MAX) + { + *pulResult = (ULONG)ullOperand; + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> ULONG_PTR conversion +// +#ifdef _WIN64 +__inline +HRESULT +ULongLongToULongPtr( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) ULONG_PTR* pulResult) +{ + *pulResult = ullOperand; + return S_OK; +} +#else +#define ULongLongToULongPtr ULongLongToULong +#endif + +// +// ULONGLONG -> DWORD conversion +// +#define ULongLongToDWord ULongLongToULong + +// +// ULONGLONG -> DWORD_PTR conversion +// +#define ULongLongToDWordPtr ULongLongToULongPtr + +// +// ULONGLONG -> LONGLONG conversion +// +__inline +HRESULT +ULongLongToLongLong( + __inn ULONGLONG ullOperand, + __outt __deref_out_range(==,ullOperand) LONGLONG* pllResult) +{ + HRESULT hr; + + if (ullOperand <= LONGLONG_MAX) + { + *pllResult = (LONGLONG)ullOperand; + hr = S_OK; + } + else + { + *pllResult = LONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONGLONG -> INT64 conversion +// +#define ULongLongToInt64 ULongLongToLongLong + +// +// ULONGLONG -> LONG64 conversion +// +#define ULongLongToLong64 ULongLongToLongLong + +// +// ULONGLONG -> ptrdiff_t conversion +// +#define ULongLongToPtrdiffT ULongLongToIntPtr + +// +// ULONGLONG -> size_t conversion +// +#define ULongLongToSizeT ULongLongToUIntPtr + +// +// ULONGLONG -> SSIZE_T conversion +// +#define ULongLongToSSIZET ULongLongToLongPtr + +// +// ULONGLONG -> SIZE_T conversion +// +#define ULongLongToSIZET ULongLongToULongPtr + +// +// DWORDLONG -> CHAR conversion +// +#define DWordLongToChar ULongLongToChar + +// +// DWORDLONG -> INT8 conversion +// +#define DWordLongToInt8 ULongLongToInt8 + +// +// DWORDLONG -> UCHAR conversion +// +#define DWordLongToUChar ULongLongToUChar + +// +// DWORDLONG -> UINT8 conversion +// +#define DWordLongToUInt8 ULongLongToUInt8 + +// +// DWORDLONG -> BYTE conversion +// +#define DWordLongToByte ULongLongToUInt8 + +// +// DWORDLONG -> SHORT conversion +// +#define DWordLongToShort ULongLongToShort + +// +// DWORDLONG -> INT16 conversion +// +#define DWordLongToInt16 ULongLongToShort + +// +// DWORDLONG -> USHORT conversion +// +#define DWordLongToUShort ULongLongToUShort + +// +// DWORDLONG -> UINT16 conversion +// +#define DWordLongToUInt16 ULongLongToUShort + +// +// DWORDLONG -> WORD conversion +// +#define DWordLongToWord ULongLongToUShort + +// +// DWORDLONG -> INT conversion +// +#define DWordLongToInt ULongLongToInt + +// +// DWORDLONG -> INT32 conversion +// +#define DWordLongToInt32 ULongLongToInt + +// +// DWORDLONG -> INT_PTR conversion +// +#define DWordLongToIntPtr ULongLongToIntPtr + +// +// DWORDLONG -> UINT conversion +// +#define DWordLongToUInt ULongLongToUInt + +// +// DWORDLONG -> UINT32 conversion +// +#define DWordLongToUInt32 ULongLongToUInt + +// +// DWORDLONG -> UINT_PTR conversion +// +#define DWordLongToUIntPtr ULongLongToUIntPtr + +// +// DWORDLONG -> LONG conversion +// +#define DWordLongToLong ULongLongToLong + +// +// DWORDLONG -> LONG_PTR conversion +// +#define DWordLongToLongPtr ULongLongToLongPtr + +// +// DWORDLONG -> ULONG conversion +// +#define DWordLongToULong ULongLongToULong + +// +// DWORDLONG -> ULONG_PTR conversion +// +#define DWordLongToULongPtr ULongLongToULongPtr + +// +// DWORDLONG -> DWORD conversion +// +#define DWordLongToDWord ULongLongToULong + +// +// DWORDLONG -> DWORD_PTR conversion +// +#define DWordLongToDWordPtr ULongLongToULongPtr + +// +// DWORDLONG -> LONGLONG conversion +// +#define DWordLongToLongLong ULongLongToLongLong + +// +// DWORDLONG -> LONG64 conversion +// +#define DWordLongToLong64 ULongLongToLongLong + +// +// DWORDLONG -> INT64 conversion +// +#define DWordLongToInt64 ULongLongToLongLong + +// +// DWORDLONG -> ptrdiff_t conversion +// +#define DWordLongToPtrdiffT ULongLongToIntPtr + +// +// DWORDLONG -> size_t conversion +// +#define DWordLongToSizeT ULongLongToUIntPtr + +// +// DWORDLONG -> SSIZE_T conversion +// +#define DWordLongToSSIZET ULongLongToLongPtr + +// +// DWORDLONG -> SIZE_T conversion +// +#define DWordLongToSIZET ULongLongToULongPtr + +// +// ULONG64 -> CHAR conversion +// +#define ULong64ToChar ULongLongToChar + +// +// ULONG64 -> INT8 conversion +// +#define ULong64ToInt8 ULongLongToInt8 + +// +// ULONG64 -> UCHAR conversion +// +#define ULong64ToUChar ULongLongToUChar + +// +// ULONG64 -> UINT8 conversion +// +#define ULong64ToUInt8 ULongLongToUInt8 + +// +// ULONG64 -> BYTE conversion +// +#define ULong64ToByte ULongLongToUInt8 + +// +// ULONG64 -> SHORT conversion +// +#define ULong64ToShort ULongLongToShort + +// +// ULONG64 -> INT16 conversion +// +#define ULong64ToInt16 ULongLongToShort + +// +// ULONG64 -> USHORT conversion +// +#define ULong64ToUShort ULongLongToUShort + +// +// ULONG64 -> UINT16 conversion +// +#define ULong64ToUInt16 ULongLongToUShort + +// +// ULONG64 -> WORD conversion +// +#define ULong64ToWord ULongLongToUShort + +// +// ULONG64 -> INT conversion +// +#define ULong64ToInt ULongLongToInt + +// +// ULONG64 -> INT32 conversion +// +#define ULong64ToInt32 ULongLongToInt + +// +// ULONG64 -> INT_PTR conversion +// +#define ULong64ToIntPtr ULongLongToIntPtr + +// +// ULONG64 -> UINT conversion +// +#define ULong64ToUInt ULongLongToUInt + +// +// ULONG64 -> UINT32 conversion +// +#define ULong64ToUInt32 ULongLongToUInt + +// +// ULONG64 -> UINT_PTR conversion +// +#define ULong64ToUIntPtr ULongLongToUIntPtr + +// +// ULONG64 -> LONG conversion +// +#define ULong64ToLong ULongLongToLong + +// +// ULONG64 -> LONG_PTR conversion +// +#define ULong64ToLongPtr ULongLongToLongPtr + +// +// ULONG64 -> ULONG conversion +// +#define ULong64ToULong ULongLongToULong + +// +// ULONG64 -> ULONG_PTR conversion +// +#define ULong64ToULongPtr ULongLongToULongPtr + +// +// ULONG64 -> DWORD conversion +// +#define ULong64ToDWord ULongLongToULong + +// +// ULONG64 -> DWORD_PTR conversion +// +#define ULong64ToDWordPtr ULongLongToULongPtr + +// +// ULONG64 -> LONGLONG conversion +// +#define ULong64ToLongLong ULongLongToLongLong + +// +// ULONG64 -> LONG64 conversion +// +#define ULong64ToLong64 ULongLongToLongLong + +// +// ULONG64 -> INT64 conversion +// +#define ULong64ToInt64 ULongLongToLongLong + +// +// ULONG64 -> ptrdiff_t conversion +// +#define ULong64ToPtrdiffT ULongLongToIntPtr + +// +// ULONG64 -> size_t conversion +// +#define ULong64ToSizeT ULongLongToUIntPtr + +// +// ULONG64 -> SSIZE_T conversion +// +#define ULong64ToSSIZET ULongLongToLongPtr + +// +// ULONG64 -> SIZE_T conversion +// +#define ULong64ToSIZET ULongLongToULongPtr + +// +// DWORD64 -> CHAR conversion +// +#define DWord64ToChar ULongLongToChar + +// +// DWORD64 -> INT8 conversion +// +#define DWord64ToInt8 ULongLongToInt8 + +// +// DWORD64 -> UCHAR conversion +// +#define DWord64ToUChar ULongLongToUChar + +// +// DWORD64 -> UINT8 conversion +// +#define DWord64ToUInt8 ULongLongToUInt8 + +// +// DWORD64 -> BYTE conversion +// +#define DWord64ToByte ULongLongToUInt8 + +// +// DWORD64 -> SHORT conversion +// +#define DWord64ToShort ULongLongToShort + +// +// DWORD64 -> INT16 conversion +// +#define DWord64ToInt16 ULongLongToShort + +// +// DWORD64 -> USHORT conversion +// +#define DWord64ToUShort ULongLongToUShort + +// +// DWORD64 -> UINT16 conversion +// +#define DWord64ToUInt16 ULongLongToUShort + +// +// DWORD64 -> WORD conversion +// +#define DWord64ToWord ULongLongToUShort + +// +// DWORD64 -> INT conversion +// +#define DWord64ToInt ULongLongToInt + +// +// DWORD64 -> INT32 conversion +// +#define DWord64ToInt32 ULongLongToInt + +// +// DWORD64 -> INT_PTR conversion +// +#define DWord64ToIntPtr ULongLongToIntPtr + +// +// DWORD64 -> UINT conversion +// +#define DWord64ToUInt ULongLongToUInt + +// +// DWORD64 -> UINT32 conversion +// +#define DWord64ToUInt32 ULongLongToUInt + +// +// DWORD64 -> UINT_PTR conversion +// +#define DWord64ToUIntPtr ULongLongToUIntPtr + +// +// DWORD64 -> LONG conversion +// +#define DWord64ToLong ULongLongToLong + +// +// DWORD64 -> LONG_PTR conversion +// +#define DWord64ToLongPtr ULongLongToLongPtr + +// +// DWORD64 -> ULONG conversion +// +#define DWord64ToULong ULongLongToULong + +// +// DWORD64 -> ULONG_PTR conversion +// +#define DWord64ToULongPtr ULongLongToULongPtr + +// +// DWORD64 -> DWORD conversion +// +#define DWord64ToDWord ULongLongToULong + +// +// DWORD64 -> DWORD_PTR conversion +// +#define DWord64ToDWordPtr ULongLongToULongPtr + +// +// DWORD64 -> LONGLONG conversion +// +#define DWord64ToLongLong ULongLongToLongLong + +// +// DWORD64 -> LONG64 conversion +// +#define DWord64ToLong64 ULongLongToLongLong + +// +// DWORD64 -> INT64 conversion +// +#define DWord64ToInt64 ULongLongToLongLong + +// +// DWORD64 -> ptrdiff_t conversion +// +#define DWord64ToPtrdiffT ULongLongToIntPtr + +// +// DWORD64 -> size_t conversion +// +#define DWord64ToSizeT ULongLongToUIntPtr + +// +// DWORD64 -> SSIZE_T conversion +// +#define DWord64ToSSIZET ULongLongToLongPtr + +// +// DWORD64 -> SIZE_T conversion +// +#define DWord64ToSIZET ULongLongToULongPtr + +// +// UINT64 -> CHAR conversion +// +#define UInt64ToChar ULongLongToChar + +// +// UINT64 -> INT8 conversion +// +#define UInt64ToInt8 ULongLongToInt8 + +// +// UINT64 -> UCHAR conversion +// +#define UInt64ToUChar ULongLongToUChar + +// +// UINT64 -> UINT8 conversion +// +#define UInt64ToUInt8 ULongLongToUInt8 + +// +// UINT64 -> BYTE conversion +// +#define UInt64ToByte ULongLongToUInt8 + +// +// UINT64 -> SHORT conversion +// +#define UInt64ToShort ULongLongToShort + +// +// UINT64 -> INT16 conversion +// +// +#define UInt64ToInt16 ULongLongToShort + +// +// UINT64 -> USHORT conversion +// +#define UInt64ToUShort ULongLongToUShort + +// +// UINT64 -> UINT16 conversion +// +#define UInt64ToUInt16 ULongLongToUShort + +// +// UINT64 -> WORD conversion +// +#define UInt64ToWord ULongLongToUShort + +// +// UINT64 -> INT conversion +// +#define UInt64ToInt ULongLongToInt + +// +// UINT64 -> INT32 conversion +// +#define UInt64ToInt32 ULongLongToInt + +// +// UINT64 -> INT_PTR conversion +// +#define UInt64ToIntPtr ULongLongToIntPtr + +// +// UINT64 -> UINT conversion +// +#define UInt64ToUInt ULongLongToUInt + +// +// UINT64 -> UINT32 conversion +// +#define UInt64ToUInt32 ULongLongToUInt + +// +// UINT64 -> UINT_PTR conversion +// +#define UInt64ToUIntPtr ULongLongToUIntPtr + +// +// UINT64 -> LONG conversion +// +#define UInt64ToLong ULongLongToLong + +// +// UINT64 -> LONG_PTR conversion +// +#define UInt64ToLongPtr ULongLongToLongPtr + +// +// UINT64 -> ULONG conversion +// +#define UInt64ToULong ULongLongToULong + +// +// UINT64 -> ULONG_PTR conversion +// +#define UInt64ToULongPtr ULongLongToULongPtr + +// +// UINT64 -> DWORD conversion +// +#define UInt64ToDWord ULongLongToULong + +// +// UINT64 -> DWORD_PTR conversion +// +#define UInt64ToDWordPtr ULongLongToULongPtr + +// +// UINT64 -> LONGLONG conversion +// +#define UInt64ToLongLong ULongLongToLongLong + +// +// UINT64 -> LONG64 conversion +// +#define UInt64ToLong64 ULongLongToLongLong + +// +// UINT64 -> INT64 conversion +// +#define UInt64ToInt64 ULongLongToLongLong + +// +// UINT64 -> ptrdiff_t conversion +// +#define UInt64ToPtrdiffT ULongLongToIntPtr + +// +// UINT64 -> size_t conversion +// +#define UInt64ToSizeT ULongLongToUIntPtr + +// +// UINT64 -> SSIZE_T conversion +// +#define UInt64ToSSIZET ULongLongToLongPtr + +// +// UINT64 -> SIZE_T conversion +// +#define UInt64ToSIZET ULongLongToULongPtr + +// +// ptrdiff_t -> CHAR conversion +// +#define PtrdiffTToChar IntPtrToChar + +// +// ptrdiff_t -> INT8 conversion +// +#define PtrdiffTToInt8 IntPtrToInt8 + +// +// ptrdiff_t -> UCHAR conversion +// +#define PtrdiffTToUChar IntPtrToUChar + +// +// ptrdiff_t -> UINT8 conversion +// +#define PtrdiffTToUInt8 IntPtrToUInt8 + +// +// ptrdiff_t -> BYTE conversion +// +#define PtrdiffTToByte IntPtrToUInt8 + +// +// ptrdiff_t -> SHORT conversion +// +#define PtrdiffTToShort IntPtrToShort + +// +// ptrdiff_t -> INT16 conversion +// +#define PtrdiffTToInt16 IntPtrToShort + +// +// ptrdiff_t -> USHORT conversion +// +#define PtrdiffTToUShort IntPtrToUShort + +// +// ptrdiff_t -> UINT16 conversion +// +#define PtrdiffTToUInt16 IntPtrToUShort + +// +// ptrdiff_t -> WORD conversion +// +#define PtrdiffTToWord IntPtrToUShort + +// +// ptrdiff_t -> INT conversion +// +#define PtrdiffTToInt IntPtrToInt + +// +// ptrdiff_t -> INT32 conversion +// +#define PtrdiffTToInt32 IntPtrToInt + +// +// ptrdiff_t -> UINT conversion +// +#define PtrdiffTToUInt IntPtrToUInt + +// +// ptrdiff_t -> UINT32 conversion +// +#define PtrdiffTToUInt32 IntPtrToUInt + +// +// ptrdiff_t -> UINT_PTR conversion +// +#define PtrdiffTToUIntPtr IntPtrToUIntPtr + +// +// ptrdiff_t -> LONG conversion +// +#define PtrdiffTToLong IntPtrToLong + +// +// ptrdiff_t -> LONG_PTR conversion +// +#define PtrdiffTToLongPtr IntPtrToLongPtr + +// +// ptrdiff_t -> ULONG conversion +// +#define PtrdiffTToULong IntPtrToULong + +// +// ptrdiff_t -> ULONG_PTR conversion +// +#define PtrdiffTToULongPtr IntPtrToULongPtr + +// +// ptrdiff_t -> DWORD conversion +// +#define PtrdiffTToDWord IntPtrToULong + +// +// ptrdiff_t -> DWORD_PTR conversion +// +#define PtrdiffTToDWordPtr IntPtrToULongPtr + +// +// ptrdiff_t -> ULONGLONG conversion +// +#define PtrdiffTToULongLong IntPtrToULongLong + +// +// ptrdiff_t -> DWORDLONG conversion +// +#define PtrdiffTToDWordLong IntPtrToULongLong + +// +// ptrdiff_t -> ULONG64 conversion +// +#define PtrdiffTToULong64 IntPtrToULongLong + +// +// ptrdiff_t -> DWORD64 conversion +// +#define PtrdiffTToDWord64 IntPtrToULongLong + +// +// ptrdiff_t -> UINT64 conversion +// +#define PtrdiffTToUInt64 IntPtrToULongLong + +// +// ptrdiff_t -> size_t conversion +// +#define PtrdiffTToSizeT IntPtrToUIntPtr + +// +// ptrdiff_t -> SIZE_T conversion +// +#define PtrdiffTToSIZET IntPtrToULongPtr + +// +// size_t -> INT8 conversion +// +#define SizeTToInt8 UIntPtrToInt8 + +// +// size_t -> UCHAR conversion +// +#define SizeTToUChar UIntPtrToUChar + +// +// size_t -> CHAR conversion +// +#define SizeTToChar UIntPtrToChar + +// +// size_t -> UINT8 conversion +// +#define SizeTToUInt8 UIntPtrToUInt8 + +// +// size_t -> BYTE conversion +// +#define SizeTToByte UIntPtrToUInt8 + +// +// size_t -> SHORT conversion +// +#define SizeTToShort UIntPtrToShort + +// +// size_t -> INT16 conversion +// +#define SizeTToInt16 UIntPtrToShort + +// +// size_t -> USHORT conversion +// +#define SizeTToUShort UIntPtrToUShort + +// +// size_t -> UINT16 conversion +// +#define SizeTToUInt16 UIntPtrToUShort + +// +// size_t -> WORD +// +#define SizeTToWord UIntPtrToUShort + +// +// size_t -> INT conversion +// +#define SizeTToInt UIntPtrToInt + +// +// size_t -> INT32 conversion +// +#define SizeTToInt32 UIntPtrToInt + +// +// size_t -> INT_PTR conversion +// +#define SizeTToIntPtr UIntPtrToIntPtr + +// +// size_t -> UINT conversion +// +#define SizeTToUInt UIntPtrToUInt + +// +// size_t -> UINT32 conversion +// +#define SizeTToUInt32 UIntPtrToUInt + +// +// size_t -> LONG conversion +// +#define SizeTToLong UIntPtrToLong + +// +// size_t -> LONG_PTR conversion +// +#define SizeTToLongPtr UIntPtrToLongPtr + +// +// size_t -> ULONG conversion +// +#define SizeTToULong UIntPtrToULong + +// +// size_t -> DWORD conversion +// +#define SizeTToDWord UIntPtrToULong + +// +// size_t -> LONGLONG conversion +// +#define SizeTToLongLong UIntPtrToLongLong + +// +// size_t -> LONG64 conversion +// +#define SizeTToLong64 UIntPtrToLongLong + +// +// size_t -> INT64 +// +#define SizeTToInt64 UIntPtrToLongLong + +// +// size_t -> ptrdiff_t conversion +// +#define SizeTToPtrdiffT UIntPtrToIntPtr + +// +// size_t -> SSIZE_T conversion +// +#define SizeTToSSIZET UIntPtrToLongPtr + +// +// SSIZE_T -> INT8 conversion +// +#define SSIZETToInt8 LongPtrToInt8 + +// +// SSIZE_T -> UCHAR conversion +// +#define SSIZETToUChar LongPtrToUChar + +// +// SSIZE_T -> CHAR conversion +// +#define SSIZETToChar LongPtrToChar + +// +// SSIZE_T -> UINT8 conversion +// +#define SSIZETToUInt8 LongPtrToUInt8 + +// +// SSIZE_T -> BYTE conversion +// +#define SSIZETToByte LongPtrToUInt8 + +// +// SSIZE_T -> SHORT conversion +// +#define SSIZETToShort LongPtrToShort + +// +// SSIZE_T -> INT16 conversion +// +#define SSIZETToInt16 LongPtrToShort + +// +// SSIZE_T -> USHORT conversion +// +#define SSIZETToUShort LongPtrToUShort + +// +// SSIZE_T -> UINT16 conversion +// +#define SSIZETToUInt16 LongPtrToUShort + +// +// SSIZE_T -> WORD conversion +// +#define SSIZETToWord LongPtrToUShort + +// +// SSIZE_T -> INT conversion +// +#define SSIZETToInt LongPtrToInt + +// +// SSIZE_T -> INT32 conversion +// +#define SSIZETToInt32 LongPtrToInt + +// +// SSIZE_T -> INT_PTR conversion +// +#define SSIZETToIntPtr LongPtrToIntPtr + +// +// SSIZE_T -> UINT conversion +// +#define SSIZETToUInt LongPtrToUInt + +// +// SSIZE_T -> UINT32 conversion +// +#define SSIZETToUInt32 LongPtrToUInt + +// +// SSIZE_T -> UINT_PTR conversion +// +#define SSIZETToUIntPtr LongPtrToUIntPtr + +// +// SSIZE_T -> LONG conversion +// +#define SSIZETToLong LongPtrToLong + +// +// SSIZE_T -> ULONG conversion +// +#define SSIZETToULong LongPtrToULong + +// +// SSIZE_T -> ULONG_PTR conversion +// +#define SSIZETToULongPtr LongPtrToULongPtr + +// +// SSIZE_T -> DWORD conversion +// +#define SSIZETToDWord LongPtrToULong + +// +// SSIZE_T -> DWORD_PTR conversion +// +#define SSIZETToDWordPtr LongPtrToULongPtr + +// +// SSIZE_T -> ULONGLONG conversion +// +#define SSIZETToULongLong LongPtrToULongLong + +// +// SSIZE_T -> DWORDLONG conversion +// +#define SSIZETToDWordLong LongPtrToULongLong + +// +// SSIZE_T -> ULONG64 conversion +// +#define SSIZETToULong64 LongPtrToULongLong + +// +// SSIZE_T -> DWORD64 conversion +// +#define SSIZETToDWord64 LongPtrToULongLong + +// +// SSIZE_T -> UINT64 conversion +// +#define SSIZETToUInt64 LongPtrToULongLong + +// +// SSIZE_T -> size_t conversion +// +#define SSIZETToSizeT LongPtrToUIntPtr + +// +// SSIZE_T -> SIZE_T conversion +// +#define SSIZETToSIZET LongPtrToULongPtr + +// +// SIZE_T -> INT8 conversion +// +#define SIZETToInt8 ULongPtrToInt8 + +// +// SIZE_T -> UCHAR conversion +// +#define SIZETToUChar ULongPtrToUChar + +// +// SIZE_T -> CHAR conversion +// +#define SIZETToChar ULongPtrToChar + +// +// SIZE_T -> UINT8 conversion +// +#define SIZETToUInt8 ULongPtrToUInt8 + +// +// SIZE_T -> BYTE conversion +// +#define SIZETToByte ULongPtrToUInt8 + +// +// SIZE_T -> SHORT conversion +// +#define SIZETToShort ULongPtrToShort + +// +// SIZE_T -> INT16 conversion +// +#define SIZETToInt16 ULongPtrToShort + +// +// SIZE_T -> USHORT conversion +// +#define SIZETToUShort ULongPtrToUShort + +// +// SIZE_T -> UINT16 conversion +// +#define SIZETToUInt16 ULongPtrToUShort + +// +// SIZE_T -> WORD +// +#define SIZETToWord ULongPtrToUShort + +// +// SIZE_T -> INT conversion +// +#define SIZETToInt ULongPtrToInt + +// +// SIZE_T -> INT32 conversion +// +#define SIZETToInt32 ULongPtrToInt + +// +// SIZE_T -> INT_PTR conversion +// +#define SIZETToIntPtr ULongPtrToIntPtr + +// +// SIZE_T -> UINT conversion +// +#define SIZETToUInt ULongPtrToUInt + +// +// SIZE_T -> UINT32 conversion +// +#define SIZETToUInt32 ULongPtrToUInt + +// +// SIZE_T -> UINT_PTR conversion +// +#define SIZETToUIntPtr ULongPtrToUIntPtr + +// +// SIZE_T -> LONG conversion +// +#define SIZETToLong ULongPtrToLong + +// +// SIZE_T -> LONG_PTR conversion +// +#define SIZETToLongPtr ULongPtrToLongPtr + +// +// SIZE_T -> ULONG conversion +// +#define SIZETToULong ULongPtrToULong + +// +// SIZE_T -> DWORD conversion +// +#define SIZETToDWord ULongPtrToULong + +// +// SIZE_T -> LONGLONG conversion +// +#define SIZETToLongLong ULongPtrToLongLong + +// +// SIZE_T -> LONG64 conversion +// +#define SIZETToLong64 ULongPtrToLongLong + +// +// SIZE_T -> INT64 +// +#define SIZETToInt64 ULongPtrToLongLong + +// +// SIZE_T -> ptrdiff_t conversion +// +#define SIZETToPtrdiffT ULongPtrToIntPtr + +// +// SIZE_T -> SSIZE_T conversion +// +#define SIZETToSSIZET ULongPtrToLongPtr + + +//============================================================================= +// Addition functions +//============================================================================= + +// +// UINT8 addition +// +__inline +HRESULT +UInt8Add( + __inn UINT8 u8Augend, + __inn UINT8 u8Addend, + __outt __deref_out_range(==,u8Augend + u8Addend) UINT8* pu8Result) +{ + HRESULT hr; + + if (((UINT8)(u8Augend + u8Addend)) >= u8Augend) + { + *pu8Result = (UINT8)(u8Augend + u8Addend); + hr = S_OK; + } + else + { + *pu8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// USHORT addition +// +__inline +HRESULT +UShortAdd( + __inn USHORT usAugend, + __inn USHORT usAddend, + __outt __deref_out_range(==,usAugend + usAddend) USHORT* pusResult) +{ + HRESULT hr; + + if (((USHORT)(usAugend + usAddend)) >= usAugend) + { + *pusResult = (USHORT)(usAugend + usAddend); + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT16 addition +// +#define UInt16Add UShortAdd + +// +// WORD addtition +// +#define WordAdd UShortAdd + +// +// UINT addition +// +__inline +HRESULT +UIntAdd( + __inn UINT uAugend, + __inn UINT uAddend, + __outt __deref_out_range(==,uAugend + uAddend) UINT* puResult) +{ + HRESULT hr; + + if ((uAugend + uAddend) >= uAugend) + { + *puResult = (uAugend + uAddend); + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT32 addition +// +#define UInt32Add UIntAdd + +// +// UINT_PTR addition +// +#ifdef _WIN64 +#define UIntPtrAdd ULongLongAdd +#else +__inline +HRESULT +UIntPtrAdd( + __inn UINT_PTR uAugend, + __inn UINT_PTR uAddend, + __outt __deref_out_range(==,uAugend + uAddend) UINT_PTR* puResult) +{ + HRESULT hr; + + if ((uAugend + uAddend) >= uAugend) + { + *puResult = (uAugend + uAddend); + hr = S_OK; + } + else + { + *puResult = UINT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif // _WIN64 + +// +// ULONG addition +// +__inline +HRESULT +ULongAdd( + __inn ULONG ulAugend, + __inn ULONG ulAddend, + __outt __deref_out_range(==,ulAugend + ulAddend) ULONG* pulResult) +{ + HRESULT hr; + + if ((ulAugend + ulAddend) >= ulAugend) + { + *pulResult = (ulAugend + ulAddend); + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR addition +// +#ifdef _WIN64 +#define ULongPtrAdd ULongLongAdd +#else +__inline +HRESULT +ULongPtrAdd( + __inn ULONG_PTR ulAugend, + __inn ULONG_PTR ulAddend, + __outt __deref_out_range(==,ulAugend + ulAddend) ULONG_PTR* pulResult) +{ + HRESULT hr; + + if ((ulAugend + ulAddend) >= ulAugend) + { + *pulResult = (ulAugend + ulAddend); + hr = S_OK; + } + else + { + *pulResult = ULONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif // _WIN64 + +// +// DWORD addition +// +#define DWordAdd ULongAdd + +// +// DWORD_PTR addition +// +#ifdef _WIN64 +#define DWordPtrAdd ULongLongAdd +#else +__inline +HRESULT +DWordPtrAdd( + __inn DWORD_PTR dwAugend, + __inn DWORD_PTR dwAddend, + __outt __deref_out_range(==,dwAugend + dwAddend) DWORD_PTR* pdwResult) +{ + HRESULT hr; + + if ((dwAugend + dwAddend) >= dwAugend) + { + *pdwResult = (dwAugend + dwAddend); + hr = S_OK; + } + else + { + *pdwResult = DWORD_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif // _WIN64 + +// +// size_t addition +// +__inline +HRESULT +SizeTAdd( + __inn size_t Augend, + __inn size_t Addend, + __outt __deref_out_range(==,Augend + Addend) size_t* pResult) +{ + HRESULT hr; + + if ((Augend + Addend) >= Augend) + { + *pResult = (Augend + Addend); + hr = S_OK; + } + else + { + *pResult = SIZE_T_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SIZE_T addition +// +#ifdef _WIN64 +#define SIZETAdd ULongLongAdd +#else +__inline +HRESULT +SIZETAdd( + __inn SIZE_T Augend, + __inn SIZE_T Addend, + __outt __deref_out_range(==,Augend + Addend) SIZE_T* pResult) +{ + HRESULT hr; + + if ((Augend + Addend) >= Augend) + { + *pResult = (Augend + Addend); + hr = S_OK; + } + else + { + *pResult = _SIZE_T_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif // _WIN64 + +// +// ULONGLONG addition +// +__inline +HRESULT +ULongLongAdd( + __inn ULONGLONG ullAugend, + __inn ULONGLONG ullAddend, + __outt __deref_out_range(==,ullAugend + ullAddend) ULONGLONG* pullResult) +{ + HRESULT hr; + + if ((ullAugend + ullAddend) >= ullAugend) + { + *pullResult = (ullAugend + ullAddend); + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// DWORDLONG addition +// +#define DWordLongAdd ULongLongAdd + +// +// ULONG64 addition +// +#define ULong64Add ULongLongAdd + +// +// DWORD64 addition +// +#define DWord64Add ULongLongAdd + +// +// UINT64 addition +// +#define UInt64Add ULongLongAdd + + +//============================================================================= +// Subtraction functions +//============================================================================= + +// +// UINT8 subtraction +// +__inline +HRESULT +UInt8Sub( + __inn UINT8 u8Minuend, + __inn UINT8 u8Subtrahend, + __outt __deref_out_range(==,u8Minuend - u8Subtrahend) UINT8* pu8Result) +{ + HRESULT hr; + + if (u8Minuend >= u8Subtrahend) + { + *pu8Result = (UINT8)(u8Minuend - u8Subtrahend); + hr = S_OK; + } + else + { + *pu8Result = UINT8_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// USHORT subtraction +// +__inline +HRESULT +UShortSub( + __inn USHORT usMinuend, + __inn USHORT usSubtrahend, + __outt __deref_out_range(==,usMinuend - usSubtrahend) USHORT* pusResult) +{ + HRESULT hr; + + if (usMinuend >= usSubtrahend) + { + *pusResult = (USHORT)(usMinuend - usSubtrahend); + hr = S_OK; + } + else + { + *pusResult = USHORT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT16 subtraction +// +#define UInt16Sub UShortSub + +// +// WORD subtraction +// +#define WordSub UShortSub + + +// +// UINT subtraction +// +__inline +HRESULT +UIntSub( + __inn UINT uMinuend, + __inn UINT uSubtrahend, + __outt __deref_out_range(==,uMinuend - uSubtrahend) UINT* puResult) +{ + HRESULT hr; + + if (uMinuend >= uSubtrahend) + { + *puResult = (uMinuend - uSubtrahend); + hr = S_OK; + } + else + { + *puResult = UINT_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// UINT32 subtraction +// +#define UInt32Sub UIntSub + +// +// UINT_PTR subtraction +// +#ifdef _WIN64 +#define UIntPtrSub ULongLongSub +#else +__inline +HRESULT +UIntPtrSub( + __inn UINT_PTR uMinuend, + __inn UINT_PTR uSubtrahend, + __outt __deref_out_range(==,uMinuend - uSubtrahend) UINT_PTR* puResult) +{ + HRESULT hr; + + if (uMinuend >= uSubtrahend) + { + *puResult = (uMinuend - uSubtrahend); + hr = S_OK; + } + else + { + *puResult = UINT_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif // _WIN64 + +// +// ULONG subtraction +// +__inline +HRESULT +ULongSub( + __inn ULONG ulMinuend, + __inn ULONG ulSubtrahend, + __outt __deref_out_range(==,ulMinuend - ulSubtrahend) ULONG* pulResult) +{ + HRESULT hr; + + if (ulMinuend >= ulSubtrahend) + { + *pulResult = (ulMinuend - ulSubtrahend); + hr = S_OK; + } + else + { + *pulResult = ULONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// ULONG_PTR subtraction +// +#ifdef _WIN64 +#define ULongPtrSub ULongLongSub +#else +__inline +HRESULT +ULongPtrSub( + __inn ULONG_PTR ulMinuend, + __inn ULONG_PTR ulSubtrahend, + __outt __deref_out_range(==,ulMinuend - ulSubtrahend) ULONG_PTR* pulResult) +{ + HRESULT hr; + + if (ulMinuend >= ulSubtrahend) + { + *pulResult = (ulMinuend - ulSubtrahend); + hr = S_OK; + } + else + { + *pulResult = ULONG_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif // _WIN64 + + +// +// DWORD subtraction +// +#define DWordSub ULongSub + +// +// DWORD_PTR subtraction +// +#ifdef _WIN64 +#define DWordPtrSub ULongLongSub +#else +__inline +HRESULT +DWordPtrSub( + __inn DWORD_PTR dwMinuend, + __inn DWORD_PTR dwSubtrahend, + __outt __deref_out_range(==,dwMinuend - dwSubtrahend) DWORD_PTR* pdwResult) +{ + HRESULT hr; + + if (dwMinuend >= dwSubtrahend) + { + *pdwResult = (dwMinuend - dwSubtrahend); + hr = S_OK; + } + else + { + *pdwResult = DWORD_PTR_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif // _WIN64 + +// +// size_t subtraction +// +__inline +HRESULT +SizeTSub( + __inn size_t Minuend, + __inn size_t Subtrahend, + __outt __deref_out_range(==,Minuend - Subtrahend) size_t* pResult) +{ + HRESULT hr; + + if (Minuend >= Subtrahend) + { + *pResult = (Minuend - Subtrahend); + hr = S_OK; + } + else + { + *pResult = SIZE_T_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// SIZE_T subtraction +// +#ifdef _WIN64 +#define SIZETSub ULongLongSub +#else +__inline +HRESULT +SIZETSub( + __inn SIZE_T Minuend, + __inn SIZE_T Subtrahend, + __outt __deref_out_range(==,Minuend - Subtrahend) SIZE_T* pResult) +{ + HRESULT hr; + + if (Minuend >= Subtrahend) + { + *pResult = (Minuend - Subtrahend); + hr = S_OK; + } + else + { + *pResult = _SIZE_T_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} +#endif // _WIN64 + +// +// ULONGLONG subtraction +// +__inline +HRESULT +ULongLongSub( + __inn ULONGLONG ullMinuend, + __inn ULONGLONG ullSubtrahend, + __outt __deref_out_range(==,ullMinuend - ullSubtrahend) ULONGLONG* pullResult) +{ + HRESULT hr; + + if (ullMinuend >= ullSubtrahend) + { + *pullResult = (ullMinuend - ullSubtrahend); + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } + + return hr; +} + +// +// DWORDLONG subtraction +// +#define DWordLongSub ULongLongSub + +// +// ULONG64 subtraction +// +#define ULong64Sub ULongLongSub + +// +// DWORD64 subtraction +// +#define DWord64Sub ULongLongSub + +// +// UINT64 subtraction +// +#define UInt64Sub ULongLongSub + + +//============================================================================= +// Multiplication functions +//============================================================================= + +// +// UINT8 multiplication +// +__inline +HRESULT +UInt8Mult( + __inn UINT8 u8Multiplicand, + __inn UINT8 u8Multiplier, + __outt __deref_out_range(==,u8Multiplier * u8Multiplicand) UINT8* pu8Result) +{ + UINT uResult = ((UINT)u8Multiplicand) * ((UINT)u8Multiplier); + + return UIntToUInt8(uResult, pu8Result); +} + +// +// USHORT multiplication +// +__inline +HRESULT +UShortMult( + __inn USHORT usMultiplicand, + __inn USHORT usMultiplier, + __outt __deref_out_range(==,usMultiplier * usMultiplicand)USHORT* pusResult) +{ + ULONG ulResult = ((ULONG)usMultiplicand) * ((ULONG)usMultiplier); + + return ULongToUShort(ulResult, pusResult); +} + +// +// UINT16 multiplication +// +#define UInt16Mult UShortMult + +// +// WORD multiplication +// +#define WordMult UShortMult + +// +// UINT multiplication +// +__inline +HRESULT +UIntMult( + __inn UINT uMultiplicand, + __inn UINT uMultiplier, + __outt __deref_out_range(==,uMultiplier * uMultiplicand) UINT* puResult) +{ + ULONGLONG ull64Result = UInt32x32To64(uMultiplicand, uMultiplier); + + return ULongLongToUInt(ull64Result, puResult); +} + +// +// UINT32 multiplication +// +#define UInt32Mult UIntMult + +// +// UINT_PTR multiplication +// +#ifdef _WIN64 +#define UIntPtrMult ULongLongMult +#else +__inline +HRESULT +UIntPtrMult( + __inn UINT_PTR uMultiplicand, + __inn UINT_PTR uMultiplier, + __outt __deref_out_range(==,uMultiplier * uMultiplicand) UINT_PTR* puResult) +{ + ULONGLONG ull64Result = UInt32x32To64(uMultiplicand, uMultiplier); + + return ULongLongToUIntPtr(ull64Result, puResult); +} +#endif // _WIN64 + +// +// ULONG multiplication +// +__inline +HRESULT +ULongMult( + __inn ULONG ulMultiplicand, + __inn ULONG ulMultiplier, + __outt __deref_out_range(==,ulMultiplier * ulMultiplicand) ULONG* pulResult) +{ + ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier); + + return ULongLongToULong(ull64Result, pulResult); +} + +// +// ULONG_PTR multiplication +// +#ifdef _WIN64 +#define ULongPtrMult ULongLongMult +#else +__inline +HRESULT +ULongPtrMult( + __inn ULONG_PTR ulMultiplicand, + __inn ULONG_PTR ulMultiplier, + __outt __deref_out_range(==,ulMultiplier * ulMultiplicand) ULONG_PTR* pulResult) +{ + ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier); + + return ULongLongToULongPtr(ull64Result, (unsigned long *)pulResult); +} +#endif // _WIN64 + +// +// DWORD multiplication +// +#define DWordMult ULongMult + +// +// DWORD_PTR multiplication +// +#ifdef _WIN64 +#define DWordPtrMult ULongLongMult +#else +__inline +HRESULT +DWordPtrMult( + __inn DWORD_PTR dwMultiplicand, + __inn DWORD_PTR dwMultiplier, + __outt __deref_out_range(==,dwMultiplier * dwMultiplicand) DWORD_PTR* pdwResult) +{ + ULONGLONG ull64Result = UInt32x32To64(dwMultiplicand, dwMultiplier); + + return ULongLongToDWordPtr(ull64Result, (unsigned long *)pdwResult); +} +#endif // _WIN64 + +// +// size_t multiplication +// + +#ifdef _WIN64 +#define SizeTMult ULongLongMult +#else +__inline +HRESULT +SizeTMult( + __inn size_t Multiplicand, + __inn size_t Multiplier, + __outt __deref_out_range(==,Multiplier * Multiplicand) UINT* pResult) +{ + ULONGLONG ull64Result = UInt32x32To64(Multiplicand, Multiplier); + + return ULongLongToSizeT(ull64Result, pResult); +} +#endif // _WIN64 + +// +// SIZE_T multiplication +// +#ifdef _WIN64 +#define SIZETMult ULongLongMult +#else +__inline +HRESULT +SIZETMult( + __inn SIZE_T Multiplicand, + __inn SIZE_T Multiplier, + __outt __deref_out_range(==,Multiplier * Multiplicand) SIZE_T* pResult) +{ + ULONGLONG ull64Result = UInt32x32To64(Multiplicand, Multiplier); + + return ULongLongToSIZET(ull64Result, (unsigned long *)pResult); +} +#endif // _WIN64 + +// +// ULONGLONG multiplication +// +__inline +HRESULT +ULongLongMult( + __inn ULONGLONG ullMultiplicand, + __inn ULONGLONG ullMultiplier, + __outt __deref_out_range(==,ullMultiplier * ullMultiplicand) ULONGLONG* pullResult) +{ + HRESULT hr; +#ifdef _AMD64_ + ULONGLONG u64ResultHigh; + ULONGLONG u64ResultLow; + + u64ResultLow = UnsignedMultiply128(ullMultiplicand, ullMultiplier, &u64ResultHigh); + if (u64ResultHigh == 0) + { + *pullResult = u64ResultLow; + hr = S_OK; + } + else + { + *pullResult = ULONGLONG_ERROR; + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + } +#else + // 64x64 into 128 is like 32.32 x 32.32. + // + // a.b * c.d = a*(c.d) + .b*(c.d) = a*c + a*.d + .b*c + .b*.d + // back in non-decimal notation where A=a*2^32 and C=c*2^32: + // A*C + A*d + b*C + b*d + // So there are four components to add together. + // result = (a*c*2^64) + (a*d*2^32) + (b*c*2^32) + (b*d) + // + // a * c must be 0 or there would be bits in the high 64-bits + // a * d must be less than 2^32 or there would be bits in the high 64-bits + // b * c must be less than 2^32 or there would be bits in the high 64-bits + // then there must be no overflow of the resulting values summed up. + + ULONG dw_a; + ULONG dw_b; + ULONG dw_c; + ULONG dw_d; + ULONGLONG ad = 0; + ULONGLONG bc = 0; + ULONGLONG bd = 0; + ULONGLONG ullResult = 0; + + hr = INTSAFE_E_ARITHMETIC_OVERFLOW; + + dw_a = (ULONG)(ullMultiplicand >> 32); + dw_c = (ULONG)(ullMultiplier >> 32); + + // common case -- if high dwords are both zero, no chance for overflow + if ((dw_a == 0) && (dw_c == 0)) + { + dw_b = (DWORD)ullMultiplicand; + dw_d = (DWORD)ullMultiplier; + + *pullResult = (((ULONGLONG)dw_b) * (ULONGLONG)dw_d); + hr = S_OK; + } + else + { + // a * c must be 0 or there would be bits set in the high 64-bits + if ((dw_a == 0) || + (dw_c == 0)) + { + dw_d = (DWORD)ullMultiplier; + + // a * d must be less than 2^32 or there would be bits set in the high 64-bits + ad = (((ULONGLONG)dw_a) * (ULONGLONG)dw_d); + if ((ad & 0xffffffff00000000LL) == 0) + { + dw_b = (DWORD)ullMultiplicand; + + // b * c must be less than 2^32 or there would be bits set in the high 64-bits + bc = (((ULONGLONG)dw_b) * (ULONGLONG)dw_c); + if ((bc & 0xffffffff00000000LL) == 0) + { + // now sum them all up checking for overflow. + // shifting is safe because we already checked for overflow above + if (SUCCEEDED(ULongLongAdd(bc << 32, ad << 32, &ullResult))) + { + // b * d + bd = (((ULONGLONG)dw_b) * (ULONGLONG)dw_d); + + if (SUCCEEDED(ULongLongAdd(ullResult, bd, &ullResult))) + { + *pullResult = ullResult; + hr = S_OK; + } + } + } + } + } + } + + if (FAILED(hr)) + { + *pullResult = ULONGLONG_ERROR; + } +#endif // _AMD64_ + + return hr; +} + +// +// DWORDLONG multiplication +// +#define DWordLongMult ULongLongMult + +// +// ULONG64 multiplication +// +#define ULong64Mult ULongLongMult + +// +// DWORD64 multiplication +// +#define DWord64Mult ULongLongMult + +// +// UINT64 multiplication +// +#define UInt64Mult ULongLongMult + +// +// Macros that are no longer used in this header but which clients may +// depend on being defined here. +// +#define LOWORD(_dw) ((WORD)(((DWORD_PTR)(_dw)) & 0xffff)) +#define HIWORD(_dw) ((WORD)((((DWORD_PTR)(_dw)) >> 16) & 0xffff)) +#define LODWORD(_qw) ((DWORD)(_qw)) +#define HIDWORD(_qw) ((DWORD)(((_qw) >> 32) & 0xffffffff)) + +#endif // XPLAT_INTSAFE_H diff --git a/source/shared/localization.hpp b/source/shared/localization.hpp new file mode 100644 index 00000000..0c013a07 --- /dev/null +++ b/source/shared/localization.hpp @@ -0,0 +1,878 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: Localization.hpp +// +// Contents: Contains portable classes for localization +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef __LOCALIZATION_HPP__ +#define __LOCALIZATION_HPP__ + +#include +#include +#include "typedefs_for_linux.h" + +#ifdef MPLAT_UNIX +namespace std +{ + // Forward reference + class locale; +} +#endif + +#define CP_UTF8 65001 +#define CP_UTF16 1200 +#define CP_UTF32 12000 +#define CP_ACP 0 // default to ANSI code page + +// This class provides allocation policies for the SystemLocale and AutoArray classes. +// This is primarily needed for the self-allocating ToUtf16/FromUtf16 methods. +// SNI needs all its allocations to use its own allocator so it would create a separate +// class that obeys this interface and provide it as a template parameter. +template< typename ArrayT > +struct ArrayTAllocator +{ + static ArrayT * Alloc( size_t cch ) + { + return reinterpret_cast< ArrayT * >( malloc(cch*sizeof(ArrayT)) ); + } + // Realloc will free the 'old' memory if new memory was successfully allocated + // and copied to. + static ArrayT * Realloc( ArrayT * old, size_t cchNewSize ) + { + return reinterpret_cast< ArrayT * >( realloc(old, cchNewSize*sizeof(ArrayT)) ); + } + static void Free( ArrayT * mem ) + { + free( mem ); + } +}; + +// This is an auto_ptr-like class that is used with the SystemLocale. +// It allows for automatic freeing of the memory using the allocator policy. +// Callers would not normally use this class directly but would use one of the +// two specializations: AutoCharArray AutoWCharArray. +template< typename ArrayT, typename AllocT = ArrayTAllocator< ArrayT > > +struct AutoArray +{ + size_t m_cchSize; + ArrayT * m_ptr; + + AutoArray( const AutoArray & ); + AutoArray & operator=( const AutoArray & ); + + AutoArray() + : m_cchSize( 0 ), m_ptr( NULL ) + { + } + explicit AutoArray( size_t cchSize ) + : m_cchSize( cchSize ), m_ptr( AllocT::Alloc(cchSize) ) + { + } + virtual ~AutoArray() + { + Free(); + } + void Free() + { + if ( NULL != m_ptr ) + { + AllocT::Free( m_ptr ); + m_ptr = NULL; + m_cchSize = 0; + } + } + bool Realloc( size_t cchSize ) + { + ArrayT * newPtr = AllocT::Realloc( m_ptr, cchSize ); + if ( NULL != newPtr ) + { + // Safe to overwrite since Realloc freed m_ptr. + m_ptr = newPtr; + m_cchSize = cchSize; + return true; + } + return false; + } + ArrayT * Detach() + { + ArrayT * oldPtr = m_ptr; + m_ptr = NULL; + m_cchSize = 0; + return oldPtr; + } + void UpdateSize() + { + if ( NULL == m_ptr ) + { + m_cchSize = 0; + } + else + { + // XPLAT_ODBC_TODO VSTS 819733 MPlat: Reconcile std c++ usage between platforms + // Should use char_traits::length + ArrayT * end = m_ptr; + while ( (ArrayT)0 != *end++ ) + ; + // Want the null terminator included + m_cchSize = end - m_ptr; + } + } +}; + + +class SystemLocale +{ +public: + // ----------------------------------------------------------------------- + // Public Static Functions +#ifdef MPLAT_UNIX + static const SystemLocale & Singleton(); +#else + // Windows returns by value since this is an empty class + static const SystemLocale Singleton(); +#endif + +#ifdef MPLAT_UNIX + int GetResourcePath( char * buffer, size_t cchBuffer ) const; + + static const int MINS_PER_HOUR = 60; + static const int MINS_PER_DAY = 24 * MINS_PER_HOUR; + + // Returns the bias between the supplied utc and local times. + // utc = local + bias + static int BiasInMinutes( const struct tm & utc, const struct tm & local ) + { + int bias = 0; + if ( utc.tm_mon != local.tm_mon ) + { + // Offset crosses month boundary so one of two must be first day of month + if ( 1 == utc.tm_mday ) + bias += MINS_PER_DAY; + else + { + assert( 1 == local.tm_mday ); + bias -= MINS_PER_DAY; + } + } + else + { + bias += MINS_PER_DAY * (utc.tm_mday - local.tm_mday); + } + + bias += MINS_PER_HOUR * (utc.tm_hour - local.tm_hour); + bias += (utc.tm_min - local.tm_min); + + // Round based on diff in secs, in case utc/local straddle a day with leap seconds + int secs_diff = (utc.tm_sec - local.tm_sec); + if ( 29 < secs_diff ) + ++bias; + else if ( secs_diff < -29 ) + --bias; + + return bias; + } + + // Returns both standard and daylight savings biases for the current year + // utc = local + bias + // Both might be equal if DST is not honored + // If platform doesn't know if bias is DST or standard (ie. unknown) + // then standard time is assumed. + // Note that applying current year's biases to dates from other years may result + // in incorrect time adjustments since regions change their rules over time. + // The current SNAC driver code uses this approach as well so we are doing this + // to preserve consistent behavior. If SNAC changes to lookup the offsets that + // were effective for a given date then we should update our logic here as well. + static DWORD TimeZoneBiases( int * stdInMinutes, int * dstInMinutes ) + { + struct tm local, utc; + // Find current year + time_t now = time( NULL ); + if ( (time_t)(-1) == now || NULL == localtime_r(&now, &local) ) + return ERROR_INVALID_DATA; + + // Find bias for first of each month until both STD and DST are found + // Possible perf improvements (can wait until perf tests indicate a need): + // Just use Dec 21 and Jun 21 (near the two soltices) + // Or calc once and cache (must be thread safe) + bool foundUNK = false; + bool foundSTD = false; + bool foundDST = false; + int std_bias = 0; + int dst_bias = 0; + + local.tm_mday = 1; + for ( int mon = 0; mon < 12; ++mon ) + { + local.tm_mon = mon; + if ( (time_t)(-1) == (now = mktime(&local)) || NULL == gmtime_r(&now, &utc) ) + return ERROR_INVALID_DATA; + + if ( 0 < local.tm_isdst ) + { + if ( !foundDST ) + { + dst_bias = BiasInMinutes( utc, local ); + foundDST = true; + if ( foundSTD ) + break; // Done checking when both STD & DST are found + } + } + else + { + // Time is STD or unknown, put in STD + if ( !foundSTD ) + { + std_bias = BiasInMinutes( utc, local ); + if ( local.tm_isdst < 0 ) + foundUNK = true; + else + { + foundSTD = true; + if ( foundDST ) + break; // Done checking when both STD and DST are found + } + } + } + } + + // At least one of STD, DST, or unknown must have been set + assert( foundSTD || foundDST || foundUNK ); + + // For zones that don't observe DST (somewhat common), + // report DST bias as the same as STD + if ( !foundDST ) + dst_bias = std_bias; + + // For zones that ONLY observe DST (extremely rare if at all), + // report STD bias as the same as DST + if ( !foundSTD && !foundUNK ) + std_bias = dst_bias; + + *stdInMinutes = std_bias; + *dstInMinutes = dst_bias; + + return ERROR_SUCCESS; + } +#endif + + static DWORD CurrentLocalTime( LPSYSTEMTIME pTime ); + + // Multi-byte UTF8 code points start with '11xx xxxx' + static bool IsUtf8LeadByte( BYTE utf8 ) + { + return (0xC0 == (utf8 & 0xC0)); + } + + // Maximum number of storage units (char or WCHAR) + // for a code page (e.g. UTF16 == 2 for surrogates) + static UINT MaxCharCchSize( UINT codepage ); + + // Inspects the byte at start, and returns the start + // of the next code point (possibly multiple bytes later). + // If NULL or start points at null terminator, than start is returned. + // If start points at a dangling UTF8 trail byte, then (start+1) is + // returned since we can't know how large this code point is. + static char * NextChar( UINT codepage, const char * start ); +#ifdef MPLAT_UNIX + // This version is for non-null terminated strings. + // Last ptr will be one past end of buffer. + static char * NextChar( UINT codepage, const char * start, size_t cchBytesLeft ); +#endif + + // Given the start byte, how many total bytes are expected for + // this code point. If start is a UTF8 trail byte, then 1 is returned. + static UINT CchExpectedNextChar( UINT codepage, BYTE start ) + { + if ( 0 == (start & (char)0x80) ) + return 1; // ASCII + else if ( CP_UTF8 == codepage ) + return IsUtf8LeadByte(start) ? CchUtf8CodePt(start) : 1; + else if ( IsDBCSLeadByteEx(codepage, start) ) + return 2; + else + return 1; + } + + // Returns the number of bytes that need to be trimmed to avoid splitting + // a multi-byte code point sequence at the end of the buffer. + // Returns zero if a trailing UTF8 code value is found but no + // matching lead byte was found for it (ie. invalid, dangling trail byte). + _Ret_range_(0, cchBuffer) static UINT TrimPartialCodePt( UINT codepage, _In_count_(cchBuffer) const BYTE * buffer, size_t cchBuffer ) + { + if ( 0 == cchBuffer ) + return 0; + + if ( CP_UTF8 == codepage ) + { + return TrimPartialUtf8CodePt( buffer, cchBuffer ); + } + else + { + size_t i = cchBuffer; + for ( ; 0 < i; --i ) + { + if ( !IsDBCSLeadByteEx( codepage, buffer[i-1] ) ) + break; + } + // If odd, then last byte is truly a lead byte so return 1 byte to trim + return ((cchBuffer-i) & 1) ? 1 : 0; + } + } + + // For all transcoding functions + // Returns zero on error. Do not call GetLastError() since that is not portable (pErrorCode has result of GetLastError()). + // pHasDataLoss will be true if an unrecognized code point was encountered in the source and a default output instead. + // Replaces calls to MultiByteToWideChar and WideCharToMultiByte + + // Transcode between a code page and UTF16 + static size_t ToUtf16( UINT srcCodePage, const char * src, SSIZE_T cchSrc, + __out_ecount_opt(cchDest) WCHAR * dest, size_t cchDest, + DWORD * pErrorCode = NULL ); + static size_t ToUtf16Strict( UINT srcCodePage, const char * src, SSIZE_T cchSrc, + __out_ecount_opt(cchDest) WCHAR * dest, size_t cchDest, + DWORD * pErrorCode = NULL ); + static size_t FromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, + __out_ecount_opt(cchDest) char * dest, size_t cchDest, + bool * pHasDataLoss = NULL, DWORD * pErrorCode = NULL ); + static size_t FromUtf16Strict(UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, + __out_ecount_opt(cchDest) char * dest, size_t cchDest, + bool * pHasDataLoss = NULL, DWORD * pErrorCode = NULL); + // Allocates destination buffer to match required size + // Template is used so call can provide allocation policy + // Used instead of the Windows API pattern of calling with zero dest buffer size to find + // required buffer size, followed by second call with newly allocated buffer. + template< typename AllocT > + static size_t ToUtf16( UINT srcCodePage, const char * src, SSIZE_T cchSrc, __deref_out_ecount(1) WCHAR ** dest, DWORD * pErrorCode = NULL ); + template< typename AllocT > + static size_t ToUtf16Strict( UINT srcCodePage, const char * src, SSIZE_T cchSrc, __deref_out_ecount(1) WCHAR ** dest, DWORD * pErrorCode = NULL ); + template< typename AllocT > + static size_t FromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, __deref_out_ecount(1) char ** dest, bool * pHasDataLoss = NULL, DWORD * pErrorCode = NULL ); + template< typename AllocT > + static size_t FromUtf16Strict(UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, __deref_out_ecount(1) char ** dest, bool * pHasDataLoss = NULL, DWORD * pErrorCode = NULL); + + + + // ----------------------------------------------------------------------- + // Public Member Functions + +#ifndef TIME_ZONE_ID_UNKNOWN + #define TIME_ZONE_ID_UNKNOWN 0 + #define TIME_ZONE_ID_STANDARD 1 + #define TIME_ZONE_ID_DAYLIGHT 2 +#endif + // pTZInfo, if supplied, holds one of the above defined values + DWORD CurrentTimeZoneBias( LONG * offsetInMinutes, DWORD * pTZInfo = NULL ) const; + + // The Ansi code page, always UTF8 for Linux + UINT AnsiCP() const; + // Used for files (e.g. returns 437 on US Windows, UTF8 for Linux) + UINT OemCP() const; + // Returns UTF-16LE for all platforms (LE == Little Endian) + UINT WideCP() const + { + return CP_UTF16; + } + + // Performs case folding to lower case using the current system locale + // Replaces calls to LCMapStringA + size_t ToLower( const char * src, SSIZE_T cchSrc, __out_ecount_opt(cchDest) char * dest, size_t cchDest, DWORD * pErrorCode = NULL ) const; + +#ifndef CSTR_ERROR + #define CSTR_ERROR 0 // compare failed + #define CSTR_LESS_THAN 1 // string 1 less than string 2 + #define CSTR_EQUAL 2 // string 1 equal to string 2 + #define CSTR_GREATER_THAN 3 // string 1 greater than string 2 +#endif + // String comparison using the rules of the current system locale. + // Replaces calls to CompareString + // Ignoring width (Bing for "Full Width Characters") has no affect on Linux + // Return value is one of the above defined values. + // On error, pErrorCode has result of GetLastError() (do not call GetLastError directly since it isn't portable). + int Compare( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode = NULL ) const; + int CompareIgnoreCase( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode = NULL ) const; + int CompareIgnoreWidth( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode = NULL ) const; + int CompareIgnoreCaseAndWidth( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode = NULL ) const; + + + + +private: + // Prevent copying. + // Also prevents misuse of return from Singleton() method. + // Since return types are different on Windows vs Linux, + // callers should not cache the result of Singleton(). + SystemLocale( const SystemLocale & ); + SystemLocale & operator=( const SystemLocale & ); + +#ifdef MPLAT_UNIX +// MPLAT_UNIX ---------------------------------------------------------------- + + std::locale * m_pLocale; + + explicit SystemLocale( const char * localeName ); + ~SystemLocale(); + + static UINT ExpandSpecialCP( UINT codepage ) + { + // Convert CP_ACP, CP_OEM to CP_UTF8 + return (codepage < 2 ? CP_UTF8 : codepage); + } + +// MPLAT_UNIX ---------------------------------------------------------------- +#else +// !MPLAT_UNIX --------------------------------------------------------------- + + SystemLocale() {} + + static size_t ReturnCchResult( SSIZE_T cch, DWORD * pErrorCode ) + { + if ( cch < 0 ) + { + cch = 0; + } + if ( NULL != pErrorCode ) + { + *pErrorCode = (0 == cch ? GetLastError() : ERROR_SUCCESS); + } + return static_cast(cch); + } + + static int CompareWithFlags( DWORD flags, const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode = NULL ); + + static size_t FastAsciiMultiByteToWideChar + ( + UINT CodePage, + __in_ecount(cch) const char *pch, // IN | source string + SSIZE_T cch, // IN | count of characters or -1 + __out_ecount_opt(cwch) PWCHAR pwch, // IN | Result string + size_t cwch, // IN | count of wchars of result buffer or 0 + DWORD* pErrorCode, // OUT | optional pointer to return error code + bool bStrict = false // IN | Return error if invalid chars in src + ); + static size_t FastAsciiWideCharToMultiByte + ( + UINT CodePage, + const WCHAR *pwch, // IN | source string + SSIZE_T cwch, // IN | count of characters or -1 + __out_bcount(cch) char *pch, // IN | Result string + size_t cch, // IN | Length of result buffer or 0 + BOOL *pfDataLoss, // OUT | True if there was data loss during CP conversion + DWORD *pErrorCode // OUT | optional pointer to return error code + ); + +// !MPLAT_UNIX --------------------------------------------------------------- +#endif + + // Returns the number of bytes this UTF8 code point expects + static UINT CchUtf8CodePt( BYTE codept ) + { + assert( IsUtf8LeadByte(codept) ); + + // Initial byte of utf8 sequence indicates its length + // 110x xxxx = 2 bytes + // 1110 xxxx = 3 bytes + // 1111 0xxx = 4 bytes + // 1111 10xx = 5 bytes, future Unicode extension not covered by this logic + // 1111 110x = 6 bytes, future Unicode extension not covered by this logic + UINT expected_size = (0xC0 == (codept & 0xE0)) ? 2 : (0xE0 == (codept & 0xF0)) ? 3 : 4; + + // Verify constraints + assert( 4 == MaxCharCchSize(CP_UTF8) ); + + return expected_size; + } + + // Returns the number of bytes that need to be trimmed to avoid splitting + // a UTF8 code point sequence at the end of the buffer. + // Returns zero for ASCII. + // Also returns zero if a trailing UTF8 code value is found but no + // matching lead byte was found for it (ie. invalid, dangling trail byte). + static UINT TrimPartialUtf8CodePt( const BYTE * buffer, size_t cchBuffer ) + { + if ( 0 == cchBuffer ) + return 0; + + if ( 0 == (buffer[cchBuffer-1] & 0x80) ) + { + // Last char is ASCII so no trim needed + return 0; + } + + // Last char is non-initial byte of multibyte utf8 sequence + // Need to determine if it is the last (ie. no trim need) + UINT cchMax = MaxCharCchSize( CP_UTF8 ); + for ( UINT i = 1; 0 < cchBuffer && i <= cchMax; --cchBuffer, ++i ) + { + if ( IsUtf8LeadByte(buffer[cchBuffer-1]) ) + { + // Found initial byte, verify size of sequence + UINT cchExpected = CchUtf8CodePt( buffer[cchBuffer-1] ); + if ( i == cchExpected ) + return 0; // utf8 sequence is complete so no trim needed + else + { + assert( i <= cchBuffer ); + return i; // trim the incomplete sequence + } + } + } + + // Did not find initial utf8 byte so trim nothing + return 0; + } +}; + + + +// Convenience wrapper for converting from UTF16 into a newly +// allocated char[]. Class behaves like auto_ptr (will free in dtor, +// but has Release method so caller can take ownership of memory). +template< typename AllocT = ArrayTAllocator< char > > +struct AutoCharArray : public AutoArray< char, AllocT > +{ + size_t AllocConvertFromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, bool * pHasDataLoss = NULL, DWORD * pErrorCode = NULL ) + { + char * converted = NULL; + size_t cchCvt = SystemLocale::FromUtf16< AllocT >( destCodePage, src, cchSrc, &converted, pHasDataLoss, pErrorCode ); + if ( 0 < cchCvt ) + { + this->Free(); + this->m_ptr = converted; + this->m_cchSize = cchCvt; + } + return cchCvt; + } +}; + +// Convenience wrapper for converting to UTF16 into a newly +// allocated WCHAR[]. Class behaves like auto_ptr (will free in dtor, +// but has Release method so caller can take ownership of memory). +template< typename AllocT = ArrayTAllocator< WCHAR > > +struct AutoWCharArray : public AutoArray< WCHAR, AllocT > +{ + size_t AllocConvertToUtf16( UINT destCodePage, const char * src, SSIZE_T cchSrc, bool * pHasDataLoss = NULL, DWORD * pErrorCode = NULL ) + { + WCHAR * converted = NULL; + size_t cchCvt = SystemLocale::ToUtf16< AllocT >( destCodePage, src, cchSrc, &converted, pErrorCode ); + if ( 0 < cchCvt ) + { + this->Free(); + this->m_ptr = converted; + this->m_cchSize = cchCvt; + } + return cchCvt; + } +}; + + + +// --------------------------------------------------------------------------- +// Inlines that vary by platform + +#if defined(MPLAT_UNIX) +// MPLAT_UNIX ---------------------------------------------------------------- + +#include "globalization.h" + +inline UINT SystemLocale::AnsiCP() const +{ + return CP_UTF8; +} + +inline UINT SystemLocale::OemCP() const +{ + return CP_UTF8; +} + +inline UINT SystemLocale::MaxCharCchSize( UINT codepage ) +{ + codepage = ExpandSpecialCP( codepage ); + switch ( codepage ) + { + case CP_UTF8: + return 4; + case 932: + case 936: + case 949: + case 950: + case CP_UTF16: + return 2; + default: + return 1; + } +} + +inline int SystemLocale::CompareIgnoreWidth( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) const +{ + // XPLAT_ODBC_TODO: VSTS 806013 MPLAT: Support IgnoreWidth for SNI string comparisons + return Compare( left, cchLeft, right, cchRight, pErrorCode ); +} + +inline int SystemLocale::CompareIgnoreCaseAndWidth( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) const +{ + // XPLAT_ODBC_TODO: VSTS 806013 MPLAT: Support IgnoreWidth for SNI string comparisons + return CompareIgnoreCase( left, cchLeft, right, cchRight, pErrorCode ); +} + +template< typename AllocT > +inline size_t SystemLocale::ToUtf16( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR ** dest, DWORD * pErrorCode ) +{ + srcCodePage = ExpandSpecialCP( srcCodePage ); + EncodingConverter cvt( CP_UTF16, srcCodePage ); + if ( !cvt.Initialize() ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + size_t cchSrcActual = (cchSrc < 0 ? (1+strlen(src)) : cchSrc); + bool hasLoss; + return cvt.Convert< WCHAR, char, AllocT >( dest, src, cchSrcActual, false, &hasLoss, pErrorCode ); +} + +template< typename AllocT > +inline size_t SystemLocale::ToUtf16Strict( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR ** dest, DWORD * pErrorCode ) +{ + srcCodePage = ExpandSpecialCP( srcCodePage ); + EncodingConverter cvt( CP_UTF16, srcCodePage ); + if ( !cvt.Initialize() ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + size_t cchSrcActual = (cchSrc < 0 ? (1+strlen(src)) : cchSrc); + bool hasLoss; + return cvt.Convert< WCHAR, char, AllocT >( dest, src, cchSrcActual, true, &hasLoss, pErrorCode ); +} + +template< typename AllocT > +inline size_t SystemLocale::FromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, char ** dest, bool * pHasDataLoss, DWORD * pErrorCode ) +{ + destCodePage = ExpandSpecialCP( destCodePage ); + EncodingConverter cvt( destCodePage, CP_UTF16 ); + if ( !cvt.Initialize() ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + size_t cchSrcActual = (cchSrc < 0 ? (1+mplat_wcslen(src)) : cchSrc); + bool hasLoss; + return cvt.Convert< char, WCHAR, AllocT >( dest, src, cchSrcActual, false, &hasLoss, pErrorCode ); +} + + +// MPLAT_UNIX ---------------------------------------------------------------- +#else +// ! MPLAT_UNIX ---------------------------------------------------------------- + + +inline const SystemLocale SystemLocale::Singleton() +{ + // On Windows, Localization is an empty class so creation of this + // should be optimized away. Empty classes have a sizeof 1 so there's + // something to take the address of. + C_ASSERT( 1 == sizeof(SystemLocale) ); + return SystemLocale(); +} + +inline DWORD SystemLocale::CurrentTimeZoneBias( LONG * offsetInMinutes, DWORD * pTZInfo ) const +{ + TIME_ZONE_INFORMATION tzi; + DWORD tzInfo; + if ( NULL == offsetInMinutes ) + return ERROR_INVALID_PARAMETER; + else if ( TIME_ZONE_ID_INVALID == (tzInfo = GetTimeZoneInformation(&tzi)) ) + return GetLastError(); + else + { + *offsetInMinutes = tzi.Bias; + if ( NULL != pTZInfo ) + *pTZInfo = tzInfo; + + return ERROR_SUCCESS; + } +} + +inline DWORD SystemLocale::CurrentLocalTime( LPSYSTEMTIME pTime ) +{ + GetLocalTime( pTime ); + return ERROR_SUCCESS; +} + +inline UINT SystemLocale::AnsiCP() const +{ + return GetACP(); +} + +inline UINT SystemLocale::OemCP() const +{ + return GetOEMCP(); +} + +inline UINT SystemLocale::MaxCharCchSize( UINT codepage ) +{ + CPINFO cpinfo; + BOOL rc = GetCPInfo( codepage, &cpinfo ); + return (rc ? cpinfo.MaxCharSize : 0); +} + +inline size_t SystemLocale::ToLower( const char * src, SSIZE_T cchSrc, char * dest, size_t cchDest, DWORD * pErrorCode ) const +{ + // Windows API takes 'int' sized parameters + if ( cchSrc < -1 || 0x7FFFFFF < cchSrc || 0x7FFFFFF < cchDest ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + + return 0; + } + +OACR_WARNING_PUSH +OACR_WARNING_DISABLE(SYSTEM_LOCALE_MISUSE , " INTERNATIONALIZATION BASELINE AT KATMAI RTM. FUTURE ANALYSIS INTENDED. ") +OACR_WARNING_DISABLE(ANSI_APICALL, " Keeping the ANSI API for now. ") + int cch = LCMapStringA( + LOCALE_SYSTEM_DEFAULT, + LCMAP_LOWERCASE, + src, + (int)cchSrc, + dest, + (int)cchDest ); +OACR_WARNING_POP + + return ReturnCchResult( cch, pErrorCode ); +} + +inline int SystemLocale::CompareWithFlags( DWORD flags, const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) +{ + // Windows API takes 'int' sized parameters + if ( cchLeft < -1 || 0x7FFFFFF < cchLeft || cchRight < -1 || 0x7FFFFFF < cchRight ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + + return 0; + } + +OACR_WARNING_PUSH +OACR_WARNING_DISABLE(SYSTEM_LOCALE_MISUSE , " INTERNATIONALIZATION BASELINE AT KATMAI RTM. FUTURE ANALYSIS INTENDED. ") + int cmp = CompareStringA( LOCALE_SYSTEM_DEFAULT, flags, left, (int)cchLeft, right, (int)cchRight ); +OACR_WARNING_POP + if ( NULL != pErrorCode ) + { + *pErrorCode = (CSTR_ERROR == cmp ? GetLastError() : ERROR_SUCCESS); + } + return cmp; +} + +inline int SystemLocale::Compare( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) const +{ + return CompareWithFlags( 0, left, cchLeft, right, cchRight, pErrorCode ); +} + +inline int SystemLocale::CompareIgnoreCase( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) const +{ + return CompareWithFlags( NORM_IGNORECASE, left, cchLeft, right, cchRight, pErrorCode ); +} + +inline int SystemLocale::CompareIgnoreCaseAndWidth( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) const +{ + return CompareWithFlags( NORM_IGNORECASE|NORM_IGNOREWIDTH, left, cchLeft, right, cchRight, pErrorCode ); +} + +inline int SystemLocale::CompareIgnoreWidth( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) const +{ + return CompareWithFlags( NORM_IGNOREWIDTH, left, cchLeft, right, cchRight, pErrorCode ); +} + +inline char * SystemLocale::NextChar( UINT codepage, const char * start ) +{ + return CharNextExA( (WORD)codepage, start, 0 ); +} + +inline size_t SystemLocale::ToUtf16( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR * dest, size_t cchDest, DWORD * pErrorCode ) +{ + return FastAsciiMultiByteToWideChar( srcCodePage, src, cchSrc, dest, cchDest, pErrorCode ); +} + +inline size_t SystemLocale::ToUtf16Strict( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR * dest, size_t cchDest, DWORD * pErrorCode ) +{ + return FastAsciiMultiByteToWideChar( srcCodePage, src, cchSrc, dest, cchDest, pErrorCode, true ); +} + +inline size_t SystemLocale::FromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, char * dest, size_t cchDest, bool * pHasDataLoss, DWORD * pErrorCode ) +{ + BOOL dataloss = FALSE; + size_t cchCvt = FastAsciiWideCharToMultiByte( destCodePage, src, cchSrc, dest, cchDest, &dataloss, pErrorCode ); + if ( NULL != pHasDataLoss ) + { + *pHasDataLoss = (FALSE != dataloss); + } + return cchCvt; +} + +template< typename AllocT > +inline size_t SystemLocale::ToUtf16( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR ** dest, DWORD * pErrorCode ) +{ + size_t cchCvt = FastAsciiMultiByteToWideChar( srcCodePage, src, cchSrc, NULL, 0, pErrorCode ); + if ( 0 < cchCvt ) + { + AutoArray< WCHAR, AllocT > newDestBuffer( cchCvt ); + cchCvt = FastAsciiMultiByteToWideChar( srcCodePage, src, cchSrc, newDestBuffer.m_ptr, cchCvt, pErrorCode ); + if ( 0 < cchCvt ) + *dest = newDestBuffer.Detach(); + } + return cchCvt; +} + +template< typename AllocT > +inline size_t SystemLocale::ToUtf16Strict( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR ** dest, DWORD * pErrorCode ) +{ + size_t cchCvt = FastAsciiMultiByteToWideChar( srcCodePage, src, cchSrc, NULL, 0, pErrorCode, true ); + if ( 0 < cchCvt ) + { + AutoArray< WCHAR, AllocT > newDestBuffer( cchCvt ); + cchCvt = FastAsciiMultiByteToWideChar( srcCodePage, src, cchSrc, newDestBuffer.m_ptr, cchCvt, pErrorCode, true ); + if ( 0 < cchCvt ) + *dest = newDestBuffer.Detach(); + } + return cchCvt; +} + +template< typename AllocT > +inline size_t SystemLocale::FromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, char ** dest, bool * pHasDataLoss, DWORD * pErrorCode ) +{ + BOOL dataloss = FALSE; + size_t cchCvt = FastAsciiWideCharToMultiByte( destCodePage, src, cchSrc, NULL, 0, &dataloss, pErrorCode ); + if ( 0 < cchCvt ) + { + AutoArray< char, AllocT > newDestBuffer( cchCvt ); + cchCvt = FastAsciiWideCharToMultiByte( destCodePage, src, cchSrc, newDestBuffer.m_ptr, cchCvt, &dataloss, pErrorCode ); + if ( 0 < cchCvt ) + *dest = newDestBuffer.Detach(); + } + if ( NULL != pHasDataLoss ) + { + *pHasDataLoss = (FALSE != dataloss); + } + return cchCvt; +} + +// ! MPLAT_UNIX ---------------------------------------------------------------- +#endif + +#endif // __LOCALIZATION_HPP__ diff --git a/source/shared/localizationimpl.cpp b/source/shared/localizationimpl.cpp new file mode 100644 index 00000000..f33a0d00 --- /dev/null +++ b/source/shared/localizationimpl.cpp @@ -0,0 +1,1039 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: LocalizationImpl.hpp +// +// Contents: Contains non-inline code for the SystemLocale class +// Must be included in one c/cpp file per binary +// A build error will occur if this inclusion policy is not followed +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#include "localization.hpp" + +#include "globalization.h" +#include "StringFunctions.h" + +struct cp_iconv +{ + UINT CodePage; + const char * IConvEncoding; + + static const cp_iconv g_cp_iconv[]; + static const size_t g_cp_iconv_count; + + static int GetIndex( UINT codepage ) + { + for ( size_t idx = 0; idx < g_cp_iconv_count; ++idx ) + { + if ( g_cp_iconv[idx].CodePage == codepage ) + return (int)idx; + } + // Should never be an unknown code page + assert( false ); + return -1; + } +}; + +// Array of CodePage-to-IConvEncoding mappings +// First few elements are most commonly used +const cp_iconv cp_iconv::g_cp_iconv[] = { + { 65001, "UTF-8" }, + { 1200, "UTF-16LE" }, + { 3, "UTF-8" }, + { 1252, "CP1252//TRANSLIT" }, + { 850, "CP850//TRANSLIT" }, + { 437, "CP437//TRANSLIT" }, + { 874, "CP874//TRANSLIT" }, + { 932, "CP932//TRANSLIT" }, + { 936, "CP936//TRANSLIT" }, + { 949, "CP949//TRANSLIT" }, + { 950, "CP950//TRANSLIT" }, + { 1250, "CP1250//TRANSLIT" }, + { 1251, "CP1251//TRANSLIT" }, + { 1253, "CP1253//TRANSLIT" }, + { 1254, "CP1254//TRANSLIT" }, + { 1255, "CP1255//TRANSLIT" }, + { 1256, "CP1256//TRANSLIT" }, + { 1257, "CP1257//TRANSLIT" }, + { 1258, "CP1258//TRANSLIT" }, + { 12000, "UTF-32LE" } +}; +const size_t cp_iconv::g_cp_iconv_count = ARRAYSIZE(cp_iconv::g_cp_iconv); + +#ifdef MPLAT_UNIX + +class IConvCachePool +{ + SLIST_HEADER m_Pool[cp_iconv::g_cp_iconv_count][cp_iconv::g_cp_iconv_count]; + + IConvCachePool( const IConvCachePool & ); + IConvCachePool & operator=( const IConvCachePool & ); + + // This bool indicates that the iconv pool is no longer available. + // For the driver,lis flag indicates the pool can no longer be used. + // Global destructors will be called by a single thread so this flag does not + // need thread synch protection. + static bool s_PoolDestroyed; + + IConvCachePool() + { + for ( int dstIdx = 0; dstIdx < cp_iconv::g_cp_iconv_count; ++dstIdx ) + { + for ( int srcIdx = 0; srcIdx < cp_iconv::g_cp_iconv_count; ++srcIdx ) + { + InitializeSListHead( &m_Pool[dstIdx][srcIdx] ); + } + } + } + + ~IConvCachePool() + { + IConvCachePool::s_PoolDestroyed = true; + + // Clean up remaining nodes + for ( int dstIdx = 0; dstIdx < cp_iconv::g_cp_iconv_count; ++dstIdx ) + { + for ( int srcIdx = 0; srcIdx < cp_iconv::g_cp_iconv_count; ++srcIdx ) + { + IConvCache * pNode = static_cast( InterlockedFlushSList(&m_Pool[dstIdx][srcIdx]) ); + while ( NULL != pNode ) + { + IConvCache * pNext = static_cast( pNode->Next ); + delete pNode; + pNode = pNext; + } + } + } + } + + USHORT Depth( int dstIdx, int srcIdx ) + { + assert( 0 <= dstIdx && dstIdx < cp_iconv::g_cp_iconv_count ); + assert( 0 <= srcIdx && srcIdx < cp_iconv::g_cp_iconv_count ); + return QueryDepthSList( &m_Pool[dstIdx][srcIdx] ); + } + + // If this returns NULL, then caller must allocate their own iconv_t. + // It will return NULL if allocation for a new instance failed (out of memory). + const IConvCache * Borrow( int dstIdx, int srcIdx ) + { + assert( 0 <= dstIdx && dstIdx < cp_iconv::g_cp_iconv_count ); + assert( 0 <= srcIdx && srcIdx < cp_iconv::g_cp_iconv_count ); + + const IConvCache * pCache = static_cast( InterlockedPopEntrySList(&m_Pool[dstIdx][srcIdx]) ); + if ( NULL == pCache ) + { + const IConvCache * pNewCache = new IConvCache( dstIdx, srcIdx ); + if ( NULL != pNewCache ) + { + if ( INVALID_ICONV != pNewCache->GetIConv() ) + pCache = pNewCache; + else + delete pNewCache; + } + } + return pCache; + } + + void Return( const IConvCache * pCache, int dstIdx, int srcIdx ) + { + assert( pCache ); + assert( 0 <= dstIdx && dstIdx < cp_iconv::g_cp_iconv_count ); + assert( 0 <= srcIdx && srcIdx < cp_iconv::g_cp_iconv_count ); + + // Setting an arbitrary limit to prevent unbounded memory use by the pool. + // Want this to be large enough for a substantial number of concurrent threads. + const USHORT MAX_POOL_SIZE = 1024; + + if ( INVALID_ICONV != pCache->GetIConv() && Depth(dstIdx, srcIdx) < MAX_POOL_SIZE ) + { + SLIST_ENTRY * pNode = const_cast( pCache ); + InterlockedPushEntrySList( &m_Pool[dstIdx][srcIdx], pNode ); + } + else + { + delete pCache; + } + } + + static IConvCachePool & Singleton() + { + // GCC ensures that function scoped static initializers are threadsafe + // We must not use the -fno-threadsafe-statics compiler option +#if !defined(__GNUC__) || defined(NO_THREADSAFE_STATICS) + #error "Relying on GCC's threadsafe initialization of local statics." +#endif + static IConvCachePool s_Pool; + return s_Pool; + } + +public: + static const IConvCache * BorrowCache( UINT dstCP, UINT srcCP ) + { + int dstIdx = cp_iconv::GetIndex(dstCP); + int srcIdx = cp_iconv::GetIndex(srcCP); + + if ( -1 == dstIdx || -1 == srcIdx ) + return NULL; + else if ( !s_PoolDestroyed ) + return Singleton().Borrow( dstIdx, srcIdx ); + else + return new IConvCache( dstIdx, srcIdx ); + } + + static void ReturnCache( const IConvCache * pCache, UINT dstCP, UINT srcCP ) + { + int dstIdx = cp_iconv::GetIndex(dstCP); + int srcIdx = cp_iconv::GetIndex(srcCP); + + if ( -1 != dstIdx && -1 != srcIdx && !s_PoolDestroyed ) + Singleton().Return( pCache, dstIdx, srcIdx ); + else + delete pCache; + } + + static USHORT Depth( UINT dstCP, UINT srcCP ) + { + if ( IConvCachePool::s_PoolDestroyed ) + return 0; + else + { + int dstIdx = cp_iconv::GetIndex(dstCP); + int srcIdx = cp_iconv::GetIndex(srcCP); + + if ( -1 == dstIdx || -1 == srcIdx ) + return 0; + else + return Singleton().Depth( dstIdx, srcIdx ); + } + } +}; + + +bool IConvCachePool::s_PoolDestroyed = false; + +#ifdef DEBUG +// This is only used by unit tests. +// Product code should directly use IConvCachePool::Depth from +// within this translation unit. +USHORT GetIConvCachePoolDepth( UINT dstCP, UINT srcCP ) +{ + return IConvCachePool::Depth( dstCP, srcCP ); +} +#endif // DEBUG + +IConvCache::IConvCache( int dstIdx, int srcIdx ) + : m_iconv( iconv_open( + cp_iconv::g_cp_iconv[dstIdx].IConvEncoding, + cp_iconv::g_cp_iconv[srcIdx].IConvEncoding) ) +{ +} + +IConvCache::~IConvCache() +{ + if ( INVALID_ICONV != m_iconv ) + iconv_close( m_iconv ); +} + +#endif // MPLAT_UNIX + +EncodingConverter::EncodingConverter( UINT dstCodePage, UINT srcCodePage ) + : m_dstCodePage( dstCodePage ), + m_srcCodePage( srcCodePage ) +#ifdef MPLAT_UNIX + , m_pCvtCache( NULL ) +#endif +{ +} + +EncodingConverter::~EncodingConverter() +{ +#ifdef MPLAT_UNIX + if ( NULL != m_pCvtCache ) + { + IConvCachePool::ReturnCache( m_pCvtCache, m_dstCodePage, m_srcCodePage ); + } +#endif +} + +bool EncodingConverter::Initialize() +{ +#if defined(MPLAT_UNIX) + if ( !IsValidIConv() ) + { + m_pCvtCache = IConvCachePool::BorrowCache( m_dstCodePage, m_srcCodePage ); + } + return IsValidIConv(); +#elif defined(MPLAT_WWOWH) + return true; +#endif +} + +//#endif + +#ifdef MPLAT_UNIX +// MPLAT_UNIX ---------------------------------------------------------------- +#include + +using namespace std; + + + +SystemLocale::SystemLocale( const char * localeName ) + : m_pLocale( new std::locale(localeName) ) +{ +} + +SystemLocale::~SystemLocale() +{ + delete m_pLocale; +} + +const SystemLocale & SystemLocale::Singleton() +{ + // GCC ensures that function scoped static initializers are threadsafe + // We must not use the -fno-threadsafe-statics compiler option +#if !defined(__GNUC__) || defined(NO_THREADSAFE_STATICS) + #error "Relying on GCC's threadsafe initialization of local statics." +#endif + static const SystemLocale s_Default( "en_US.utf8" ); + return s_Default; +} + +int SystemLocale::GetResourcePath( char * buffer, size_t cchBuffer ) const +{ + // XPLAT_ODBC_TODO: VSTS 718708 Localization + // Also need to use AdjustLCID logic when handling more locales + return snprintf( buffer, cchBuffer, "/opt/microsoft/msodbcsql/share/resources/en_US/"); +} + +DWORD SystemLocale::CurrentTimeZoneBias( LONG * offsetInMinutes, DWORD * tzinfo ) const +{ + if ( NULL == offsetInMinutes ) + return ERROR_INVALID_PARAMETER; + + time_t now = time( NULL ); + if ( (time_t)(-1) == now ) + return ERROR_NOT_SUPPORTED; + + struct tm utc, local; + if ( NULL == gmtime_r(&now, &utc) || NULL == localtime_r(&now, &local) ) + return ERROR_INVALID_DATA; + + *offsetInMinutes = BiasInMinutes( utc, local ); + + if ( NULL != tzinfo ) + { + *tzinfo = (0 == local.tm_isdst ? TIME_ZONE_ID_STANDARD : (0 < local.tm_isdst ? TIME_ZONE_ID_DAYLIGHT : TIME_ZONE_ID_UNKNOWN)); + } + + return ERROR_SUCCESS; +} + +DWORD SystemLocale::CurrentLocalTime( LPSYSTEMTIME pTime ) +{ + if ( NULL == pTime ) + return ERROR_INVALID_PARAMETER; + + memset( pTime, 0, sizeof(SYSTEMTIME) ); + + time_t now = time( NULL ); + if ( (time_t)(-1) == now ) + return ERROR_NOT_SUPPORTED; + + struct tm local; + if ( NULL == localtime_r(&now, &local) ) + return ERROR_INVALID_DATA; + + pTime->wYear = local.tm_year + 1900; + pTime->wMonth = local.tm_mon + 1; + pTime->wDay = local.tm_mday; + pTime->wHour = local.tm_hour; + pTime->wMinute = local.tm_min; + pTime->wSecond = local.tm_sec; + pTime->wMilliseconds = 0; + pTime->wDayOfWeek = local.tm_wday; + + return ERROR_SUCCESS; +} + +size_t SystemLocale::ToUtf16( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR * dest, size_t cchDest, DWORD * pErrorCode ) +{ + srcCodePage = ExpandSpecialCP( srcCodePage ); + EncodingConverter cvt( CP_UTF16, srcCodePage ); + if ( !cvt.Initialize() ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + size_t cchSrcActual = (cchSrc < 0 ? (1+strlen(src)) : cchSrc); + bool hasLoss; + return cvt.Convert( dest, cchDest, src, cchSrcActual, false, &hasLoss, pErrorCode ); +} + +size_t SystemLocale::ToUtf16Strict( UINT srcCodePage, const char * src, SSIZE_T cchSrc, WCHAR * dest, size_t cchDest, DWORD * pErrorCode ) +{ + srcCodePage = ExpandSpecialCP( srcCodePage ); + EncodingConverter cvt( CP_UTF16, srcCodePage ); + if ( !cvt.Initialize() ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + size_t cchSrcActual = (cchSrc < 0 ? (1+strlen(src)) : cchSrc); + bool hasLoss; + return cvt.Convert( dest, cchDest, src, cchSrcActual, true, &hasLoss, pErrorCode ); +} + +size_t SystemLocale::FromUtf16( UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, char * dest, size_t cchDest, bool * pHasDataLoss, DWORD * pErrorCode ) +{ + destCodePage = ExpandSpecialCP( destCodePage ); + EncodingConverter cvt( destCodePage, CP_UTF16 ); + if ( !cvt.Initialize() ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + size_t cchSrcActual = (cchSrc < 0 ? (1+mplat_wcslen(src)) : cchSrc); + bool hasLoss; + return cvt.Convert( dest, cchDest, src, cchSrcActual, false, &hasLoss, pErrorCode ); +} + +size_t SystemLocale::FromUtf16Strict(UINT destCodePage, const WCHAR * src, SSIZE_T cchSrc, char * dest, size_t cchDest, bool * pHasDataLoss, DWORD * pErrorCode) +{ + destCodePage = ExpandSpecialCP(destCodePage); + EncodingConverter cvt(destCodePage, CP_UTF16); + if (!cvt.Initialize()) + { + if (NULL != pErrorCode) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + size_t cchSrcActual = (cchSrc < 0 ? (1 + mplat_wcslen(src)) : cchSrc); + bool hasLoss; + return cvt.Convert(dest, cchDest, src, cchSrcActual, true, &hasLoss, pErrorCode); +} + +size_t SystemLocale::ToLower( const char * src, SSIZE_T cchSrc, char * dest, size_t cchDest, DWORD * pErrorCode ) const +{ + size_t cchSrcActual = (cchSrc < 0 ? (1+strlen(src)) : cchSrc); + if ( 0 == cchSrcActual ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return 0; + } + if ( 0 == cchDest ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return cchSrcActual; + } + else if ( cchDest < cchSrcActual ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INSUFFICIENT_BUFFER; + return 0; + } + memcpy_s( dest, cchSrcActual, src, cchSrcActual ); + + use_facet< ctype< char > >(*m_pLocale).tolower( dest, dest+cchSrcActual ); + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return cchSrcActual; +} + +int SystemLocale::Compare( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) const +{ + if ( NULL == left || NULL == right || 0 == cchLeft || 0 == cchRight ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return CSTR_ERROR; + } + + size_t cchLeftActual = (cchLeft < 0 ? strlen(left) : cchLeft); + size_t cchRightActual = (cchRight < 0 ? strlen(right) : cchRight); + + int cmp = strncmp( left, right, min(cchLeftActual, cchRightActual) ); + if ( 0 == cmp ) + { + if ( cchLeftActual < cchRightActual ) + cmp = -1; + else if ( cchLeftActual > cchRightActual ) + cmp = 1; + } + else if ( cmp < 0 ) + cmp = 1; // CompareString is inverse of strcmp + else + cmp = -1; // CompareString is inverse of strcmp + + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return cmp+2; +} + +int SystemLocale::CompareIgnoreCase( const char * left, SSIZE_T cchLeft, const char * right, SSIZE_T cchRight, DWORD * pErrorCode ) const +{ + if ( NULL == left || NULL == right || 0 == cchLeft || 0 == cchRight ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + return CSTR_ERROR; + } + + size_t cchLeftActual = (cchLeft < 0 ? strlen(left) : cchLeft); + size_t cchRightActual = (cchRight < 0 ? strlen(right) : cchRight); + + int cmp = strncasecmp( left, right, min(cchLeftActual, cchRightActual) ); + if ( 0 == cmp ) + { + if ( cchLeftActual < cchRightActual ) + cmp = -1; + else if ( cchLeftActual > cchRightActual ) + cmp = 1; + } + else if ( cmp < 0 ) + cmp = 1; // CompareString is inverse of strcmp + else + cmp = -1; // CompareString is inverse of strcmp + + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return cmp+2; +} + +char * SystemLocale::NextChar( UINT codepage, const char * start, size_t cchBytesLeft ) +{ + if ( NULL == start || '\0' == *start || 0 == cchBytesLeft ) + return const_cast( start ); + + char first = *start; + codepage = ExpandSpecialCP( codepage ); + if ( CP_UTF8 != codepage ) + { + if ( !IsDBCSLeadByteEx(codepage, first) || '\0' == *(start+1) ) + return const_cast( start+1 ); // single byte char or truncated double byte char + else + return const_cast( start+2 ); // double byte char + } + + // CP_UTF8 + // MB utf8 sequences have this format + // Lead byte starts with 2 set bits, '11' + // Rest of bytes start with one set and one not, '10' + + // ASCII or not first of utf8 sequence + // If this isn't the first byte of a utf8 sequence, just move one byte at a time + // since we don't know where the correct boundary is located. + if ( (char)0 == (first & (char)0x80) || !SystemLocale::IsUtf8LeadByte((BYTE)first) ) + return const_cast( start+1 ); + else + { + // Initial char tells us how many bytes are supposed to be in this sequence + UINT cchExpectedSize = SystemLocale::CchUtf8CodePt( (BYTE)first ); + + // Skip lead bye + ++start; + --cchExpectedSize; + --cchBytesLeft; + + // Proceed to end of utf8 sequence, null term, or end of expected size + while ( 0 < cchExpectedSize && 0 < cchBytesLeft && (char)0x80 == (*start & (char)0xC0) ) + { + ++start; + --cchExpectedSize; + --cchBytesLeft; + } + return const_cast( start ); + } +} + +char * SystemLocale::NextChar( UINT codepage, const char * start ) +{ + // Just assume some large max buffer size since caller is saying + // start is null terminated. + return NextChar( codepage, start, DWORD_MAX ); +} + +// MPLAT_UNIX ---------------------------------------------------------------- +#else +// !MPLAT_UNIX ---------------------------------------------------------------- + +//----------------------------------------------------------------------------------- +// IsW2CZeroFlagCodePage +// +// @func Does this code page need special handling for WideCharToMultiByte or +// MultiByteToWideChar to avoid error code as ERROR_INVALID_PARAMETER to be returned +// +// @rdesc bool +// @flag TRUE | needs special handling +// @flag FALSE | doesn't need special handling +//----------------------------------------------------------------------------------- + +#define IsW2CZeroFlagCodePage(codePage) (((codePage) < 50220) ? FALSE : _IsW2CZeroFlagCodePage(codePage)) + +inline BOOL _IsW2CZeroFlagCodePage +( + UINT CodePage +) +{ + assert(CodePage >= 50220); + + // According to MSDN, these code pages need special handling + // during WideCharToMultiByte call w/r its parameter flags + if (CodePage == 50220 || + CodePage == 50221 || + CodePage == 50222 || + CodePage == 50225 || + CodePage == 50227 || + CodePage == 50229 || + CodePage == 52936 || + CodePage == 54936 || + CodePage == 65000 || + CodePage == 65001 || + CodePage >= 57002 && CodePage <= 57011) + { + return TRUE; + } + + return FALSE; +} + +//------------------------------------------------------------------- +// Custom version of MultiByteToWideChar (faster for all ASCII strings) +// Convert ASCII data (0x00-0x7f) until first non-ASCII data, +// calling OS MultiByteToWideChar in that case. +// +size_t SystemLocale::FastAsciiMultiByteToWideChar( + UINT CodePage, + __in_ecount(cch) const char *pch, // IN | source string + SSIZE_T cch, // IN | count of characters or -1 + __out_ecount_opt(cwch) PWCHAR pwch, // IN | Result string + size_t cwch, // IN | counter of wcharacters of result buffer or 0 + DWORD* pErrorCode, // OUT | optional pointer to return error code + bool bStrict // IN | Return error if invalid chars in src +) +{ + if ( 0 == cch || cch < -1 || NULL == pch ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + + return 0; + } + + const char *pchStart = pch; + + // Divide into + // Case 1a: cch, do convert + // Case 1b: cch, just count + // Case 2a: null-term, do convert + // Case 2b: null-term, just count + if (-1 != cch) + { + // 0 <= cch + // + // Case 1: We have counter of characters + if (0 != cch) + { + if (0 != cwch) + { + // Case 1a: Have to convert, not just calculate necessary space + + // Optimization: When converting first cwch characters, it's not + // necessary to check for buffer overflow. Also, loop is unrolled. + size_t cquads = min((size_t)cch, cwch) >> 2; + + while (0 != cquads) + { + unsigned quad = *(unsigned UNALIGNED *)pch; + + if (quad & 0x80808080) + goto general; + + OACR_WARNING_SUPPRESS ( INCORRECT_VALIDATION, "Due to performance, we suppress this PREFast warning" ); + *(unsigned UNALIGNED *)pwch = (quad & 0x7F) | ((quad & 0x7F00) << 8); + + quad >>= 16; + + OACR_WARNING_SUPPRESS ( POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "PREFast incorrectly warns of buffer overrun for cwch < 4, which won't enter this loop." ); + *(unsigned UNALIGNED *)(pwch+2) = (quad & 0x7F) | ((quad & 0x7F00) << 8); + + pch += 4; + pwch += 4; + cch -= 4; + cquads --; + } + + // Convert end of string - slower, but the loop will be executed 3 times max + if (0 != cch) + { + const char *pchEnd = pchStart + cwch; + + do + { + unsigned ch = (unsigned)*pch; + + if (pch == pchEnd) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INSUFFICIENT_BUFFER; + return 0; // Not enough space + } + + if (ch > 0x7F) + goto general; + + *(pwch++) = (WCHAR)ch; + + pch++; + cch--; + } while (0 != cch); + + } + } + else + { + // Case 1b: Have to calculate necessary space only + if (SystemLocale::MaxCharCchSize(CodePage) == 1) // SBCS code pages 1char = 1 unc char + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return static_cast(cch); + } + + do + { + if ((unsigned)*pch > 0x7F) + goto general; + + pch++; + } while (0 != --cch); + } + } + + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return static_cast(pch - pchStart); + } + else + { + // Case 2: zero-terminated string + if (0 != cwch) + { + // Case 2a: Have to convert, not just calculate necessary space + const char *pchEnd = pch + cwch; + + do + { + unsigned ch = (unsigned)*pch; + + if (ch > 0x7F) + goto general; + else + { + *pwch = (WCHAR)ch; + pch ++; + if (0 == ch) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return static_cast(pch - pchStart); + } + pwch ++; + } + } while (pch != pchEnd); + + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INSUFFICIENT_BUFFER; + return 0; // Not enough space + } + else + { + // Case 2b: Have to calculate necessary space + unsigned ch; + + do + { + ch = (unsigned)*pch; + + if (ch > 0x7F) + goto general; + pch ++; + } while (0 != ch); + + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return static_cast(pch - pchStart); + } + } + + // Have to call Win32 API +general: + { + size_t cwchConverted; + size_t cwchUnicode; + + cwchConverted = (pch - pchStart); + + if ( cwch > cwchConverted ) + cwch -= cwchConverted; + else + cwch = 0; + + // Windows MBtoWC takes int inputs + if ( INT32_MAX < cch || INT32_MAX < cwch ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + + return 0; + } + + cwchUnicode = (UINT)MultiByteToWideChar( + CodePage, + (IsW2CZeroFlagCodePage(CodePage) ? 0 : MB_PRECOMPOSED) + | (bStrict ? MB_ERR_INVALID_CHARS : 0), + pch, + (int)cch, + pwch, + (int)cwch); + + if ( 0 == cwchUnicode ) + { + if ( NULL != pErrorCode ) + *pErrorCode = GetLastError(); + return 0; + } + else + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return (cwchConverted + cwchUnicode); + } + } +} + +//------------------------------------------------------------------- +// Custom version of WideCharToMultiByte (faster for all ASCII strings) +// Convert ASCII data (0x00-0x7f) until first non-ASCII data, +// calling OS WideCharToMultiByte in that case. +size_t SystemLocale::FastAsciiWideCharToMultiByte +( + UINT CodePage, + const WCHAR *pwch, // IN | source string + SSIZE_T cwch, // IN | count of characters or -1 + __out_ecount(cch) char *pch, // IN | Result string + size_t cch, // IN | Length of result buffer or 0 + BOOL *pfDataLoss, // IN | True if there was data loss during CP conversion + DWORD *pErrorCode +) +{ + if ( 0 == cwch || NULL == pwch || cwch < -1 ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + + return 0; + } + + const WCHAR *pwchStart = pwch; + const char *pchStart = pch; + + // Divide into + // Case 1a: cwch, do convert + // Case 1b: cwch, just count + // Case 2a: null-term, do convert + // Case 2b: null-term, just count + if (-1 != cwch) + { + // Case 1: We have counter of characters + if (0 != cwch) + { + if (0 != cch) + { + // Case 1a: Have to convert, not just calculate necessary space + + // Optimization: When converting first cch characters, it's not + // necessary to check for buffer overflow. Also, loop is unrolled. + size_t cquads = cch >> 2; + + while (0 != cquads && 4 <= cwch) + { + unsigned pairLo = *(unsigned UNALIGNED *)pwch; + unsigned pairHi = *(unsigned UNALIGNED *)(pwch+2); + + if ((pairLo | pairHi) & 0xFF80FF80) + goto general; + + *(unsigned UNALIGNED *)pch = (pairLo & 0x7F) | + ((pairLo >> 8) & 0x7F00) | + ((pairHi & 0x7F) << 16) | + ((pairHi & 0x7F0000) << 8); + pch += 4; + pwch += 4; + cwch -= 4; + cquads --; + } + // Convert end of string - slower, but the loop will be executed 3 times max + if (0 != cwch) + { + const char *pchEnd = pchStart + cch; + + do + { + unsigned wch = (unsigned)*pwch; + + if (pch == pchEnd) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INSUFFICIENT_BUFFER; + return 0; // Not enough space + } + + if ((unsigned)*pwch > 0x7F) + goto general; + + *(pch ++) = (char) wch; + pwch ++; + cwch --; + } while (0 != cwch); + } + } + else + { + // Case 1b: Have to calculate necessary space + do + { + if ((unsigned)*pwch > 0x7F) + goto general; + + pwch ++; + cwch --; + } while (0 != cwch); + } + } + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return static_cast(pwch - pwchStart); + } + else + { + // Case 2: zero-terminated string + if (0 != cch) + { + // Case 2a: Have to convert, not just calculate necessary space + const char *pchEnd = pch + cch; + + do + { + unsigned wch = (unsigned)*pwch; + + if (wch > 0x7F) + goto general; + else + { + *pch = (char) wch; + pwch ++; + if (0 == wch) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return static_cast(pwch - pwchStart); + } + pch ++; + } + } while (pch != pchEnd); + + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INSUFFICIENT_BUFFER; + return 0; // Not enough space + } + else + { + // Case 2b: Have to calculate necessary space + unsigned wch; + + do + { + wch = (unsigned)*pwch; + if (wch > 0x7F) + goto general; + pwch ++; + } while (0 != wch); + + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return static_cast(pwch - pwchStart); + } + } + + // Have to call Win32 API +general: + { + size_t cchConverted; + size_t cchUnicode; + + // initialize output param if any + if (pfDataLoss) + *pfDataLoss = FALSE; + + cchConverted = (pwch - pwchStart); + + if ( cch > cchConverted ) + cch -= cchConverted; + else + cch = 0; + + // Windows MBtoWC takes int inputs + if ( INT32_MAX < cch || INT32_MAX < cwch ) + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_INVALID_PARAMETER; + + return 0; + } + + cchUnicode = (UINT)WideCharToMultiByte ( + CodePage, + 0, + pwch, + (int)cwch, + pch, + (int)cch, + NULL, + IsW2CZeroFlagCodePage(CodePage) ? NULL : pfDataLoss); + + if ( 0 == cchUnicode ) + { + if ( NULL != pErrorCode ) + *pErrorCode = GetLastError(); + return 0; + } + else + { + if ( NULL != pErrorCode ) + *pErrorCode = ERROR_SUCCESS; + return (cchConverted + cchUnicode); + } + } +} + +// !MPLAT_UNIX ---------------------------------------------------------------- +#endif + diff --git a/source/shared/sal.h b/source/shared/sal.h new file mode 100644 index 00000000..352c8b3a --- /dev/null +++ b/source/shared/sal.h @@ -0,0 +1,796 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: sal_def.h +// +// Contents: Contains the minimal definitions to build on non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef XPLAT_SAL_DEFINED +#define XPLAT_SAL_DEFINED + +#define __allocator +#define __analysis_assert(e) +#define __analysis_assume(e) +#define __bcount(size) +#define __bcount_opt(size) +#define __blocksOn(resource) +#define __bound +#define __callback +#define __checkReturn +#define __control_entrypoint(category) +#define __data_entrypoint(category) +#define __deref +#define __deref_bcount(size) +#define __deref_bcount_opt(size) +#define __deref_ecount(size) +#define __deref_ecount_opt(size) +#define __deref_in +#define __deref_in +#define __deref_in_bcount(size) +#define __deref_in_bcount_opt(size) +#define __deref_in_ecount(size) +#define __deref_in_ecount_opt(size) +#define __deref_in_opt +#define __deref_in_range(lb,ub) +#define __deref_in_xcount(size) +#define __deref_in_xcount_opt(size) +#define __deref_inout +#define __deref_inout_bcount(size) +#define __deref_inout_bcount_full(size) +#define __deref_inout_bcount_full_opt(size) +#define __deref_inout_bcount_nz(size) +#define __deref_inout_bcount_nz_opt(size) +#define __deref_inout_bcount_opt(size) +#define __deref_inout_bcount_part(size,length) +#define __deref_inout_bcount_part_opt(size,length) +#define __deref_inout_bcount_z(size) +#define __deref_inout_bcount_z_opt(size) +#define __deref_inout_ecount(size) +#define __deref_inout_ecount_full(size) +#define __deref_inout_ecount_full_opt(size) +#define __deref_inout_ecount_nz(size) +#define __deref_inout_ecount_nz_opt(size) +#define __deref_inout_ecount_opt(size) +#define __deref_inout_ecount_part(size,length) +#define __deref_inout_ecount_part_opt(size,length) +#define __deref_inout_ecount_z(size) +#define __deref_inout_ecount_z_opt(size) +#define __deref_inout_nz +#define __deref_inout_nz_opt +#define __deref_inout_opt +#define __deref_inout_xcount(size) +#define __deref_inout_xcount_full(size) +#define __deref_inout_xcount_full_opt(size) +#define __deref_inout_xcount_opt(size) +#define __deref_inout_xcount_part(size,length) +#define __deref_inout_xcount_part_opt(size,length) +#define __deref_inout_z +#define __deref_inout_z_opt +#define __deref_opt_bcount(size) +#define __deref_opt_bcount_opt(size) +#define __deref_opt_ecount(size) +#define __deref_opt_ecount_opt(size) +#define __deref_opt_in +#define __deref_opt_in_bcount(size) +#define __deref_opt_in_bcount_opt(size) +#define __deref_opt_in_ecount(size) +#define __deref_opt_in_ecount_opt(size) +#define __deref_opt_in_opt +#define __deref_opt_in_xcount(size) +#define __deref_opt_in_xcount_opt(size) +#define __deref_opt_inout +#define __deref_opt_inout_bcount(size) +#define __deref_opt_inout_bcount_full(size) +#define __deref_opt_inout_bcount_full_opt(size) +#define __deref_opt_inout_bcount_nz(size) +#define __deref_opt_inout_bcount_nz_opt(size) +#define __deref_opt_inout_bcount_opt(size) +#define __deref_opt_inout_bcount_part(size,length) +#define __deref_opt_inout_bcount_part_opt(size,length) +#define __deref_opt_inout_bcount_z(size) +#define __deref_opt_inout_bcount_z_opt(size) +#define __deref_opt_inout_ecount(size) +#define __deref_opt_inout_ecount_full(size) +#define __deref_opt_inout_ecount_full_opt(size) +#define __deref_opt_inout_ecount_nz(size) +#define __deref_opt_inout_ecount_nz_opt(size) +#define __deref_opt_inout_ecount_opt(size) +#define __deref_opt_inout_ecount_part(size,length) +#define __deref_opt_inout_ecount_part_opt(size,length) +#define __deref_opt_inout_ecount_z(size) +#define __deref_opt_inout_ecount_z_opt(size) +#define __deref_opt_inout_nz +#define __deref_opt_inout_nz_opt +#define __deref_opt_inout_opt +#define __deref_opt_inout_xcount(size) +#define __deref_opt_inout_xcount_full(size) +#define __deref_opt_inout_xcount_full_opt(size) +#define __deref_opt_inout_xcount_opt(size) +#define __deref_opt_inout_xcount_part(size,length) +#define __deref_opt_inout_xcount_part_opt(size,length) +#define __deref_opt_inout_z +#define __deref_opt_inout_z_opt +#define __deref_opt_out +#define __deref_opt_out_bcount(size) +#define __deref_opt_out_bcount_full(size) +#define __deref_opt_out_bcount_full_opt(size) +#define __deref_opt_out_bcount_nz_opt(size) +#define __deref_opt_out_bcount_opt(size) +#define __deref_opt_out_bcount_part(size,length) +#define __deref_opt_out_bcount_part_opt(size,length) +#define __deref_opt_out_bcount_z_opt(size) +#define __deref_opt_out_ecount(size) +#define __deref_opt_out_ecount_full(size) +#define __deref_opt_out_ecount_full_opt(size) +#define __deref_opt_out_ecount_nz_opt(size) +#define __deref_opt_out_ecount_opt(size) +#define __deref_opt_out_ecount_part(size,length) +#define __deref_opt_out_ecount_part_opt(size,length) +#define __deref_opt_out_ecount_z_opt(size) +#define __deref_opt_out_nz_opt +#define __deref_opt_out_opt +#define __deref_opt_out_xcount(size) +#define __deref_opt_out_xcount_full(size) +#define __deref_opt_out_xcount_full_opt(size) +#define __deref_opt_out_xcount_opt(size) +#define __deref_opt_out_xcount_part(size,length) +#define __deref_opt_out_xcount_part_opt(size,length) +#define __deref_opt_out_z +#define __deref_opt_out_z_opt +#define __deref_opt_xcount(size) +#define __deref_opt_xcount_opt(size) +#define __deref_out +#define __deref_out_bcount(size) +#define __deref_out_bcount_full(size) +#define __deref_out_bcount_full_opt(size) +#define __deref_out_bcount_nz(size) +#define __deref_out_bcount_nz_opt(size) +#define __deref_out_bcount_opt(size) +#define __deref_out_bcount_part(size,length) +#define __deref_out_bcount_part_opt(size,length) +#define __deref_out_bcount_z(size) +#define __deref_out_bcount_z_opt(size) +#define __deref_out_bound +#define __deref_out_ecount(size) +#define __deref_out_ecount_full(size) +#define __deref_out_ecount_full_opt(size) +#define __deref_out_ecount_nz(size) +#define __deref_out_ecount_nz_opt(size) +#define __deref_out_ecount_opt(size) +#define __deref_out_ecount_part(size,length) +#define __deref_out_ecount_part_opt(size,length) +#define __deref_out_ecount_z(size) +#define __deref_out_ecount_z_opt(size) +#define __deref_out_nz +#define __deref_out_nz_opt +#define __deref_out_opt +#define __deref_out_range(lb,ub) +#define __deref_out_xcount(size) +#define __deref_out_xcount_full(size) +#define __deref_out_xcount_full_opt(size) +#define __deref_out_xcount_opt(size) +#define __deref_out_xcount_part(size,length) +#define __deref_out_xcount_part_opt(size,length) +#define __deref_out_z +#define __deref_out_z_opt +#define __deref_xcount(size) +#define __deref_xcount_opt(size) +#define __ecount(size) +#define __ecount_opt(size) +#define __fallthrough +#define __field_bcount(size) +#define __field_bcount_full(size) +#define __field_bcount_full_opt(size) +#define __field_bcount_opt(size) +#define __field_bcount_part(size,init) +#define __field_bcount_part_opt(size,init) +#define __field_data_source(src_sym) +#define __field_ecount(size) +#define __field_ecount_full(size) +#define __field_ecount_full_opt(size) +#define __field_ecount_opt(size) +#define __field_ecount_part(size,init) +#define __field_ecount_part_opt(size,init) +#define __field_range(lb,ub) +#define __field_xcount(size) +#define __field_xcount_full(size) +#define __field_xcount_full_opt(size) +#define __field_xcount_opt(size) +#define __field_xcount_part(size,init) +#define __field_xcount_part_opt(size,init) +#define __format_string +#define __inn +#define __in_bcount(size) +#define __in_bcount_nz(size) +#define __in_bcount_nz_opt(size) +#define __in_bcount_opt(size) +#define __in_bcount_z(size) +#define __in_bcount_z_opt(size) +#define __in_bound +#define __in_ecount(size) +#define __in_ecount_nz(size) +#define __in_ecount_nz_opt(size) +#define __in_ecount_opt(size) +#define __in_ecount_z(size) +#define __in_ecount_z_opt(size) +#define __in_nz +#define __in_nz_opt +#define __in_opt +#define __in_range(lb,ub) +#define __in_xcount(size) +#define __in_xcount_opt(size) +#define __in_z +#define __in_z_opt +#define __inexpressible_readableTo(size) +#define __inexpressible_writableTo(size) +#define __inner_allocator +#define __inner_assume_bound(i) +#define __inner_assume_bound_dec +#define __inner_bound +#define __inner_range(lb,ub) +#define __inout +#define __inout_bcount(size) +#define __inout_bcount_full(size) +#define __inout_bcount_full_opt(size) +#define __inout_bcount_nz(size) +#define __inout_bcount_nz_opt(size) +#define __inout_bcount_opt(size) +#define __inout_bcount_part(size,length) +#define __inout_bcount_part_opt(size,length) +#define __inout_bcount_z(size) +#define __inout_bcount_z_opt(size) +#define __inout_ecount(size) +#define __inout_ecount_full(size) +#define __inout_ecount_full_opt(size) +#define __inout_ecount_nz(size) +#define __inout_ecount_nz_opt(size) +#define __inout_ecount_opt(size) +#define __inout_ecount_part(size,length) +#define __inout_ecount_part_opt(size,length) +#define __inout_ecount_z(size) +#define __inout_ecount_z_opt(size) +#define __inout_nz +#define __inout_nz_opt +#define __inout_opt +#define __inout_xcount(size) +#define __inout_xcount_full(size) +#define __inout_xcount_full_opt(size) +#define __inout_xcount_opt(size) +#define __inout_xcount_opt(size) +#define __inout_xcount_part(size,length) +#define __inout_xcount_part_opt(size,length) +#define __inout_z +#define __inout_z_opt +#define __nullnullterminated +#define __nullterminated +#define __outt +#define __out_bcount(size) +#define __out_bcount_full(size) +#define __out_bcount_full_opt(size) +#define __out_bcount_full_z(size) +#define __out_bcount_full_z_opt(size) +#define __out_bcount_nz(size) +#define __out_bcount_nz_opt(size) +#define __out_bcount_opt(size) +#define __out_bcount_part(size,length) +#define __out_bcount_part_opt(size,length) +#define __out_bcount_part_z(size,length) +#define __out_bcount_part_z_opt(size,length) +#define __out_bcount_z(size) +#define __out_bcount_z_opt(size) +#define __out_bound +#define __out_ecount(size) +#define __out_ecount_full(size) +#define __out_ecount_full_opt(size) +#define __out_ecount_full_z(size) +#define __out_ecount_full_z_opt(size) +#define __out_ecount_nz(size) +#define __out_ecount_nz_opt(size) +#define __out_ecount_opt(size) +#define __out_ecount_part(size,length) +#define __out_ecount_part_opt(size,length) +#define __out_ecount_part_z(size,length) +#define __out_ecount_part_z_opt(size,length) +#define __out_ecount_z(size) +#define __out_ecount_z_opt(size) +#define __out_nz +#define __out_nz_opt +#define __out_opt +#define __out_range(lb,ub) +#define __out_xcount(size) +#define __out_xcount_full(size) +#define __out_xcount_full_opt(size) +#define __out_xcount_opt(size) +#define __out_xcount_part(size,length) +#define __out_xcount_part_opt(size,length) +#define __out_z +#define __out_z_opt +#define __override +#define __range(lb,ub) +#define __reserved +#define __sql_escaped_and_delimited_right_bracket +#define __struct_bcount(size) +#define __struct_xcount(size) +#define __success(expr) +#define __transfer(formal) +#define __typefix(ctype) +#define __xcount(size) +#define __xcount_opt(size) +#define _Analysis_assume_ +#define _Check_return_ +#define _Check_return_ +#define _Deref +#define _Deref_in_bound_ +#define _Deref_in_range_(lb,ub) +#define _Deref_inout_bound_ +#define _Deref_inout_z_ +#define _Deref_inout_z_bytecap_c_(size) +#define _Deref_inout_z_cap_c_(size) +#define _Deref_opt_out_ +#define _Deref_opt_out_opt_ +#define _Deref_opt_out_opt_z_ +#define _Deref_opt_out_z_ +#define _Deref_out_ +#define _Deref_out_bound_ +#define _Deref_out_opt_ +#define _Deref_out_opt_z_ +#define _Deref_out_range_(lb,ub) +#define _Deref_out_z_ +#define _Deref_out_z_bytecap_c_(size) +#define _Deref_out_z_cap_c_(size) +#define _Deref_post_bytecap_(size) +#define _Deref_post_bytecap_c_(size) +#define _Deref_post_bytecap_x_(size) +#define _Deref_post_bytecount_(size) +#define _Deref_post_bytecount_c_(size) +#define _Deref_post_bytecount_x_(size) +#define _Deref_post_cap_(size) +#define _Deref_post_cap_c_(size) +#define _Deref_post_cap_x_(size) +#define _Deref_post_count_(size) +#define _Deref_post_count_c_(size) +#define _Deref_post_count_x_(size) +#define _Deref_post_maybenull_ +#define _Deref_post_notnull_ +#define _Deref_post_null_ +#define _Deref_post_opt_bytecap_(size) +#define _Deref_post_opt_bytecap_c_(size) +#define _Deref_post_opt_bytecap_x_(size) +#define _Deref_post_opt_bytecount_(size) +#define _Deref_post_opt_bytecount_c_(size) +#define _Deref_post_opt_bytecount_x_(size) +#define _Deref_post_opt_cap_(size) +#define _Deref_post_opt_cap_c_(size) +#define _Deref_post_opt_cap_x_(size) +#define _Deref_post_opt_count_(size) +#define _Deref_post_opt_count_c_(size) +#define _Deref_post_opt_count_x_(size) +#define _Deref_post_opt_valid_ +#define _Deref_post_opt_valid_bytecap_(size) +#define _Deref_post_opt_valid_bytecap_c_(size) +#define _Deref_post_opt_valid_bytecap_x_(size) +#define _Deref_post_opt_valid_cap_(size) +#define _Deref_post_opt_valid_cap_c_(size) +#define _Deref_post_opt_valid_cap_x_(size) +#define _Deref_post_opt_z_ +#define _Deref_post_opt_z_bytecap_(size) +#define _Deref_post_opt_z_bytecap_c_(size) +#define _Deref_post_opt_z_bytecap_x_(size) +#define _Deref_post_opt_z_cap_(size) +#define _Deref_post_opt_z_cap_c_(size) +#define _Deref_post_opt_z_cap_x_(size) +#define _Deref_post_valid_ +#define _Deref_post_valid_bytecap_(size) +#define _Deref_post_valid_bytecap_c_(size) +#define _Deref_post_valid_bytecap_x_(size) +#define _Deref_post_valid_cap_(size) +#define _Deref_post_valid_cap_c_(size) +#define _Deref_post_valid_cap_x_(size) +#define _Deref_post_z_ +#define _Deref_post_z_ +#define _Deref_post_z_bytecap_(size) +#define _Deref_post_z_bytecap_c_(size) +#define _Deref_post_z_bytecap_x_(size) +#define _Deref_post_z_cap_(size) +#define _Deref_post_z_cap_c_(size) +#define _Deref_post_z_cap_x_(size) +#define _Deref_pre_bytecap_(size) +#define _Deref_pre_bytecap_c_(size) +#define _Deref_pre_bytecap_x_(size) +#define _Deref_pre_bytecount_(size) +#define _Deref_pre_bytecount_c_(size) +#define _Deref_pre_bytecount_x_(size) +#define _Deref_pre_cap_(size) +#define _Deref_pre_cap_c_(size) +#define _Deref_pre_cap_x_(size) +#define _Deref_pre_count_(size) +#define _Deref_pre_count_c_(size) +#define _Deref_pre_count_x_(size) +#define _Deref_pre_invalid_ +#define _Deref_pre_maybenull_ +#define _Deref_pre_notnull_ +#define _Deref_pre_null_ +#define _Deref_pre_opt_bytecap_(size) +#define _Deref_pre_opt_bytecap_c_(size) +#define _Deref_pre_opt_bytecap_x_(size) +#define _Deref_pre_opt_bytecount_(size) +#define _Deref_pre_opt_bytecount_c_(size) +#define _Deref_pre_opt_bytecount_x_(size) +#define _Deref_pre_opt_cap_(size) +#define _Deref_pre_opt_cap_c_(size) +#define _Deref_pre_opt_cap_x_(size) +#define _Deref_pre_opt_count_(size) +#define _Deref_pre_opt_count_c_(size) +#define _Deref_pre_opt_count_x_(size) +#define _Deref_pre_opt_valid_ +#define _Deref_pre_opt_valid_bytecap_(size) +#define _Deref_pre_opt_valid_bytecap_c_(size) +#define _Deref_pre_opt_valid_bytecap_x_(size) +#define _Deref_pre_opt_valid_cap_(size) +#define _Deref_pre_opt_valid_cap_c_(size) +#define _Deref_pre_opt_valid_cap_x_(size) +#define _Deref_pre_opt_z_ +#define _Deref_pre_opt_z_bytecap_(size) +#define _Deref_pre_opt_z_bytecap_c_(size) +#define _Deref_pre_opt_z_bytecap_x_(size) +#define _Deref_pre_opt_z_cap_(size) +#define _Deref_pre_opt_z_cap_c_(size) +#define _Deref_pre_opt_z_cap_x_(size) +#define _Deref_pre_readonly_ +#define _Deref_pre_valid_ +#define _Deref_pre_valid_bytecap_(size) +#define _Deref_pre_valid_bytecap_c_(size) +#define _Deref_pre_valid_bytecap_x_(size) +#define _Deref_pre_valid_cap_(size) +#define _Deref_pre_valid_cap_c_(size) +#define _Deref_pre_valid_cap_x_(size) +#define _Deref_pre_writeonly_ +#define _Deref_pre_z_ +#define _Deref_pre_z_bytecap_(size) +#define _Deref_pre_z_bytecap_c_(size) +#define _Deref_pre_z_bytecap_x_(size) +#define _Deref_pre_z_cap_(size) +#define _Deref_pre_z_cap_c_(size) +#define _Deref_pre_z_cap_x_(size) +#define _Deref_prepost_bytecap_(size) +#define _Deref_prepost_bytecap_x_(size) +#define _Deref_prepost_bytecount_(size) +#define _Deref_prepost_bytecount_x_(size) +#define _Deref_prepost_cap_(size) +#define _Deref_prepost_cap_x_(size) +#define _Deref_prepost_count_(size) +#define _Deref_prepost_count_x_(size) +#define _Deref_prepost_opt_bytecap_(size) +#define _Deref_prepost_opt_bytecap_x_(size) +#define _Deref_prepost_opt_bytecount_(size) +#define _Deref_prepost_opt_bytecount_x_(size) +#define _Deref_prepost_opt_cap_(size) +#define _Deref_prepost_opt_cap_x_(size) +#define _Deref_prepost_opt_count_(size) +#define _Deref_prepost_opt_count_x_(size) +#define _Deref_prepost_opt_valid_ +#define _Deref_prepost_opt_valid_bytecap_(size) +#define _Deref_prepost_opt_valid_bytecap_x_(size) +#define _Deref_prepost_opt_valid_cap_(size) +#define _Deref_prepost_opt_valid_cap_x_(size) +#define _Deref_prepost_opt_z_ +#define _Deref_prepost_opt_z_bytecap_(size) +#define _Deref_prepost_opt_z_cap_(size) +#define _Deref_prepost_valid_ +#define _Deref_prepost_valid_bytecap_(size) +#define _Deref_prepost_valid_bytecap_x_(size) +#define _Deref_prepost_valid_cap_(size) +#define _Deref_prepost_valid_cap_x_(size) +#define _Deref_prepost_z_ +#define _Deref_prepost_z_bytecap_(size) +#define _Deref_prepost_z_cap_(size) +#define _Deref_ret_bound_ +#define _Deref_ret_opt_z_ +#define _Deref_ret_range_(lb,ub) +#define _Deref_ret_z_ +#define _FormatMessage_format_string_ +#define _In_ +#define _In_bound_ +#define _In_bytecount_(size) +#define _In_bytecount_c_(size) +#define _In_bytecount_x_(size) +#define _In_count_(size) +#define _In_count_c_(size) +#define _In_count_x_(size) +#define _In_opt_ +#define _In_opt_ +#define _In_opt_bytecount_(size) +#define _In_opt_bytecount_c_(size) +#define _In_opt_bytecount_x_(size) +#define _In_opt_count_(size) +#define _In_opt_count_c_(size) +#define _In_opt_count_x_(size) +#define _In_opt_ptrdiff_count_(size) +#define _In_opt_z_ +#define _In_opt_z_bytecount_(size) +#define _In_opt_z_bytecount_c_(size) +#define _In_opt_z_count_(size) +#define _In_opt_z_count_c_(size) +#define _In_ptrdiff_count_(size) +#define _In_range_(lb,ub) +#define _In_reads_bytes_(size) +#define _In_z_ +#define _In_z_bytecount_(size) +#define _In_z_bytecount_c_(size) +#define _In_z_count_(size) +#define _In_z_count_c_(size) +#define _Inout_ +#define _Inout_bytecap_(size) +#define _Inout_bytecap_c_(size) +#define _Inout_bytecap_x_(size) +#define _Inout_bytecount_(size) +#define _Inout_bytecount_c_(size) +#define _Inout_bytecount_x_(size) +#define _Inout_cap_(size) +#define _Inout_cap_c_(size) +#define _Inout_cap_x_(size) +#define _Inout_count_(size) +#define _Inout_count_c_(size) +#define _Inout_count_x_(size) +#define _Inout_opt_ +#define _Inout_opt_bytecap_(size) +#define _Inout_opt_bytecap_c_(size) +#define _Inout_opt_bytecap_x_(size) +#define _Inout_opt_bytecount_(size) +#define _Inout_opt_bytecount_c_(size) +#define _Inout_opt_bytecount_x_(size) +#define _Inout_opt_cap_(size) +#define _Inout_opt_cap_c_(size) +#define _Inout_opt_cap_x_(size) +#define _Inout_opt_count_(size) +#define _Inout_opt_count_c_(size) +#define _Inout_opt_count_x_(size) +#define _Inout_opt_ptrdiff_count_(size) +#define _Inout_opt_z_ +#define _Inout_opt_z_bytecap_(size) +#define _Inout_opt_z_bytecap_c_(size) +#define _Inout_opt_z_bytecap_x_(size) +#define _Inout_opt_z_bytecount_(size) +#define _Inout_opt_z_bytecount_c_(size) +#define _Inout_opt_z_cap_(size) +#define _Inout_opt_z_cap_c_(size) +#define _Inout_opt_z_cap_x_(size) +#define _Inout_opt_z_count_(size) +#define _Inout_opt_z_count_c_(size) +#define _Inout_ptrdiff_count_(size) +#define _Inout_z_ +#define _Inout_z_bytecap_(size) +#define _Inout_z_bytecap_c_(size) +#define _Inout_z_bytecap_x_(size) +#define _Inout_z_bytecount_(size) +#define _Inout_z_bytecount_c_(size) +#define _Inout_z_cap_(size) +#define _Inout_z_cap_c_(size) +#define _Inout_z_cap_x_(size) +#define _Inout_z_count_(size) +#define _Inout_z_count_c_(size) +#define _Out_ +#define _Out_bound_ +#define _Out_bytecap_(size) +#define _Out_bytecap_c_(size) +#define _Out_bytecap_post_bytecount_(cap,count) +#define _Out_bytecap_x_(size) +#define _Out_bytecapcount_(capcount) +#define _Out_bytecapcount_x_(capcount) +#define _Out_cap_(size) +#define _Out_cap_c_(size) +#define _Out_cap_m_(mult,size) +#define _Out_cap_post_count_(cap,count) +#define _Out_cap_x_(size) +#define _Out_capcount_(capcount) +#define _Out_capcount_x_(capcount) +#define _Out_opt_ +#define _Out_opt_bytecap_(size) +#define _Out_opt_bytecap_c_(size) +#define _Out_opt_bytecap_post_bytecount_(cap,count) +#define _Out_opt_bytecap_x_(size) +#define _Out_opt_bytecapcount_(capcount) +#define _Out_opt_bytecapcount_x_(capcount) +#define _Out_opt_cap_(size) +#define _Out_opt_cap_c_(size) +#define _Out_opt_cap_m_(mult,size) +#define _Out_opt_cap_post_count_(cap,count) +#define _Out_opt_cap_x_(size) +#define _Out_opt_capcount_(capcount) +#define _Out_opt_capcount_x_(capcount) +#define _Out_opt_ptrdiff_cap_(size) +#define _Out_opt_z_bytecap_(size) +#define _Out_opt_z_bytecap_c_(size) +#define _Out_opt_z_bytecap_post_bytecount_(cap,count) +#define _Out_opt_z_bytecap_x_(size) +#define _Out_opt_z_bytecapcount_(capcount) +#define _Out_opt_z_cap_(size) +#define _Out_opt_z_cap_c_(size) +#define _Out_opt_z_cap_m_(mult,size) +#define _Out_opt_z_cap_post_count_(cap,count) +#define _Out_opt_z_cap_x_(size) +#define _Out_opt_z_capcount_(capcount) +#define _Out_ptrdiff_cap_(size) +#define _Out_range_(lb,ub) +#define _Out_writes_(size) +#define _Out_writes_bytes_(count) +#define _Out_z_bytecap_(size) +#define _Out_z_bytecap_c_(size) +#define _Out_z_bytecap_post_bytecount_(cap,count) +#define _Out_z_bytecap_x_(size) +#define _Out_z_bytecapcount_(capcount) +#define _Out_z_cap_(size) +#define _Out_z_cap_c_(size) +#define _Out_z_cap_m_(mult,size) +#define _Out_z_cap_post_count_(cap,count) +#define _Out_z_cap_x_(size) +#define _Out_z_capcount_(capcount) +#define _Post_bytecap_(size) +#define _Post_bytecount_(size) +#define _Post_bytecount_c_(size) +#define _Post_bytecount_x_(size) +#define _Post_cap_(size) +#define _Post_count_(size) +#define _Post_count_c_(size) +#define _Post_count_x_(size) +#define _Post_invalid_ +#define _Post_maybez_ +#define _Post_notnull_ +#define _Post_ptr_invalid_ +#define _Post_valid_ +#define _Post_z_ +#define _Post_z_bytecount_(size) +#define _Post_z_bytecount_c_(size) +#define _Post_z_bytecount_x_(size) +#define _Post_z_count_(size) +#define _Post_z_count_c_(size) +#define _Post_z_count_x_(size) +#define _Pre_bytecap_(size) +#define _Pre_bytecap_c_(size) +#define _Pre_bytecap_x_(size) +#define _Pre_bytecount_(size) +#define _Pre_bytecount_c_(size) +#define _Pre_bytecount_x_(size) +#define _Pre_cap_(size) +#define _Pre_cap_c_(size) +#define _Pre_cap_for_(param) +#define _Pre_cap_m_(mult,size) +#define _Pre_cap_x_(size) +#define _Pre_count_(size) +#define _Pre_count_c_(size) +#define _Pre_count_x_(size) +#define _Pre_invalid_ +#define _Pre_maybenull_ +#define _Pre_notnull_ +#define _Pre_null_ +#define _Pre_opt_bytecap_(size) +#define _Pre_opt_bytecap_c_(size) +#define _Pre_opt_bytecap_x_(size) +#define _Pre_opt_bytecount_(size) +#define _Pre_opt_bytecount_c_(size) +#define _Pre_opt_bytecount_x_(size) +#define _Pre_opt_cap_(size) +#define _Pre_opt_cap_c_(size) +#define _Pre_opt_cap_for_(param) +#define _Pre_opt_cap_m_(mult,size) +#define _Pre_opt_cap_x_(size) +#define _Pre_opt_count_(size) +#define _Pre_opt_count_c_(size) +#define _Pre_opt_count_x_(size) +#define _Pre_opt_ptrdiff_cap_(ptr) +#define _Pre_opt_ptrdiff_count_(ptr) +#define _Pre_opt_valid_ +#define _Pre_opt_valid_bytecap_(size) +#define _Pre_opt_valid_bytecap_c_(size) +#define _Pre_opt_valid_bytecap_x_(size) +#define _Pre_opt_valid_cap_(size) +#define _Pre_opt_valid_cap_c_(size) +#define _Pre_opt_valid_cap_x_(size) +#define _Pre_opt_z_ +#define _Pre_opt_z_bytecap_(size) +#define _Pre_opt_z_bytecap_c_(size) +#define _Pre_opt_z_bytecap_x_(size) +#define _Pre_opt_z_cap_(size) +#define _Pre_opt_z_cap_c_(size) +#define _Pre_opt_z_cap_x_(size) +#define _Pre_ptrdiff_cap_(ptr) +#define _Pre_ptrdiff_count_(ptr) +#define _Pre_readonly_ +#define _Pre_valid_ +#define _Pre_valid_bytecap_(size) +#define _Pre_valid_bytecap_c_(size) +#define _Pre_valid_bytecap_x_(size) +#define _Pre_valid_cap_(size) +#define _Pre_valid_cap_c_(size) +#define _Pre_valid_cap_x_(size) +#define _Pre_writeonly_ +#define _Pre_z_ +#define _Pre_z_bytecap_(size) +#define _Pre_z_bytecap_c_(size) +#define _Pre_z_bytecap_x_(size) +#define _Pre_z_cap_(size) +#define _Pre_z_cap_c_(size) +#define _Pre_z_cap_x_(size) +#define _Prepost_bytecount_(size) +#define _Prepost_bytecount_c_(size) +#define _Prepost_bytecount_x_(size) +#define _Prepost_count_(size) +#define _Prepost_count_c_(size) +#define _Prepost_count_x_(size) +#define _Prepost_opt_bytecount_(size) +#define _Prepost_opt_bytecount_c_(size) +#define _Prepost_opt_bytecount_x_(size) +#define _Prepost_opt_count_(size) +#define _Prepost_opt_count_c_(size) +#define _Prepost_opt_count_x_(size) +#define _Prepost_opt_valid_ +#define _Prepost_opt_z_ +#define _Prepost_valid_ +#define _Prepost_z_ +#define _Printf_format_string_ +#define _Ret_ +#define _Ret_bound_ +#define _Ret_bytecap_(size) +#define _Ret_bytecap_c_(size) +#define _Ret_bytecap_x_(size) +#define _Ret_bytecount_(size) +#define _Ret_bytecount_c_(size) +#define _Ret_bytecount_x_(size) +#define _Ret_cap_(size) +#define _Ret_cap_c_(size) +#define _Ret_cap_x_(size) +#define _Ret_count_(size) +#define _Ret_count_c_(size) +#define _Ret_count_x_(size) +#define _Ret_maybenull_ +#define _Ret_notnull_ +#define _Ret_null_ +#define _Ret_opt_ +#define _Ret_opt_ +#define _Ret_opt_bytecap_(size) +#define _Ret_opt_bytecap_c_(size) +#define _Ret_opt_bytecap_x_(size) +#define _Ret_opt_bytecount_(size) +#define _Ret_opt_bytecount_c_(size) +#define _Ret_opt_bytecount_x_(size) +#define _Ret_opt_cap_(size) +#define _Ret_opt_cap_c_(size) +#define _Ret_opt_cap_x_(size) +#define _Ret_opt_count_(size) +#define _Ret_opt_count_c_(size) +#define _Ret_opt_count_x_(size) +#define _Ret_opt_valid_ +#define _Ret_opt_z_ +#define _Ret_opt_z_ +#define _Ret_opt_z_bytecap_(size) +#define _Ret_opt_z_bytecount_(size) +#define _Ret_opt_z_cap_(size) +#define _Ret_opt_z_count_(size) +#define _Ret_range_(lb,ub) +#define _Ret_valid_ +#define _Ret_z_ +#define _Ret_z_ +#define _Ret_z_bytecap_(size) +#define _Ret_z_bytecount_(size) +#define _Ret_z_cap_(size) +#define _Ret_z_count_(size) +#define _Scanf_format_string_ +#define _Scanf_s_format_string_ +#define _Success_(expr) +#define _Outptr_ +#define _Notnull_ + +#endif // XPLAT_SAL_DEFINED + diff --git a/source/shared/typedefs_for_linux.h b/source/shared/typedefs_for_linux.h new file mode 100644 index 00000000..dfdd2ad9 --- /dev/null +++ b/source/shared/typedefs_for_linux.h @@ -0,0 +1,109 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: typedefs_for_linux.h +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef __linux_typedefs__ +#define __linux_typedefs__ + +#define MPLAT_UNIX + +#include "xplat.h" +#include "interlockedslist.h" + +#define CP_OEMCP 1 // default to OEM code page +#define CP_MACCP 2 // default to MAC code page +#define CP_THREAD_ACP 3 // current thread's ANSI code page +#define CP_SYMBOL 42 // SYMBOL translations + +#define CP_UTF7 65000 // UTF-7 translation + +#define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) +#define LANG_NEUTRAL 0x00 +#define SUBLANG_DEFAULT 0x01 // user default + +// #ifndef _GETLASTERROR +// #define _GETLASTERROR +// void SSetLastError(DWORD err); +// unsigned int GGetLastError(); +// #endif + +DWORD FormatMessageA( + DWORD dwFlags, + LPCVOID lpSource, + DWORD dwMessageId, + DWORD dwLanguageId, + LPTSTR lpBuffer, + DWORD nSize, + va_list *Arguments + ); + +DWORD FormatMessageW( + DWORD dwFlags, + LPCVOID lpSource, + DWORD dwMessageId, + DWORD dwLanguageId, + LPWSTR lpBuffer, + DWORD nSize, + va_list *Arguments + ); + +#ifdef __linux__ +#define FormatMessage FormatMessageA +#else +#define FormatMessage FormatMessageW +#endif + +#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100 +#define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200 +#define FORMAT_MESSAGE_FROM_STRING 0x00000400 +#define FORMAT_MESSAGE_FROM_HMODULE 0x00000800 +#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000 +#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x00002000 +#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0x000000FF + +#define ERROR_NO_UNICODE_TRANSLATION 1113L +#define ERROR_SUCCESS 0L +#define ERROR_INVALID_DATA 13L + +typedef int errno_t; +int mplat_snwprintf_s(WCHAR *str, size_t sizeOfBuffer, size_t count, const WCHAR *format, ...); +int mplat_vsnwprintf( WCHAR * buffer, size_t count, const WCHAR * format, va_list args ); +int mplat_snprintf_s(char *str, size_t sizeOfBuffer, size_t count, const char *format, ...); +int mplat_vsnprintf( char * buffer, size_t count, const char * format, va_list args ); +errno_t mplat_wctomb_s(int *pRetValue, char *mbchar, size_t sizeInBytes, WCHAR wchar); +WCHAR * mplat_wcscpy(WCHAR * _Dst, const WCHAR * _Src); +char * mplat_cscpy(char * _Dst, const char * _Src); +BOOL IsDBCSLeadByteEx(__inn UINT CodePage, __inn BYTE TestChar); + +typedef struct _SYSTEMTIME { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; +} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME; + +typedef HINSTANCE HMODULE; /* HMODULEs can be used in place of HINSTANCEs */ + +//From sqlext.h +#define SQL_GUID (-11) + +size_t mplat_wcslen( const WCHAR * ); + +#endif // __linux_typedefs__ diff --git a/source/shared/winerror.h b/source/shared/winerror.h new file mode 100644 index 00000000..25653cd1 --- /dev/null +++ b/source/shared/winerror.h @@ -0,0 +1,132 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: winerror.h +// +// Contents: Contains the minimal definitions to build on non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef XPLAT_WINERROR_H +#define XPLAT_WINERROR_H + +#define NOERROR 0 +#define WAIT_TIMEOUT 258L // dderror +#define S_OK ((HRESULT)0L) +#define S_FALSE ((HRESULT)1L) +#define E_NOTIMPL ((HRESULT) 0x80004001L) +#define E_FAIL ((HRESULT) 0x80004005L) +#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L) +#define ERROR_HANDLE_EOF 38L +#define E_UNEXPECTED ((HRESULT) 0x8000FFFFL) +#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) +#define FAILED(hr) (((HRESULT)(hr)) < 0) +#define ERROR_SUCCESS 0L +#define ERROR_ACCESS_DENIED 5L +#define ERROR_TIMEOUT 1460L +#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L) +#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc) +#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL) +#define NO_ERROR 0L +#define ERROR_CANCELLED 1223L +#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L) +#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L) +#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL) +#define ERROR_INSUFFICIENT_BUFFER 122L // dderror +#define FACILITY_WIN32 7 +#define __HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) +#define HRESULT_FROM_WIN32(x) __HRESULT_FROM_WIN32(x) +#define SEVERITY_ERROR 1 +#define FACILITY_ITF 4 +#define MAKE_HRESULT(sev,fac,code) \ + ((HRESULT) (((windowsULong_t)(sev)<<31) | ((windowsULong_t)(fac)<<16) | ((windowsULong_t)(code))) ) +#define ERROR_INVALID_DATA 13L +#define ERROR_INVALID_PARAMETER 87L // dderror +#define ERROR_POSSIBLE_DEADLOCK 1131L +#define ERROR_INVALID_FLAGS 1004L +#define ERROR_NO_UNICODE_TRANSLATION 1113L + +#define ERROR_FILE_NOT_FOUND 2L +#define ERROR_PATH_NOT_FOUND 3L +#define ERROR_TOO_MANY_OPEN_FILES 4L +#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L) + +#define ERROR_MOD_NOT_FOUND 126L +#define ERROR_NO_MORE_FILES 18L +#define ERROR_FILE_EXISTS 80L +#define ERROR_ALREADY_EXISTS 183L +#define ERROR_SHARING_VIOLATION 32L +#define SCODE_CODE(sc) ((sc) & 0xFFFF) +#define ERROR_READ_FAULT 30L +#define ERROR_INTERNAL_ERROR 1359L +//---------------------------------------------------------------------------- +// Error codes used by SNI +// +#define ERROR_NOT_ENOUGH_MEMORY 8L // dderror +#define ERROR_IO_PENDING 997L +#define WSA_IO_PENDING (ERROR_IO_PENDING) +#define WSAHOST_NOT_FOUND 11001L +#define WSATRY_AGAIN 11002L +#define WSANO_RECOVERY 11003L +#define WSANO_DATA 11004L +#define WSATYPE_NOT_FOUND 10109L +#define WSA_NOT_ENOUGH_MEMORY 8L +#define WSAEINTR 10004L +#define WSAEACCES 10013L +#define WSAEFAULT 10014L +#define WSAEINVAL 10022L +#define WSAEMFILE 10024L +#define WSAEWOULDBLOCK 10035L +#define WSAEALREADY 10037L +#define WSAENOTSOCK 10038L +#define WSAEMSGSIZE 10040L +#define WSAENOPROTOOPT 10042L +#define WSAEPROTONOSUPPORT 10043L +#define WSAESOCKTNOSUPPORT 10044L +#define WSAEOPNOTSUPP 10045L +#define WSAEAFNOSUPPORT 10047L +#define WSAEADDRINUSE 10048L +#define WSAEADDRNOTAVAIL 10049L +#define WSAENETUNREACH 10051L +#define WSAECONNRESET 10054L +#define WSAENOBUFS 10055L +#define WSAEISCONN 10056L +#define WSAENOTCONN 10057L +#define WSAETIMEDOUT 10060L +#define WSAECONNREFUSED 10061L +#define WSANOTINITIALISED 10093L +#define ERROR_OUTOFMEMORY 14L +#define ERROR_NOT_SUPPORTED 50L +#define ERROR_BUFFER_OVERFLOW 111L +#define ERROR_MAX_THRDS_REACHED 164L +#define ERROR_INVALID_OPERATION 4317L +#define ERROR_INVALID_STATE 5023L +#define SEC_E_BAD_BINDINGS _HRESULT_TYPEDEF_(0x80090346L) +#define ERROR_MORE_DATA 234L // dderror +#define ERROR_ARITHMETIC_OVERFLOW 534L +#define SEC_E_INCOMPLETE_MESSAGE _HRESULT_TYPEDEF_(0x80090318L) +#define ERROR_OPERATION_ABORTED 995L +#define ERROR_CONNECTION_REFUSED 1225L +#define SEC_E_OK ((HRESULT)0x00000000L) +#define SEC_E_UNSUPPORTED_FUNCTION _HRESULT_TYPEDEF_(0x80090302L) +#define SEC_E_TARGET_UNKNOWN _HRESULT_TYPEDEF_(0x80090303L) +#define SEC_E_OUT_OF_SEQUENCE _HRESULT_TYPEDEF_(0x80090310L) +#define SEC_E_INVALID_TOKEN _HRESULT_TYPEDEF_(0x80090308L) +#define SEC_I_CONTINUE_NEEDED _HRESULT_TYPEDEF_(0x00090312L) +#define ERROR_INVALID_FUNCTION 1L // dderror +#define TRUST_E_TIME_STAMP _HRESULT_TYPEDEF_(0x80096005L) +#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L) +#define WAIT_TIMEOUT 258L // dderror + + +#endif // XPLAT_WINERROR_H diff --git a/source/shared/winnls.h b/source/shared/winnls.h new file mode 100644 index 00000000..d0a7166e --- /dev/null +++ b/source/shared/winnls.h @@ -0,0 +1,144 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: winnls.h +// +// Contents: Contains the minimal definitions to build on non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef XPLAT_WINNLS_H +#define XPLAT_WINNLS_H + +#include +#include "typedefs_for_linux.h" + +struct threadlocaleinfostruct; +struct threadmbcinfostruct; +typedef struct threadlocaleinfostruct * pthreadlocinfo; +typedef struct threadmbcinfostruct * pthreadmbcinfo; + +typedef struct localeinfo_struct +{ + pthreadlocinfo locinfo; + pthreadmbcinfo mbcinfo; +} _locale_tstruct, *_locale_t; + +#define LOCALE_SDECIMAL 0x0000000E // decimal separator +#define LOCALE_SCURRENCY 0x00000014 // local monetary symbol +#define LOCALE_SMONDECIMALSEP 0x00000016 // monetary decimal separator +#define LOCALE_SMONTHOUSANDSEP 0x00000017 // monetary thousand separator +#define LOCALE_SMONGROUPING 0x00000018 // monetary grouping +#define LOCALE_ILDATE 0x00000022 // long date format ordering (derived from LOCALE_SLONGDATE, use that instead) +#define LOCALE_ITIME 0x00000023 // time format specifier (derived from LOCALE_STIMEFORMAT, use that instead) +#define LOCALE_SABBREVMONTHNAME1 0x00000044 // abbreviated name for January + +#define LOCALE_IDEFAULTLANGUAGE 0x00000009 // default language id +#define LOCALE_IDEFAULTCOUNTRY 0x0000000A // default country/region code, deprecated +#define LOCALE_IDEFAULTCODEPAGE 0x0000000B // default oem code page +#define LOCALE_IDEFAULTANSICODEPAGE 0x00001004 // default ansi code page +#define LOCALE_IDEFAULTMACCODEPAGE 0x00001011 // default mac code page + +#define LOCALE_STIMEFORMAT 0x00001003 // time format string, eg "HH:mm:ss" + +typedef DWORD LCTYPE; + +#define NORM_IGNORECASE 0x00000001 // ignore case +#define NORM_IGNORENONSPACE 0x00000002 // ignore nonspacing chars +#define NORM_IGNORESYMBOLS 0x00000004 // ignore symbols + +#define LINGUISTIC_IGNORECASE 0x00000010 // linguistically appropriate 'ignore case' +#define LINGUISTIC_IGNOREDIACRITIC 0x00000020 // linguistically appropriate 'ignore nonspace' + +#define NORM_IGNOREKANATYPE 0x00010000 // ignore kanatype +#define NORM_IGNOREWIDTH 0x00020000 // ignore width +#define NORM_LINGUISTIC_CASING 0x08000000 // use linguistic rules for casing + + +#define NORM_IGNORECASE 0x00000001 // ignore case + +#define MB_PRECOMPOSED 0x00000001 // use precomposed chars +#define MB_COMPOSITE 0x00000002 // use composite chars +#define MB_USEGLYPHCHARS 0x00000004 // use glyph chars, not ctrl chars +#define MB_ERR_INVALID_CHARS 0x00000008 // error for invalid chars + +#define WC_COMPOSITECHECK 0x00000200 // convert composite to precomposed +#define WC_DISCARDNS 0x00000010 // discard non-spacing chars +#define WC_SEPCHARS 0x00000020 // generate separate chars +#define WC_DEFAULTCHAR 0x00000040 // replace w/ default char + + +typedef WORD LANGID; + + + + +#define NLS_VALID_LOCALE_MASK 0x000fffff + +#define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p)) +#define MAKELCID(lgid, srtid) ((DWORD)((((DWORD)((WORD )(srtid))) << 16) | \ + ((DWORD)((WORD )(lgid))))) +#define LANG_NEUTRAL 0x00 +#define SUBLANG_DEFAULT 0x01 // user default +#define SUBLANG_SYS_DEFAULT 0x02 // system default +#define SORT_DEFAULT 0x0 // sorting default +#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)) +#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT)) +#define SUBLANG_ENGLISH_US 0x01 // English (USA) +#define LANG_ENGLISH 0x09 +#define LOCALE_ENGLISH_US MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT) +#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT)) +#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT, SORT_DEFAULT)) + +BOOL +WINAPI +IsDBCSLeadByte( + __inn BYTE TestChar); + + +#ifdef MPLAT_UNIX +// XPLAT_ODBC_TODO: VSTS 718708 Localization +// Find way to remove this +LCID GetUserDefaultLCID(); +#endif + + +BOOL IsValidCodePage(UINT CodePage); + +#define HIGH_SURROGATE_START 0xd800 +#define HIGH_SURROGATE_END 0xdbff +#define LOW_SURROGATE_START 0xdc00 +#define LOW_SURROGATE_END 0xdfff +#define IS_HIGH_SURROGATE(wch) (((wch) >= HIGH_SURROGATE_START) && ((wch) <= HIGH_SURROGATE_END)) +#define IS_LOW_SURROGATE(wch) (((wch) >= LOW_SURROGATE_START) && ((wch) <= LOW_SURROGATE_END)) + +int +GetLocaleInfoA( + __inn LCID Locale, + __inn LCTYPE LCType, + __out_ecount_opt(cchData) LPSTR lpLCData, + __inn int cchData); +int +GetLocaleInfoW( + __inn LCID Locale, + __inn LCTYPE LCType, + __out_ecount_opt(cchData) LPWSTR lpLCData, + __inn int cchData); +#ifdef UNICODE +#define GetLocaleInfo GetLocaleInfoW +#else +#define GetLocaleInfo GetLocaleInfoA +#endif // !UNICODE + + +#endif // XPLAT_WINNLS_H diff --git a/source/shared/xplat.h b/source/shared/xplat.h new file mode 100644 index 00000000..3ab8442a --- /dev/null +++ b/source/shared/xplat.h @@ -0,0 +1,509 @@ +//--------------------------------------------------------------------------------------------------------------------------------- +// File: xplat.h +// +// Contents: include for definition of Windows types for non-Windows platforms +// +// Microsoft Drivers 4.0 for PHP for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//--------------------------------------------------------------------------------------------------------------------------------- + +#ifndef __XPLAT_H__ +#define __XPLAT_H__ + +#ifndef _WCHART_DEFINED +#define _WCHART_DEFINED +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msodbcsql.h" + +#if defined(_MSC_VER) +// Turned on all warnings in WwoWH projects +// These warnings need to be disabled to be build warning free +// Note that some of these should be enabled and the code fixed +#pragma warning( disable : 4668 ) // preprocessor macro not defined +#pragma warning( disable : 4820 ) // padding after data member +#pragma warning( disable : 4201 ) // nonstandard: nameless union +#pragma warning( disable : 4100 ) // unreferenced formal parameter +#pragma warning( disable : 4514 ) // unreferenced inline function +#pragma warning( disable : 4505 ) // unreferenced inline function +#pragma warning( disable : 4710 ) // function not inlined +#pragma warning( disable : 4191 ) // unsafe conversion +#pragma warning( disable : 4365 ) // signed/unsigned argument conversion +#pragma warning( disable : 4245 ) // signed/unsigned assignment conversion +#pragma warning( disable : 4389 ) // signed/unsigned == +#pragma warning( disable : 4987 ) // nonstandard: throw(...) +#pragma warning( disable : 4510 ) // default ctor could not be generated +#pragma warning( disable : 4512 ) // operator= could not be generated +#pragma warning( disable : 4626 ) // operator= could not be generated +#pragma warning( disable : 4625 ) // copy ctor could not be generated or accessed +#pragma warning( disable : 4189 ) // unused initialized local variable +#pragma warning( disable : 4127 ) // constant conditional test +#pragma warning( disable : 4061 ) // Unused enum values in switch +#pragma warning( disable : 4062 ) // Unused enum values in switch +#pragma warning( disable : 4706 ) // assignment within conditional +#pragma warning( disable : 4610 ) // can never be instantiated +#pragma warning( disable : 4244 ) // possible loss of data in conversion +#pragma warning( disable : 4701 ) // possible use of uninitialized variable +#pragma warning( disable : 4918 ) // invalid pragma optimization parameter +#pragma warning( disable : 4702 ) // unreachable code +#pragma warning( disable : 4265 ) // class with virtual fxns has non-virtual dtor +#pragma warning( disable : 4238 ) // nonstandard: class rvalue used as lvalue +#pragma warning( disable : 4310 ) // cast truncates constant value +#pragma warning( disable : 4946 ) // reinterpret_cast between related classes +#pragma warning( disable : 4264 ) // no matching override, hides base fxn +#pragma warning( disable : 4242 ) // conversion: possible loss of data +#pragma warning( disable : 4820 ) // added padding bytes +#endif + +// Compiler specific items +#define _cdecl +#define __cdecl +#define __fastcall +#define _inline inline +#define __inline inline +#define __forceinline inline +#define __stdcall + +#if !defined(_MSC_VER) +#define __declspec__noinline __attribute__((noinline)) +#define __declspec__selectany +#define __declspec(a) __declspec__##a +#define __FUNCTION__ __func__ + +#define __int8 char +#define __int32 int + +// __int64 +// This type must be defined in a way that allows "unsigned __int64" as a valid type declaration. +// That precludes using the obvious "int64_t" from stdint.h, because "unsigned int64_t" is not allowed +// (one should use "uint64_t" for unsigned 64-bit integers). As a result, we must use compiler-specific +// types such as GCC's "long long" instead +#if defined(_LP64) +#define __int64 long +#elif defined(__GNUC__) +#define __int64 long long +#else +#error "Compiler-specific definition required for __int64 in 32-bit builds" +#endif +#endif + +// GCC-specific definitions +#if defined(__GNUC__) +#define MPLAT_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif // defined(__GNUC__) + +// For compilers that don't support cross-module inlining (part of whole-program/link-time +// optimization), such as the current MPLAT compilers (GCC 4.1.2 for RHEL5 and GCC 4.4 for RHEL6), +// we must force the generation of out-of-line definitions for functions that otherwise +// are only defined inline when those functions are called from other translation units. +// There are a handful of instances of these in SNI code as well as ODBC code. +// +// To force the compiler to emit an out-of-line definition for a function, just add an otherwise +// unused global (external linkage) non-const pointer pointing to the function: +// +// #if defined(MPLAT_NO_LTO) +// void (* g_pfnMyFunctionUnused)(MyFunctionArguments *) = MyFunction; +// #endif // defined(MPLAT_NO_LTO) +// +// This works because, absent whole-program optimization, the compiler cannot determine that the +// pointers are never called through, and the out-of-line definition cannot be optimized out, +// giving calling translation units something to link to. +// +// GCC adds LTO as of version 4.5 +//JL - TODO: this version check doesn't work in Ubuntu +//#if defined(__GNUC__) && MPLAT_GCC_VERSION < 40500 +#define MPLAT_NO_LTO +//#endif + +#ifdef MPLAT_UNIX + +// Needed to use the standard library min and max +#include +using std::min; +using std::max; + +#elif MPLAT_WWOWH + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#endif // MPLAT_WWOWH + +// Deal with differences between Windows and *nix interpretations of the C/C++ 'long' data type. +// +// On 64-bit Windows, 'long' is 32 bits. On 64-bit Linux, 'long' is 64 bits. Assuming the Windows code +// depends on it being 32 bits, use a definition that provides a guaranteed 32-bit type definition. +// +// Similarly, because 'long long' (and its cousin 'unsigned long long') are not portable across +// Linux/UNIX platforms and compilers, provide common definitions for 64-bit types as well. +// +// These types are used in this file primarily to define common Windows types (DWORD, LONG, etc.) +// Cross-platform code should use either the Windows types or appropriate types from . +#if defined(_MSC_VER) // WwoWH +typedef long windowsLong_t; +typedef unsigned long windowsULong_t; +typedef __int64 windowsLongLong_t; +typedef unsigned __int64 windowsULongLong_t; +#else // *nix (!WwoWH) +#include // Use standard bit-specific types (signed/unsigned integrated) +typedef int32_t windowsLong_t; +typedef uint32_t windowsULong_t; +typedef int64_t windowsLongLong_t; +typedef uint64_t windowsULongLong_t; +#endif +typedef windowsLong_t LONG, *PLONG, *LPLONG; +typedef windowsLongLong_t LONGLONG; +typedef windowsULongLong_t ULONGLONG; + +#include +#include +#include + +// Exclude these headers in Windows machines (just for building on Windows w/o Windows headers) +#define SPECSTRINGS_H // specstrings.h +#define ASOSHOST_DEFINED // asoshost.h +#define _WINDOWS_ // windows.h +#define _INC_WINDOWSX // windowsx.h +#define _WINBASE_ // winbase.h +#define _WINNLS_ // winnls.h +#define _WINERROR_ // winerror.h +#define NETCONS_INCLUDED // lmcons.h +#define __WINCRYPT_H__ // wincrypt.h +#define _INC_TCHAR // tchar.h +#define _INC_FCNTL // fcntl.h +#define _INC_SHARE // share.h +#define _INC_IO // io.h +#define _INC_TYPES // sys/types.h +#define _INC_STAT // sys/stat.h +#define _INC_TIMEB // sys/timeb.h +#define __unknwn_h__ // unknwn.h +#define __objidl_h__ // objidl.h +#define _OBJBASE_H_ // objbase.h +#define __RPC_H__ // rpc.h +#define __RPCNDR_H__ // rpcndr.h +#define _NP_HPP_ // np.hpp (no named pipes) +#define _SM_HPP_ // sm.hpp (no shared memory) +#define VIA_HEADER // via.hpp (no via) +#define _WINUSER_ // winuser.h + +#define interface struct + +// What we need from dlgattr.h +#define OPTIONON L"Yes" +#define OPTIONOFF L"No" + + +//----------------------------------------------------------------------------- +// Definitions for UnixODBC Driver Manager + +// Define this to enable driver code to conditionalize around UnixODBC Driver +// Manager "quirks"... +#ifndef MPLAT_WWOWH +#define UNIXODBC +#endif + +/* can be defined in php sources */ +#ifdef ODBCVER +#undef ODBCVER +#endif +// Build the mplat driver as an ODBC 3.8 driver, so that all of the +// source code shared with Windows SNAC (which is ODBC 3.8) compiles. +#define ODBCVER 0x0380 + +// Define this to indicate that we provide our own definitions for Windows types +#define ALLREADY_HAVE_WINDOWS_TYPE + +// Definitions not otherwise provided in sqltypes.h, given that we define our own Windows types +#define SQL_API +typedef signed char SCHAR; +typedef SCHAR SQLSCHAR; +typedef int SDWORD; +typedef unsigned int UDWORD; +typedef signed short int SWORD; +typedef signed short SSHORT; +typedef double SDOUBLE; +typedef double LDOUBLE; +typedef float SFLOAT; +typedef void* PTR; +typedef signed short RETCODE; +typedef void* SQLHWND; + +// Definitions missing from sql.h +#define SQL_PARAM_DATA_AVAILABLE 101 +#define SQL_APD_TYPE (-100) + +// Bid control bit, only for xplat +// It traces everything we current enabled for bid. +// The correlated tracing feature is not enabled. +#define DEFAULT_BID_CORT_BIT 0xFFFFBFFFF + +// End definitions for UnixODBC SQL headers +// ---------------------------------------------------------------------------- + +#define UNREFERENCED_PARAMETER(arg) + +// From share.h +#define _SH_DENYNO 0x40 /* deny none mode */ + + +// WinNT.h +#define CONST const +#define VOID void +#define DLL_PROCESS_ATTACH 1 +#define DLL_THREAD_ATTACH 2 +#define DLL_THREAD_DETACH 3 +#define DLL_PROCESS_DETACH 0 +#define VER_GREATER_EQUAL 3 +#define VER_MINORVERSION 0x0000001 +#define VER_MAJORVERSION 0x0000002 +#define VER_SERVICEPACKMINOR 0x0000010 +#define VER_SERVICEPACKMAJOR 0x0000020 +#define VER_SET_CONDITION(_m_,_t_,_c_) \ + ((_m_)=VerSetConditionMask((_m_),(_t_),(_c_))) + + +// Predeclared types from windef needed for remaining WinNT types +// to break circular dependency between WinNT.h and windef.h types. +//typedef ULONG DWORD; +typedef unsigned char BYTE; +typedef unsigned char UCHAR; +typedef UCHAR *PUCHAR; + +typedef DWORD LCID; +typedef LONG HRESULT; +typedef char CHAR; +typedef CHAR *LPSTR, *PSTR; +typedef CHAR *PCHAR, *LPCH, *PCH; +typedef CONST CHAR *LPCCH, *PCCH; +#ifdef SQL_WCHART_CONVERT +typedef wchar_t WCHAR; +#else +typedef unsigned short WCHAR; +#endif +typedef WCHAR *LPWSTR; +typedef WCHAR *PWSTR; +typedef CONST WCHAR *LPCWSTR; +typedef CONST WCHAR *PCWSTR; +typedef CONST CHAR *LPCSTR, *PCSTR; +typedef void *PVOID; +typedef PVOID HANDLE; +typedef BYTE BOOLEAN; +typedef BOOLEAN *PBOOLEAN; +typedef HANDLE *PHANDLE; +typedef WCHAR *PWCHAR, *LPWCH, *PWCH; +typedef CONST WCHAR *LPCWCH, *PCWCH; +typedef int HFILE; + +typedef short SHORT; +typedef CONST CHAR *LPCCH, *PCCH; + +typedef unsigned short WORD; + +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) +#define ARRAYSIZE(A) RTL_NUMBER_OF_V1(A) +#define STATUS_STACK_OVERFLOW ((DWORD )0xC00000FDL) +typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + }; + struct { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; +} LARGE_INTEGER; +typedef LARGE_INTEGER *PLARGE_INTEGER; +typedef void * RPC_IF_HANDLE; + +typedef WORD LANGID; + +typedef enum _HEAP_INFORMATION_CLASS { + + HeapCompatibilityInformation, + HeapEnableTerminationOnCorruption + + +} HEAP_INFORMATION_CLASS; + + +#define REG_SZ ( 1 ) // Unicode nul terminated string +#define REG_DWORD ( 4 ) // 32-bit number + +#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0])) +#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A) + + +// windef.h +typedef VOID *LPVOID; +typedef CONST void *LPCVOID; +typedef int INT; +typedef int *LPINT; +typedef unsigned int UINT; +typedef ULONGLONG UINT64; +typedef unsigned int *PUINT; +typedef unsigned char BYTE; +typedef BYTE *PBYTE; +typedef BYTE *LPBYTE; +typedef const BYTE *LPCBYTE; +#define _LPCBYTE_DEFINED +//typedef int BOOL; +typedef BOOL * LPBOOL; +typedef unsigned short WORD; +typedef WORD * LPWORD; +typedef WORD UWORD; +typedef DWORD * LPDWORD; +typedef DWORD * PDWORD; +typedef unsigned short USHORT; +#define CDECL // TODO _cdecl and cdecl not portable? +#define WINAPI // TODO __stdcall not portable? +#define MAX_PATH 260 +typedef HANDLE HINSTANCE; +typedef HANDLE HGLOBAL; +typedef ULONGLONG DWORDLONG; +typedef DWORDLONG *PDWORDLONG; +typedef float FLOAT; + +typedef struct _FILETIME { + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME, *PFILETIME, *LPFILETIME; +typedef double DOUBLE; +#define MAKELONG(a, b) ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16)) + +// INT_PTR - http://msdn.microsoft.com/en-us/library/aa384154(VS.85).aspx +#ifdef _WIN64 +typedef __int64 INT_PTR; +#else +typedef int INT_PTR; +#endif + +typedef INT_PTR (*FARPROC)(); +typedef INT_PTR (*NEARPROC)(); +typedef INT_PTR (*PROC)(); + + +DWORD GetFileSize( + __inn HANDLE hFile, + __out_opt LPDWORD lpFileSizeHigh +); + +typedef union _ULARGE_INTEGER { + struct { + DWORD LowPart; + DWORD HighPart; + }; + struct { + DWORD LowPart; + DWORD HighPart; + } u; + ULONGLONG QuadPart; +} ULARGE_INTEGER; + +typedef ULARGE_INTEGER *PULARGE_INTEGER; + +#ifndef IN +#define IN +#endif + +#ifndef OUT +#define OUT +#endif + +#ifndef OPTIONAL +#define OPTIONAL +#endif + + +ULONGLONG +VerSetConditionMask( + IN ULONGLONG ConditionMask, + IN DWORD TypeMask, + IN BYTE Condition + ); + + + +//#include + +//// ntdef.h +#define __unaligned +#ifndef UNALIGNED +#define UNALIGNED +#endif +//typedef __nullterminated WCHAR UNALIGNED *LPUWSTR; + +//// crtdefs.h +//#if !defined(_TRUNCATE) +//#define _TRUNCATE ((size_t)-1) +//#endif + +//// ?? +//typedef ULONG_PTR DWORD_PTR; +#define FALSE ((BOOL)0) +#define TRUE ((BOOL)1) + + +//// asoshost.h (excluded above) +//struct ISOSHost_MemObj; +//struct ISOSHost; +//extern ISOSHost_MemObj *g_pMO; +//extern ISOSHost *g_pISOSHost; +//inline HRESULT CreateSQLSOSHostInterface() { return 0; } +//inline HRESULT CreateGlobalSOSHostInterface() { return 0; } + +//// These are temporary solution versions of the real files that contain the minimal declarations +//// needed to compile for non-Windows platforms. See the special include path for the +//// location of these files. +//#include +//#include +//#include +//#include +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +//#define LMEM_FIXED 0 +typedef void * HLOCAL; +HLOCAL LocalAlloc(UINT uFlags, SIZE_T uBytes); +//HLOCAL LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags); +HLOCAL LocalFree(HLOCAL hMem); + +// End of xplat.h +#endif //__XPLAT_H__