You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6611 lines
210 KiB
6611 lines
210 KiB
/****************************************************************** |
|
* * |
|
* strsafe.h -- This module defines safer C library string * |
|
* routine replacements. These are meant to make C * |
|
* a bit more safe in reference to security and * |
|
* robustness * |
|
* * |
|
* Copyright (c) Microsoft Corp. All rights reserved. * |
|
* * |
|
******************************************************************/ |
|
#ifndef _STRSAFE_H_INCLUDED_ |
|
#define _STRSAFE_H_INCLUDED_ |
|
#pragma once |
|
|
|
#include <stdio.h> // for _vsnprintf, _vsnwprintf, getc, getwc |
|
#include <string.h> // for memset |
|
#include <stdarg.h> // for va_start, etc. |
|
|
|
|
|
#ifndef _SIZE_T_DEFINED |
|
#ifdef _WIN64 |
|
typedef unsigned __int64 size_t; |
|
#else |
|
typedef __w64 unsigned int size_t; |
|
#endif // !_WIN64 |
|
#define _SIZE_T_DEFINED |
|
#endif // !_SIZE_T_DEFINED |
|
|
|
#if !defined(_WCHAR_T_DEFINED) && !defined(_NATIVE_WCHAR_T_DEFINED) |
|
typedef unsigned short wchar_t; |
|
#define _WCHAR_T_DEFINED |
|
#endif |
|
|
|
#ifndef _HRESULT_DEFINED |
|
#define _HRESULT_DEFINED |
|
typedef long HRESULT; |
|
#endif // !_HRESULT_DEFINED |
|
|
|
#ifndef SUCCEEDED |
|
#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) |
|
#endif |
|
|
|
#ifndef FAILED |
|
#define FAILED(hr) ((HRESULT)(hr) < 0) |
|
#endif |
|
|
|
#ifndef S_OK |
|
#define S_OK ((HRESULT)0x00000000L) |
|
#endif |
|
|
|
#ifdef __cplusplus |
|
#define _STRSAFE_EXTERN_C extern "C" |
|
#else |
|
#define _STRSAFE_EXTERN_C extern |
|
#endif |
|
|
|
// If you do not want to use these functions inline (and instead want to link w/ strsafe.lib), then |
|
// #define STRSAFE_LIB before including this header file. |
|
#if defined(STRSAFE_LIB) |
|
#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall |
|
#pragma comment(lib, "strsafe.lib") |
|
#elif defined(STRSAFE_LIB_IMPL) |
|
#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall |
|
#else |
|
#define STRSAFEAPI __inline HRESULT __stdcall |
|
#define STRSAFE_INLINE |
|
#endif |
|
|
|
// Some functions always run inline because they use stdin and we want to avoid building multiple |
|
// versions of strsafe lib depending on if you use msvcrt, libcmt, etc. |
|
#define STRSAFE_INLINE_API __inline HRESULT __stdcall |
|
|
|
// The user can request no "Cb" or no "Cch" fuctions, but not both! |
|
#if defined(STRSAFE_NO_CB_FUNCTIONS) && defined(STRSAFE_NO_CCH_FUNCTIONS) |
|
#error cannot specify both STRSAFE_NO_CB_FUNCTIONS and STRSAFE_NO_CCH_FUNCTIONS !! |
|
#endif |
|
|
|
// This should only be defined when we are building strsafe.lib |
|
#ifdef STRSAFE_LIB_IMPL |
|
#define STRSAFE_INLINE |
|
#endif |
|
|
|
|
|
// If both strsafe.h and ntstrsafe.h are included, only use definitions from one. |
|
#ifndef _NTSTRSAFE_H_INCLUDED_ |
|
|
|
#define STRSAFE_MAX_CCH 2147483647 // max # of characters we support (same as INT_MAX) |
|
|
|
// Flags for controling the Ex functions |
|
// |
|
// STRSAFE_FILL_BYTE(0xFF) 0x000000FF // bottom byte specifies fill pattern |
|
#define STRSAFE_IGNORE_NULLS 0x00000100 // treat null as TEXT("") -- don't fault on NULL buffers |
|
#define STRSAFE_FILL_BEHIND_NULL 0x00000200 // fill in extra space behind the null terminator |
|
#define STRSAFE_FILL_ON_FAILURE 0x00000400 // on failure, overwrite pszDest with fill pattern and null terminate it |
|
#define STRSAFE_NULL_ON_FAILURE 0x00000800 // on failure, set *pszDest = TEXT('\0') |
|
#define STRSAFE_NO_TRUNCATION 0x00001000 // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it |
|
|
|
#define STRSAFE_VALID_FLAGS (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION) |
|
|
|
// helper macro to set the fill character and specify buffer filling |
|
#define STRSAFE_FILL_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL)) |
|
#define STRSAFE_FAILURE_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE)) |
|
|
|
#define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)(dwFlags & 0x000000FF)) |
|
|
|
#endif // _NTSTRSAFE_H_INCLUDED_ |
|
|
|
// STRSAFE error return codes |
|
// |
|
#define STRSAFE_E_INSUFFICIENT_BUFFER ((HRESULT)0x8007007AL) // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER |
|
#define STRSAFE_E_INVALID_PARAMETER ((HRESULT)0x80070057L) // 0x57 = 87L = ERROR_INVALID_PARAMETER |
|
#define STRSAFE_E_END_OF_FILE ((HRESULT)0x80070026L) // 0x26 = 38L = ERROR_HANDLE_EOF |
|
|
|
// prototypes for the worker functions |
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc); |
|
STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc); |
|
STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc); |
|
STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc); |
|
STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc); |
|
STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc); |
|
STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend); |
|
STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend); |
|
STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList); |
|
STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList); |
|
STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList); |
|
STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList); |
|
STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch); |
|
STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch); |
|
#endif // STRSAFE_INLINE |
|
|
|
#ifndef STRSAFE_LIB_IMPL |
|
// these functions are always inline |
|
STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
#endif |
|
|
|
#ifdef _NTSTRSAFE_H_INCLUDED_ |
|
#pragma warning(push) |
|
#pragma warning(disable : 4995) |
|
#endif // _NTSTRSAFE_H_INCLUDED_ |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchCopy( |
|
OUT LPTSTR pszDest, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszSrc |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strcpy'. |
|
The size of the destination buffer (in characters) is a parameter and |
|
this function will not write past the end of this buffer and it will |
|
ALWAYS null terminate the destination buffer (unless it is zero length). |
|
|
|
This routine is not a replacement for strncpy. That function will pad the |
|
destination string with extra null termination characters if the count is |
|
greater than the length of the source string, and it will fail to null |
|
terminate the destination string if the source string length is greater |
|
than or equal to the count. You can not blindly use this instead of strncpy: |
|
it is common for code to use it to "patch" strings and you would introduce |
|
errors if the code started null terminating in the middle of the string. |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string was copied without truncation and null terminated, |
|
otherwise it will return a failure code. In failure cases as much of |
|
pszSrc will be copied to pszDest as possible, and pszDest will be null |
|
terminated. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be = (_tcslen(src) + 1) to hold all of the |
|
source including the null terminator |
|
|
|
pszSrc - source string which must be null terminated |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL. See StringCchCopyEx if you require |
|
the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all copied and the |
|
resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the copy |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc); |
|
STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc); |
|
#ifdef UNICODE |
|
#define StringCchCopy StringCchCopyW |
|
#else |
|
#define StringCchCopy StringCchCopyA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyWorkerA(pszDest, cchDest, pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyWorkerW(pszDest, cchDest, pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbCopy( |
|
OUT LPTSTR pszDest, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszSrc |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strcpy'. |
|
The size of the destination buffer (in bytes) is a parameter and this |
|
function will not write past the end of this buffer and it will ALWAYS |
|
null terminate the destination buffer (unless it is zero length). |
|
|
|
This routine is not a replacement for strncpy. That function will pad the |
|
destination string with extra null termination characters if the count is |
|
greater than the length of the source string, and it will fail to null |
|
terminate the destination string if the source string length is greater |
|
than or equal to the count. You can not blindly use this instead of strncpy: |
|
it is common for code to use it to "patch" strings and you would introduce |
|
errors if the code started null terminating in the middle of the string. |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string was copied without truncation and null terminated, |
|
otherwise it will return a failure code. In failure cases as much of pszSrc |
|
will be copied to pszDest as possible, and pszDest will be null terminated. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to |
|
hold all of the source including the null terminator |
|
|
|
pszSrc - source string which must be null terminated |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require |
|
the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all copied and the |
|
resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the copy |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc); |
|
STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc); |
|
#ifdef UNICODE |
|
#define StringCbCopy StringCbCopyW |
|
#else |
|
#define StringCbCopy StringCbCopyA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
// convert to count of characters |
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyWorkerA(pszDest, cchDest, pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
// convert to count of characters |
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyWorkerW(pszDest, cchDest, pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchCopyEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszSrc OPTIONAL, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcchRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strcpy' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCchCopy, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be = (_tcslen(pszSrc) + 1) to hold all of |
|
the source including the null terminator |
|
|
|
pszSrc - source string which must be null terminated |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function copied any data, the result will point to the |
|
null termination character |
|
|
|
pcchRemaining - if pcchRemaining is non-null, the function will return the |
|
number of characters left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")). |
|
this flag is useful for emulating functions like lstrcpy |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any truncated |
|
string returned when the failure is |
|
STRSAFE_E_INSUFFICIENT_BUFFER |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any truncated string |
|
returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag |
|
is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc |
|
may be NULL. An error may still be returned even though NULLS are ignored |
|
due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all copied and the |
|
resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the copy |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCchCopyEx StringCchCopyExW |
|
#else |
|
#define StringCchCopyEx StringCchCopyExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
cbDest = cchDest * sizeof(char); |
|
|
|
hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
cbDest = cchDest * sizeof(wchar_t); |
|
|
|
hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbCopyEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszSrc OPTIONAL, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcbRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strcpy' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCbCopy, this routine also returns a pointer to the end of the |
|
destination string and the number of bytes left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to |
|
hold all of the source including the null terminator |
|
|
|
pszSrc - source string which must be null terminated |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function copied any data, the result will point to the |
|
null termination character |
|
|
|
pcbRemaining - pcbRemaining is non-null,the function will return the |
|
number of bytes left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")). |
|
this flag is useful for emulating functions like lstrcpy |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any truncated |
|
string returned when the failure is |
|
STRSAFE_E_INSUFFICIENT_BUFFER |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any truncated string |
|
returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag |
|
is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc |
|
may be NULL. An error may still be returned even though NULLS are ignored |
|
due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all copied and the |
|
resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the copy |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCbCopyEx StringCbCopyExW |
|
#else |
|
#define StringCbCopyEx StringCbCopyExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
*pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
*pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchCopyN( |
|
OUT LPTSTR pszDest, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszSrc, |
|
IN size_t cchSrc |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strncpy'. |
|
The size of the destination buffer (in characters) is a parameter and |
|
this function will not write past the end of this buffer and it will |
|
ALWAYS null terminate the destination buffer (unless it is zero length). |
|
|
|
This routine is meant as a replacement for strncpy, but it does behave |
|
differently. This function will not pad the destination buffer with extra |
|
null termination characters if cchSrc is greater than the length of pszSrc. |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the entire string or the first cchSrc characters were copied |
|
without truncation and the resultant destination string was null terminated, |
|
otherwise it will return a failure code. In failure cases as much of pszSrc |
|
will be copied to pszDest as possible, and pszDest will be null terminated. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be = (_tcslen(src) + 1) to hold all of the |
|
source including the null terminator |
|
|
|
pszSrc - source string |
|
|
|
cchSrc - maximum number of characters to copy from source string, |
|
not including the null terminator. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL. See StringCchCopyNEx if you require |
|
the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all copied and the |
|
resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the copy |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc); |
|
STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc); |
|
#ifdef UNICODE |
|
#define StringCchCopyN StringCchCopyNW |
|
#else |
|
#define StringCchCopyN StringCchCopyNA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc) |
|
{ |
|
HRESULT hr; |
|
|
|
if ((cchDest > STRSAFE_MAX_CCH) || |
|
(cchSrc > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc) |
|
{ |
|
HRESULT hr; |
|
|
|
if ((cchDest > STRSAFE_MAX_CCH) || |
|
(cchSrc > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbCopyN( |
|
OUT LPTSTR pszDest, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszSrc, |
|
IN size_t cbSrc |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strncpy'. |
|
The size of the destination buffer (in bytes) is a parameter and this |
|
function will not write past the end of this buffer and it will ALWAYS |
|
null terminate the destination buffer (unless it is zero length). |
|
|
|
This routine is meant as a replacement for strncpy, but it does behave |
|
differently. This function will not pad the destination buffer with extra |
|
null termination characters if cbSrc is greater than the size of pszSrc. |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the entire string or the first cbSrc characters were |
|
copied without truncation and the resultant destination string was null |
|
terminated, otherwise it will return a failure code. In failure cases as |
|
much of pszSrc will be copied to pszDest as possible, and pszDest will be |
|
null terminated. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to |
|
hold all of the source including the null terminator |
|
|
|
pszSrc - source string |
|
|
|
cbSrc - maximum number of bytes to copy from source string, |
|
not including the null terminator. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require |
|
the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all copied and the |
|
resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the copy |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc); |
|
STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc); |
|
#ifdef UNICODE |
|
#define StringCbCopyN StringCbCopyNW |
|
#else |
|
#define StringCbCopyN StringCbCopyNA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchSrc; |
|
|
|
// convert to count of characters |
|
cchDest = cbDest / sizeof(char); |
|
cchSrc = cbSrc / sizeof(char); |
|
|
|
if ((cchDest > STRSAFE_MAX_CCH) || |
|
(cchSrc > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchSrc; |
|
|
|
// convert to count of characters |
|
cchDest = cbDest / sizeof(wchar_t); |
|
cchSrc = cbSrc / sizeof(wchar_t); |
|
|
|
if ((cchDest > STRSAFE_MAX_CCH) || |
|
(cchSrc > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchCopyNEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszSrc OPTIONAL, |
|
IN size_t cchSrc, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcchRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strncpy' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCchCopyN, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination |
|
string including the null terminator. The flags parameter allows |
|
additional controls. |
|
|
|
This routine is meant as a replacement for strncpy, but it does behave |
|
differently. This function will not pad the destination buffer with extra |
|
null termination characters if cchSrc is greater than the length of pszSrc. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be = (_tcslen(pszSrc) + 1) to hold all of |
|
the source including the null terminator |
|
|
|
pszSrc - source string |
|
|
|
cchSrc - maximum number of characters to copy from the source |
|
string |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function copied any data, the result will point to the |
|
null termination character |
|
|
|
pcchRemaining - if pcchRemaining is non-null, the function will return the |
|
number of characters left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")). |
|
this flag is useful for emulating functions like lstrcpy |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any truncated |
|
string returned when the failure is |
|
STRSAFE_E_INSUFFICIENT_BUFFER |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any truncated string |
|
returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag |
|
is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc |
|
may be NULL. An error may still be returned even though NULLS are ignored |
|
due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all copied and the |
|
resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the copy |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCchCopyNEx StringCchCopyNExW |
|
#else |
|
#define StringCchCopyNEx StringCchCopyNExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if ((cchDest > STRSAFE_MAX_CCH) || |
|
(cchSrc > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
cbDest = cchDest * sizeof(char); |
|
|
|
hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if ((cchDest > STRSAFE_MAX_CCH) || |
|
(cchSrc > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
cbDest = cchDest * sizeof(wchar_t); |
|
|
|
hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbCopyNEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszSrc OPTIONAL, |
|
IN size_t cbSrc, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcbRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strncpy' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCbCopyN, this routine also returns a pointer to the end of the |
|
destination string and the number of bytes left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
This routine is meant as a replacement for strncpy, but it does behave |
|
differently. This function will not pad the destination buffer with extra |
|
null termination characters if cbSrc is greater than the size of pszSrc. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to |
|
hold all of the source including the null terminator |
|
|
|
pszSrc - source string |
|
|
|
cbSrc - maximum number of bytes to copy from source string |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function copied any data, the result will point to the |
|
null termination character |
|
|
|
pcbRemaining - pcbRemaining is non-null,the function will return the |
|
number of bytes left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")). |
|
this flag is useful for emulating functions like lstrcpy |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any truncated |
|
string returned when the failure is |
|
STRSAFE_E_INSUFFICIENT_BUFFER |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any truncated string |
|
returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag |
|
is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc |
|
may be NULL. An error may still be returned even though NULLS are ignored |
|
due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all copied and the |
|
resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the copy |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCbCopyNEx StringCbCopyNExW |
|
#else |
|
#define StringCbCopyNEx StringCbCopyNExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchSrc; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
cchSrc = cbSrc / sizeof(char); |
|
|
|
if ((cchDest > STRSAFE_MAX_CCH) || |
|
(cchSrc > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
*pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchSrc; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
cchSrc = cbSrc / sizeof(wchar_t); |
|
|
|
if ((cchDest > STRSAFE_MAX_CCH) || |
|
(cchSrc > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
*pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchCat( |
|
IN OUT LPTSTR pszDest, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszSrc |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strcat'. |
|
The size of the destination buffer (in characters) is a parameter and this |
|
function will not write past the end of this buffer and it will ALWAYS |
|
null terminate the destination buffer (unless it is zero length). |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string was concatenated without truncation and null terminated, |
|
otherwise it will return a failure code. In failure cases as much of pszSrc |
|
will be appended to pszDest as possible, and pszDest will be null |
|
terminated. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string which must be null terminated |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1) |
|
to hold all of the combine string plus the null |
|
terminator |
|
|
|
pszSrc - source string which must be null terminated |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL. See StringCchCatEx if you require |
|
the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all concatenated and |
|
the resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the operation |
|
failed due to insufficient space. When this error occurs, |
|
the destination buffer is modified to contain a truncated |
|
version of the ideal result and is null terminated. This |
|
is useful for situations where truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc); |
|
STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc); |
|
#ifdef UNICODE |
|
#define StringCchCat StringCchCatW |
|
#else |
|
#define StringCchCat StringCchCatA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCatWorkerA(pszDest, cchDest, pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCatWorkerW(pszDest, cchDest, pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbCat( |
|
IN OUT LPTSTR pszDest, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszSrc |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strcat'. |
|
The size of the destination buffer (in bytes) is a parameter and this |
|
function will not write past the end of this buffer and it will ALWAYS |
|
null terminate the destination buffer (unless it is zero length). |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string was concatenated without truncation and null terminated, |
|
otherwise it will return a failure code. In failure cases as much of pszSrc |
|
will be appended to pszDest as possible, and pszDest will be null |
|
terminated. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string which must be null terminated |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR) |
|
to hold all of the combine string plus the null |
|
terminator |
|
|
|
pszSrc - source string which must be null terminated |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL. See StringCbCatEx if you require |
|
the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all concatenated and |
|
the resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the operation |
|
failed due to insufficient space. When this error occurs, |
|
the destination buffer is modified to contain a truncated |
|
version of the ideal result and is null terminated. This |
|
is useful for situations where truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc); |
|
STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc); |
|
#ifdef UNICODE |
|
#define StringCbCat StringCbCatW |
|
#else |
|
#define StringCbCat StringCbCatA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCatWorkerA(pszDest, cchDest, pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCatWorkerW(pszDest, cchDest, pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchCatEx( |
|
IN OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszSrc OPTIONAL, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcchRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strcat' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCchCat, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string which must be null terminated |
|
|
|
cchDest - size of destination buffer in characters |
|
length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1) |
|
to hold all of the combine string plus the null |
|
terminator. |
|
|
|
pszSrc - source string which must be null terminated |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function appended any data, the result will point to the |
|
null termination character |
|
|
|
pcchRemaining - if pcchRemaining is non-null, the function will return the |
|
number of characters left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")). |
|
this flag is useful for emulating functions like lstrcat |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any pre-existing |
|
or truncated string |
|
|
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any pre-existing or |
|
truncated string |
|
|
|
STRSAFE_NO_TRUNCATION |
|
if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest |
|
will not contain a truncated string, it will remain unchanged. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag |
|
is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc |
|
may be NULL. An error may still be returned even though NULLS are ignored |
|
due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all concatenated and |
|
the resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the operation |
|
failed due to insufficient space. When this error |
|
occurs, the destination buffer is modified to contain |
|
a truncated version of the ideal result and is null |
|
terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCchCatEx StringCchCatExW |
|
#else |
|
#define StringCchCatEx StringCchCatExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
cbDest = cchDest * sizeof(char); |
|
|
|
hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
cbDest = cchDest * sizeof(wchar_t); |
|
|
|
hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbCatEx( |
|
IN OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszSrc OPTIONAL, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcbRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strcat' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCbCat, this routine also returns a pointer to the end of the |
|
destination string and the number of bytes left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string which must be null terminated |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR) |
|
to hold all of the combine string plus the null |
|
terminator. |
|
|
|
pszSrc - source string which must be null terminated |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function appended any data, the result will point to the |
|
null termination character |
|
|
|
pcbRemaining - if pcbRemaining is non-null, the function will return |
|
the number of bytes left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")). |
|
this flag is useful for emulating functions like lstrcat |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any pre-existing |
|
or truncated string |
|
|
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any pre-existing or |
|
truncated string |
|
|
|
STRSAFE_NO_TRUNCATION |
|
if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest |
|
will not contain a truncated string, it will remain unchanged. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag |
|
is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc |
|
may be NULL. An error may still be returned even though NULLS are ignored |
|
due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all concatenated |
|
and the resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the operation |
|
failed due to insufficient space. When this error |
|
occurs, the destination buffer is modified to contain |
|
a truncated version of the ideal result and is null |
|
terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCbCatEx StringCbCatExW |
|
#else |
|
#define StringCbCatEx StringCbCatExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
*pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
*pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchCatN( |
|
IN OUT LPTSTR pszDest, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszSrc, |
|
IN size_t cchMaxAppend |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strncat'. |
|
The size of the destination buffer (in characters) is a parameter as well as |
|
the maximum number of characters to append, excluding the null terminator. |
|
This function will not write past the end of the destination buffer and it will |
|
ALWAYS null terminate pszDest (unless it is zero length). |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if all of pszSrc or the first cchMaxAppend characters were appended |
|
to the destination string and it was null terminated, otherwise it will |
|
return a failure code. In failure cases as much of pszSrc will be appended |
|
to pszDest as possible, and pszDest will be null terminated. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string which must be null terminated |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1) |
|
to hold all of the combine string plus the null |
|
terminator. |
|
|
|
pszSrc - source string |
|
|
|
cchMaxAppend - maximum number of characters to append |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL. See StringCchCatNEx if you require |
|
the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if all of pszSrc or the first cchMaxAppend characters |
|
were concatenated to pszDest and the resultant dest |
|
string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the operation |
|
failed due to insufficient space. When this error |
|
occurs, the destination buffer is modified to contain |
|
a truncated version of the ideal result and is null |
|
terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend); |
|
STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend); |
|
#ifdef UNICODE |
|
#define StringCchCatN StringCchCatNW |
|
#else |
|
#define StringCchCatN StringCchCatNA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbCatN( |
|
IN OUT LPTSTR pszDest, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszSrc, |
|
IN size_t cbMaxAppend |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strncat'. |
|
The size of the destination buffer (in bytes) is a parameter as well as |
|
the maximum number of bytes to append, excluding the null terminator. |
|
This function will not write past the end of the destination buffer and it will |
|
ALWAYS null terminate pszDest (unless it is zero length). |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if all of pszSrc or the first cbMaxAppend bytes were appended |
|
to the destination string and it was null terminated, otherwise it will |
|
return a failure code. In failure cases as much of pszSrc will be appended |
|
to pszDest as possible, and pszDest will be null terminated. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string which must be null terminated |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR) |
|
to hold all of the combine string plus the null |
|
terminator. |
|
|
|
pszSrc - source string |
|
|
|
cbMaxAppend - maximum number of bytes to append |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL. See StringCbCatNEx if you require |
|
the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if all of pszSrc or the first cbMaxAppend bytes were |
|
concatenated to pszDest and the resultant dest string |
|
was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the operation |
|
failed due to insufficient space. When this error |
|
occurs, the destination buffer is modified to contain |
|
a truncated version of the ideal result and is null |
|
terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend); |
|
STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend); |
|
#ifdef UNICODE |
|
#define StringCbCatN StringCbCatNW |
|
#else |
|
#define StringCbCatN StringCbCatNA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cchMaxAppend; |
|
|
|
cchMaxAppend = cbMaxAppend / sizeof(char); |
|
|
|
hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cchMaxAppend; |
|
|
|
cchMaxAppend = cbMaxAppend / sizeof(wchar_t); |
|
|
|
hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchCatNEx( |
|
IN OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszSrc OPTIONAL, |
|
IN size_t cchMaxAppend, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcchRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strncat', with |
|
some additional parameters. In addition to functionality provided by |
|
StringCchCatN, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string which must be null terminated |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1) |
|
to hold all of the combine string plus the null |
|
terminator. |
|
|
|
pszSrc - source string |
|
|
|
cchMaxAppend - maximum number of characters to append |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function appended any data, the result will point to the |
|
null termination character |
|
|
|
pcchRemaining - if pcchRemaining is non-null, the function will return the |
|
number of characters left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")) |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any pre-existing |
|
or truncated string |
|
|
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any pre-existing or |
|
truncated string |
|
|
|
STRSAFE_NO_TRUNCATION |
|
if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest |
|
will not contain a truncated string, it will remain unchanged. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag |
|
is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc |
|
may be NULL. An error may still be returned even though NULLS are ignored |
|
due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if all of pszSrc or the first cchMaxAppend characters |
|
were concatenated to pszDest and the resultant dest |
|
string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the operation |
|
failed due to insufficient space. When this error |
|
occurs, the destination buffer is modified to contain |
|
a truncated version of the ideal result and is null |
|
terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCchCatNEx StringCchCatNExW |
|
#else |
|
#define StringCchCatNEx StringCchCatNExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
cbDest = cchDest * sizeof(char); |
|
|
|
hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
cbDest = cchDest * sizeof(wchar_t); |
|
|
|
hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbCatNEx( |
|
IN OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszSrc OPTIONAL, |
|
IN size_t cbMaxAppend, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcchRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strncat', with |
|
some additional parameters. In addition to functionality provided by |
|
StringCbCatN, this routine also returns a pointer to the end of the |
|
destination string and the number of bytes left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string which must be null terminated |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR) |
|
to hold all of the combine string plus the null |
|
terminator. |
|
|
|
pszSrc - source string |
|
|
|
cbMaxAppend - maximum number of bytes to append |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function appended any data, the result will point to the |
|
null termination character |
|
|
|
pcbRemaining - if pcbRemaining is non-null, the function will return the |
|
number of bytes left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")) |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any pre-existing |
|
or truncated string |
|
|
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any pre-existing or |
|
truncated string |
|
|
|
STRSAFE_NO_TRUNCATION |
|
if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest |
|
will not contain a truncated string, it will remain unchanged. |
|
|
|
Notes: |
|
Behavior is undefined if source and destination strings overlap. |
|
|
|
pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag |
|
is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc |
|
may be NULL. An error may still be returned even though NULLS are ignored |
|
due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if all of pszSrc or the first cbMaxAppend bytes were |
|
concatenated to pszDest and the resultant dest string |
|
was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the operation |
|
failed due to insufficient space. When this error |
|
occurs, the destination buffer is modified to contain |
|
a truncated version of the ideal result and is null |
|
terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCbCatNEx StringCbCatNExW |
|
#else |
|
#define StringCbCatNEx StringCbCatNExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cchMaxAppend; |
|
|
|
cchMaxAppend = cbMaxAppend / sizeof(char); |
|
|
|
hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
*pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cchMaxAppend; |
|
|
|
cchMaxAppend = cbMaxAppend / sizeof(wchar_t); |
|
|
|
hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
*pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchVPrintf( |
|
OUT LPTSTR pszDest, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszFormat, |
|
IN va_list argList |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'vsprintf'. |
|
The size of the destination buffer (in characters) is a parameter and |
|
this function will not write past the end of this buffer and it will |
|
ALWAYS null terminate the destination buffer (unless it is zero length). |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string was printed without truncation and null terminated, |
|
otherwise it will return a failure code. In failure cases it will return |
|
a truncated version of the ideal result. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters |
|
length must be sufficient to hold the resulting formatted |
|
string, including the null terminator. |
|
|
|
pszFormat - format string which must be null terminated |
|
|
|
argList - va_list from the variable arguments according to the |
|
stdarg.h convention |
|
|
|
Notes: |
|
Behavior is undefined if destination, format strings or any arguments |
|
strings overlap. |
|
|
|
pszDest and pszFormat should not be NULL. See StringCchVPrintfEx if you |
|
require the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was sufficient space in the dest buffer for |
|
the resultant string and it was null terminated. |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the print |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList); |
|
STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList); |
|
#ifdef UNICODE |
|
#define StringCchVPrintf StringCchVPrintfW |
|
#else |
|
#define StringCchVPrintf StringCchVPrintfA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbVPrintf( |
|
OUT LPTSTR pszDest, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszFormat, |
|
IN va_list argList |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'vsprintf'. |
|
The size of the destination buffer (in bytes) is a parameter and |
|
this function will not write past the end of this buffer and it will |
|
ALWAYS null terminate the destination buffer (unless it is zero length). |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string was printed without truncation and null terminated, |
|
otherwise it will return a failure code. In failure cases it will return |
|
a truncated version of the ideal result. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes |
|
length must be sufficient to hold the resulting formatted |
|
string, including the null terminator. |
|
|
|
pszFormat - format string which must be null terminated |
|
|
|
argList - va_list from the variable arguments according to the |
|
stdarg.h convention |
|
|
|
Notes: |
|
Behavior is undefined if destination, format strings or any arguments |
|
strings overlap. |
|
|
|
pszDest and pszFormat should not be NULL. See StringCbVPrintfEx if you |
|
require the handling of NULL values. |
|
|
|
|
|
Return Value: |
|
|
|
S_OK - if there was sufficient space in the dest buffer for |
|
the resultant string and it was null terminated. |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the print |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList); |
|
STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList); |
|
#ifdef UNICODE |
|
#define StringCbVPrintf StringCbVPrintfW |
|
#else |
|
#define StringCbVPrintf StringCbVPrintfA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchPrintf( |
|
OUT LPTSTR pszDest, |
|
IN size_t cchDest, |
|
IN LPCTSTR pszFormat, |
|
... |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'sprintf'. |
|
The size of the destination buffer (in characters) is a parameter and |
|
this function will not write past the end of this buffer and it will |
|
ALWAYS null terminate the destination buffer (unless it is zero length). |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string was printed without truncation and null terminated, |
|
otherwise it will return a failure code. In failure cases it will return |
|
a truncated version of the ideal result. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters |
|
length must be sufficient to hold the resulting formatted |
|
string, including the null terminator. |
|
|
|
pszFormat - format string which must be null terminated |
|
|
|
... - additional parameters to be formatted according to |
|
the format string |
|
|
|
Notes: |
|
Behavior is undefined if destination, format strings or any arguments |
|
strings overlap. |
|
|
|
pszDest and pszFormat should not be NULL. See StringCchPrintfEx if you |
|
require the handling of NULL values. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was sufficient space in the dest buffer for |
|
the resultant string and it was null terminated. |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the print |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...); |
|
STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...); |
|
#ifdef UNICODE |
|
#define StringCchPrintf StringCchPrintfW |
|
#else |
|
#define StringCchPrintf StringCchPrintfA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
va_list argList; |
|
|
|
va_start(argList, pszFormat); |
|
|
|
hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList); |
|
|
|
va_end(argList); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
va_list argList; |
|
|
|
va_start(argList, pszFormat); |
|
|
|
hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList); |
|
|
|
va_end(argList); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbPrintf( |
|
OUT LPTSTR pszDest, |
|
IN size_t cbDest, |
|
IN LPCTSTR pszFormat, |
|
... |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'sprintf'. |
|
The size of the destination buffer (in bytes) is a parameter and |
|
this function will not write past the end of this buffer and it will |
|
ALWAYS null terminate the destination buffer (unless it is zero length). |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string was printed without truncation and null terminated, |
|
otherwise it will return a failure code. In failure cases it will return |
|
a truncated version of the ideal result. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes |
|
length must be sufficient to hold the resulting formatted |
|
string, including the null terminator. |
|
|
|
pszFormat - format string which must be null terminated |
|
|
|
... - additional parameters to be formatted according to |
|
the format string |
|
|
|
Notes: |
|
Behavior is undefined if destination, format strings or any arguments |
|
strings overlap. |
|
|
|
pszDest and pszFormat should not be NULL. See StringCbPrintfEx if you |
|
require the handling of NULL values. |
|
|
|
|
|
Return Value: |
|
|
|
S_OK - if there was sufficient space in the dest buffer for |
|
the resultant string and it was null terminated. |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the print |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...); |
|
STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...); |
|
#ifdef UNICODE |
|
#define StringCbPrintf StringCbPrintfW |
|
#else |
|
#define StringCbPrintf StringCbPrintfA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
va_list argList; |
|
|
|
va_start(argList, pszFormat); |
|
|
|
hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList); |
|
|
|
va_end(argList); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
va_list argList; |
|
|
|
va_start(argList, pszFormat); |
|
|
|
hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList); |
|
|
|
va_end(argList); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchPrintfEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cchDest, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcchRemaining OPTIONAL, |
|
IN DWORD dwFlags, |
|
IN LPCTSTR pszFormat OPTIONAL, |
|
... |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'sprintf' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCchPrintf, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be sufficient to contain the resulting |
|
formatted string plus the null terminator. |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function printed any data, the result will point to the |
|
null termination character |
|
|
|
pcchRemaining - if pcchRemaining is non-null, the function will return |
|
the number of characters left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")) |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any truncated |
|
string returned when the failure is |
|
STRSAFE_E_INSUFFICIENT_BUFFER |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any truncated string |
|
returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. |
|
|
|
pszFormat - format string which must be null terminated |
|
|
|
... - additional parameters to be formatted according to |
|
the format string |
|
|
|
Notes: |
|
Behavior is undefined if destination, format strings or any arguments |
|
strings overlap. |
|
|
|
pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS |
|
flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and |
|
pszFormat may be NULL. An error may still be returned even though NULLS |
|
are ignored due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all concatenated and |
|
the resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the print |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...); |
|
STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...); |
|
#ifdef UNICODE |
|
#define StringCchPrintfEx StringCchPrintfExW |
|
#else |
|
#define StringCchPrintfEx StringCchPrintfExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
va_list argList; |
|
|
|
// safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
cbDest = cchDest * sizeof(char); |
|
va_start(argList, pszFormat); |
|
|
|
hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList); |
|
|
|
va_end(argList); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
va_list argList; |
|
|
|
// safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
cbDest = cchDest * sizeof(wchar_t); |
|
va_start(argList, pszFormat); |
|
|
|
hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList); |
|
|
|
va_end(argList); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbPrintfEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cbDest, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcbRemaining OPTIONAL, |
|
IN DWORD dwFlags, |
|
IN LPCTSTR pszFormat OPTIONAL, |
|
... |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'sprintf' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCbPrintf, this routine also returns a pointer to the end of the |
|
destination string and the number of bytes left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be sufficient to contain the resulting |
|
formatted string plus the null terminator. |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function printed any data, the result will point to the |
|
null termination character |
|
|
|
pcbRemaining - if pcbRemaining is non-null, the function will return |
|
the number of bytes left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")) |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any truncated |
|
string returned when the failure is |
|
STRSAFE_E_INSUFFICIENT_BUFFER |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any truncated string |
|
returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. |
|
|
|
pszFormat - format string which must be null terminated |
|
|
|
... - additional parameters to be formatted according to |
|
the format string |
|
|
|
Notes: |
|
Behavior is undefined if destination, format strings or any arguments |
|
strings overlap. |
|
|
|
pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS |
|
flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and |
|
pszFormat may be NULL. An error may still be returned even though NULLS |
|
are ignored due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all concatenated and |
|
the resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the print |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...); |
|
STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...); |
|
#ifdef UNICODE |
|
#define StringCbPrintfEx StringCbPrintfExW |
|
#else |
|
#define StringCbPrintfEx StringCbPrintfExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
va_list argList; |
|
|
|
va_start(argList, pszFormat); |
|
|
|
hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList); |
|
|
|
va_end(argList); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
*pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
va_list argList; |
|
|
|
va_start(argList, pszFormat); |
|
|
|
hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList); |
|
|
|
va_end(argList); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
*pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchVPrintfEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cchDest, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcchRemaining OPTIONAL, |
|
IN DWORD dwFlags, |
|
IN LPCTSTR pszFormat OPTIONAL, |
|
IN va_list argList |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'vsprintf' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCchVPrintf, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters. |
|
length must be sufficient to contain the resulting |
|
formatted string plus the null terminator. |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function printed any data, the result will point to the |
|
null termination character |
|
|
|
pcchRemaining - if pcchRemaining is non-null, the function will return |
|
the number of characters left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")) |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any truncated |
|
string returned when the failure is |
|
STRSAFE_E_INSUFFICIENT_BUFFER |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any truncated string |
|
returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. |
|
|
|
pszFormat - format string which must be null terminated |
|
|
|
argList - va_list from the variable arguments according to the |
|
stdarg.h convention |
|
|
|
Notes: |
|
Behavior is undefined if destination, format strings or any arguments |
|
strings overlap. |
|
|
|
pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS |
|
flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and |
|
pszFormat may be NULL. An error may still be returned even though NULLS |
|
are ignored due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all concatenated and |
|
the resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the print |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList); |
|
STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList); |
|
#ifdef UNICODE |
|
#define StringCchVPrintfEx StringCchVPrintfExW |
|
#else |
|
#define StringCchVPrintfEx StringCchVPrintfExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
cbDest = cchDest * sizeof(char); |
|
|
|
hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
cbDest = cchDest * sizeof(wchar_t); |
|
|
|
hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbVPrintfEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cbDest, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcbRemaining OPTIONAL, |
|
IN DWORD dwFlags, |
|
IN LPCTSTR pszFormat OPTIONAL, |
|
IN va_list argList |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'vsprintf' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCbVPrintf, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes. |
|
length must be sufficient to contain the resulting |
|
formatted string plus the null terminator. |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return |
|
a pointer to the end of the destination string. If the |
|
function printed any data, the result will point to the |
|
null termination character |
|
|
|
pcbRemaining - if pcbRemaining is non-null, the function will return |
|
the number of bytes left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")) |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. This will overwrite any truncated |
|
string returned when the failure is |
|
STRSAFE_E_INSUFFICIENT_BUFFER |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. This will overwrite any truncated string |
|
returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER. |
|
|
|
pszFormat - format string which must be null terminated |
|
|
|
argList - va_list from the variable arguments according to the |
|
stdarg.h convention |
|
|
|
Notes: |
|
Behavior is undefined if destination, format strings or any arguments |
|
strings overlap. |
|
|
|
pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS |
|
flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and |
|
pszFormat may be NULL. An error may still be returned even though NULLS |
|
are ignored due to insufficient space. |
|
|
|
Return Value: |
|
|
|
S_OK - if there was source data and it was all concatenated and |
|
the resultant dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that the print |
|
operation failed due to insufficient space. When this |
|
error occurs, the destination buffer is modified to |
|
contain a truncated version of the ideal result and is |
|
null terminated. This is useful for situations where |
|
truncation is ok. |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList); |
|
STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList); |
|
#ifdef UNICODE |
|
#define StringCbVPrintfEx StringCbVPrintfExW |
|
#else |
|
#define StringCbVPrintfEx StringCbVPrintfExA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
*pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList); |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
*pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchGets( |
|
OUT LPTSTR pszDest, |
|
IN size_t cchDest |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'gets'. |
|
The size of the destination buffer (in characters) is a parameter and |
|
this function will not write past the end of this buffer and it will |
|
ALWAYS null terminate the destination buffer (unless it is zero length). |
|
|
|
This routine is not a replacement for fgets. That function does not replace |
|
newline characters with a null terminator. |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if any characters were read from stdin and copied to pszDest and |
|
pszDest was null terminated, otherwise it will return a failure code. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters. |
|
|
|
Notes: |
|
pszDest should not be NULL. See StringCchGetsEx if you require the handling |
|
of NULL values. |
|
|
|
cchDest must be > 1 for this function to succeed. |
|
|
|
Return Value: |
|
|
|
S_OK - data was read from stdin and copied, and the resultant |
|
dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_END_OF_FILE / |
|
HRESULT_CODE(hr) == ERROR_HANDLE_EOF |
|
- this return value indicates an error or end-of-file |
|
condition, use feof or ferror to determine which one has |
|
occured. |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that there was |
|
insufficient space in the destination buffer to copy any |
|
data |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
#ifndef STRSAFE_LIB_IMPL |
|
STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest); |
|
STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest); |
|
#ifdef UNICODE |
|
#define StringCchGets StringCchGetsW |
|
#else |
|
#define StringCchGets StringCchGetsA |
|
#endif // !UNICODE |
|
|
|
STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
cbDest = cchDest * sizeof(char); |
|
|
|
hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
cbDest = cchDest * sizeof(wchar_t); |
|
|
|
hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
#endif // !STRSAFE_LIB_IMPL |
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbGets( |
|
OUT LPTSTR pszDest, |
|
IN size_t cbDest |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'gets'. |
|
The size of the destination buffer (in bytes) is a parameter and |
|
this function will not write past the end of this buffer and it will |
|
ALWAYS null terminate the destination buffer (unless it is zero length). |
|
|
|
This routine is not a replacement for fgets. That function does not replace |
|
newline characters with a null terminator. |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if any characters were read from stdin and copied to pszDest |
|
and pszDest was null terminated, otherwise it will return a failure code. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes. |
|
|
|
Notes: |
|
pszDest should not be NULL. See StringCbGetsEx if you require the handling |
|
of NULL values. |
|
|
|
cbDest must be > sizeof(TCHAR) for this function to succeed. |
|
|
|
Return Value: |
|
|
|
S_OK - data was read from stdin and copied, and the resultant |
|
dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_END_OF_FILE / |
|
HRESULT_CODE(hr) == ERROR_HANDLE_EOF |
|
- this return value indicates an error or end-of-file |
|
condition, use feof or ferror to determine which one has |
|
occured. |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that there was |
|
insufficient space in the destination buffer to copy any |
|
data |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
#ifndef STRSAFE_LIB_IMPL |
|
STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest); |
|
STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest); |
|
#ifdef UNICODE |
|
#define StringCbGets StringCbGetsW |
|
#else |
|
#define StringCbGets StringCbGetsA |
|
#endif // !UNICODE |
|
|
|
STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
// convert to count of characters |
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
|
|
// convert to count of characters |
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
#endif // !STRSAFE_LIB_IMPL |
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchGetsEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cchDest, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcchRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'gets' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCchGets, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cchDest - size of destination buffer in characters. |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function copied any data, the result will point to the |
|
null termination character |
|
|
|
pcchRemaining - if pcchRemaining is non-null, the function will return the |
|
number of characters left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")). |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. |
|
|
|
Notes: |
|
pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified. |
|
If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be |
|
returned even though NULLS are ignored |
|
|
|
cchDest must be > 1 for this function to succeed. |
|
|
|
Return Value: |
|
|
|
S_OK - data was read from stdin and copied, and the resultant |
|
dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_END_OF_FILE / |
|
HRESULT_CODE(hr) == ERROR_HANDLE_EOF |
|
- this return value indicates an error or end-of-file |
|
condition, use feof or ferror to determine which one has |
|
occured. |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that there was |
|
insufficient space in the destination buffer to copy any |
|
data |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
#ifndef STRSAFE_LIB_IMPL |
|
STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCchGetsEx StringCchGetsExW |
|
#else |
|
#define StringCchGetsEx StringCchGetsExA |
|
#endif // !UNICODE |
|
|
|
STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
cbDest = cchDest * sizeof(char); |
|
|
|
hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cbDest; |
|
|
|
// safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
cbDest = cchDest * sizeof(wchar_t); |
|
|
|
hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
#endif // !STRSAFE_LIB_IMPL |
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbGetsEx( |
|
OUT LPTSTR pszDest OPTIONAL, |
|
IN size_t cbDest, |
|
OUT LPTSTR* ppszDestEnd OPTIONAL, |
|
OUT size_t* pcbRemaining OPTIONAL, |
|
IN DWORD dwFlags |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'gets' with |
|
some additional parameters. In addition to functionality provided by |
|
StringCbGets, this routine also returns a pointer to the end of the |
|
destination string and the number of characters left in the destination string |
|
including the null terminator. The flags parameter allows additional controls. |
|
|
|
Arguments: |
|
|
|
pszDest - destination string |
|
|
|
cbDest - size of destination buffer in bytes. |
|
|
|
ppszDestEnd - if ppszDestEnd is non-null, the function will return a |
|
pointer to the end of the destination string. If the |
|
function copied any data, the result will point to the |
|
null termination character |
|
|
|
pcbRemaining - if pbRemaining is non-null, the function will return the |
|
number of bytes left in the destination string, |
|
including the null terminator |
|
|
|
dwFlags - controls some details of the string copy: |
|
|
|
STRSAFE_FILL_BEHIND_NULL |
|
if the function succeeds, the low byte of dwFlags will be |
|
used to fill the uninitialize part of destination buffer |
|
behind the null terminator |
|
|
|
STRSAFE_IGNORE_NULLS |
|
treat NULL string pointers like empty strings (TEXT("")). |
|
|
|
STRSAFE_FILL_ON_FAILURE |
|
if the function fails, the low byte of dwFlags will be |
|
used to fill all of the destination buffer, and it will |
|
be null terminated. |
|
|
|
STRSAFE_NO_TRUNCATION / |
|
STRSAFE_NULL_ON_FAILURE |
|
if the function fails, the destination buffer will be set |
|
to the empty string. |
|
|
|
Notes: |
|
pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified. |
|
If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be |
|
returned even though NULLS are ignored |
|
|
|
cbDest must be > sizeof(TCHAR) for this function to succeed |
|
|
|
Return Value: |
|
|
|
S_OK - data was read from stdin and copied, and the resultant |
|
dest string was null terminated |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
STRSAFE_E_END_OF_FILE / |
|
HRESULT_CODE(hr) == ERROR_HANDLE_EOF |
|
- this return value indicates an error or end-of-file |
|
condition, use feof or ferror to determine which one has |
|
occured. |
|
|
|
STRSAFE_E_INSUFFICIENT_BUFFER / |
|
HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER |
|
- this return value is an indication that there was |
|
insufficient space in the destination buffer to copy any |
|
data |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
#ifndef STRSAFE_LIB_IMPL |
|
STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pbRemaining, unsigned long dwFlags); |
|
STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags); |
|
#ifdef UNICODE |
|
#define StringCbGetsEx StringCbGetsExW |
|
#else |
|
#define StringCbGetsEx StringCbGetsExA |
|
#endif // !UNICODE |
|
|
|
STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(char); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || |
|
(hr == STRSAFE_E_INSUFFICIENT_BUFFER) || |
|
(hr == STRSAFE_E_END_OF_FILE)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
*pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr; |
|
size_t cchDest; |
|
size_t cchRemaining = 0; |
|
|
|
cchDest = cbDest / sizeof(wchar_t); |
|
|
|
if (cchDest > STRSAFE_MAX_CCH) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags); |
|
} |
|
|
|
if (SUCCEEDED(hr) || |
|
(hr == STRSAFE_E_INSUFFICIENT_BUFFER) || |
|
(hr == STRSAFE_E_END_OF_FILE)) |
|
{ |
|
if (pcbRemaining) |
|
{ |
|
// safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
*pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)); |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
#endif // !STRSAFE_LIB_IMPL |
|
|
|
#ifndef STRSAFE_NO_CCH_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCchLength( |
|
IN LPCTSTR psz, |
|
IN size_t cchMax, |
|
OUT size_t* pcch OPTIONAL |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strlen'. |
|
It is used to make sure a string is not larger than a given length, and |
|
it optionally returns the current length in characters not including |
|
the null terminator. |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string is non-null and the length including the null |
|
terminator is less than or equal to cchMax characters. |
|
|
|
Arguments: |
|
|
|
psz - string to check the length of |
|
|
|
cchMax - maximum number of characters including the null terminator |
|
that psz is allowed to contain |
|
|
|
pcch - if the function succeeds and pcch is non-null, the current length |
|
in characters of psz excluding the null terminator will be returned. |
|
This out parameter is equivalent to the return value of strlen(psz) |
|
|
|
Notes: |
|
psz can be null but the function will fail |
|
|
|
cchMax should be greater than zero or the function will fail |
|
|
|
Return Value: |
|
|
|
S_OK - psz is non-null and the length including the null |
|
terminator is less than or equal to cchMax characters |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch); |
|
STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch); |
|
#ifdef UNICODE |
|
#define StringCchLength StringCchLengthW |
|
#else |
|
#define StringCchLength StringCchLengthA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch) |
|
{ |
|
HRESULT hr; |
|
|
|
if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerA(psz, cchMax, pcch); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch) |
|
{ |
|
HRESULT hr; |
|
|
|
if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerW(psz, cchMax, pcch); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CCH_FUNCTIONS |
|
|
|
|
|
#ifndef STRSAFE_NO_CB_FUNCTIONS |
|
/*++ |
|
|
|
STDAPI |
|
StringCbLength( |
|
IN LPCTSTR psz, |
|
IN size_t cbMax, |
|
OUT size_t* pcb OPTIONAL |
|
); |
|
|
|
Routine Description: |
|
|
|
This routine is a safer version of the C built-in function 'strlen'. |
|
It is used to make sure a string is not larger than a given length, and |
|
it optionally returns the current length in bytes not including |
|
the null terminator. |
|
|
|
This function returns a hresult, and not a pointer. It returns |
|
S_OK if the string is non-null and the length including the null |
|
terminator is less than or equal to cbMax bytes. |
|
|
|
Arguments: |
|
|
|
psz - string to check the length of |
|
|
|
cbMax - maximum number of bytes including the null terminator |
|
that psz is allowed to contain |
|
|
|
pcb - if the function succeeds and pcb is non-null, the current length |
|
in bytes of psz excluding the null terminator will be returned. |
|
This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR) |
|
|
|
Notes: |
|
psz can be null but the function will fail |
|
|
|
cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail |
|
|
|
Return Value: |
|
|
|
S_OK - psz is non-null and the length including the null |
|
terminator is less than or equal to cbMax bytes |
|
|
|
failure - you can use the macro HRESULT_CODE() to get a win32 |
|
error code for all hresult failure cases |
|
|
|
It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the |
|
return value of this function. |
|
|
|
--*/ |
|
|
|
STRSAFEAPI StringCbLengthA(const char* psz, size_t cchMax, size_t* pcch); |
|
STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch); |
|
#ifdef UNICODE |
|
#define StringCbLength StringCbLengthW |
|
#else |
|
#define StringCbLength StringCbLengthA |
|
#endif // !UNICODE |
|
|
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCbLengthA(const char* psz, size_t cbMax, size_t* pcb) |
|
{ |
|
HRESULT hr; |
|
size_t cchMax; |
|
size_t cch = 0; |
|
|
|
cchMax = cbMax / sizeof(char); |
|
|
|
if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerA(psz, cchMax, &cch); |
|
} |
|
|
|
if (SUCCEEDED(hr) && pcb) |
|
{ |
|
// safe to multiply cch * sizeof(char) since cch < STRSAFE_MAX_CCH and sizeof(char) is 1 |
|
*pcb = cch * sizeof(char); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cbMax, size_t* pcb) |
|
{ |
|
HRESULT hr; |
|
size_t cchMax; |
|
size_t cch = 0; |
|
|
|
cchMax = cbMax / sizeof(wchar_t); |
|
|
|
if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerW(psz, cchMax, &cch); |
|
} |
|
|
|
if (SUCCEEDED(hr) && pcb) |
|
{ |
|
// safe to multiply cch * sizeof(wchar_t) since cch < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2 |
|
*pcb = cch * sizeof(wchar_t); |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
#endif // !STRSAFE_NO_CB_FUNCTIONS |
|
|
|
|
|
// these are the worker functions that actually do the work |
|
#ifdef STRSAFE_INLINE |
|
STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
if (cchDest == 0) |
|
{ |
|
// can not null terminate a zero-byte dest buffer |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
while (cchDest && (*pszSrc != '\0')) |
|
{ |
|
*pszDest++ = *pszSrc++; |
|
cchDest--; |
|
} |
|
|
|
if (cchDest == 0) |
|
{ |
|
// we are going to truncate pszDest |
|
pszDest--; |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
|
|
*pszDest= '\0'; |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
if (cchDest == 0) |
|
{ |
|
// can not null terminate a zero-byte dest buffer |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
while (cchDest && (*pszSrc != L'\0')) |
|
{ |
|
*pszDest++ = *pszSrc++; |
|
cchDest--; |
|
} |
|
|
|
if (cchDest == 0) |
|
{ |
|
// we are going to truncate pszDest |
|
pszDest--; |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
|
|
*pszDest= L'\0'; |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
char* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(char)) || |
|
// cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest != 0) || (cbDest != 0)) |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
|
|
if (pszSrc == NULL) |
|
{ |
|
pszSrc = ""; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = 0; |
|
|
|
// only fail if there was actually src data to copy |
|
if (*pszSrc != '\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
while (cchRemaining && (*pszSrc != '\0')) |
|
{ |
|
*pszDestEnd++= *pszSrc++; |
|
cchRemaining--; |
|
} |
|
|
|
if (cchRemaining > 0) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_BEHIND_NULL) |
|
{ |
|
memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char))); |
|
} |
|
} |
|
else |
|
{ |
|
// we are going to truncate pszDest |
|
pszDestEnd--; |
|
cchRemaining++; |
|
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
|
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
wchar_t* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || |
|
// cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest != 0) || (cbDest != 0)) |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
|
|
if (pszSrc == NULL) |
|
{ |
|
pszSrc = L""; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = 0; |
|
|
|
// only fail if there was actually src data to copy |
|
if (*pszSrc != L'\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
while (cchRemaining && (*pszSrc != L'\0')) |
|
{ |
|
*pszDestEnd++= *pszSrc++; |
|
cchRemaining--; |
|
} |
|
|
|
if (cchRemaining > 0) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_BEHIND_NULL) |
|
{ |
|
memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
} |
|
} |
|
else |
|
{ |
|
// we are going to truncate pszDest |
|
pszDestEnd--; |
|
cchRemaining++; |
|
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
|
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
if (cchDest == 0) |
|
{ |
|
// can not null terminate a zero-byte dest buffer |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
while (cchDest && cchSrc && (*pszSrc != '\0')) |
|
{ |
|
*pszDest++= *pszSrc++; |
|
cchDest--; |
|
cchSrc--; |
|
} |
|
|
|
if (cchDest == 0) |
|
{ |
|
// we are going to truncate pszDest |
|
pszDest--; |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
|
|
*pszDest= '\0'; |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
if (cchDest == 0) |
|
{ |
|
// can not null terminate a zero-byte dest buffer |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
while (cchDest && cchSrc && (*pszSrc != L'\0')) |
|
{ |
|
*pszDest++= *pszSrc++; |
|
cchDest--; |
|
cchSrc--; |
|
} |
|
|
|
if (cchDest == 0) |
|
{ |
|
// we are going to truncate pszDest |
|
pszDest--; |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
|
|
*pszDest= L'\0'; |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
char* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(char)) || |
|
// cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest != 0) || (cbDest != 0)) |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
|
|
if (pszSrc == NULL) |
|
{ |
|
pszSrc = ""; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = 0; |
|
|
|
// only fail if there was actually src data to copy |
|
if (*pszSrc != '\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
while (cchRemaining && cchSrc && (*pszSrc != '\0')) |
|
{ |
|
*pszDestEnd++= *pszSrc++; |
|
cchRemaining--; |
|
cchSrc--; |
|
} |
|
|
|
if (cchRemaining > 0) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_BEHIND_NULL) |
|
{ |
|
memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char))); |
|
} |
|
} |
|
else |
|
{ |
|
// we are going to truncate pszDest |
|
pszDestEnd--; |
|
cchRemaining++; |
|
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
|
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
wchar_t* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || |
|
// cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest != 0) || (cbDest != 0)) |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
|
|
if (pszSrc == NULL) |
|
{ |
|
pszSrc = L""; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = 0; |
|
|
|
// only fail if there was actually src data to copy |
|
if (*pszSrc != L'\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
while (cchRemaining && cchSrc && (*pszSrc != L'\0')) |
|
{ |
|
*pszDestEnd++= *pszSrc++; |
|
cchRemaining--; |
|
cchSrc--; |
|
} |
|
|
|
if (cchRemaining > 0) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_BEHIND_NULL) |
|
{ |
|
memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
} |
|
} |
|
else |
|
{ |
|
// we are going to truncate pszDest |
|
pszDestEnd--; |
|
cchRemaining++; |
|
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
|
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc) |
|
{ |
|
HRESULT hr; |
|
size_t cchDestCurrent; |
|
|
|
hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
hr = StringCopyWorkerA(pszDest + cchDestCurrent, |
|
cchDest - cchDestCurrent, |
|
pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc) |
|
{ |
|
HRESULT hr; |
|
size_t cchDestCurrent; |
|
|
|
hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
hr = StringCopyWorkerW(pszDest + cchDestCurrent, |
|
cchDest - cchDestCurrent, |
|
pszSrc); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
char* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(char)) || |
|
// cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cchDestCurrent; |
|
|
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest == 0) && (cbDest == 0)) |
|
{ |
|
cchDestCurrent = 0; |
|
} |
|
else |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
pszDestEnd = pszDest + cchDestCurrent; |
|
cchRemaining = cchDest - cchDestCurrent; |
|
} |
|
} |
|
|
|
if (pszSrc == NULL) |
|
{ |
|
pszSrc = ""; |
|
} |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
pszDestEnd = pszDest + cchDestCurrent; |
|
cchRemaining = cchDest - cchDestCurrent; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
// only fail if there was actually src data to append |
|
if (*pszSrc != '\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass |
|
// those flags through |
|
hr = StringCopyExWorkerA(pszDestEnd, |
|
cchRemaining, |
|
(cchRemaining * sizeof(char)) + (cbDest % sizeof(char)), |
|
pszSrc, |
|
&pszDestEnd, |
|
&cchRemaining, |
|
dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE))); |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
// STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerA() |
|
|
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & STRSAFE_NULL_ON_FAILURE) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
wchar_t* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || |
|
// cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
size_t cchDestCurrent; |
|
|
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest == 0) && (cbDest == 0)) |
|
{ |
|
cchDestCurrent = 0; |
|
} |
|
else |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
pszDestEnd = pszDest + cchDestCurrent; |
|
cchRemaining = cchDest - cchDestCurrent; |
|
} |
|
} |
|
|
|
if (pszSrc == NULL) |
|
{ |
|
pszSrc = L""; |
|
} |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
pszDestEnd = pszDest + cchDestCurrent; |
|
cchRemaining = cchDest - cchDestCurrent; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
// only fail if there was actually src data to append |
|
if (*pszSrc != L'\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass |
|
// those flags through |
|
hr = StringCopyExWorkerW(pszDestEnd, |
|
cchRemaining, |
|
(cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)), |
|
pszSrc, |
|
&pszDestEnd, |
|
&cchRemaining, |
|
dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE))); |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
// STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerW() |
|
|
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & STRSAFE_NULL_ON_FAILURE) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend) |
|
{ |
|
HRESULT hr; |
|
size_t cchDestCurrent; |
|
|
|
hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
hr = StringCopyNWorkerA(pszDest + cchDestCurrent, |
|
cchDest - cchDestCurrent, |
|
pszSrc, |
|
cchMaxAppend); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend) |
|
{ |
|
HRESULT hr; |
|
size_t cchDestCurrent; |
|
|
|
hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
hr = StringCopyNWorkerW(pszDest + cchDestCurrent, |
|
cchDest - cchDestCurrent, |
|
pszSrc, |
|
cchMaxAppend); |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
char* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
size_t cchDestCurrent = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(char)) || |
|
// cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest == 0) && (cbDest == 0)) |
|
{ |
|
cchDestCurrent = 0; |
|
} |
|
else |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
pszDestEnd = pszDest + cchDestCurrent; |
|
cchRemaining = cchDest - cchDestCurrent; |
|
} |
|
} |
|
|
|
if (pszSrc == NULL) |
|
{ |
|
pszSrc = ""; |
|
} |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
pszDestEnd = pszDest + cchDestCurrent; |
|
cchRemaining = cchDest - cchDestCurrent; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
// only fail if there was actually src data to append |
|
if (*pszSrc != '\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass |
|
// those flags through |
|
hr = StringCopyNExWorkerA(pszDestEnd, |
|
cchRemaining, |
|
(cchRemaining * sizeof(char)) + (cbDest % sizeof(char)), |
|
pszSrc, |
|
cchMaxAppend, |
|
&pszDestEnd, |
|
&cchRemaining, |
|
dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE))); |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
// STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerA() |
|
|
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
wchar_t* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
size_t cchDestCurrent = 0; |
|
|
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || |
|
// cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest == 0) && (cbDest == 0)) |
|
{ |
|
cchDestCurrent = 0; |
|
} |
|
else |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
pszDestEnd = pszDest + cchDestCurrent; |
|
cchRemaining = cchDest - cchDestCurrent; |
|
} |
|
} |
|
|
|
if (pszSrc == NULL) |
|
{ |
|
pszSrc = L""; |
|
} |
|
} |
|
else |
|
{ |
|
hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent); |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
pszDestEnd = pszDest + cchDestCurrent; |
|
cchRemaining = cchDest - cchDestCurrent; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
// only fail if there was actually src data to append |
|
if (*pszSrc != L'\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass |
|
// those flags through |
|
hr = StringCopyNExWorkerW(pszDestEnd, |
|
cchRemaining, |
|
(cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)), |
|
pszSrc, |
|
cchMaxAppend, |
|
&pszDestEnd, |
|
&cchRemaining, |
|
dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE))); |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
// STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerW() |
|
|
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
if (cchDest == 0) |
|
{ |
|
// can not null terminate a zero-byte dest buffer |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
int iRet; |
|
size_t cchMax; |
|
|
|
// leave the last space for the null terminator |
|
cchMax = cchDest - 1; |
|
|
|
iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList); |
|
// ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); |
|
|
|
if ((iRet < 0) || (((size_t)iRet) > cchMax)) |
|
{ |
|
// need to null terminate the string |
|
pszDest += cchMax; |
|
*pszDest = '\0'; |
|
|
|
// we have truncated pszDest |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
else if (((size_t)iRet) == cchMax) |
|
{ |
|
// need to null terminate the string |
|
pszDest += cchMax; |
|
*pszDest = '\0'; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr = S_OK; |
|
|
|
if (cchDest == 0) |
|
{ |
|
// can not null terminate a zero-byte dest buffer |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
int iRet; |
|
size_t cchMax; |
|
|
|
// leave the last space for the null terminator |
|
cchMax = cchDest - 1; |
|
|
|
iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList); |
|
// ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); |
|
|
|
if ((iRet < 0) || (((size_t)iRet) > cchMax)) |
|
{ |
|
// need to null terminate the string |
|
pszDest += cchMax; |
|
*pszDest = L'\0'; |
|
|
|
// we have truncated pszDest |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
else if (((size_t)iRet) == cchMax) |
|
{ |
|
// need to null terminate the string |
|
pszDest += cchMax; |
|
*pszDest = L'\0'; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr = S_OK; |
|
char* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(char)) || |
|
// cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest != 0) || (cbDest != 0)) |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
|
|
if (pszFormat == NULL) |
|
{ |
|
pszFormat = ""; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = 0; |
|
|
|
// only fail if there was actually a non-empty format string |
|
if (*pszFormat != '\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
int iRet; |
|
size_t cchMax; |
|
|
|
// leave the last space for the null terminator |
|
cchMax = cchDest - 1; |
|
|
|
iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList); |
|
// ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); |
|
|
|
if ((iRet < 0) || (((size_t)iRet) > cchMax)) |
|
{ |
|
// we have truncated pszDest |
|
pszDestEnd = pszDest + cchMax; |
|
cchRemaining = 1; |
|
|
|
// need to null terminate the string |
|
*pszDestEnd = '\0'; |
|
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
else if (((size_t)iRet) == cchMax) |
|
{ |
|
// string fit perfectly |
|
pszDestEnd = pszDest + cchMax; |
|
cchRemaining = 1; |
|
|
|
// need to null terminate the string |
|
*pszDestEnd = '\0'; |
|
} |
|
else if (((size_t)iRet) < cchMax) |
|
{ |
|
// there is extra room |
|
pszDestEnd = pszDest + iRet; |
|
cchRemaining = cchDest - iRet; |
|
|
|
if (dwFlags & STRSAFE_FILL_BEHIND_NULL) |
|
{ |
|
memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char))); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList) |
|
{ |
|
HRESULT hr = S_OK; |
|
wchar_t* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(wchar_t)) || |
|
// cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest != 0) || (cbDest != 0)) |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
|
|
if (pszFormat == NULL) |
|
{ |
|
pszFormat = L""; |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = 0; |
|
|
|
// only fail if there was actually a non-empty format string |
|
if (*pszFormat != L'\0') |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
int iRet; |
|
size_t cchMax; |
|
|
|
// leave the last space for the null terminator |
|
cchMax = cchDest - 1; |
|
|
|
iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList); |
|
// ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); |
|
|
|
if ((iRet < 0) || (((size_t)iRet) > cchMax)) |
|
{ |
|
// we have truncated pszDest |
|
pszDestEnd = pszDest + cchMax; |
|
cchRemaining = 1; |
|
|
|
// need to null terminate the string |
|
*pszDestEnd = L'\0'; |
|
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
else if (((size_t)iRet) == cchMax) |
|
{ |
|
// string fit perfectly |
|
pszDestEnd = pszDest + cchMax; |
|
cchRemaining = 1; |
|
|
|
// need to null terminate the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
else if (((size_t)iRet) < cchMax) |
|
{ |
|
// there is extra room |
|
pszDestEnd = pszDest + iRet; |
|
cchRemaining = cchDest - iRet; |
|
|
|
if (dwFlags & STRSAFE_FILL_BEHIND_NULL) |
|
{ |
|
memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch) |
|
{ |
|
HRESULT hr = S_OK; |
|
size_t cchMaxPrev = cchMax; |
|
|
|
while (cchMax && (*psz != '\0')) |
|
{ |
|
psz++; |
|
cchMax--; |
|
} |
|
|
|
if (cchMax == 0) |
|
{ |
|
// the string is longer than cchMax |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
|
|
if (SUCCEEDED(hr) && pcch) |
|
{ |
|
*pcch = cchMaxPrev - cchMax; |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch) |
|
{ |
|
HRESULT hr = S_OK; |
|
size_t cchMaxPrev = cchMax; |
|
|
|
while (cchMax && (*psz != L'\0')) |
|
{ |
|
psz++; |
|
cchMax--; |
|
} |
|
|
|
if (cchMax == 0) |
|
{ |
|
// the string is longer than cchMax |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
|
|
if (SUCCEEDED(hr) && pcch) |
|
{ |
|
*pcch = cchMaxPrev - cchMax; |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // STRSAFE_INLINE |
|
|
|
#ifndef STRSAFE_LIB_IMPL |
|
STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
char* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(char)) || |
|
// cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest != 0) || (cbDest != 0)) |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest <= 1) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
if (cchDest == 1) |
|
{ |
|
*pszDestEnd = '\0'; |
|
} |
|
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
else |
|
{ |
|
char ch; |
|
|
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
while ((cchRemaining > 1) && (ch = (char)getc(stdin)) != '\n') |
|
{ |
|
if (ch == EOF) |
|
{ |
|
if (pszDestEnd == pszDest) |
|
{ |
|
// we failed to read anything from stdin |
|
hr = STRSAFE_E_END_OF_FILE; |
|
} |
|
break; |
|
} |
|
|
|
*pszDestEnd = ch; |
|
|
|
pszDestEnd++; |
|
cchRemaining--; |
|
} |
|
|
|
if (cchRemaining > 0) |
|
{ |
|
// there is extra room |
|
if (dwFlags & STRSAFE_FILL_BEHIND_NULL) |
|
{ |
|
memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char))); |
|
} |
|
} |
|
|
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = '\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || |
|
(hr == STRSAFE_E_INSUFFICIENT_BUFFER) || |
|
(hr == STRSAFE_E_END_OF_FILE)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
|
|
STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags) |
|
{ |
|
HRESULT hr = S_OK; |
|
wchar_t* pszDestEnd = pszDest; |
|
size_t cchRemaining = 0; |
|
|
|
// ASSERT(cbDest == (cchDest * sizeof(char)) || |
|
// cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char))); |
|
|
|
// only accept valid flags |
|
if (dwFlags & (~STRSAFE_VALID_FLAGS)) |
|
{ |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
else |
|
{ |
|
if (dwFlags & STRSAFE_IGNORE_NULLS) |
|
{ |
|
if (pszDest == NULL) |
|
{ |
|
if ((cchDest != 0) || (cbDest != 0)) |
|
{ |
|
// NULL pszDest and non-zero cchDest/cbDest is invalid |
|
hr = STRSAFE_E_INVALID_PARAMETER; |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr)) |
|
{ |
|
if (cchDest <= 1) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
if (cchDest == 1) |
|
{ |
|
*pszDestEnd = L'\0'; |
|
} |
|
|
|
hr = STRSAFE_E_INSUFFICIENT_BUFFER; |
|
} |
|
else |
|
{ |
|
wchar_t ch; |
|
|
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
while ((cchRemaining > 1) && (ch = (wchar_t)getwc(stdin)) != L'\n') |
|
{ |
|
if (ch == EOF) |
|
{ |
|
if (pszDestEnd == pszDest) |
|
{ |
|
// we failed to read anything from stdin |
|
hr = STRSAFE_E_END_OF_FILE; |
|
} |
|
break; |
|
} |
|
|
|
*pszDestEnd = ch; |
|
|
|
pszDestEnd++; |
|
cchRemaining--; |
|
} |
|
|
|
if (cchRemaining > 0) |
|
{ |
|
// there is extra room |
|
if (dwFlags & STRSAFE_FILL_BEHIND_NULL) |
|
{ |
|
memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t))); |
|
} |
|
} |
|
|
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
|
|
if (FAILED(hr)) |
|
{ |
|
if (pszDest) |
|
{ |
|
if (dwFlags & STRSAFE_FILL_ON_FAILURE) |
|
{ |
|
memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest); |
|
|
|
if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
} |
|
else if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest + cchDest - 1; |
|
cchRemaining = 1; |
|
|
|
// null terminate the end of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
|
|
if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) |
|
{ |
|
if (cchDest > 0) |
|
{ |
|
pszDestEnd = pszDest; |
|
cchRemaining = cchDest; |
|
|
|
// null terminate the beginning of the string |
|
*pszDestEnd = L'\0'; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (SUCCEEDED(hr) || |
|
(hr == STRSAFE_E_INSUFFICIENT_BUFFER) || |
|
(hr == STRSAFE_E_END_OF_FILE)) |
|
{ |
|
if (ppszDestEnd) |
|
{ |
|
*ppszDestEnd = pszDestEnd; |
|
} |
|
|
|
if (pcchRemaining) |
|
{ |
|
*pcchRemaining = cchRemaining; |
|
} |
|
} |
|
|
|
return hr; |
|
} |
|
#endif // !STRSAFE_LIB_IMPL |
|
|
|
|
|
// Do not call these functions, they are worker functions for internal use within this file |
|
#ifdef DEPRECATE_SUPPORTED |
|
#pragma deprecated(StringCopyWorkerA) |
|
#pragma deprecated(StringCopyWorkerW) |
|
#pragma deprecated(StringCopyExWorkerA) |
|
#pragma deprecated(StringCopyExWorkerW) |
|
#pragma deprecated(StringCatWorkerA) |
|
#pragma deprecated(StringCatWorkerW) |
|
#pragma deprecated(StringCatExWorkerA) |
|
#pragma deprecated(StringCatExWorkerW) |
|
#pragma deprecated(StringCatNWorkerA) |
|
#pragma deprecated(StringCatNWorkerW) |
|
#pragma deprecated(StringCatNExWorkerA) |
|
#pragma deprecated(StringCatNExWorkerW) |
|
#pragma deprecated(StringVPrintfWorkerA) |
|
#pragma deprecated(StringVPrintfWorkerW) |
|
#pragma deprecated(StringVPrintfExWorkerA) |
|
#pragma deprecated(StringVPrintfExWorkerW) |
|
#pragma deprecated(StringLengthWorkerA) |
|
#pragma deprecated(StringLengthWorkerW) |
|
#else |
|
#define StringCopyWorkerA StringCopyWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA; |
|
#define StringCopyWorkerW StringCopyWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW; |
|
#define StringCopyExWorkerA StringCopyExWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA; |
|
#define StringCopyExWorkerW StringCopyExWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW; |
|
#define StringCatWorkerA StringCatWorkerA_instead_use_StringCchCatA_or_StringCchCatExA; |
|
#define StringCatWorkerW StringCatWorkerW_instead_use_StringCchCatW_or_StringCchCatExW; |
|
#define StringCatExWorkerA StringCatExWorkerA_instead_use_StringCchCatA_or_StringCchCatExA; |
|
#define StringCatExWorkerW StringCatExWorkerW_instead_use_StringCchCatW_or_StringCchCatExW; |
|
#define StringCatNWorkerA StringCatNWorkerA_instead_use_StringCchCatNA_or_StrincCbCatNA; |
|
#define StringCatNWorkerW StringCatNWorkerW_instead_use_StringCchCatNW_or_StringCbCatNW; |
|
#define StringCatNExWorkerA StringCatNExWorkerA_instead_use_StringCchCatNExA_or_StringCbCatNExA; |
|
#define StringCatNExWorkerW StringCatNExWorkerW_instead_use_StringCchCatNExW_or_StringCbCatNExW; |
|
#define StringVPrintfWorkerA StringVPrintfWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA; |
|
#define StringVPrintfWorkerW StringVPrintfWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW; |
|
#define StringVPrintfExWorkerA StringVPrintfExWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA; |
|
#define StringVPrintfExWorkerW StringVPrintfExWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW; |
|
#define StringLengthWorkerA StringLengthWorkerA_instead_use_StringCchLengthA_or_StringCbLengthA; |
|
#define StringLengthWorkerW StringLengthWorkerW_instead_use_StringCchLengthW_or_StringCbLengthW; |
|
#endif // !DEPRECATE_SUPPORTED |
|
|
|
|
|
#ifndef STRSAFE_NO_DEPRECATE |
|
// Deprecate all of the unsafe functions to generate compiletime errors. If you do not want |
|
// this then you can #define STRSAFE_NO_DEPRECATE before including this file. |
|
#ifdef DEPRECATE_SUPPORTED |
|
|
|
// First all the names that are a/w variants (or shouldn't be #defined by now anyway). |
|
#pragma deprecated(lstrcpyA) |
|
#pragma deprecated(lstrcpyW) |
|
#pragma deprecated(lstrcatA) |
|
#pragma deprecated(lstrcatW) |
|
#pragma deprecated(wsprintfA) |
|
#pragma deprecated(wsprintfW) |
|
|
|
#pragma deprecated(StrCpyW) |
|
#pragma deprecated(StrCatW) |
|
#pragma deprecated(StrNCatA) |
|
#pragma deprecated(StrNCatW) |
|
#pragma deprecated(StrCatNA) |
|
#pragma deprecated(StrCatNW) |
|
#pragma deprecated(wvsprintfA) |
|
#pragma deprecated(wvsprintfW) |
|
|
|
#pragma deprecated(strcpy) |
|
#pragma deprecated(wcscpy) |
|
#pragma deprecated(strcat) |
|
#pragma deprecated(wcscat) |
|
#pragma deprecated(sprintf) |
|
#pragma deprecated(swprintf) |
|
#pragma deprecated(vsprintf) |
|
#pragma deprecated(vswprintf) |
|
#pragma deprecated(_snprintf) |
|
#pragma deprecated(_snwprintf) |
|
#pragma deprecated(_vsnprintf) |
|
#pragma deprecated(_vsnwprintf) |
|
#pragma deprecated(gets) |
|
#pragma deprecated(_getws) |
|
|
|
// Then all the windows.h names - we need to undef and redef based on UNICODE setting |
|
#undef lstrcpy |
|
#undef lstrcat |
|
#undef wsprintf |
|
#undef wvsprintf |
|
#pragma deprecated(lstrcpy) |
|
#pragma deprecated(lstrcat) |
|
#pragma deprecated(wsprintf) |
|
#pragma deprecated(wvsprintf) |
|
#ifdef UNICODE |
|
#define lstrcpy lstrcpyW |
|
#define lstrcat lstrcatW |
|
#define wsprintf wsprintfW |
|
#define wvsprintf wvsprintfW |
|
#else |
|
#define lstrcpy lstrcpyA |
|
#define lstrcat lstrcatA |
|
#define wsprintf wsprintfA |
|
#define wvsprintf wvsprintfA |
|
#endif |
|
|
|
// Then the shlwapi names - they key off UNICODE also. |
|
#undef StrCpyA |
|
#undef StrCpy |
|
#undef StrCatA |
|
#undef StrCat |
|
#undef StrNCat |
|
#undef StrCatN |
|
#pragma deprecated(StrCpyA) |
|
#pragma deprecated(StrCatA) |
|
#pragma deprecated(StrCatN) |
|
#pragma deprecated(StrCpy) |
|
#pragma deprecated(StrCat) |
|
#pragma deprecated(StrNCat) |
|
#define StrCpyA lstrcpyA |
|
#define StrCatA lstrcatA |
|
#define StrCatN StrNCat |
|
#ifdef UNICODE |
|
#define StrCpy StrCpyW |
|
#define StrCat StrCatW |
|
#define StrNCat StrNCatW |
|
#else |
|
#define StrCpy lstrcpyA |
|
#define StrCat lstrcatA |
|
#define StrNCat StrNCatA |
|
#endif |
|
|
|
// Then all the CRT names - we need to undef/redef based on _UNICODE value. |
|
#undef _tcscpy |
|
#undef _ftcscpy |
|
#undef _tcscat |
|
#undef _ftcscat |
|
#undef _stprintf |
|
#undef _sntprintf |
|
#undef _vstprintf |
|
#undef _vsntprintf |
|
#undef _getts |
|
#pragma deprecated(_tcscpy) |
|
#pragma deprecated(_ftcscpy) |
|
#pragma deprecated(_tcscat) |
|
#pragma deprecated(_ftcscat) |
|
#pragma deprecated(_stprintf) |
|
#pragma deprecated(_sntprintf) |
|
#pragma deprecated(_vstprintf) |
|
#pragma deprecated(_vsntprintf) |
|
#pragma deprecated(_getts) |
|
#ifdef _UNICODE |
|
#define _tcscpy wcscpy |
|
#define _ftcscpy wcscpy |
|
#define _tcscat wcscat |
|
#define _ftcscat wcscat |
|
#define _stprintf swprintf |
|
#define _sntprintf _snwprintf |
|
#define _vstprintf vswprintf |
|
#define _vsntprintf _vsnwprintf |
|
#define _getts _getws |
|
#else |
|
#define _tcscpy strcpy |
|
#define _ftcscpy strcpy |
|
#define _tcscat strcat |
|
#define _ftcscat strcat |
|
#define _stprintf sprintf |
|
#define _sntprintf _snprintf |
|
#define _vstprintf vsprintf |
|
#define _vsntprintf _vsnprintf |
|
#define _getts gets |
|
#endif |
|
|
|
#else // DEPRECATE_SUPPORTED |
|
|
|
#undef strcpy |
|
#define strcpy strcpy_instead_use_StringCbCopyA_or_StringCchCopyA; |
|
|
|
#undef wcscpy |
|
#define wcscpy wcscpy_instead_use_StringCbCopyW_or_StringCchCopyW; |
|
|
|
#undef strcat |
|
#define strcat strcat_instead_use_StringCbCatA_or_StringCchCatA; |
|
|
|
#undef wcscat |
|
#define wcscat wcscat_instead_use_StringCbCatW_or_StringCchCatW; |
|
|
|
#undef sprintf |
|
#define sprintf sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA; |
|
|
|
#undef swprintf |
|
#define swprintf swprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW; |
|
|
|
#undef vsprintf |
|
#define vsprintf vsprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA; |
|
|
|
#undef vswprintf |
|
#define vswprintf vswprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW; |
|
|
|
#undef _snprintf |
|
#define _snprintf _snprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA; |
|
|
|
#undef _snwprintf |
|
#define _snwprintf _snwprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW; |
|
|
|
#undef _vsnprintf |
|
#define _vsnprintf _vsnprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA; |
|
|
|
#undef _vsnwprintf |
|
#define _vsnwprintf _vsnwprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW; |
|
|
|
#undef strcpyA |
|
#define strcpyA strcpyA_instead_use_StringCbCopyA_or_StringCchCopyA; |
|
|
|
#undef strcpyW |
|
#define strcpyW strcpyW_instead_use_StringCbCopyW_or_StringCchCopyW; |
|
|
|
#undef lstrcpy |
|
#define lstrcpy lstrcpy_instead_use_StringCbCopy_or_StringCchCopy; |
|
|
|
#undef lstrcpyA |
|
#define lstrcpyA lstrcpyA_instead_use_StringCbCopyA_or_StringCchCopyA; |
|
|
|
#undef lstrcpyW |
|
#define lstrcpyW lstrcpyW_instead_use_StringCbCopyW_or_StringCchCopyW; |
|
|
|
#undef StrCpy |
|
#define StrCpy StrCpy_instead_use_StringCbCopy_or_StringCchCopy; |
|
|
|
#undef StrCpyA |
|
#define StrCpyA StrCpyA_instead_use_StringCbCopyA_or_StringCchCopyA; |
|
|
|
#undef StrCpyW |
|
#define StrCpyW StrCpyW_instead_use_StringCbCopyW_or_StringCchCopyW; |
|
|
|
#undef _tcscpy |
|
#define _tcscpy _tcscpy_instead_use_StringCbCopy_or_StringCchCopy; |
|
|
|
#undef _ftcscpy |
|
#define _ftcscpy _ftcscpy_instead_use_StringCbCopy_or_StringCchCopy; |
|
|
|
#undef lstrcat |
|
#define lstrcat lstrcat_instead_use_StringCbCat_or_StringCchCat; |
|
|
|
#undef lstrcatA |
|
#define lstrcatA lstrcatA_instead_use_StringCbCatA_or_StringCchCatA; |
|
|
|
#undef lstrcatW |
|
#define lstrcatW lstrcatW_instead_use_StringCbCatW_or_StringCchCatW; |
|
|
|
#undef StrCat |
|
#define StrCat StrCat_instead_use_StringCbCat_or_StringCchCat; |
|
|
|
#undef StrCatA |
|
#define StrCatA StrCatA_instead_use_StringCbCatA_or_StringCchCatA; |
|
|
|
#undef StrCatW |
|
#define StrCatW StrCatW_instead_use_StringCbCatW_or_StringCchCatW; |
|
|
|
#undef StrNCat |
|
#define StrNCat StrNCat_instead_use_StringCbCatN_or_StringCchCatN; |
|
|
|
#undef StrNCatA |
|
#define StrNCatA StrNCatA_instead_use_StringCbCatNA_or_StringCchCatNA; |
|
|
|
#undef StrNCatW |
|
#define StrNCatW StrNCatW_instead_use_StringCbCatNW_or_StringCchCatNW; |
|
|
|
#undef StrCatN |
|
#define StrCatN StrCatN_instead_use_StringCbCatN_or_StringCchCatN; |
|
|
|
#undef StrCatNA |
|
#define StrCatNA StrCatNA_instead_use_StringCbCatNA_or_StringCchCatNA; |
|
|
|
#undef StrCatNW |
|
#define StrCatNW StrCatNW_instead_use_StringCbCatNW_or_StringCchCatNW; |
|
|
|
#undef _tcscat |
|
#define _tcscat _tcscat_instead_use_StringCbCat_or_StringCchCat; |
|
|
|
#undef _ftcscat |
|
#define _ftcscat _ftcscat_instead_use_StringCbCat_or_StringCchCat; |
|
|
|
#undef wsprintf |
|
#define wsprintf wsprintf_instead_use_StringCbPrintf_or_StringCchPrintf; |
|
|
|
#undef wsprintfA |
|
#define wsprintfA wsprintfA_instead_use_StringCbPrintfA_or_StringCchPrintfA; |
|
|
|
#undef wsprintfW |
|
#define wsprintfW wsprintfW_instead_use_StringCbPrintfW_or_StringCchPrintfW; |
|
|
|
#undef wvsprintf |
|
#define wvsprintf wvsprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf; |
|
|
|
#undef wvsprintfA |
|
#define wvsprintfA wvsprintfA_instead_use_StringCbVPrintfA_or_StringCchVPrintfA; |
|
|
|
#undef wvsprintfW |
|
#define wvsprintfW wvsprintfW_instead_use_StringCbVPrintfW_or_StringCchVPrintfW; |
|
|
|
#undef _vstprintf |
|
#define _vstprintf _vstprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf; |
|
|
|
#undef _vsntprintf |
|
#define _vsntprintf _vsntprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf; |
|
|
|
#undef _stprintf |
|
#define _stprintf _stprintf_instead_use_StringCbPrintf_or_StringCchPrintf; |
|
|
|
#undef _sntprintf |
|
#define _sntprintf _sntprintf_instead_use_StringCbPrintf_or_StringCchPrintf; |
|
|
|
#undef _getts |
|
#define _getts _getts_instead_use_StringCbGets_or_StringCchGets; |
|
|
|
#undef gets |
|
#define gets _gets_instead_use_StringCbGetsA_or_StringCchGetsA; |
|
|
|
#undef _getws |
|
#define _getws _getws_instead_use_StringCbGetsW_or_StringCchGetsW; |
|
|
|
#endif // !DEPRECATE_SUPPORTED |
|
#endif // !STRSAFE_NO_DEPRECATE |
|
|
|
#ifdef _NTSTRSAFE_H_INCLUDED_ |
|
#pragma warning(pop) |
|
#endif // _NTSTRSAFE_H_INCLUDED_ |
|
|
|
#endif // _STRSAFE_H_INCLUDED_
|
|
|