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
216 KiB
6611 lines
216 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_
|