Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6611 lines
210 KiB

  1. /******************************************************************
  2. * *
  3. * strsafe.h -- This module defines safer C library string *
  4. * routine replacements. These are meant to make C *
  5. * a bit more safe in reference to security and *
  6. * robustness *
  7. * *
  8. * Copyright (c) Microsoft Corp. All rights reserved. *
  9. * *
  10. ******************************************************************/
  11. #ifndef _STRSAFE_H_INCLUDED_
  12. #define _STRSAFE_H_INCLUDED_
  13. #pragma once
  14. #include <stdio.h> // for _vsnprintf, _vsnwprintf, getc, getwc
  15. #include <string.h> // for memset
  16. #include <stdarg.h> // for va_start, etc.
  17. #ifndef _SIZE_T_DEFINED
  18. #ifdef _WIN64
  19. typedef unsigned __int64 size_t;
  20. #else
  21. typedef __w64 unsigned int size_t;
  22. #endif // !_WIN64
  23. #define _SIZE_T_DEFINED
  24. #endif // !_SIZE_T_DEFINED
  25. #if !defined(_WCHAR_T_DEFINED) && !defined(_NATIVE_WCHAR_T_DEFINED)
  26. typedef unsigned short wchar_t;
  27. #define _WCHAR_T_DEFINED
  28. #endif
  29. #ifndef _HRESULT_DEFINED
  30. #define _HRESULT_DEFINED
  31. typedef long HRESULT;
  32. #endif // !_HRESULT_DEFINED
  33. #ifndef SUCCEEDED
  34. #define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
  35. #endif
  36. #ifndef FAILED
  37. #define FAILED(hr) ((HRESULT)(hr) < 0)
  38. #endif
  39. #ifndef S_OK
  40. #define S_OK ((HRESULT)0x00000000L)
  41. #endif
  42. #ifdef __cplusplus
  43. #define _STRSAFE_EXTERN_C extern "C"
  44. #else
  45. #define _STRSAFE_EXTERN_C extern
  46. #endif
  47. // If you do not want to use these functions inline (and instead want to link w/ strsafe.lib), then
  48. // #define STRSAFE_LIB before including this header file.
  49. #if defined(STRSAFE_LIB)
  50. #define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall
  51. #pragma comment(lib, "strsafe.lib")
  52. #elif defined(STRSAFE_LIB_IMPL)
  53. #define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall
  54. #else
  55. #define STRSAFEAPI __inline HRESULT __stdcall
  56. #define STRSAFE_INLINE
  57. #endif
  58. // Some functions always run inline because they use stdin and we want to avoid building multiple
  59. // versions of strsafe lib depending on if you use msvcrt, libcmt, etc.
  60. #define STRSAFE_INLINE_API __inline HRESULT __stdcall
  61. // The user can request no "Cb" or no "Cch" fuctions, but not both!
  62. #if defined(STRSAFE_NO_CB_FUNCTIONS) && defined(STRSAFE_NO_CCH_FUNCTIONS)
  63. #error cannot specify both STRSAFE_NO_CB_FUNCTIONS and STRSAFE_NO_CCH_FUNCTIONS !!
  64. #endif
  65. // This should only be defined when we are building strsafe.lib
  66. #ifdef STRSAFE_LIB_IMPL
  67. #define STRSAFE_INLINE
  68. #endif
  69. // If both strsafe.h and ntstrsafe.h are included, only use definitions from one.
  70. #ifndef _NTSTRSAFE_H_INCLUDED_
  71. #define STRSAFE_MAX_CCH 2147483647 // max # of characters we support (same as INT_MAX)
  72. // Flags for controling the Ex functions
  73. //
  74. // STRSAFE_FILL_BYTE(0xFF) 0x000000FF // bottom byte specifies fill pattern
  75. #define STRSAFE_IGNORE_NULLS 0x00000100 // treat null as TEXT("") -- don't fault on NULL buffers
  76. #define STRSAFE_FILL_BEHIND_NULL 0x00000200 // fill in extra space behind the null terminator
  77. #define STRSAFE_FILL_ON_FAILURE 0x00000400 // on failure, overwrite pszDest with fill pattern and null terminate it
  78. #define STRSAFE_NULL_ON_FAILURE 0x00000800 // on failure, set *pszDest = TEXT('\0')
  79. #define STRSAFE_NO_TRUNCATION 0x00001000 // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it
  80. #define STRSAFE_VALID_FLAGS (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)
  81. // helper macro to set the fill character and specify buffer filling
  82. #define STRSAFE_FILL_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL))
  83. #define STRSAFE_FAILURE_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE))
  84. #define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)(dwFlags & 0x000000FF))
  85. #endif // _NTSTRSAFE_H_INCLUDED_
  86. // STRSAFE error return codes
  87. //
  88. #define STRSAFE_E_INSUFFICIENT_BUFFER ((HRESULT)0x8007007AL) // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER
  89. #define STRSAFE_E_INVALID_PARAMETER ((HRESULT)0x80070057L) // 0x57 = 87L = ERROR_INVALID_PARAMETER
  90. #define STRSAFE_E_END_OF_FILE ((HRESULT)0x80070026L) // 0x26 = 38L = ERROR_HANDLE_EOF
  91. // prototypes for the worker functions
  92. #ifdef STRSAFE_INLINE
  93. STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
  94. STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  95. STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  96. STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  97. STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
  98. STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
  99. STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  100. 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);
  101. STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
  102. STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  103. STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  104. STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  105. STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
  106. STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
  107. STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  108. 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);
  109. STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
  110. STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
  111. STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  112. 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);
  113. STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch);
  114. STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  115. #endif // STRSAFE_INLINE
  116. #ifndef STRSAFE_LIB_IMPL
  117. // these functions are always inline
  118. STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  119. STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  120. #endif
  121. #ifdef _NTSTRSAFE_H_INCLUDED_
  122. #pragma warning(push)
  123. #pragma warning(disable : 4995)
  124. #endif // _NTSTRSAFE_H_INCLUDED_
  125. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  126. /*++
  127. STDAPI
  128. StringCchCopy(
  129. OUT LPTSTR pszDest,
  130. IN size_t cchDest,
  131. IN LPCTSTR pszSrc
  132. );
  133. Routine Description:
  134. This routine is a safer version of the C built-in function 'strcpy'.
  135. The size of the destination buffer (in characters) is a parameter and
  136. this function will not write past the end of this buffer and it will
  137. ALWAYS null terminate the destination buffer (unless it is zero length).
  138. This routine is not a replacement for strncpy. That function will pad the
  139. destination string with extra null termination characters if the count is
  140. greater than the length of the source string, and it will fail to null
  141. terminate the destination string if the source string length is greater
  142. than or equal to the count. You can not blindly use this instead of strncpy:
  143. it is common for code to use it to "patch" strings and you would introduce
  144. errors if the code started null terminating in the middle of the string.
  145. This function returns a hresult, and not a pointer. It returns
  146. S_OK if the string was copied without truncation and null terminated,
  147. otherwise it will return a failure code. In failure cases as much of
  148. pszSrc will be copied to pszDest as possible, and pszDest will be null
  149. terminated.
  150. Arguments:
  151. pszDest - destination string
  152. cchDest - size of destination buffer in characters.
  153. length must be = (_tcslen(src) + 1) to hold all of the
  154. source including the null terminator
  155. pszSrc - source string which must be null terminated
  156. Notes:
  157. Behavior is undefined if source and destination strings overlap.
  158. pszDest and pszSrc should not be NULL. See StringCchCopyEx if you require
  159. the handling of NULL values.
  160. Return Value:
  161. S_OK - if there was source data and it was all copied and the
  162. resultant dest string was null terminated
  163. failure - you can use the macro HRESULT_CODE() to get a win32
  164. error code for all hresult failure cases
  165. STRSAFE_E_INSUFFICIENT_BUFFER /
  166. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  167. - this return value is an indication that the copy
  168. operation failed due to insufficient space. When this
  169. error occurs, the destination buffer is modified to
  170. contain a truncated version of the ideal result and is
  171. null terminated. This is useful for situations where
  172. truncation is ok
  173. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  174. return value of this function.
  175. --*/
  176. STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc);
  177. STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  178. #ifdef UNICODE
  179. #define StringCchCopy StringCchCopyW
  180. #else
  181. #define StringCchCopy StringCchCopyA
  182. #endif // !UNICODE
  183. #ifdef STRSAFE_INLINE
  184. STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc)
  185. {
  186. HRESULT hr;
  187. if (cchDest > STRSAFE_MAX_CCH)
  188. {
  189. hr = STRSAFE_E_INVALID_PARAMETER;
  190. }
  191. else
  192. {
  193. hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
  194. }
  195. return hr;
  196. }
  197. STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  198. {
  199. HRESULT hr;
  200. if (cchDest > STRSAFE_MAX_CCH)
  201. {
  202. hr = STRSAFE_E_INVALID_PARAMETER;
  203. }
  204. else
  205. {
  206. hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
  207. }
  208. return hr;
  209. }
  210. #endif // STRSAFE_INLINE
  211. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  212. #ifndef STRSAFE_NO_CB_FUNCTIONS
  213. /*++
  214. STDAPI
  215. StringCbCopy(
  216. OUT LPTSTR pszDest,
  217. IN size_t cbDest,
  218. IN LPCTSTR pszSrc
  219. );
  220. Routine Description:
  221. This routine is a safer version of the C built-in function 'strcpy'.
  222. The size of the destination buffer (in bytes) is a parameter and this
  223. function will not write past the end of this buffer and it will ALWAYS
  224. null terminate the destination buffer (unless it is zero length).
  225. This routine is not a replacement for strncpy. That function will pad the
  226. destination string with extra null termination characters if the count is
  227. greater than the length of the source string, and it will fail to null
  228. terminate the destination string if the source string length is greater
  229. than or equal to the count. You can not blindly use this instead of strncpy:
  230. it is common for code to use it to "patch" strings and you would introduce
  231. errors if the code started null terminating in the middle of the string.
  232. This function returns a hresult, and not a pointer. It returns
  233. S_OK if the string was copied without truncation and null terminated,
  234. otherwise it will return a failure code. In failure cases as much of pszSrc
  235. will be copied to pszDest as possible, and pszDest will be null terminated.
  236. Arguments:
  237. pszDest - destination string
  238. cbDest - size of destination buffer in bytes.
  239. length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
  240. hold all of the source including the null terminator
  241. pszSrc - source string which must be null terminated
  242. Notes:
  243. Behavior is undefined if source and destination strings overlap.
  244. pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require
  245. the handling of NULL values.
  246. Return Value:
  247. S_OK - if there was source data and it was all copied and the
  248. resultant dest string was null terminated
  249. failure - you can use the macro HRESULT_CODE() to get a win32
  250. error code for all hresult failure cases
  251. STRSAFE_E_INSUFFICIENT_BUFFER /
  252. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  253. - this return value is an indication that the copy
  254. operation failed due to insufficient space. When this
  255. error occurs, the destination buffer is modified to
  256. contain a truncated version of the ideal result and is
  257. null terminated. This is useful for situations where
  258. truncation is ok
  259. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  260. return value of this function.
  261. --*/
  262. STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc);
  263. STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
  264. #ifdef UNICODE
  265. #define StringCbCopy StringCbCopyW
  266. #else
  267. #define StringCbCopy StringCbCopyA
  268. #endif // !UNICODE
  269. #ifdef STRSAFE_INLINE
  270. STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc)
  271. {
  272. HRESULT hr;
  273. size_t cchDest;
  274. // convert to count of characters
  275. cchDest = cbDest / sizeof(char);
  276. if (cchDest > STRSAFE_MAX_CCH)
  277. {
  278. hr = STRSAFE_E_INVALID_PARAMETER;
  279. }
  280. else
  281. {
  282. hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
  283. }
  284. return hr;
  285. }
  286. STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
  287. {
  288. HRESULT hr;
  289. size_t cchDest;
  290. // convert to count of characters
  291. cchDest = cbDest / sizeof(wchar_t);
  292. if (cchDest > STRSAFE_MAX_CCH)
  293. {
  294. hr = STRSAFE_E_INVALID_PARAMETER;
  295. }
  296. else
  297. {
  298. hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
  299. }
  300. return hr;
  301. }
  302. #endif // STRSAFE_INLINE
  303. #endif // !STRSAFE_NO_CB_FUNCTIONS
  304. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  305. /*++
  306. STDAPI
  307. StringCchCopyEx(
  308. OUT LPTSTR pszDest OPTIONAL,
  309. IN size_t cchDest,
  310. IN LPCTSTR pszSrc OPTIONAL,
  311. OUT LPTSTR* ppszDestEnd OPTIONAL,
  312. OUT size_t* pcchRemaining OPTIONAL,
  313. IN DWORD dwFlags
  314. );
  315. Routine Description:
  316. This routine is a safer version of the C built-in function 'strcpy' with
  317. some additional parameters. In addition to functionality provided by
  318. StringCchCopy, this routine also returns a pointer to the end of the
  319. destination string and the number of characters left in the destination string
  320. including the null terminator. The flags parameter allows additional controls.
  321. Arguments:
  322. pszDest - destination string
  323. cchDest - size of destination buffer in characters.
  324. length must be = (_tcslen(pszSrc) + 1) to hold all of
  325. the source including the null terminator
  326. pszSrc - source string which must be null terminated
  327. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  328. pointer to the end of the destination string. If the
  329. function copied any data, the result will point to the
  330. null termination character
  331. pcchRemaining - if pcchRemaining is non-null, the function will return the
  332. number of characters left in the destination string,
  333. including the null terminator
  334. dwFlags - controls some details of the string copy:
  335. STRSAFE_FILL_BEHIND_NULL
  336. if the function succeeds, the low byte of dwFlags will be
  337. used to fill the uninitialize part of destination buffer
  338. behind the null terminator
  339. STRSAFE_IGNORE_NULLS
  340. treat NULL string pointers like empty strings (TEXT("")).
  341. this flag is useful for emulating functions like lstrcpy
  342. STRSAFE_FILL_ON_FAILURE
  343. if the function fails, the low byte of dwFlags will be
  344. used to fill all of the destination buffer, and it will
  345. be null terminated. This will overwrite any truncated
  346. string returned when the failure is
  347. STRSAFE_E_INSUFFICIENT_BUFFER
  348. STRSAFE_NO_TRUNCATION /
  349. STRSAFE_NULL_ON_FAILURE
  350. if the function fails, the destination buffer will be set
  351. to the empty string. This will overwrite any truncated string
  352. returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  353. Notes:
  354. Behavior is undefined if source and destination strings overlap.
  355. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  356. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  357. may be NULL. An error may still be returned even though NULLS are ignored
  358. due to insufficient space.
  359. Return Value:
  360. S_OK - if there was source data and it was all copied and the
  361. resultant dest string was null terminated
  362. failure - you can use the macro HRESULT_CODE() to get a win32
  363. error code for all hresult failure cases
  364. STRSAFE_E_INSUFFICIENT_BUFFER /
  365. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  366. - this return value is an indication that the copy
  367. operation failed due to insufficient space. When this
  368. error occurs, the destination buffer is modified to
  369. contain a truncated version of the ideal result and is
  370. null terminated. This is useful for situations where
  371. truncation is ok.
  372. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  373. return value of this function
  374. --*/
  375. STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  376. STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  377. #ifdef UNICODE
  378. #define StringCchCopyEx StringCchCopyExW
  379. #else
  380. #define StringCchCopyEx StringCchCopyExA
  381. #endif // !UNICODE
  382. #ifdef STRSAFE_INLINE
  383. STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  384. {
  385. HRESULT hr;
  386. if (cchDest > STRSAFE_MAX_CCH)
  387. {
  388. hr = STRSAFE_E_INVALID_PARAMETER;
  389. }
  390. else
  391. {
  392. size_t cbDest;
  393. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  394. cbDest = cchDest * sizeof(char);
  395. hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  396. }
  397. return hr;
  398. }
  399. STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  400. {
  401. HRESULT hr;
  402. if (cchDest > STRSAFE_MAX_CCH)
  403. {
  404. hr = STRSAFE_E_INVALID_PARAMETER;
  405. }
  406. else
  407. {
  408. size_t cbDest;
  409. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  410. cbDest = cchDest * sizeof(wchar_t);
  411. hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  412. }
  413. return hr;
  414. }
  415. #endif // STRSAFE_INLINE
  416. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  417. #ifndef STRSAFE_NO_CB_FUNCTIONS
  418. /*++
  419. STDAPI
  420. StringCbCopyEx(
  421. OUT LPTSTR pszDest OPTIONAL,
  422. IN size_t cbDest,
  423. IN LPCTSTR pszSrc OPTIONAL,
  424. OUT LPTSTR* ppszDestEnd OPTIONAL,
  425. OUT size_t* pcbRemaining OPTIONAL,
  426. IN DWORD dwFlags
  427. );
  428. Routine Description:
  429. This routine is a safer version of the C built-in function 'strcpy' with
  430. some additional parameters. In addition to functionality provided by
  431. StringCbCopy, this routine also returns a pointer to the end of the
  432. destination string and the number of bytes left in the destination string
  433. including the null terminator. The flags parameter allows additional controls.
  434. Arguments:
  435. pszDest - destination string
  436. cbDest - size of destination buffer in bytes.
  437. length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
  438. hold all of the source including the null terminator
  439. pszSrc - source string which must be null terminated
  440. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  441. pointer to the end of the destination string. If the
  442. function copied any data, the result will point to the
  443. null termination character
  444. pcbRemaining - pcbRemaining is non-null,the function will return the
  445. number of bytes left in the destination string,
  446. including the null terminator
  447. dwFlags - controls some details of the string copy:
  448. STRSAFE_FILL_BEHIND_NULL
  449. if the function succeeds, the low byte of dwFlags will be
  450. used to fill the uninitialize part of destination buffer
  451. behind the null terminator
  452. STRSAFE_IGNORE_NULLS
  453. treat NULL string pointers like empty strings (TEXT("")).
  454. this flag is useful for emulating functions like lstrcpy
  455. STRSAFE_FILL_ON_FAILURE
  456. if the function fails, the low byte of dwFlags will be
  457. used to fill all of the destination buffer, and it will
  458. be null terminated. This will overwrite any truncated
  459. string returned when the failure is
  460. STRSAFE_E_INSUFFICIENT_BUFFER
  461. STRSAFE_NO_TRUNCATION /
  462. STRSAFE_NULL_ON_FAILURE
  463. if the function fails, the destination buffer will be set
  464. to the empty string. This will overwrite any truncated string
  465. returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  466. Notes:
  467. Behavior is undefined if source and destination strings overlap.
  468. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  469. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  470. may be NULL. An error may still be returned even though NULLS are ignored
  471. due to insufficient space.
  472. Return Value:
  473. S_OK - if there was source data and it was all copied and the
  474. resultant dest string was null terminated
  475. failure - you can use the macro HRESULT_CODE() to get a win32
  476. error code for all hresult failure cases
  477. STRSAFE_E_INSUFFICIENT_BUFFER /
  478. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  479. - this return value is an indication that the copy
  480. operation failed due to insufficient space. When this
  481. error occurs, the destination buffer is modified to
  482. contain a truncated version of the ideal result and is
  483. null terminated. This is useful for situations where
  484. truncation is ok.
  485. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  486. return value of this function
  487. --*/
  488. STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  489. STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  490. #ifdef UNICODE
  491. #define StringCbCopyEx StringCbCopyExW
  492. #else
  493. #define StringCbCopyEx StringCbCopyExA
  494. #endif // !UNICODE
  495. #ifdef STRSAFE_INLINE
  496. STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  497. {
  498. HRESULT hr;
  499. size_t cchDest;
  500. size_t cchRemaining = 0;
  501. cchDest = cbDest / sizeof(char);
  502. if (cchDest > STRSAFE_MAX_CCH)
  503. {
  504. hr = STRSAFE_E_INVALID_PARAMETER;
  505. }
  506. else
  507. {
  508. hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  509. }
  510. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  511. {
  512. if (pcbRemaining)
  513. {
  514. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  515. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  516. }
  517. }
  518. return hr;
  519. }
  520. STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  521. {
  522. HRESULT hr;
  523. size_t cchDest;
  524. size_t cchRemaining = 0;
  525. cchDest = cbDest / sizeof(wchar_t);
  526. if (cchDest > STRSAFE_MAX_CCH)
  527. {
  528. hr = STRSAFE_E_INVALID_PARAMETER;
  529. }
  530. else
  531. {
  532. hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  533. }
  534. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  535. {
  536. if (pcbRemaining)
  537. {
  538. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  539. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  540. }
  541. }
  542. return hr;
  543. }
  544. #endif // STRSAFE_INLINE
  545. #endif // !STRSAFE_NO_CB_FUNCTIONS
  546. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  547. /*++
  548. STDAPI
  549. StringCchCopyN(
  550. OUT LPTSTR pszDest,
  551. IN size_t cchDest,
  552. IN LPCTSTR pszSrc,
  553. IN size_t cchSrc
  554. );
  555. Routine Description:
  556. This routine is a safer version of the C built-in function 'strncpy'.
  557. The size of the destination buffer (in characters) is a parameter and
  558. this function will not write past the end of this buffer and it will
  559. ALWAYS null terminate the destination buffer (unless it is zero length).
  560. This routine is meant as a replacement for strncpy, but it does behave
  561. differently. This function will not pad the destination buffer with extra
  562. null termination characters if cchSrc is greater than the length of pszSrc.
  563. This function returns a hresult, and not a pointer. It returns
  564. S_OK if the entire string or the first cchSrc characters were copied
  565. without truncation and the resultant destination string was null terminated,
  566. otherwise it will return a failure code. In failure cases as much of pszSrc
  567. will be copied to pszDest as possible, and pszDest will be null terminated.
  568. Arguments:
  569. pszDest - destination string
  570. cchDest - size of destination buffer in characters.
  571. length must be = (_tcslen(src) + 1) to hold all of the
  572. source including the null terminator
  573. pszSrc - source string
  574. cchSrc - maximum number of characters to copy from source string,
  575. not including the null terminator.
  576. Notes:
  577. Behavior is undefined if source and destination strings overlap.
  578. pszDest and pszSrc should not be NULL. See StringCchCopyNEx if you require
  579. the handling of NULL values.
  580. Return Value:
  581. S_OK - if there was source data and it was all copied and the
  582. resultant dest string was null terminated
  583. failure - you can use the macro HRESULT_CODE() to get a win32
  584. error code for all hresult failure cases
  585. STRSAFE_E_INSUFFICIENT_BUFFER /
  586. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  587. - this return value is an indication that the copy
  588. operation failed due to insufficient space. When this
  589. error occurs, the destination buffer is modified to
  590. contain a truncated version of the ideal result and is
  591. null terminated. This is useful for situations where
  592. truncation is ok
  593. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  594. return value of this function.
  595. --*/
  596. STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
  597. STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
  598. #ifdef UNICODE
  599. #define StringCchCopyN StringCchCopyNW
  600. #else
  601. #define StringCchCopyN StringCchCopyNA
  602. #endif // !UNICODE
  603. #ifdef STRSAFE_INLINE
  604. STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
  605. {
  606. HRESULT hr;
  607. if ((cchDest > STRSAFE_MAX_CCH) ||
  608. (cchSrc > STRSAFE_MAX_CCH))
  609. {
  610. hr = STRSAFE_E_INVALID_PARAMETER;
  611. }
  612. else
  613. {
  614. hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
  615. }
  616. return hr;
  617. }
  618. STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
  619. {
  620. HRESULT hr;
  621. if ((cchDest > STRSAFE_MAX_CCH) ||
  622. (cchSrc > STRSAFE_MAX_CCH))
  623. {
  624. hr = STRSAFE_E_INVALID_PARAMETER;
  625. }
  626. else
  627. {
  628. hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
  629. }
  630. return hr;
  631. }
  632. #endif // STRSAFE_INLINE
  633. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  634. #ifndef STRSAFE_NO_CB_FUNCTIONS
  635. /*++
  636. STDAPI
  637. StringCbCopyN(
  638. OUT LPTSTR pszDest,
  639. IN size_t cbDest,
  640. IN LPCTSTR pszSrc,
  641. IN size_t cbSrc
  642. );
  643. Routine Description:
  644. This routine is a safer version of the C built-in function 'strncpy'.
  645. The size of the destination buffer (in bytes) is a parameter and this
  646. function will not write past the end of this buffer and it will ALWAYS
  647. null terminate the destination buffer (unless it is zero length).
  648. This routine is meant as a replacement for strncpy, but it does behave
  649. differently. This function will not pad the destination buffer with extra
  650. null termination characters if cbSrc is greater than the size of pszSrc.
  651. This function returns a hresult, and not a pointer. It returns
  652. S_OK if the entire string or the first cbSrc characters were
  653. copied without truncation and the resultant destination string was null
  654. terminated, otherwise it will return a failure code. In failure cases as
  655. much of pszSrc will be copied to pszDest as possible, and pszDest will be
  656. null terminated.
  657. Arguments:
  658. pszDest - destination string
  659. cbDest - size of destination buffer in bytes.
  660. length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
  661. hold all of the source including the null terminator
  662. pszSrc - source string
  663. cbSrc - maximum number of bytes to copy from source string,
  664. not including the null terminator.
  665. Notes:
  666. Behavior is undefined if source and destination strings overlap.
  667. pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require
  668. the handling of NULL values.
  669. Return Value:
  670. S_OK - if there was source data and it was all copied and the
  671. resultant dest string was null terminated
  672. failure - you can use the macro HRESULT_CODE() to get a win32
  673. error code for all hresult failure cases
  674. STRSAFE_E_INSUFFICIENT_BUFFER /
  675. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  676. - this return value is an indication that the copy
  677. operation failed due to insufficient space. When this
  678. error occurs, the destination buffer is modified to
  679. contain a truncated version of the ideal result and is
  680. null terminated. This is useful for situations where
  681. truncation is ok
  682. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  683. return value of this function.
  684. --*/
  685. STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc);
  686. STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc);
  687. #ifdef UNICODE
  688. #define StringCbCopyN StringCbCopyNW
  689. #else
  690. #define StringCbCopyN StringCbCopyNA
  691. #endif // !UNICODE
  692. #ifdef STRSAFE_INLINE
  693. STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc)
  694. {
  695. HRESULT hr;
  696. size_t cchDest;
  697. size_t cchSrc;
  698. // convert to count of characters
  699. cchDest = cbDest / sizeof(char);
  700. cchSrc = cbSrc / sizeof(char);
  701. if ((cchDest > STRSAFE_MAX_CCH) ||
  702. (cchSrc > STRSAFE_MAX_CCH))
  703. {
  704. hr = STRSAFE_E_INVALID_PARAMETER;
  705. }
  706. else
  707. {
  708. hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
  709. }
  710. return hr;
  711. }
  712. STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc)
  713. {
  714. HRESULT hr;
  715. size_t cchDest;
  716. size_t cchSrc;
  717. // convert to count of characters
  718. cchDest = cbDest / sizeof(wchar_t);
  719. cchSrc = cbSrc / sizeof(wchar_t);
  720. if ((cchDest > STRSAFE_MAX_CCH) ||
  721. (cchSrc > STRSAFE_MAX_CCH))
  722. {
  723. hr = STRSAFE_E_INVALID_PARAMETER;
  724. }
  725. else
  726. {
  727. hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
  728. }
  729. return hr;
  730. }
  731. #endif // STRSAFE_INLINE
  732. #endif // !STRSAFE_NO_CB_FUNCTIONS
  733. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  734. /*++
  735. STDAPI
  736. StringCchCopyNEx(
  737. OUT LPTSTR pszDest OPTIONAL,
  738. IN size_t cchDest,
  739. IN LPCTSTR pszSrc OPTIONAL,
  740. IN size_t cchSrc,
  741. OUT LPTSTR* ppszDestEnd OPTIONAL,
  742. OUT size_t* pcchRemaining OPTIONAL,
  743. IN DWORD dwFlags
  744. );
  745. Routine Description:
  746. This routine is a safer version of the C built-in function 'strncpy' with
  747. some additional parameters. In addition to functionality provided by
  748. StringCchCopyN, this routine also returns a pointer to the end of the
  749. destination string and the number of characters left in the destination
  750. string including the null terminator. The flags parameter allows
  751. additional controls.
  752. This routine is meant as a replacement for strncpy, but it does behave
  753. differently. This function will not pad the destination buffer with extra
  754. null termination characters if cchSrc is greater than the length of pszSrc.
  755. Arguments:
  756. pszDest - destination string
  757. cchDest - size of destination buffer in characters.
  758. length must be = (_tcslen(pszSrc) + 1) to hold all of
  759. the source including the null terminator
  760. pszSrc - source string
  761. cchSrc - maximum number of characters to copy from the source
  762. string
  763. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  764. pointer to the end of the destination string. If the
  765. function copied any data, the result will point to the
  766. null termination character
  767. pcchRemaining - if pcchRemaining is non-null, the function will return the
  768. number of characters left in the destination string,
  769. including the null terminator
  770. dwFlags - controls some details of the string copy:
  771. STRSAFE_FILL_BEHIND_NULL
  772. if the function succeeds, the low byte of dwFlags will be
  773. used to fill the uninitialize part of destination buffer
  774. behind the null terminator
  775. STRSAFE_IGNORE_NULLS
  776. treat NULL string pointers like empty strings (TEXT("")).
  777. this flag is useful for emulating functions like lstrcpy
  778. STRSAFE_FILL_ON_FAILURE
  779. if the function fails, the low byte of dwFlags will be
  780. used to fill all of the destination buffer, and it will
  781. be null terminated. This will overwrite any truncated
  782. string returned when the failure is
  783. STRSAFE_E_INSUFFICIENT_BUFFER
  784. STRSAFE_NO_TRUNCATION /
  785. STRSAFE_NULL_ON_FAILURE
  786. if the function fails, the destination buffer will be set
  787. to the empty string. This will overwrite any truncated string
  788. returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  789. Notes:
  790. Behavior is undefined if source and destination strings overlap.
  791. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  792. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  793. may be NULL. An error may still be returned even though NULLS are ignored
  794. due to insufficient space.
  795. Return Value:
  796. S_OK - if there was source data and it was all copied and the
  797. resultant dest string was null terminated
  798. failure - you can use the macro HRESULT_CODE() to get a win32
  799. error code for all hresult failure cases
  800. STRSAFE_E_INSUFFICIENT_BUFFER /
  801. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  802. - this return value is an indication that the copy
  803. operation failed due to insufficient space. When this
  804. error occurs, the destination buffer is modified to
  805. contain a truncated version of the ideal result and is
  806. null terminated. This is useful for situations where
  807. truncation is ok.
  808. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  809. return value of this function
  810. --*/
  811. STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  812. STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  813. #ifdef UNICODE
  814. #define StringCchCopyNEx StringCchCopyNExW
  815. #else
  816. #define StringCchCopyNEx StringCchCopyNExA
  817. #endif // !UNICODE
  818. #ifdef STRSAFE_INLINE
  819. STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  820. {
  821. HRESULT hr;
  822. if ((cchDest > STRSAFE_MAX_CCH) ||
  823. (cchSrc > STRSAFE_MAX_CCH))
  824. {
  825. hr = STRSAFE_E_INVALID_PARAMETER;
  826. }
  827. else
  828. {
  829. size_t cbDest;
  830. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  831. cbDest = cchDest * sizeof(char);
  832. hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
  833. }
  834. return hr;
  835. }
  836. STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  837. {
  838. HRESULT hr;
  839. if ((cchDest > STRSAFE_MAX_CCH) ||
  840. (cchSrc > STRSAFE_MAX_CCH))
  841. {
  842. hr = STRSAFE_E_INVALID_PARAMETER;
  843. }
  844. else
  845. {
  846. size_t cbDest;
  847. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  848. cbDest = cchDest * sizeof(wchar_t);
  849. hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
  850. }
  851. return hr;
  852. }
  853. #endif // STRSAFE_INLINE
  854. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  855. #ifndef STRSAFE_NO_CB_FUNCTIONS
  856. /*++
  857. STDAPI
  858. StringCbCopyNEx(
  859. OUT LPTSTR pszDest OPTIONAL,
  860. IN size_t cbDest,
  861. IN LPCTSTR pszSrc OPTIONAL,
  862. IN size_t cbSrc,
  863. OUT LPTSTR* ppszDestEnd OPTIONAL,
  864. OUT size_t* pcbRemaining OPTIONAL,
  865. IN DWORD dwFlags
  866. );
  867. Routine Description:
  868. This routine is a safer version of the C built-in function 'strncpy' with
  869. some additional parameters. In addition to functionality provided by
  870. StringCbCopyN, this routine also returns a pointer to the end of the
  871. destination string and the number of bytes left in the destination string
  872. including the null terminator. The flags parameter allows additional controls.
  873. This routine is meant as a replacement for strncpy, but it does behave
  874. differently. This function will not pad the destination buffer with extra
  875. null termination characters if cbSrc is greater than the size of pszSrc.
  876. Arguments:
  877. pszDest - destination string
  878. cbDest - size of destination buffer in bytes.
  879. length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
  880. hold all of the source including the null terminator
  881. pszSrc - source string
  882. cbSrc - maximum number of bytes to copy from source string
  883. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  884. pointer to the end of the destination string. If the
  885. function copied any data, the result will point to the
  886. null termination character
  887. pcbRemaining - pcbRemaining is non-null,the function will return the
  888. number of bytes left in the destination string,
  889. including the null terminator
  890. dwFlags - controls some details of the string copy:
  891. STRSAFE_FILL_BEHIND_NULL
  892. if the function succeeds, the low byte of dwFlags will be
  893. used to fill the uninitialize part of destination buffer
  894. behind the null terminator
  895. STRSAFE_IGNORE_NULLS
  896. treat NULL string pointers like empty strings (TEXT("")).
  897. this flag is useful for emulating functions like lstrcpy
  898. STRSAFE_FILL_ON_FAILURE
  899. if the function fails, the low byte of dwFlags will be
  900. used to fill all of the destination buffer, and it will
  901. be null terminated. This will overwrite any truncated
  902. string returned when the failure is
  903. STRSAFE_E_INSUFFICIENT_BUFFER
  904. STRSAFE_NO_TRUNCATION /
  905. STRSAFE_NULL_ON_FAILURE
  906. if the function fails, the destination buffer will be set
  907. to the empty string. This will overwrite any truncated string
  908. returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  909. Notes:
  910. Behavior is undefined if source and destination strings overlap.
  911. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  912. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  913. may be NULL. An error may still be returned even though NULLS are ignored
  914. due to insufficient space.
  915. Return Value:
  916. S_OK - if there was source data and it was all copied and the
  917. resultant dest string was null terminated
  918. failure - you can use the macro HRESULT_CODE() to get a win32
  919. error code for all hresult failure cases
  920. STRSAFE_E_INSUFFICIENT_BUFFER /
  921. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  922. - this return value is an indication that the copy
  923. operation failed due to insufficient space. When this
  924. error occurs, the destination buffer is modified to
  925. contain a truncated version of the ideal result and is
  926. null terminated. This is useful for situations where
  927. truncation is ok.
  928. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  929. return value of this function
  930. --*/
  931. STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  932. STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  933. #ifdef UNICODE
  934. #define StringCbCopyNEx StringCbCopyNExW
  935. #else
  936. #define StringCbCopyNEx StringCbCopyNExA
  937. #endif // !UNICODE
  938. #ifdef STRSAFE_INLINE
  939. STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  940. {
  941. HRESULT hr;
  942. size_t cchDest;
  943. size_t cchSrc;
  944. size_t cchRemaining = 0;
  945. cchDest = cbDest / sizeof(char);
  946. cchSrc = cbSrc / sizeof(char);
  947. if ((cchDest > STRSAFE_MAX_CCH) ||
  948. (cchSrc > STRSAFE_MAX_CCH))
  949. {
  950. hr = STRSAFE_E_INVALID_PARAMETER;
  951. }
  952. else
  953. {
  954. hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
  955. }
  956. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  957. {
  958. if (pcbRemaining)
  959. {
  960. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  961. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  962. }
  963. }
  964. return hr;
  965. }
  966. STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  967. {
  968. HRESULT hr;
  969. size_t cchDest;
  970. size_t cchSrc;
  971. size_t cchRemaining = 0;
  972. cchDest = cbDest / sizeof(wchar_t);
  973. cchSrc = cbSrc / sizeof(wchar_t);
  974. if ((cchDest > STRSAFE_MAX_CCH) ||
  975. (cchSrc > STRSAFE_MAX_CCH))
  976. {
  977. hr = STRSAFE_E_INVALID_PARAMETER;
  978. }
  979. else
  980. {
  981. hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
  982. }
  983. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  984. {
  985. if (pcbRemaining)
  986. {
  987. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  988. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  989. }
  990. }
  991. return hr;
  992. }
  993. #endif // STRSAFE_INLINE
  994. #endif // !STRSAFE_NO_CB_FUNCTIONS
  995. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  996. /*++
  997. STDAPI
  998. StringCchCat(
  999. IN OUT LPTSTR pszDest,
  1000. IN size_t cchDest,
  1001. IN LPCTSTR pszSrc
  1002. );
  1003. Routine Description:
  1004. This routine is a safer version of the C built-in function 'strcat'.
  1005. The size of the destination buffer (in characters) is a parameter and this
  1006. function will not write past the end of this buffer and it will ALWAYS
  1007. null terminate the destination buffer (unless it is zero length).
  1008. This function returns a hresult, and not a pointer. It returns
  1009. S_OK if the string was concatenated without truncation and null terminated,
  1010. otherwise it will return a failure code. In failure cases as much of pszSrc
  1011. will be appended to pszDest as possible, and pszDest will be null
  1012. terminated.
  1013. Arguments:
  1014. pszDest - destination string which must be null terminated
  1015. cchDest - size of destination buffer in characters.
  1016. length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
  1017. to hold all of the combine string plus the null
  1018. terminator
  1019. pszSrc - source string which must be null terminated
  1020. Notes:
  1021. Behavior is undefined if source and destination strings overlap.
  1022. pszDest and pszSrc should not be NULL. See StringCchCatEx if you require
  1023. the handling of NULL values.
  1024. Return Value:
  1025. S_OK - if there was source data and it was all concatenated and
  1026. the resultant dest string was null terminated
  1027. failure - you can use the macro HRESULT_CODE() to get a win32
  1028. error code for all hresult failure cases
  1029. STRSAFE_E_INSUFFICIENT_BUFFER /
  1030. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1031. - this return value is an indication that the operation
  1032. failed due to insufficient space. When this error occurs,
  1033. the destination buffer is modified to contain a truncated
  1034. version of the ideal result and is null terminated. This
  1035. is useful for situations where truncation is ok.
  1036. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1037. return value of this function
  1038. --*/
  1039. STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc);
  1040. STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  1041. #ifdef UNICODE
  1042. #define StringCchCat StringCchCatW
  1043. #else
  1044. #define StringCchCat StringCchCatA
  1045. #endif // !UNICODE
  1046. #ifdef STRSAFE_INLINE
  1047. STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc)
  1048. {
  1049. HRESULT hr;
  1050. if (cchDest > STRSAFE_MAX_CCH)
  1051. {
  1052. hr = STRSAFE_E_INVALID_PARAMETER;
  1053. }
  1054. else
  1055. {
  1056. hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
  1057. }
  1058. return hr;
  1059. }
  1060. STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  1061. {
  1062. HRESULT hr;
  1063. if (cchDest > STRSAFE_MAX_CCH)
  1064. {
  1065. hr = STRSAFE_E_INVALID_PARAMETER;
  1066. }
  1067. else
  1068. {
  1069. hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
  1070. }
  1071. return hr;
  1072. }
  1073. #endif // STRSAFE_INLINE
  1074. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  1075. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1076. /*++
  1077. STDAPI
  1078. StringCbCat(
  1079. IN OUT LPTSTR pszDest,
  1080. IN size_t cbDest,
  1081. IN LPCTSTR pszSrc
  1082. );
  1083. Routine Description:
  1084. This routine is a safer version of the C built-in function 'strcat'.
  1085. The size of the destination buffer (in bytes) is a parameter and this
  1086. function will not write past the end of this buffer and it will ALWAYS
  1087. null terminate the destination buffer (unless it is zero length).
  1088. This function returns a hresult, and not a pointer. It returns
  1089. S_OK if the string was concatenated without truncation and null terminated,
  1090. otherwise it will return a failure code. In failure cases as much of pszSrc
  1091. will be appended to pszDest as possible, and pszDest will be null
  1092. terminated.
  1093. Arguments:
  1094. pszDest - destination string which must be null terminated
  1095. cbDest - size of destination buffer in bytes.
  1096. length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
  1097. to hold all of the combine string plus the null
  1098. terminator
  1099. pszSrc - source string which must be null terminated
  1100. Notes:
  1101. Behavior is undefined if source and destination strings overlap.
  1102. pszDest and pszSrc should not be NULL. See StringCbCatEx if you require
  1103. the handling of NULL values.
  1104. Return Value:
  1105. S_OK - if there was source data and it was all concatenated and
  1106. the resultant dest string was null terminated
  1107. failure - you can use the macro HRESULT_CODE() to get a win32
  1108. error code for all hresult failure cases
  1109. STRSAFE_E_INSUFFICIENT_BUFFER /
  1110. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1111. - this return value is an indication that the operation
  1112. failed due to insufficient space. When this error occurs,
  1113. the destination buffer is modified to contain a truncated
  1114. version of the ideal result and is null terminated. This
  1115. is useful for situations where truncation is ok.
  1116. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1117. return value of this function
  1118. --*/
  1119. STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc);
  1120. STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
  1121. #ifdef UNICODE
  1122. #define StringCbCat StringCbCatW
  1123. #else
  1124. #define StringCbCat StringCbCatA
  1125. #endif // !UNICODE
  1126. #ifdef STRSAFE_INLINE
  1127. STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc)
  1128. {
  1129. HRESULT hr;
  1130. size_t cchDest;
  1131. cchDest = cbDest / sizeof(char);
  1132. if (cchDest > STRSAFE_MAX_CCH)
  1133. {
  1134. hr = STRSAFE_E_INVALID_PARAMETER;
  1135. }
  1136. else
  1137. {
  1138. hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
  1139. }
  1140. return hr;
  1141. }
  1142. STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
  1143. {
  1144. HRESULT hr;
  1145. size_t cchDest;
  1146. cchDest = cbDest / sizeof(wchar_t);
  1147. if (cchDest > STRSAFE_MAX_CCH)
  1148. {
  1149. hr = STRSAFE_E_INVALID_PARAMETER;
  1150. }
  1151. else
  1152. {
  1153. hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
  1154. }
  1155. return hr;
  1156. }
  1157. #endif // STRSAFE_INLINE
  1158. #endif // !STRSAFE_NO_CB_FUNCTIONS
  1159. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  1160. /*++
  1161. STDAPI
  1162. StringCchCatEx(
  1163. IN OUT LPTSTR pszDest OPTIONAL,
  1164. IN size_t cchDest,
  1165. IN LPCTSTR pszSrc OPTIONAL,
  1166. OUT LPTSTR* ppszDestEnd OPTIONAL,
  1167. OUT size_t* pcchRemaining OPTIONAL,
  1168. IN DWORD dwFlags
  1169. );
  1170. Routine Description:
  1171. This routine is a safer version of the C built-in function 'strcat' with
  1172. some additional parameters. In addition to functionality provided by
  1173. StringCchCat, this routine also returns a pointer to the end of the
  1174. destination string and the number of characters left in the destination string
  1175. including the null terminator. The flags parameter allows additional controls.
  1176. Arguments:
  1177. pszDest - destination string which must be null terminated
  1178. cchDest - size of destination buffer in characters
  1179. length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
  1180. to hold all of the combine string plus the null
  1181. terminator.
  1182. pszSrc - source string which must be null terminated
  1183. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  1184. pointer to the end of the destination string. If the
  1185. function appended any data, the result will point to the
  1186. null termination character
  1187. pcchRemaining - if pcchRemaining is non-null, the function will return the
  1188. number of characters left in the destination string,
  1189. including the null terminator
  1190. dwFlags - controls some details of the string copy:
  1191. STRSAFE_FILL_BEHIND_NULL
  1192. if the function succeeds, the low byte of dwFlags will be
  1193. used to fill the uninitialize part of destination buffer
  1194. behind the null terminator
  1195. STRSAFE_IGNORE_NULLS
  1196. treat NULL string pointers like empty strings (TEXT("")).
  1197. this flag is useful for emulating functions like lstrcat
  1198. STRSAFE_FILL_ON_FAILURE
  1199. if the function fails, the low byte of dwFlags will be
  1200. used to fill all of the destination buffer, and it will
  1201. be null terminated. This will overwrite any pre-existing
  1202. or truncated string
  1203. STRSAFE_NULL_ON_FAILURE
  1204. if the function fails, the destination buffer will be set
  1205. to the empty string. This will overwrite any pre-existing or
  1206. truncated string
  1207. STRSAFE_NO_TRUNCATION
  1208. if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  1209. will not contain a truncated string, it will remain unchanged.
  1210. Notes:
  1211. Behavior is undefined if source and destination strings overlap.
  1212. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1213. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1214. may be NULL. An error may still be returned even though NULLS are ignored
  1215. due to insufficient space.
  1216. Return Value:
  1217. S_OK - if there was source data and it was all concatenated and
  1218. the resultant dest string was null terminated
  1219. failure - you can use the macro HRESULT_CODE() to get a win32
  1220. error code for all hresult failure cases
  1221. STRSAFE_E_INSUFFICIENT_BUFFER /
  1222. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1223. - this return value is an indication that the operation
  1224. failed due to insufficient space. When this error
  1225. occurs, the destination buffer is modified to contain
  1226. a truncated version of the ideal result and is null
  1227. terminated. This is useful for situations where
  1228. truncation is ok.
  1229. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1230. return value of this function
  1231. --*/
  1232. STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1233. STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1234. #ifdef UNICODE
  1235. #define StringCchCatEx StringCchCatExW
  1236. #else
  1237. #define StringCchCatEx StringCchCatExA
  1238. #endif // !UNICODE
  1239. #ifdef STRSAFE_INLINE
  1240. STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1241. {
  1242. HRESULT hr;
  1243. if (cchDest > STRSAFE_MAX_CCH)
  1244. {
  1245. hr = STRSAFE_E_INVALID_PARAMETER;
  1246. }
  1247. else
  1248. {
  1249. size_t cbDest;
  1250. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  1251. cbDest = cchDest * sizeof(char);
  1252. hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  1253. }
  1254. return hr;
  1255. }
  1256. STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1257. {
  1258. HRESULT hr;
  1259. if (cchDest > STRSAFE_MAX_CCH)
  1260. {
  1261. hr = STRSAFE_E_INVALID_PARAMETER;
  1262. }
  1263. else
  1264. {
  1265. size_t cbDest;
  1266. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1267. cbDest = cchDest * sizeof(wchar_t);
  1268. hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  1269. }
  1270. return hr;
  1271. }
  1272. #endif // STRSAFE_INLINE
  1273. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  1274. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1275. /*++
  1276. STDAPI
  1277. StringCbCatEx(
  1278. IN OUT LPTSTR pszDest OPTIONAL,
  1279. IN size_t cbDest,
  1280. IN LPCTSTR pszSrc OPTIONAL,
  1281. OUT LPTSTR* ppszDestEnd OPTIONAL,
  1282. OUT size_t* pcbRemaining OPTIONAL,
  1283. IN DWORD dwFlags
  1284. );
  1285. Routine Description:
  1286. This routine is a safer version of the C built-in function 'strcat' with
  1287. some additional parameters. In addition to functionality provided by
  1288. StringCbCat, this routine also returns a pointer to the end of the
  1289. destination string and the number of bytes left in the destination string
  1290. including the null terminator. The flags parameter allows additional controls.
  1291. Arguments:
  1292. pszDest - destination string which must be null terminated
  1293. cbDest - size of destination buffer in bytes.
  1294. length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
  1295. to hold all of the combine string plus the null
  1296. terminator.
  1297. pszSrc - source string which must be null terminated
  1298. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  1299. pointer to the end of the destination string. If the
  1300. function appended any data, the result will point to the
  1301. null termination character
  1302. pcbRemaining - if pcbRemaining is non-null, the function will return
  1303. the number of bytes left in the destination string,
  1304. including the null terminator
  1305. dwFlags - controls some details of the string copy:
  1306. STRSAFE_FILL_BEHIND_NULL
  1307. if the function succeeds, the low byte of dwFlags will be
  1308. used to fill the uninitialize part of destination buffer
  1309. behind the null terminator
  1310. STRSAFE_IGNORE_NULLS
  1311. treat NULL string pointers like empty strings (TEXT("")).
  1312. this flag is useful for emulating functions like lstrcat
  1313. STRSAFE_FILL_ON_FAILURE
  1314. if the function fails, the low byte of dwFlags will be
  1315. used to fill all of the destination buffer, and it will
  1316. be null terminated. This will overwrite any pre-existing
  1317. or truncated string
  1318. STRSAFE_NULL_ON_FAILURE
  1319. if the function fails, the destination buffer will be set
  1320. to the empty string. This will overwrite any pre-existing or
  1321. truncated string
  1322. STRSAFE_NO_TRUNCATION
  1323. if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  1324. will not contain a truncated string, it will remain unchanged.
  1325. Notes:
  1326. Behavior is undefined if source and destination strings overlap.
  1327. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1328. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1329. may be NULL. An error may still be returned even though NULLS are ignored
  1330. due to insufficient space.
  1331. Return Value:
  1332. S_OK - if there was source data and it was all concatenated
  1333. and the resultant dest string was null terminated
  1334. failure - you can use the macro HRESULT_CODE() to get a win32
  1335. error code for all hresult failure cases
  1336. STRSAFE_E_INSUFFICIENT_BUFFER /
  1337. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1338. - this return value is an indication that the operation
  1339. failed due to insufficient space. When this error
  1340. occurs, the destination buffer is modified to contain
  1341. a truncated version of the ideal result and is null
  1342. terminated. This is useful for situations where
  1343. truncation is ok.
  1344. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1345. return value of this function
  1346. --*/
  1347. STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1348. STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1349. #ifdef UNICODE
  1350. #define StringCbCatEx StringCbCatExW
  1351. #else
  1352. #define StringCbCatEx StringCbCatExA
  1353. #endif // !UNICODE
  1354. #ifdef STRSAFE_INLINE
  1355. STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1356. {
  1357. HRESULT hr;
  1358. size_t cchDest;
  1359. size_t cchRemaining = 0;
  1360. cchDest = cbDest / sizeof(char);
  1361. if (cchDest > STRSAFE_MAX_CCH)
  1362. {
  1363. hr = STRSAFE_E_INVALID_PARAMETER;
  1364. }
  1365. else
  1366. {
  1367. hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  1368. }
  1369. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  1370. {
  1371. if (pcbRemaining)
  1372. {
  1373. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  1374. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  1375. }
  1376. }
  1377. return hr;
  1378. }
  1379. STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1380. {
  1381. HRESULT hr;
  1382. size_t cchDest;
  1383. size_t cchRemaining = 0;
  1384. cchDest = cbDest / sizeof(wchar_t);
  1385. if (cchDest > STRSAFE_MAX_CCH)
  1386. {
  1387. hr = STRSAFE_E_INVALID_PARAMETER;
  1388. }
  1389. else
  1390. {
  1391. hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  1392. }
  1393. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  1394. {
  1395. if (pcbRemaining)
  1396. {
  1397. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1398. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  1399. }
  1400. }
  1401. return hr;
  1402. }
  1403. #endif // STRSAFE_INLINE
  1404. #endif // !STRSAFE_NO_CB_FUNCTIONS
  1405. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  1406. /*++
  1407. STDAPI
  1408. StringCchCatN(
  1409. IN OUT LPTSTR pszDest,
  1410. IN size_t cchDest,
  1411. IN LPCTSTR pszSrc,
  1412. IN size_t cchMaxAppend
  1413. );
  1414. Routine Description:
  1415. This routine is a safer version of the C built-in function 'strncat'.
  1416. The size of the destination buffer (in characters) is a parameter as well as
  1417. the maximum number of characters to append, excluding the null terminator.
  1418. This function will not write past the end of the destination buffer and it will
  1419. ALWAYS null terminate pszDest (unless it is zero length).
  1420. This function returns a hresult, and not a pointer. It returns
  1421. S_OK if all of pszSrc or the first cchMaxAppend characters were appended
  1422. to the destination string and it was null terminated, otherwise it will
  1423. return a failure code. In failure cases as much of pszSrc will be appended
  1424. to pszDest as possible, and pszDest will be null terminated.
  1425. Arguments:
  1426. pszDest - destination string which must be null terminated
  1427. cchDest - size of destination buffer in characters.
  1428. length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
  1429. to hold all of the combine string plus the null
  1430. terminator.
  1431. pszSrc - source string
  1432. cchMaxAppend - maximum number of characters to append
  1433. Notes:
  1434. Behavior is undefined if source and destination strings overlap.
  1435. pszDest and pszSrc should not be NULL. See StringCchCatNEx if you require
  1436. the handling of NULL values.
  1437. Return Value:
  1438. S_OK - if all of pszSrc or the first cchMaxAppend characters
  1439. were concatenated to pszDest and the resultant dest
  1440. string was null terminated
  1441. failure - you can use the macro HRESULT_CODE() to get a win32
  1442. error code for all hresult failure cases
  1443. STRSAFE_E_INSUFFICIENT_BUFFER /
  1444. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1445. - this return value is an indication that the operation
  1446. failed due to insufficient space. When this error
  1447. occurs, the destination buffer is modified to contain
  1448. a truncated version of the ideal result and is null
  1449. terminated. This is useful for situations where
  1450. truncation is ok.
  1451. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1452. return value of this function
  1453. --*/
  1454. STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
  1455. STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
  1456. #ifdef UNICODE
  1457. #define StringCchCatN StringCchCatNW
  1458. #else
  1459. #define StringCchCatN StringCchCatNA
  1460. #endif // !UNICODE
  1461. #ifdef STRSAFE_INLINE
  1462. STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
  1463. {
  1464. HRESULT hr;
  1465. if (cchDest > STRSAFE_MAX_CCH)
  1466. {
  1467. hr = STRSAFE_E_INVALID_PARAMETER;
  1468. }
  1469. else
  1470. {
  1471. hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
  1472. }
  1473. return hr;
  1474. }
  1475. STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
  1476. {
  1477. HRESULT hr;
  1478. if (cchDest > STRSAFE_MAX_CCH)
  1479. {
  1480. hr = STRSAFE_E_INVALID_PARAMETER;
  1481. }
  1482. else
  1483. {
  1484. hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
  1485. }
  1486. return hr;
  1487. }
  1488. #endif // STRSAFE_INLINE
  1489. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  1490. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1491. /*++
  1492. STDAPI
  1493. StringCbCatN(
  1494. IN OUT LPTSTR pszDest,
  1495. IN size_t cbDest,
  1496. IN LPCTSTR pszSrc,
  1497. IN size_t cbMaxAppend
  1498. );
  1499. Routine Description:
  1500. This routine is a safer version of the C built-in function 'strncat'.
  1501. The size of the destination buffer (in bytes) is a parameter as well as
  1502. the maximum number of bytes to append, excluding the null terminator.
  1503. This function will not write past the end of the destination buffer and it will
  1504. ALWAYS null terminate pszDest (unless it is zero length).
  1505. This function returns a hresult, and not a pointer. It returns
  1506. S_OK if all of pszSrc or the first cbMaxAppend bytes were appended
  1507. to the destination string and it was null terminated, otherwise it will
  1508. return a failure code. In failure cases as much of pszSrc will be appended
  1509. to pszDest as possible, and pszDest will be null terminated.
  1510. Arguments:
  1511. pszDest - destination string which must be null terminated
  1512. cbDest - size of destination buffer in bytes.
  1513. length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
  1514. to hold all of the combine string plus the null
  1515. terminator.
  1516. pszSrc - source string
  1517. cbMaxAppend - maximum number of bytes to append
  1518. Notes:
  1519. Behavior is undefined if source and destination strings overlap.
  1520. pszDest and pszSrc should not be NULL. See StringCbCatNEx if you require
  1521. the handling of NULL values.
  1522. Return Value:
  1523. S_OK - if all of pszSrc or the first cbMaxAppend bytes were
  1524. concatenated to pszDest and the resultant dest string
  1525. was null terminated
  1526. failure - you can use the macro HRESULT_CODE() to get a win32
  1527. error code for all hresult failure cases
  1528. STRSAFE_E_INSUFFICIENT_BUFFER /
  1529. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1530. - this return value is an indication that the operation
  1531. failed due to insufficient space. When this error
  1532. occurs, the destination buffer is modified to contain
  1533. a truncated version of the ideal result and is null
  1534. terminated. This is useful for situations where
  1535. truncation is ok.
  1536. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1537. return value of this function
  1538. --*/
  1539. STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend);
  1540. STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend);
  1541. #ifdef UNICODE
  1542. #define StringCbCatN StringCbCatNW
  1543. #else
  1544. #define StringCbCatN StringCbCatNA
  1545. #endif // !UNICODE
  1546. #ifdef STRSAFE_INLINE
  1547. STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend)
  1548. {
  1549. HRESULT hr;
  1550. size_t cchDest;
  1551. cchDest = cbDest / sizeof(char);
  1552. if (cchDest > STRSAFE_MAX_CCH)
  1553. {
  1554. hr = STRSAFE_E_INVALID_PARAMETER;
  1555. }
  1556. else
  1557. {
  1558. size_t cchMaxAppend;
  1559. cchMaxAppend = cbMaxAppend / sizeof(char);
  1560. hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
  1561. }
  1562. return hr;
  1563. }
  1564. STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend)
  1565. {
  1566. HRESULT hr;
  1567. size_t cchDest;
  1568. cchDest = cbDest / sizeof(wchar_t);
  1569. if (cchDest > STRSAFE_MAX_CCH)
  1570. {
  1571. hr = STRSAFE_E_INVALID_PARAMETER;
  1572. }
  1573. else
  1574. {
  1575. size_t cchMaxAppend;
  1576. cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
  1577. hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
  1578. }
  1579. return hr;
  1580. }
  1581. #endif // STRSAFE_INLINE
  1582. #endif // !STRSAFE_NO_CB_FUNCTIONS
  1583. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  1584. /*++
  1585. STDAPI
  1586. StringCchCatNEx(
  1587. IN OUT LPTSTR pszDest OPTIONAL,
  1588. IN size_t cchDest,
  1589. IN LPCTSTR pszSrc OPTIONAL,
  1590. IN size_t cchMaxAppend,
  1591. OUT LPTSTR* ppszDestEnd OPTIONAL,
  1592. OUT size_t* pcchRemaining OPTIONAL,
  1593. IN DWORD dwFlags
  1594. );
  1595. Routine Description:
  1596. This routine is a safer version of the C built-in function 'strncat', with
  1597. some additional parameters. In addition to functionality provided by
  1598. StringCchCatN, this routine also returns a pointer to the end of the
  1599. destination string and the number of characters left in the destination string
  1600. including the null terminator. The flags parameter allows additional controls.
  1601. Arguments:
  1602. pszDest - destination string which must be null terminated
  1603. cchDest - size of destination buffer in characters.
  1604. length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
  1605. to hold all of the combine string plus the null
  1606. terminator.
  1607. pszSrc - source string
  1608. cchMaxAppend - maximum number of characters to append
  1609. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  1610. pointer to the end of the destination string. If the
  1611. function appended any data, the result will point to the
  1612. null termination character
  1613. pcchRemaining - if pcchRemaining is non-null, the function will return the
  1614. number of characters left in the destination string,
  1615. including the null terminator
  1616. dwFlags - controls some details of the string copy:
  1617. STRSAFE_FILL_BEHIND_NULL
  1618. if the function succeeds, the low byte of dwFlags will be
  1619. used to fill the uninitialize part of destination buffer
  1620. behind the null terminator
  1621. STRSAFE_IGNORE_NULLS
  1622. treat NULL string pointers like empty strings (TEXT(""))
  1623. STRSAFE_FILL_ON_FAILURE
  1624. if the function fails, the low byte of dwFlags will be
  1625. used to fill all of the destination buffer, and it will
  1626. be null terminated. This will overwrite any pre-existing
  1627. or truncated string
  1628. STRSAFE_NULL_ON_FAILURE
  1629. if the function fails, the destination buffer will be set
  1630. to the empty string. This will overwrite any pre-existing or
  1631. truncated string
  1632. STRSAFE_NO_TRUNCATION
  1633. if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  1634. will not contain a truncated string, it will remain unchanged.
  1635. Notes:
  1636. Behavior is undefined if source and destination strings overlap.
  1637. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1638. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1639. may be NULL. An error may still be returned even though NULLS are ignored
  1640. due to insufficient space.
  1641. Return Value:
  1642. S_OK - if all of pszSrc or the first cchMaxAppend characters
  1643. were concatenated to pszDest and the resultant dest
  1644. string was null terminated
  1645. failure - you can use the macro HRESULT_CODE() to get a win32
  1646. error code for all hresult failure cases
  1647. STRSAFE_E_INSUFFICIENT_BUFFER /
  1648. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1649. - this return value is an indication that the operation
  1650. failed due to insufficient space. When this error
  1651. occurs, the destination buffer is modified to contain
  1652. a truncated version of the ideal result and is null
  1653. terminated. This is useful for situations where
  1654. truncation is ok.
  1655. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1656. return value of this function
  1657. --*/
  1658. STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1659. STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1660. #ifdef UNICODE
  1661. #define StringCchCatNEx StringCchCatNExW
  1662. #else
  1663. #define StringCchCatNEx StringCchCatNExA
  1664. #endif // !UNICODE
  1665. #ifdef STRSAFE_INLINE
  1666. STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1667. {
  1668. HRESULT hr;
  1669. if (cchDest > STRSAFE_MAX_CCH)
  1670. {
  1671. hr = STRSAFE_E_INVALID_PARAMETER;
  1672. }
  1673. else
  1674. {
  1675. size_t cbDest;
  1676. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  1677. cbDest = cchDest * sizeof(char);
  1678. hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
  1679. }
  1680. return hr;
  1681. }
  1682. STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1683. {
  1684. HRESULT hr;
  1685. if (cchDest > STRSAFE_MAX_CCH)
  1686. {
  1687. hr = STRSAFE_E_INVALID_PARAMETER;
  1688. }
  1689. else
  1690. {
  1691. size_t cbDest;
  1692. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1693. cbDest = cchDest * sizeof(wchar_t);
  1694. hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
  1695. }
  1696. return hr;
  1697. }
  1698. #endif // STRSAFE_INLINE
  1699. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  1700. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1701. /*++
  1702. STDAPI
  1703. StringCbCatNEx(
  1704. IN OUT LPTSTR pszDest OPTIONAL,
  1705. IN size_t cbDest,
  1706. IN LPCTSTR pszSrc OPTIONAL,
  1707. IN size_t cbMaxAppend,
  1708. OUT LPTSTR* ppszDestEnd OPTIONAL,
  1709. OUT size_t* pcchRemaining OPTIONAL,
  1710. IN DWORD dwFlags
  1711. );
  1712. Routine Description:
  1713. This routine is a safer version of the C built-in function 'strncat', with
  1714. some additional parameters. In addition to functionality provided by
  1715. StringCbCatN, this routine also returns a pointer to the end of the
  1716. destination string and the number of bytes left in the destination string
  1717. including the null terminator. The flags parameter allows additional controls.
  1718. Arguments:
  1719. pszDest - destination string which must be null terminated
  1720. cbDest - size of destination buffer in bytes.
  1721. length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
  1722. to hold all of the combine string plus the null
  1723. terminator.
  1724. pszSrc - source string
  1725. cbMaxAppend - maximum number of bytes to append
  1726. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  1727. pointer to the end of the destination string. If the
  1728. function appended any data, the result will point to the
  1729. null termination character
  1730. pcbRemaining - if pcbRemaining is non-null, the function will return the
  1731. number of bytes left in the destination string,
  1732. including the null terminator
  1733. dwFlags - controls some details of the string copy:
  1734. STRSAFE_FILL_BEHIND_NULL
  1735. if the function succeeds, the low byte of dwFlags will be
  1736. used to fill the uninitialize part of destination buffer
  1737. behind the null terminator
  1738. STRSAFE_IGNORE_NULLS
  1739. treat NULL string pointers like empty strings (TEXT(""))
  1740. STRSAFE_FILL_ON_FAILURE
  1741. if the function fails, the low byte of dwFlags will be
  1742. used to fill all of the destination buffer, and it will
  1743. be null terminated. This will overwrite any pre-existing
  1744. or truncated string
  1745. STRSAFE_NULL_ON_FAILURE
  1746. if the function fails, the destination buffer will be set
  1747. to the empty string. This will overwrite any pre-existing or
  1748. truncated string
  1749. STRSAFE_NO_TRUNCATION
  1750. if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  1751. will not contain a truncated string, it will remain unchanged.
  1752. Notes:
  1753. Behavior is undefined if source and destination strings overlap.
  1754. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1755. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1756. may be NULL. An error may still be returned even though NULLS are ignored
  1757. due to insufficient space.
  1758. Return Value:
  1759. S_OK - if all of pszSrc or the first cbMaxAppend bytes were
  1760. concatenated to pszDest and the resultant dest string
  1761. was null terminated
  1762. failure - you can use the macro HRESULT_CODE() to get a win32
  1763. error code for all hresult failure cases
  1764. STRSAFE_E_INSUFFICIENT_BUFFER /
  1765. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1766. - this return value is an indication that the operation
  1767. failed due to insufficient space. When this error
  1768. occurs, the destination buffer is modified to contain
  1769. a truncated version of the ideal result and is null
  1770. terminated. This is useful for situations where
  1771. truncation is ok.
  1772. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1773. return value of this function
  1774. --*/
  1775. STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1776. STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1777. #ifdef UNICODE
  1778. #define StringCbCatNEx StringCbCatNExW
  1779. #else
  1780. #define StringCbCatNEx StringCbCatNExA
  1781. #endif // !UNICODE
  1782. #ifdef STRSAFE_INLINE
  1783. STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1784. {
  1785. HRESULT hr;
  1786. size_t cchDest;
  1787. size_t cchRemaining = 0;
  1788. cchDest = cbDest / sizeof(char);
  1789. if (cchDest > STRSAFE_MAX_CCH)
  1790. {
  1791. hr = STRSAFE_E_INVALID_PARAMETER;
  1792. }
  1793. else
  1794. {
  1795. size_t cchMaxAppend;
  1796. cchMaxAppend = cbMaxAppend / sizeof(char);
  1797. hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
  1798. }
  1799. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  1800. {
  1801. if (pcbRemaining)
  1802. {
  1803. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  1804. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  1805. }
  1806. }
  1807. return hr;
  1808. }
  1809. STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1810. {
  1811. HRESULT hr;
  1812. size_t cchDest;
  1813. size_t cchRemaining = 0;
  1814. cchDest = cbDest / sizeof(wchar_t);
  1815. if (cchDest > STRSAFE_MAX_CCH)
  1816. {
  1817. hr = STRSAFE_E_INVALID_PARAMETER;
  1818. }
  1819. else
  1820. {
  1821. size_t cchMaxAppend;
  1822. cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
  1823. hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
  1824. }
  1825. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  1826. {
  1827. if (pcbRemaining)
  1828. {
  1829. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1830. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  1831. }
  1832. }
  1833. return hr;
  1834. }
  1835. #endif // STRSAFE_INLINE
  1836. #endif // !STRSAFE_NO_CB_FUNCTIONS
  1837. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  1838. /*++
  1839. STDAPI
  1840. StringCchVPrintf(
  1841. OUT LPTSTR pszDest,
  1842. IN size_t cchDest,
  1843. IN LPCTSTR pszFormat,
  1844. IN va_list argList
  1845. );
  1846. Routine Description:
  1847. This routine is a safer version of the C built-in function 'vsprintf'.
  1848. The size of the destination buffer (in characters) is a parameter and
  1849. this function will not write past the end of this buffer and it will
  1850. ALWAYS null terminate the destination buffer (unless it is zero length).
  1851. This function returns a hresult, and not a pointer. It returns
  1852. S_OK if the string was printed without truncation and null terminated,
  1853. otherwise it will return a failure code. In failure cases it will return
  1854. a truncated version of the ideal result.
  1855. Arguments:
  1856. pszDest - destination string
  1857. cchDest - size of destination buffer in characters
  1858. length must be sufficient to hold the resulting formatted
  1859. string, including the null terminator.
  1860. pszFormat - format string which must be null terminated
  1861. argList - va_list from the variable arguments according to the
  1862. stdarg.h convention
  1863. Notes:
  1864. Behavior is undefined if destination, format strings or any arguments
  1865. strings overlap.
  1866. pszDest and pszFormat should not be NULL. See StringCchVPrintfEx if you
  1867. require the handling of NULL values.
  1868. Return Value:
  1869. S_OK - if there was sufficient space in the dest buffer for
  1870. the resultant string and it was null terminated.
  1871. failure - you can use the macro HRESULT_CODE() to get a win32
  1872. error code for all hresult failure cases
  1873. STRSAFE_E_INSUFFICIENT_BUFFER /
  1874. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1875. - this return value is an indication that the print
  1876. operation failed due to insufficient space. When this
  1877. error occurs, the destination buffer is modified to
  1878. contain a truncated version of the ideal result and is
  1879. null terminated. This is useful for situations where
  1880. truncation is ok.
  1881. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1882. return value of this function
  1883. --*/
  1884. STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
  1885. STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
  1886. #ifdef UNICODE
  1887. #define StringCchVPrintf StringCchVPrintfW
  1888. #else
  1889. #define StringCchVPrintf StringCchVPrintfA
  1890. #endif // !UNICODE
  1891. #ifdef STRSAFE_INLINE
  1892. STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
  1893. {
  1894. HRESULT hr;
  1895. if (cchDest > STRSAFE_MAX_CCH)
  1896. {
  1897. hr = STRSAFE_E_INVALID_PARAMETER;
  1898. }
  1899. else
  1900. {
  1901. hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  1902. }
  1903. return hr;
  1904. }
  1905. STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
  1906. {
  1907. HRESULT hr;
  1908. if (cchDest > STRSAFE_MAX_CCH)
  1909. {
  1910. hr = STRSAFE_E_INVALID_PARAMETER;
  1911. }
  1912. else
  1913. {
  1914. hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  1915. }
  1916. return hr;
  1917. }
  1918. #endif // STRSAFE_INLINE
  1919. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  1920. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1921. /*++
  1922. STDAPI
  1923. StringCbVPrintf(
  1924. OUT LPTSTR pszDest,
  1925. IN size_t cbDest,
  1926. IN LPCTSTR pszFormat,
  1927. IN va_list argList
  1928. );
  1929. Routine Description:
  1930. This routine is a safer version of the C built-in function 'vsprintf'.
  1931. The size of the destination buffer (in bytes) is a parameter and
  1932. this function will not write past the end of this buffer and it will
  1933. ALWAYS null terminate the destination buffer (unless it is zero length).
  1934. This function returns a hresult, and not a pointer. It returns
  1935. S_OK if the string was printed without truncation and null terminated,
  1936. otherwise it will return a failure code. In failure cases it will return
  1937. a truncated version of the ideal result.
  1938. Arguments:
  1939. pszDest - destination string
  1940. cbDest - size of destination buffer in bytes
  1941. length must be sufficient to hold the resulting formatted
  1942. string, including the null terminator.
  1943. pszFormat - format string which must be null terminated
  1944. argList - va_list from the variable arguments according to the
  1945. stdarg.h convention
  1946. Notes:
  1947. Behavior is undefined if destination, format strings or any arguments
  1948. strings overlap.
  1949. pszDest and pszFormat should not be NULL. See StringCbVPrintfEx if you
  1950. require the handling of NULL values.
  1951. Return Value:
  1952. S_OK - if there was sufficient space in the dest buffer for
  1953. the resultant string and it was null terminated.
  1954. failure - you can use the macro HRESULT_CODE() to get a win32
  1955. error code for all hresult failure cases
  1956. STRSAFE_E_INSUFFICIENT_BUFFER /
  1957. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1958. - this return value is an indication that the print
  1959. operation failed due to insufficient space. When this
  1960. error occurs, the destination buffer is modified to
  1961. contain a truncated version of the ideal result and is
  1962. null terminated. This is useful for situations where
  1963. truncation is ok.
  1964. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1965. return value of this function
  1966. --*/
  1967. STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList);
  1968. STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList);
  1969. #ifdef UNICODE
  1970. #define StringCbVPrintf StringCbVPrintfW
  1971. #else
  1972. #define StringCbVPrintf StringCbVPrintfA
  1973. #endif // !UNICODE
  1974. #ifdef STRSAFE_INLINE
  1975. STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList)
  1976. {
  1977. HRESULT hr;
  1978. size_t cchDest;
  1979. cchDest = cbDest / sizeof(char);
  1980. if (cchDest > STRSAFE_MAX_CCH)
  1981. {
  1982. hr = STRSAFE_E_INVALID_PARAMETER;
  1983. }
  1984. else
  1985. {
  1986. hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  1987. }
  1988. return hr;
  1989. }
  1990. STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList)
  1991. {
  1992. HRESULT hr;
  1993. size_t cchDest;
  1994. cchDest = cbDest / sizeof(wchar_t);
  1995. if (cchDest > STRSAFE_MAX_CCH)
  1996. {
  1997. hr = STRSAFE_E_INVALID_PARAMETER;
  1998. }
  1999. else
  2000. {
  2001. hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  2002. }
  2003. return hr;
  2004. }
  2005. #endif // STRSAFE_INLINE
  2006. #endif // !STRSAFE_NO_CB_FUNCTIONS
  2007. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2008. /*++
  2009. STDAPI
  2010. StringCchPrintf(
  2011. OUT LPTSTR pszDest,
  2012. IN size_t cchDest,
  2013. IN LPCTSTR pszFormat,
  2014. ...
  2015. );
  2016. Routine Description:
  2017. This routine is a safer version of the C built-in function 'sprintf'.
  2018. The size of the destination buffer (in characters) is a parameter and
  2019. this function will not write past the end of this buffer and it will
  2020. ALWAYS null terminate the destination buffer (unless it is zero length).
  2021. This function returns a hresult, and not a pointer. It returns
  2022. S_OK if the string was printed without truncation and null terminated,
  2023. otherwise it will return a failure code. In failure cases it will return
  2024. a truncated version of the ideal result.
  2025. Arguments:
  2026. pszDest - destination string
  2027. cchDest - size of destination buffer in characters
  2028. length must be sufficient to hold the resulting formatted
  2029. string, including the null terminator.
  2030. pszFormat - format string which must be null terminated
  2031. ... - additional parameters to be formatted according to
  2032. the format string
  2033. Notes:
  2034. Behavior is undefined if destination, format strings or any arguments
  2035. strings overlap.
  2036. pszDest and pszFormat should not be NULL. See StringCchPrintfEx if you
  2037. require the handling of NULL values.
  2038. Return Value:
  2039. S_OK - if there was sufficient space in the dest buffer for
  2040. the resultant string and it was null terminated.
  2041. failure - you can use the macro HRESULT_CODE() to get a win32
  2042. error code for all hresult failure cases
  2043. STRSAFE_E_INSUFFICIENT_BUFFER /
  2044. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2045. - this return value is an indication that the print
  2046. operation failed due to insufficient space. When this
  2047. error occurs, the destination buffer is modified to
  2048. contain a truncated version of the ideal result and is
  2049. null terminated. This is useful for situations where
  2050. truncation is ok.
  2051. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2052. return value of this function
  2053. --*/
  2054. STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...);
  2055. STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...);
  2056. #ifdef UNICODE
  2057. #define StringCchPrintf StringCchPrintfW
  2058. #else
  2059. #define StringCchPrintf StringCchPrintfA
  2060. #endif // !UNICODE
  2061. #ifdef STRSAFE_INLINE
  2062. STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...)
  2063. {
  2064. HRESULT hr;
  2065. if (cchDest > STRSAFE_MAX_CCH)
  2066. {
  2067. hr = STRSAFE_E_INVALID_PARAMETER;
  2068. }
  2069. else
  2070. {
  2071. va_list argList;
  2072. va_start(argList, pszFormat);
  2073. hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  2074. va_end(argList);
  2075. }
  2076. return hr;
  2077. }
  2078. STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...)
  2079. {
  2080. HRESULT hr;
  2081. if (cchDest > STRSAFE_MAX_CCH)
  2082. {
  2083. hr = STRSAFE_E_INVALID_PARAMETER;
  2084. }
  2085. else
  2086. {
  2087. va_list argList;
  2088. va_start(argList, pszFormat);
  2089. hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  2090. va_end(argList);
  2091. }
  2092. return hr;
  2093. }
  2094. #endif // STRSAFE_INLINE
  2095. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  2096. #ifndef STRSAFE_NO_CB_FUNCTIONS
  2097. /*++
  2098. STDAPI
  2099. StringCbPrintf(
  2100. OUT LPTSTR pszDest,
  2101. IN size_t cbDest,
  2102. IN LPCTSTR pszFormat,
  2103. ...
  2104. );
  2105. Routine Description:
  2106. This routine is a safer version of the C built-in function 'sprintf'.
  2107. The size of the destination buffer (in bytes) is a parameter and
  2108. this function will not write past the end of this buffer and it will
  2109. ALWAYS null terminate the destination buffer (unless it is zero length).
  2110. This function returns a hresult, and not a pointer. It returns
  2111. S_OK if the string was printed without truncation and null terminated,
  2112. otherwise it will return a failure code. In failure cases it will return
  2113. a truncated version of the ideal result.
  2114. Arguments:
  2115. pszDest - destination string
  2116. cbDest - size of destination buffer in bytes
  2117. length must be sufficient to hold the resulting formatted
  2118. string, including the null terminator.
  2119. pszFormat - format string which must be null terminated
  2120. ... - additional parameters to be formatted according to
  2121. the format string
  2122. Notes:
  2123. Behavior is undefined if destination, format strings or any arguments
  2124. strings overlap.
  2125. pszDest and pszFormat should not be NULL. See StringCbPrintfEx if you
  2126. require the handling of NULL values.
  2127. Return Value:
  2128. S_OK - if there was sufficient space in the dest buffer for
  2129. the resultant string and it was null terminated.
  2130. failure - you can use the macro HRESULT_CODE() to get a win32
  2131. error code for all hresult failure cases
  2132. STRSAFE_E_INSUFFICIENT_BUFFER /
  2133. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2134. - this return value is an indication that the print
  2135. operation failed due to insufficient space. When this
  2136. error occurs, the destination buffer is modified to
  2137. contain a truncated version of the ideal result and is
  2138. null terminated. This is useful for situations where
  2139. truncation is ok.
  2140. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2141. return value of this function
  2142. --*/
  2143. STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...);
  2144. STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...);
  2145. #ifdef UNICODE
  2146. #define StringCbPrintf StringCbPrintfW
  2147. #else
  2148. #define StringCbPrintf StringCbPrintfA
  2149. #endif // !UNICODE
  2150. #ifdef STRSAFE_INLINE
  2151. STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...)
  2152. {
  2153. HRESULT hr;
  2154. size_t cchDest;
  2155. cchDest = cbDest / sizeof(char);
  2156. if (cchDest > STRSAFE_MAX_CCH)
  2157. {
  2158. hr = STRSAFE_E_INVALID_PARAMETER;
  2159. }
  2160. else
  2161. {
  2162. va_list argList;
  2163. va_start(argList, pszFormat);
  2164. hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  2165. va_end(argList);
  2166. }
  2167. return hr;
  2168. }
  2169. STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...)
  2170. {
  2171. HRESULT hr;
  2172. size_t cchDest;
  2173. cchDest = cbDest / sizeof(wchar_t);
  2174. if (cchDest > STRSAFE_MAX_CCH)
  2175. {
  2176. hr = STRSAFE_E_INVALID_PARAMETER;
  2177. }
  2178. else
  2179. {
  2180. va_list argList;
  2181. va_start(argList, pszFormat);
  2182. hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  2183. va_end(argList);
  2184. }
  2185. return hr;
  2186. }
  2187. #endif // STRSAFE_INLINE
  2188. #endif // !STRSAFE_NO_CB_FUNCTIONS
  2189. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2190. /*++
  2191. STDAPI
  2192. StringCchPrintfEx(
  2193. OUT LPTSTR pszDest OPTIONAL,
  2194. IN size_t cchDest,
  2195. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2196. OUT size_t* pcchRemaining OPTIONAL,
  2197. IN DWORD dwFlags,
  2198. IN LPCTSTR pszFormat OPTIONAL,
  2199. ...
  2200. );
  2201. Routine Description:
  2202. This routine is a safer version of the C built-in function 'sprintf' with
  2203. some additional parameters. In addition to functionality provided by
  2204. StringCchPrintf, this routine also returns a pointer to the end of the
  2205. destination string and the number of characters left in the destination string
  2206. including the null terminator. The flags parameter allows additional controls.
  2207. Arguments:
  2208. pszDest - destination string
  2209. cchDest - size of destination buffer in characters.
  2210. length must be sufficient to contain the resulting
  2211. formatted string plus the null terminator.
  2212. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  2213. pointer to the end of the destination string. If the
  2214. function printed any data, the result will point to the
  2215. null termination character
  2216. pcchRemaining - if pcchRemaining is non-null, the function will return
  2217. the number of characters left in the destination string,
  2218. including the null terminator
  2219. dwFlags - controls some details of the string copy:
  2220. STRSAFE_FILL_BEHIND_NULL
  2221. if the function succeeds, the low byte of dwFlags will be
  2222. used to fill the uninitialize part of destination buffer
  2223. behind the null terminator
  2224. STRSAFE_IGNORE_NULLS
  2225. treat NULL string pointers like empty strings (TEXT(""))
  2226. STRSAFE_FILL_ON_FAILURE
  2227. if the function fails, the low byte of dwFlags will be
  2228. used to fill all of the destination buffer, and it will
  2229. be null terminated. This will overwrite any truncated
  2230. string returned when the failure is
  2231. STRSAFE_E_INSUFFICIENT_BUFFER
  2232. STRSAFE_NO_TRUNCATION /
  2233. STRSAFE_NULL_ON_FAILURE
  2234. if the function fails, the destination buffer will be set
  2235. to the empty string. This will overwrite any truncated string
  2236. returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  2237. pszFormat - format string which must be null terminated
  2238. ... - additional parameters to be formatted according to
  2239. the format string
  2240. Notes:
  2241. Behavior is undefined if destination, format strings or any arguments
  2242. strings overlap.
  2243. pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2244. flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2245. pszFormat may be NULL. An error may still be returned even though NULLS
  2246. are ignored due to insufficient space.
  2247. Return Value:
  2248. S_OK - if there was source data and it was all concatenated and
  2249. the resultant dest string was null terminated
  2250. failure - you can use the macro HRESULT_CODE() to get a win32
  2251. error code for all hresult failure cases
  2252. STRSAFE_E_INSUFFICIENT_BUFFER /
  2253. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2254. - this return value is an indication that the print
  2255. operation failed due to insufficient space. When this
  2256. error occurs, the destination buffer is modified to
  2257. contain a truncated version of the ideal result and is
  2258. null terminated. This is useful for situations where
  2259. truncation is ok.
  2260. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2261. return value of this function
  2262. --*/
  2263. STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...);
  2264. STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
  2265. #ifdef UNICODE
  2266. #define StringCchPrintfEx StringCchPrintfExW
  2267. #else
  2268. #define StringCchPrintfEx StringCchPrintfExA
  2269. #endif // !UNICODE
  2270. #ifdef STRSAFE_INLINE
  2271. STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...)
  2272. {
  2273. HRESULT hr;
  2274. if (cchDest > STRSAFE_MAX_CCH)
  2275. {
  2276. hr = STRSAFE_E_INVALID_PARAMETER;
  2277. }
  2278. else
  2279. {
  2280. size_t cbDest;
  2281. va_list argList;
  2282. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  2283. cbDest = cchDest * sizeof(char);
  2284. va_start(argList, pszFormat);
  2285. hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2286. va_end(argList);
  2287. }
  2288. return hr;
  2289. }
  2290. STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
  2291. {
  2292. HRESULT hr;
  2293. if (cchDest > STRSAFE_MAX_CCH)
  2294. {
  2295. hr = STRSAFE_E_INVALID_PARAMETER;
  2296. }
  2297. else
  2298. {
  2299. size_t cbDest;
  2300. va_list argList;
  2301. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2302. cbDest = cchDest * sizeof(wchar_t);
  2303. va_start(argList, pszFormat);
  2304. hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2305. va_end(argList);
  2306. }
  2307. return hr;
  2308. }
  2309. #endif // STRSAFE_INLINE
  2310. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  2311. #ifndef STRSAFE_NO_CB_FUNCTIONS
  2312. /*++
  2313. STDAPI
  2314. StringCbPrintfEx(
  2315. OUT LPTSTR pszDest OPTIONAL,
  2316. IN size_t cbDest,
  2317. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2318. OUT size_t* pcbRemaining OPTIONAL,
  2319. IN DWORD dwFlags,
  2320. IN LPCTSTR pszFormat OPTIONAL,
  2321. ...
  2322. );
  2323. Routine Description:
  2324. This routine is a safer version of the C built-in function 'sprintf' with
  2325. some additional parameters. In addition to functionality provided by
  2326. StringCbPrintf, this routine also returns a pointer to the end of the
  2327. destination string and the number of bytes left in the destination string
  2328. including the null terminator. The flags parameter allows additional controls.
  2329. Arguments:
  2330. pszDest - destination string
  2331. cbDest - size of destination buffer in bytes.
  2332. length must be sufficient to contain the resulting
  2333. formatted string plus the null terminator.
  2334. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  2335. pointer to the end of the destination string. If the
  2336. function printed any data, the result will point to the
  2337. null termination character
  2338. pcbRemaining - if pcbRemaining is non-null, the function will return
  2339. the number of bytes left in the destination string,
  2340. including the null terminator
  2341. dwFlags - controls some details of the string copy:
  2342. STRSAFE_FILL_BEHIND_NULL
  2343. if the function succeeds, the low byte of dwFlags will be
  2344. used to fill the uninitialize part of destination buffer
  2345. behind the null terminator
  2346. STRSAFE_IGNORE_NULLS
  2347. treat NULL string pointers like empty strings (TEXT(""))
  2348. STRSAFE_FILL_ON_FAILURE
  2349. if the function fails, the low byte of dwFlags will be
  2350. used to fill all of the destination buffer, and it will
  2351. be null terminated. This will overwrite any truncated
  2352. string returned when the failure is
  2353. STRSAFE_E_INSUFFICIENT_BUFFER
  2354. STRSAFE_NO_TRUNCATION /
  2355. STRSAFE_NULL_ON_FAILURE
  2356. if the function fails, the destination buffer will be set
  2357. to the empty string. This will overwrite any truncated string
  2358. returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  2359. pszFormat - format string which must be null terminated
  2360. ... - additional parameters to be formatted according to
  2361. the format string
  2362. Notes:
  2363. Behavior is undefined if destination, format strings or any arguments
  2364. strings overlap.
  2365. pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2366. flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2367. pszFormat may be NULL. An error may still be returned even though NULLS
  2368. are ignored due to insufficient space.
  2369. Return Value:
  2370. S_OK - if there was source data and it was all concatenated and
  2371. the resultant dest string was null terminated
  2372. failure - you can use the macro HRESULT_CODE() to get a win32
  2373. error code for all hresult failure cases
  2374. STRSAFE_E_INSUFFICIENT_BUFFER /
  2375. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2376. - this return value is an indication that the print
  2377. operation failed due to insufficient space. When this
  2378. error occurs, the destination buffer is modified to
  2379. contain a truncated version of the ideal result and is
  2380. null terminated. This is useful for situations where
  2381. truncation is ok.
  2382. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2383. return value of this function
  2384. --*/
  2385. STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...);
  2386. STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
  2387. #ifdef UNICODE
  2388. #define StringCbPrintfEx StringCbPrintfExW
  2389. #else
  2390. #define StringCbPrintfEx StringCbPrintfExA
  2391. #endif // !UNICODE
  2392. #ifdef STRSAFE_INLINE
  2393. STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...)
  2394. {
  2395. HRESULT hr;
  2396. size_t cchDest;
  2397. size_t cchRemaining = 0;
  2398. cchDest = cbDest / sizeof(char);
  2399. if (cchDest > STRSAFE_MAX_CCH)
  2400. {
  2401. hr = STRSAFE_E_INVALID_PARAMETER;
  2402. }
  2403. else
  2404. {
  2405. va_list argList;
  2406. va_start(argList, pszFormat);
  2407. hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  2408. va_end(argList);
  2409. }
  2410. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  2411. {
  2412. if (pcbRemaining)
  2413. {
  2414. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  2415. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  2416. }
  2417. }
  2418. return hr;
  2419. }
  2420. STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
  2421. {
  2422. HRESULT hr;
  2423. size_t cchDest;
  2424. size_t cchRemaining = 0;
  2425. cchDest = cbDest / sizeof(wchar_t);
  2426. if (cchDest > STRSAFE_MAX_CCH)
  2427. {
  2428. hr = STRSAFE_E_INVALID_PARAMETER;
  2429. }
  2430. else
  2431. {
  2432. va_list argList;
  2433. va_start(argList, pszFormat);
  2434. hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  2435. va_end(argList);
  2436. }
  2437. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  2438. {
  2439. if (pcbRemaining)
  2440. {
  2441. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2442. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  2443. }
  2444. }
  2445. return hr;
  2446. }
  2447. #endif // STRSAFE_INLINE
  2448. #endif // !STRSAFE_NO_CB_FUNCTIONS
  2449. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2450. /*++
  2451. STDAPI
  2452. StringCchVPrintfEx(
  2453. OUT LPTSTR pszDest OPTIONAL,
  2454. IN size_t cchDest,
  2455. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2456. OUT size_t* pcchRemaining OPTIONAL,
  2457. IN DWORD dwFlags,
  2458. IN LPCTSTR pszFormat OPTIONAL,
  2459. IN va_list argList
  2460. );
  2461. Routine Description:
  2462. This routine is a safer version of the C built-in function 'vsprintf' with
  2463. some additional parameters. In addition to functionality provided by
  2464. StringCchVPrintf, this routine also returns a pointer to the end of the
  2465. destination string and the number of characters left in the destination string
  2466. including the null terminator. The flags parameter allows additional controls.
  2467. Arguments:
  2468. pszDest - destination string
  2469. cchDest - size of destination buffer in characters.
  2470. length must be sufficient to contain the resulting
  2471. formatted string plus the null terminator.
  2472. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  2473. pointer to the end of the destination string. If the
  2474. function printed any data, the result will point to the
  2475. null termination character
  2476. pcchRemaining - if pcchRemaining is non-null, the function will return
  2477. the number of characters left in the destination string,
  2478. including the null terminator
  2479. dwFlags - controls some details of the string copy:
  2480. STRSAFE_FILL_BEHIND_NULL
  2481. if the function succeeds, the low byte of dwFlags will be
  2482. used to fill the uninitialize part of destination buffer
  2483. behind the null terminator
  2484. STRSAFE_IGNORE_NULLS
  2485. treat NULL string pointers like empty strings (TEXT(""))
  2486. STRSAFE_FILL_ON_FAILURE
  2487. if the function fails, the low byte of dwFlags will be
  2488. used to fill all of the destination buffer, and it will
  2489. be null terminated. This will overwrite any truncated
  2490. string returned when the failure is
  2491. STRSAFE_E_INSUFFICIENT_BUFFER
  2492. STRSAFE_NO_TRUNCATION /
  2493. STRSAFE_NULL_ON_FAILURE
  2494. if the function fails, the destination buffer will be set
  2495. to the empty string. This will overwrite any truncated string
  2496. returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  2497. pszFormat - format string which must be null terminated
  2498. argList - va_list from the variable arguments according to the
  2499. stdarg.h convention
  2500. Notes:
  2501. Behavior is undefined if destination, format strings or any arguments
  2502. strings overlap.
  2503. pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2504. flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2505. pszFormat may be NULL. An error may still be returned even though NULLS
  2506. are ignored due to insufficient space.
  2507. Return Value:
  2508. S_OK - if there was source data and it was all concatenated and
  2509. the resultant dest string was null terminated
  2510. failure - you can use the macro HRESULT_CODE() to get a win32
  2511. error code for all hresult failure cases
  2512. STRSAFE_E_INSUFFICIENT_BUFFER /
  2513. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2514. - this return value is an indication that the print
  2515. operation failed due to insufficient space. When this
  2516. error occurs, the destination buffer is modified to
  2517. contain a truncated version of the ideal result and is
  2518. null terminated. This is useful for situations where
  2519. truncation is ok.
  2520. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2521. return value of this function
  2522. --*/
  2523. STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  2524. STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
  2525. #ifdef UNICODE
  2526. #define StringCchVPrintfEx StringCchVPrintfExW
  2527. #else
  2528. #define StringCchVPrintfEx StringCchVPrintfExA
  2529. #endif // !UNICODE
  2530. #ifdef STRSAFE_INLINE
  2531. STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  2532. {
  2533. HRESULT hr;
  2534. if (cchDest > STRSAFE_MAX_CCH)
  2535. {
  2536. hr = STRSAFE_E_INVALID_PARAMETER;
  2537. }
  2538. else
  2539. {
  2540. size_t cbDest;
  2541. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  2542. cbDest = cchDest * sizeof(char);
  2543. hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2544. }
  2545. return hr;
  2546. }
  2547. STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
  2548. {
  2549. HRESULT hr;
  2550. if (cchDest > STRSAFE_MAX_CCH)
  2551. {
  2552. hr = STRSAFE_E_INVALID_PARAMETER;
  2553. }
  2554. else
  2555. {
  2556. size_t cbDest;
  2557. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2558. cbDest = cchDest * sizeof(wchar_t);
  2559. hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2560. }
  2561. return hr;
  2562. }
  2563. #endif // STRSAFE_INLINE
  2564. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  2565. #ifndef STRSAFE_NO_CB_FUNCTIONS
  2566. /*++
  2567. STDAPI
  2568. StringCbVPrintfEx(
  2569. OUT LPTSTR pszDest OPTIONAL,
  2570. IN size_t cbDest,
  2571. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2572. OUT size_t* pcbRemaining OPTIONAL,
  2573. IN DWORD dwFlags,
  2574. IN LPCTSTR pszFormat OPTIONAL,
  2575. IN va_list argList
  2576. );
  2577. Routine Description:
  2578. This routine is a safer version of the C built-in function 'vsprintf' with
  2579. some additional parameters. In addition to functionality provided by
  2580. StringCbVPrintf, this routine also returns a pointer to the end of the
  2581. destination string and the number of characters left in the destination string
  2582. including the null terminator. The flags parameter allows additional controls.
  2583. Arguments:
  2584. pszDest - destination string
  2585. cbDest - size of destination buffer in bytes.
  2586. length must be sufficient to contain the resulting
  2587. formatted string plus the null terminator.
  2588. ppszDestEnd - if ppszDestEnd is non-null, the function will return
  2589. a pointer to the end of the destination string. If the
  2590. function printed any data, the result will point to the
  2591. null termination character
  2592. pcbRemaining - if pcbRemaining is non-null, the function will return
  2593. the number of bytes left in the destination string,
  2594. including the null terminator
  2595. dwFlags - controls some details of the string copy:
  2596. STRSAFE_FILL_BEHIND_NULL
  2597. if the function succeeds, the low byte of dwFlags will be
  2598. used to fill the uninitialize part of destination buffer
  2599. behind the null terminator
  2600. STRSAFE_IGNORE_NULLS
  2601. treat NULL string pointers like empty strings (TEXT(""))
  2602. STRSAFE_FILL_ON_FAILURE
  2603. if the function fails, the low byte of dwFlags will be
  2604. used to fill all of the destination buffer, and it will
  2605. be null terminated. This will overwrite any truncated
  2606. string returned when the failure is
  2607. STRSAFE_E_INSUFFICIENT_BUFFER
  2608. STRSAFE_NO_TRUNCATION /
  2609. STRSAFE_NULL_ON_FAILURE
  2610. if the function fails, the destination buffer will be set
  2611. to the empty string. This will overwrite any truncated string
  2612. returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  2613. pszFormat - format string which must be null terminated
  2614. argList - va_list from the variable arguments according to the
  2615. stdarg.h convention
  2616. Notes:
  2617. Behavior is undefined if destination, format strings or any arguments
  2618. strings overlap.
  2619. pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2620. flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2621. pszFormat may be NULL. An error may still be returned even though NULLS
  2622. are ignored due to insufficient space.
  2623. Return Value:
  2624. S_OK - if there was source data and it was all concatenated and
  2625. the resultant dest string was null terminated
  2626. failure - you can use the macro HRESULT_CODE() to get a win32
  2627. error code for all hresult failure cases
  2628. STRSAFE_E_INSUFFICIENT_BUFFER /
  2629. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2630. - this return value is an indication that the print
  2631. operation failed due to insufficient space. When this
  2632. error occurs, the destination buffer is modified to
  2633. contain a truncated version of the ideal result and is
  2634. null terminated. This is useful for situations where
  2635. truncation is ok.
  2636. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2637. return value of this function
  2638. --*/
  2639. STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  2640. STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
  2641. #ifdef UNICODE
  2642. #define StringCbVPrintfEx StringCbVPrintfExW
  2643. #else
  2644. #define StringCbVPrintfEx StringCbVPrintfExA
  2645. #endif // !UNICODE
  2646. #ifdef STRSAFE_INLINE
  2647. STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  2648. {
  2649. HRESULT hr;
  2650. size_t cchDest;
  2651. size_t cchRemaining = 0;
  2652. cchDest = cbDest / sizeof(char);
  2653. if (cchDest > STRSAFE_MAX_CCH)
  2654. {
  2655. hr = STRSAFE_E_INVALID_PARAMETER;
  2656. }
  2657. else
  2658. {
  2659. hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  2660. }
  2661. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  2662. {
  2663. if (pcbRemaining)
  2664. {
  2665. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  2666. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  2667. }
  2668. }
  2669. return hr;
  2670. }
  2671. STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
  2672. {
  2673. HRESULT hr;
  2674. size_t cchDest;
  2675. size_t cchRemaining = 0;
  2676. cchDest = cbDest / sizeof(wchar_t);
  2677. if (cchDest > STRSAFE_MAX_CCH)
  2678. {
  2679. hr = STRSAFE_E_INVALID_PARAMETER;
  2680. }
  2681. else
  2682. {
  2683. hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  2684. }
  2685. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  2686. {
  2687. if (pcbRemaining)
  2688. {
  2689. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2690. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  2691. }
  2692. }
  2693. return hr;
  2694. }
  2695. #endif // STRSAFE_INLINE
  2696. #endif // !STRSAFE_NO_CB_FUNCTIONS
  2697. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2698. /*++
  2699. STDAPI
  2700. StringCchGets(
  2701. OUT LPTSTR pszDest,
  2702. IN size_t cchDest
  2703. );
  2704. Routine Description:
  2705. This routine is a safer version of the C built-in function 'gets'.
  2706. The size of the destination buffer (in characters) is a parameter and
  2707. this function will not write past the end of this buffer and it will
  2708. ALWAYS null terminate the destination buffer (unless it is zero length).
  2709. This routine is not a replacement for fgets. That function does not replace
  2710. newline characters with a null terminator.
  2711. This function returns a hresult, and not a pointer. It returns
  2712. S_OK if any characters were read from stdin and copied to pszDest and
  2713. pszDest was null terminated, otherwise it will return a failure code.
  2714. Arguments:
  2715. pszDest - destination string
  2716. cchDest - size of destination buffer in characters.
  2717. Notes:
  2718. pszDest should not be NULL. See StringCchGetsEx if you require the handling
  2719. of NULL values.
  2720. cchDest must be > 1 for this function to succeed.
  2721. Return Value:
  2722. S_OK - data was read from stdin and copied, and the resultant
  2723. dest string was null terminated
  2724. failure - you can use the macro HRESULT_CODE() to get a win32
  2725. error code for all hresult failure cases
  2726. STRSAFE_E_END_OF_FILE /
  2727. HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  2728. - this return value indicates an error or end-of-file
  2729. condition, use feof or ferror to determine which one has
  2730. occured.
  2731. STRSAFE_E_INSUFFICIENT_BUFFER /
  2732. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2733. - this return value is an indication that there was
  2734. insufficient space in the destination buffer to copy any
  2735. data
  2736. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2737. return value of this function.
  2738. --*/
  2739. #ifndef STRSAFE_LIB_IMPL
  2740. STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest);
  2741. STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest);
  2742. #ifdef UNICODE
  2743. #define StringCchGets StringCchGetsW
  2744. #else
  2745. #define StringCchGets StringCchGetsA
  2746. #endif // !UNICODE
  2747. STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest)
  2748. {
  2749. HRESULT hr;
  2750. if (cchDest > STRSAFE_MAX_CCH)
  2751. {
  2752. hr = STRSAFE_E_INVALID_PARAMETER;
  2753. }
  2754. else
  2755. {
  2756. size_t cbDest;
  2757. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  2758. cbDest = cchDest * sizeof(char);
  2759. hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
  2760. }
  2761. return hr;
  2762. }
  2763. STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest)
  2764. {
  2765. HRESULT hr;
  2766. if (cchDest > STRSAFE_MAX_CCH)
  2767. {
  2768. hr = STRSAFE_E_INVALID_PARAMETER;
  2769. }
  2770. else
  2771. {
  2772. size_t cbDest;
  2773. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2774. cbDest = cchDest * sizeof(wchar_t);
  2775. hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
  2776. }
  2777. return hr;
  2778. }
  2779. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  2780. #endif // !STRSAFE_LIB_IMPL
  2781. #ifndef STRSAFE_NO_CB_FUNCTIONS
  2782. /*++
  2783. STDAPI
  2784. StringCbGets(
  2785. OUT LPTSTR pszDest,
  2786. IN size_t cbDest
  2787. );
  2788. Routine Description:
  2789. This routine is a safer version of the C built-in function 'gets'.
  2790. The size of the destination buffer (in bytes) is a parameter and
  2791. this function will not write past the end of this buffer and it will
  2792. ALWAYS null terminate the destination buffer (unless it is zero length).
  2793. This routine is not a replacement for fgets. That function does not replace
  2794. newline characters with a null terminator.
  2795. This function returns a hresult, and not a pointer. It returns
  2796. S_OK if any characters were read from stdin and copied to pszDest
  2797. and pszDest was null terminated, otherwise it will return a failure code.
  2798. Arguments:
  2799. pszDest - destination string
  2800. cbDest - size of destination buffer in bytes.
  2801. Notes:
  2802. pszDest should not be NULL. See StringCbGetsEx if you require the handling
  2803. of NULL values.
  2804. cbDest must be > sizeof(TCHAR) for this function to succeed.
  2805. Return Value:
  2806. S_OK - data was read from stdin and copied, and the resultant
  2807. dest string was null terminated
  2808. failure - you can use the macro HRESULT_CODE() to get a win32
  2809. error code for all hresult failure cases
  2810. STRSAFE_E_END_OF_FILE /
  2811. HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  2812. - this return value indicates an error or end-of-file
  2813. condition, use feof or ferror to determine which one has
  2814. occured.
  2815. STRSAFE_E_INSUFFICIENT_BUFFER /
  2816. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2817. - this return value is an indication that there was
  2818. insufficient space in the destination buffer to copy any
  2819. data
  2820. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2821. return value of this function.
  2822. --*/
  2823. #ifndef STRSAFE_LIB_IMPL
  2824. STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest);
  2825. STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest);
  2826. #ifdef UNICODE
  2827. #define StringCbGets StringCbGetsW
  2828. #else
  2829. #define StringCbGets StringCbGetsA
  2830. #endif // !UNICODE
  2831. STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest)
  2832. {
  2833. HRESULT hr;
  2834. size_t cchDest;
  2835. // convert to count of characters
  2836. cchDest = cbDest / sizeof(char);
  2837. if (cchDest > STRSAFE_MAX_CCH)
  2838. {
  2839. hr = STRSAFE_E_INVALID_PARAMETER;
  2840. }
  2841. else
  2842. {
  2843. hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
  2844. }
  2845. return hr;
  2846. }
  2847. STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest)
  2848. {
  2849. HRESULT hr;
  2850. size_t cchDest;
  2851. // convert to count of characters
  2852. cchDest = cbDest / sizeof(wchar_t);
  2853. if (cchDest > STRSAFE_MAX_CCH)
  2854. {
  2855. hr = STRSAFE_E_INVALID_PARAMETER;
  2856. }
  2857. else
  2858. {
  2859. hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
  2860. }
  2861. return hr;
  2862. }
  2863. #endif // !STRSAFE_NO_CB_FUNCTIONS
  2864. #endif // !STRSAFE_LIB_IMPL
  2865. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2866. /*++
  2867. STDAPI
  2868. StringCchGetsEx(
  2869. OUT LPTSTR pszDest OPTIONAL,
  2870. IN size_t cchDest,
  2871. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2872. OUT size_t* pcchRemaining OPTIONAL,
  2873. IN DWORD dwFlags
  2874. );
  2875. Routine Description:
  2876. This routine is a safer version of the C built-in function 'gets' with
  2877. some additional parameters. In addition to functionality provided by
  2878. StringCchGets, this routine also returns a pointer to the end of the
  2879. destination string and the number of characters left in the destination string
  2880. including the null terminator. The flags parameter allows additional controls.
  2881. Arguments:
  2882. pszDest - destination string
  2883. cchDest - size of destination buffer in characters.
  2884. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  2885. pointer to the end of the destination string. If the
  2886. function copied any data, the result will point to the
  2887. null termination character
  2888. pcchRemaining - if pcchRemaining is non-null, the function will return the
  2889. number of characters left in the destination string,
  2890. including the null terminator
  2891. dwFlags - controls some details of the string copy:
  2892. STRSAFE_FILL_BEHIND_NULL
  2893. if the function succeeds, the low byte of dwFlags will be
  2894. used to fill the uninitialize part of destination buffer
  2895. behind the null terminator
  2896. STRSAFE_IGNORE_NULLS
  2897. treat NULL string pointers like empty strings (TEXT("")).
  2898. STRSAFE_FILL_ON_FAILURE
  2899. if the function fails, the low byte of dwFlags will be
  2900. used to fill all of the destination buffer, and it will
  2901. be null terminated.
  2902. STRSAFE_NO_TRUNCATION /
  2903. STRSAFE_NULL_ON_FAILURE
  2904. if the function fails, the destination buffer will be set
  2905. to the empty string.
  2906. Notes:
  2907. pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
  2908. If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
  2909. returned even though NULLS are ignored
  2910. cchDest must be > 1 for this function to succeed.
  2911. Return Value:
  2912. S_OK - data was read from stdin and copied, and the resultant
  2913. dest string was null terminated
  2914. failure - you can use the macro HRESULT_CODE() to get a win32
  2915. error code for all hresult failure cases
  2916. STRSAFE_E_END_OF_FILE /
  2917. HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  2918. - this return value indicates an error or end-of-file
  2919. condition, use feof or ferror to determine which one has
  2920. occured.
  2921. STRSAFE_E_INSUFFICIENT_BUFFER /
  2922. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2923. - this return value is an indication that there was
  2924. insufficient space in the destination buffer to copy any
  2925. data
  2926. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2927. return value of this function.
  2928. --*/
  2929. #ifndef STRSAFE_LIB_IMPL
  2930. STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  2931. STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  2932. #ifdef UNICODE
  2933. #define StringCchGetsEx StringCchGetsExW
  2934. #else
  2935. #define StringCchGetsEx StringCchGetsExA
  2936. #endif // !UNICODE
  2937. STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  2938. {
  2939. HRESULT hr;
  2940. if (cchDest > STRSAFE_MAX_CCH)
  2941. {
  2942. hr = STRSAFE_E_INVALID_PARAMETER;
  2943. }
  2944. else
  2945. {
  2946. size_t cbDest;
  2947. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  2948. cbDest = cchDest * sizeof(char);
  2949. hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
  2950. }
  2951. return hr;
  2952. }
  2953. STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  2954. {
  2955. HRESULT hr;
  2956. if (cchDest > STRSAFE_MAX_CCH)
  2957. {
  2958. hr = STRSAFE_E_INVALID_PARAMETER;
  2959. }
  2960. else
  2961. {
  2962. size_t cbDest;
  2963. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2964. cbDest = cchDest * sizeof(wchar_t);
  2965. hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
  2966. }
  2967. return hr;
  2968. }
  2969. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  2970. #endif // !STRSAFE_LIB_IMPL
  2971. #ifndef STRSAFE_NO_CB_FUNCTIONS
  2972. /*++
  2973. STDAPI
  2974. StringCbGetsEx(
  2975. OUT LPTSTR pszDest OPTIONAL,
  2976. IN size_t cbDest,
  2977. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2978. OUT size_t* pcbRemaining OPTIONAL,
  2979. IN DWORD dwFlags
  2980. );
  2981. Routine Description:
  2982. This routine is a safer version of the C built-in function 'gets' with
  2983. some additional parameters. In addition to functionality provided by
  2984. StringCbGets, this routine also returns a pointer to the end of the
  2985. destination string and the number of characters left in the destination string
  2986. including the null terminator. The flags parameter allows additional controls.
  2987. Arguments:
  2988. pszDest - destination string
  2989. cbDest - size of destination buffer in bytes.
  2990. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  2991. pointer to the end of the destination string. If the
  2992. function copied any data, the result will point to the
  2993. null termination character
  2994. pcbRemaining - if pbRemaining is non-null, the function will return the
  2995. number of bytes left in the destination string,
  2996. including the null terminator
  2997. dwFlags - controls some details of the string copy:
  2998. STRSAFE_FILL_BEHIND_NULL
  2999. if the function succeeds, the low byte of dwFlags will be
  3000. used to fill the uninitialize part of destination buffer
  3001. behind the null terminator
  3002. STRSAFE_IGNORE_NULLS
  3003. treat NULL string pointers like empty strings (TEXT("")).
  3004. STRSAFE_FILL_ON_FAILURE
  3005. if the function fails, the low byte of dwFlags will be
  3006. used to fill all of the destination buffer, and it will
  3007. be null terminated.
  3008. STRSAFE_NO_TRUNCATION /
  3009. STRSAFE_NULL_ON_FAILURE
  3010. if the function fails, the destination buffer will be set
  3011. to the empty string.
  3012. Notes:
  3013. pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
  3014. If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
  3015. returned even though NULLS are ignored
  3016. cbDest must be > sizeof(TCHAR) for this function to succeed
  3017. Return Value:
  3018. S_OK - data was read from stdin and copied, and the resultant
  3019. dest string was null terminated
  3020. failure - you can use the macro HRESULT_CODE() to get a win32
  3021. error code for all hresult failure cases
  3022. STRSAFE_E_END_OF_FILE /
  3023. HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  3024. - this return value indicates an error or end-of-file
  3025. condition, use feof or ferror to determine which one has
  3026. occured.
  3027. STRSAFE_E_INSUFFICIENT_BUFFER /
  3028. HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  3029. - this return value is an indication that there was
  3030. insufficient space in the destination buffer to copy any
  3031. data
  3032. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3033. return value of this function.
  3034. --*/
  3035. #ifndef STRSAFE_LIB_IMPL
  3036. STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pbRemaining, unsigned long dwFlags);
  3037. STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  3038. #ifdef UNICODE
  3039. #define StringCbGetsEx StringCbGetsExW
  3040. #else
  3041. #define StringCbGetsEx StringCbGetsExA
  3042. #endif // !UNICODE
  3043. STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  3044. {
  3045. HRESULT hr;
  3046. size_t cchDest;
  3047. size_t cchRemaining = 0;
  3048. cchDest = cbDest / sizeof(char);
  3049. if (cchDest > STRSAFE_MAX_CCH)
  3050. {
  3051. hr = STRSAFE_E_INVALID_PARAMETER;
  3052. }
  3053. else
  3054. {
  3055. hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
  3056. }
  3057. if (SUCCEEDED(hr) ||
  3058. (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
  3059. (hr == STRSAFE_E_END_OF_FILE))
  3060. {
  3061. if (pcbRemaining)
  3062. {
  3063. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  3064. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  3065. }
  3066. }
  3067. return hr;
  3068. }
  3069. STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  3070. {
  3071. HRESULT hr;
  3072. size_t cchDest;
  3073. size_t cchRemaining = 0;
  3074. cchDest = cbDest / sizeof(wchar_t);
  3075. if (cchDest > STRSAFE_MAX_CCH)
  3076. {
  3077. hr = STRSAFE_E_INVALID_PARAMETER;
  3078. }
  3079. else
  3080. {
  3081. hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
  3082. }
  3083. if (SUCCEEDED(hr) ||
  3084. (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
  3085. (hr == STRSAFE_E_END_OF_FILE))
  3086. {
  3087. if (pcbRemaining)
  3088. {
  3089. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  3090. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  3091. }
  3092. }
  3093. return hr;
  3094. }
  3095. #endif // !STRSAFE_NO_CB_FUNCTIONS
  3096. #endif // !STRSAFE_LIB_IMPL
  3097. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  3098. /*++
  3099. STDAPI
  3100. StringCchLength(
  3101. IN LPCTSTR psz,
  3102. IN size_t cchMax,
  3103. OUT size_t* pcch OPTIONAL
  3104. );
  3105. Routine Description:
  3106. This routine is a safer version of the C built-in function 'strlen'.
  3107. It is used to make sure a string is not larger than a given length, and
  3108. it optionally returns the current length in characters not including
  3109. the null terminator.
  3110. This function returns a hresult, and not a pointer. It returns
  3111. S_OK if the string is non-null and the length including the null
  3112. terminator is less than or equal to cchMax characters.
  3113. Arguments:
  3114. psz - string to check the length of
  3115. cchMax - maximum number of characters including the null terminator
  3116. that psz is allowed to contain
  3117. pcch - if the function succeeds and pcch is non-null, the current length
  3118. in characters of psz excluding the null terminator will be returned.
  3119. This out parameter is equivalent to the return value of strlen(psz)
  3120. Notes:
  3121. psz can be null but the function will fail
  3122. cchMax should be greater than zero or the function will fail
  3123. Return Value:
  3124. S_OK - psz is non-null and the length including the null
  3125. terminator is less than or equal to cchMax characters
  3126. failure - you can use the macro HRESULT_CODE() to get a win32
  3127. error code for all hresult failure cases
  3128. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3129. return value of this function.
  3130. --*/
  3131. STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch);
  3132. STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  3133. #ifdef UNICODE
  3134. #define StringCchLength StringCchLengthW
  3135. #else
  3136. #define StringCchLength StringCchLengthA
  3137. #endif // !UNICODE
  3138. #ifdef STRSAFE_INLINE
  3139. STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch)
  3140. {
  3141. HRESULT hr;
  3142. if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  3143. {
  3144. hr = STRSAFE_E_INVALID_PARAMETER;
  3145. }
  3146. else
  3147. {
  3148. hr = StringLengthWorkerA(psz, cchMax, pcch);
  3149. }
  3150. return hr;
  3151. }
  3152. STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch)
  3153. {
  3154. HRESULT hr;
  3155. if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  3156. {
  3157. hr = STRSAFE_E_INVALID_PARAMETER;
  3158. }
  3159. else
  3160. {
  3161. hr = StringLengthWorkerW(psz, cchMax, pcch);
  3162. }
  3163. return hr;
  3164. }
  3165. #endif // STRSAFE_INLINE
  3166. #endif // !STRSAFE_NO_CCH_FUNCTIONS
  3167. #ifndef STRSAFE_NO_CB_FUNCTIONS
  3168. /*++
  3169. STDAPI
  3170. StringCbLength(
  3171. IN LPCTSTR psz,
  3172. IN size_t cbMax,
  3173. OUT size_t* pcb OPTIONAL
  3174. );
  3175. Routine Description:
  3176. This routine is a safer version of the C built-in function 'strlen'.
  3177. It is used to make sure a string is not larger than a given length, and
  3178. it optionally returns the current length in bytes not including
  3179. the null terminator.
  3180. This function returns a hresult, and not a pointer. It returns
  3181. S_OK if the string is non-null and the length including the null
  3182. terminator is less than or equal to cbMax bytes.
  3183. Arguments:
  3184. psz - string to check the length of
  3185. cbMax - maximum number of bytes including the null terminator
  3186. that psz is allowed to contain
  3187. pcb - if the function succeeds and pcb is non-null, the current length
  3188. in bytes of psz excluding the null terminator will be returned.
  3189. This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR)
  3190. Notes:
  3191. psz can be null but the function will fail
  3192. cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail
  3193. Return Value:
  3194. S_OK - psz is non-null and the length including the null
  3195. terminator is less than or equal to cbMax bytes
  3196. failure - you can use the macro HRESULT_CODE() to get a win32
  3197. error code for all hresult failure cases
  3198. It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3199. return value of this function.
  3200. --*/
  3201. STRSAFEAPI StringCbLengthA(const char* psz, size_t cchMax, size_t* pcch);
  3202. STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  3203. #ifdef UNICODE
  3204. #define StringCbLength StringCbLengthW
  3205. #else
  3206. #define StringCbLength StringCbLengthA
  3207. #endif // !UNICODE
  3208. #ifdef STRSAFE_INLINE
  3209. STRSAFEAPI StringCbLengthA(const char* psz, size_t cbMax, size_t* pcb)
  3210. {
  3211. HRESULT hr;
  3212. size_t cchMax;
  3213. size_t cch = 0;
  3214. cchMax = cbMax / sizeof(char);
  3215. if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  3216. {
  3217. hr = STRSAFE_E_INVALID_PARAMETER;
  3218. }
  3219. else
  3220. {
  3221. hr = StringLengthWorkerA(psz, cchMax, &cch);
  3222. }
  3223. if (SUCCEEDED(hr) && pcb)
  3224. {
  3225. // safe to multiply cch * sizeof(char) since cch < STRSAFE_MAX_CCH and sizeof(char) is 1
  3226. *pcb = cch * sizeof(char);
  3227. }
  3228. return hr;
  3229. }
  3230. STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cbMax, size_t* pcb)
  3231. {
  3232. HRESULT hr;
  3233. size_t cchMax;
  3234. size_t cch = 0;
  3235. cchMax = cbMax / sizeof(wchar_t);
  3236. if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  3237. {
  3238. hr = STRSAFE_E_INVALID_PARAMETER;
  3239. }
  3240. else
  3241. {
  3242. hr = StringLengthWorkerW(psz, cchMax, &cch);
  3243. }
  3244. if (SUCCEEDED(hr) && pcb)
  3245. {
  3246. // safe to multiply cch * sizeof(wchar_t) since cch < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  3247. *pcb = cch * sizeof(wchar_t);
  3248. }
  3249. return hr;
  3250. }
  3251. #endif // STRSAFE_INLINE
  3252. #endif // !STRSAFE_NO_CB_FUNCTIONS
  3253. // these are the worker functions that actually do the work
  3254. #ifdef STRSAFE_INLINE
  3255. STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
  3256. {
  3257. HRESULT hr = S_OK;
  3258. if (cchDest == 0)
  3259. {
  3260. // can not null terminate a zero-byte dest buffer
  3261. hr = STRSAFE_E_INVALID_PARAMETER;
  3262. }
  3263. else
  3264. {
  3265. while (cchDest && (*pszSrc != '\0'))
  3266. {
  3267. *pszDest++ = *pszSrc++;
  3268. cchDest--;
  3269. }
  3270. if (cchDest == 0)
  3271. {
  3272. // we are going to truncate pszDest
  3273. pszDest--;
  3274. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3275. }
  3276. *pszDest= '\0';
  3277. }
  3278. return hr;
  3279. }
  3280. STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  3281. {
  3282. HRESULT hr = S_OK;
  3283. if (cchDest == 0)
  3284. {
  3285. // can not null terminate a zero-byte dest buffer
  3286. hr = STRSAFE_E_INVALID_PARAMETER;
  3287. }
  3288. else
  3289. {
  3290. while (cchDest && (*pszSrc != L'\0'))
  3291. {
  3292. *pszDest++ = *pszSrc++;
  3293. cchDest--;
  3294. }
  3295. if (cchDest == 0)
  3296. {
  3297. // we are going to truncate pszDest
  3298. pszDest--;
  3299. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3300. }
  3301. *pszDest= L'\0';
  3302. }
  3303. return hr;
  3304. }
  3305. STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3306. {
  3307. HRESULT hr = S_OK;
  3308. char* pszDestEnd = pszDest;
  3309. size_t cchRemaining = 0;
  3310. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  3311. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  3312. // only accept valid flags
  3313. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3314. {
  3315. hr = STRSAFE_E_INVALID_PARAMETER;
  3316. }
  3317. else
  3318. {
  3319. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3320. {
  3321. if (pszDest == NULL)
  3322. {
  3323. if ((cchDest != 0) || (cbDest != 0))
  3324. {
  3325. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3326. hr = STRSAFE_E_INVALID_PARAMETER;
  3327. }
  3328. }
  3329. if (pszSrc == NULL)
  3330. {
  3331. pszSrc = "";
  3332. }
  3333. }
  3334. if (SUCCEEDED(hr))
  3335. {
  3336. if (cchDest == 0)
  3337. {
  3338. pszDestEnd = pszDest;
  3339. cchRemaining = 0;
  3340. // only fail if there was actually src data to copy
  3341. if (*pszSrc != '\0')
  3342. {
  3343. if (pszDest == NULL)
  3344. {
  3345. hr = STRSAFE_E_INVALID_PARAMETER;
  3346. }
  3347. else
  3348. {
  3349. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3350. }
  3351. }
  3352. }
  3353. else
  3354. {
  3355. pszDestEnd = pszDest;
  3356. cchRemaining = cchDest;
  3357. while (cchRemaining && (*pszSrc != '\0'))
  3358. {
  3359. *pszDestEnd++= *pszSrc++;
  3360. cchRemaining--;
  3361. }
  3362. if (cchRemaining > 0)
  3363. {
  3364. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  3365. {
  3366. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  3367. }
  3368. }
  3369. else
  3370. {
  3371. // we are going to truncate pszDest
  3372. pszDestEnd--;
  3373. cchRemaining++;
  3374. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3375. }
  3376. *pszDestEnd = '\0';
  3377. }
  3378. }
  3379. }
  3380. if (FAILED(hr))
  3381. {
  3382. if (pszDest)
  3383. {
  3384. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3385. {
  3386. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3387. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3388. {
  3389. pszDestEnd = pszDest;
  3390. cchRemaining = cchDest;
  3391. }
  3392. else if (cchDest > 0)
  3393. {
  3394. pszDestEnd = pszDest + cchDest - 1;
  3395. cchRemaining = 1;
  3396. // null terminate the end of the string
  3397. *pszDestEnd = '\0';
  3398. }
  3399. }
  3400. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  3401. {
  3402. if (cchDest > 0)
  3403. {
  3404. pszDestEnd = pszDest;
  3405. cchRemaining = cchDest;
  3406. // null terminate the beginning of the string
  3407. *pszDestEnd = '\0';
  3408. }
  3409. }
  3410. }
  3411. }
  3412. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3413. {
  3414. if (ppszDestEnd)
  3415. {
  3416. *ppszDestEnd = pszDestEnd;
  3417. }
  3418. if (pcchRemaining)
  3419. {
  3420. *pcchRemaining = cchRemaining;
  3421. }
  3422. }
  3423. return hr;
  3424. }
  3425. STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3426. {
  3427. HRESULT hr = S_OK;
  3428. wchar_t* pszDestEnd = pszDest;
  3429. size_t cchRemaining = 0;
  3430. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  3431. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  3432. // only accept valid flags
  3433. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3434. {
  3435. hr = STRSAFE_E_INVALID_PARAMETER;
  3436. }
  3437. else
  3438. {
  3439. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3440. {
  3441. if (pszDest == NULL)
  3442. {
  3443. if ((cchDest != 0) || (cbDest != 0))
  3444. {
  3445. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3446. hr = STRSAFE_E_INVALID_PARAMETER;
  3447. }
  3448. }
  3449. if (pszSrc == NULL)
  3450. {
  3451. pszSrc = L"";
  3452. }
  3453. }
  3454. if (SUCCEEDED(hr))
  3455. {
  3456. if (cchDest == 0)
  3457. {
  3458. pszDestEnd = pszDest;
  3459. cchRemaining = 0;
  3460. // only fail if there was actually src data to copy
  3461. if (*pszSrc != L'\0')
  3462. {
  3463. if (pszDest == NULL)
  3464. {
  3465. hr = STRSAFE_E_INVALID_PARAMETER;
  3466. }
  3467. else
  3468. {
  3469. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3470. }
  3471. }
  3472. }
  3473. else
  3474. {
  3475. pszDestEnd = pszDest;
  3476. cchRemaining = cchDest;
  3477. while (cchRemaining && (*pszSrc != L'\0'))
  3478. {
  3479. *pszDestEnd++= *pszSrc++;
  3480. cchRemaining--;
  3481. }
  3482. if (cchRemaining > 0)
  3483. {
  3484. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  3485. {
  3486. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  3487. }
  3488. }
  3489. else
  3490. {
  3491. // we are going to truncate pszDest
  3492. pszDestEnd--;
  3493. cchRemaining++;
  3494. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3495. }
  3496. *pszDestEnd = L'\0';
  3497. }
  3498. }
  3499. }
  3500. if (FAILED(hr))
  3501. {
  3502. if (pszDest)
  3503. {
  3504. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3505. {
  3506. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3507. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3508. {
  3509. pszDestEnd = pszDest;
  3510. cchRemaining = cchDest;
  3511. }
  3512. else if (cchDest > 0)
  3513. {
  3514. pszDestEnd = pszDest + cchDest - 1;
  3515. cchRemaining = 1;
  3516. // null terminate the end of the string
  3517. *pszDestEnd = L'\0';
  3518. }
  3519. }
  3520. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  3521. {
  3522. if (cchDest > 0)
  3523. {
  3524. pszDestEnd = pszDest;
  3525. cchRemaining = cchDest;
  3526. // null terminate the beginning of the string
  3527. *pszDestEnd = L'\0';
  3528. }
  3529. }
  3530. }
  3531. }
  3532. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3533. {
  3534. if (ppszDestEnd)
  3535. {
  3536. *ppszDestEnd = pszDestEnd;
  3537. }
  3538. if (pcchRemaining)
  3539. {
  3540. *pcchRemaining = cchRemaining;
  3541. }
  3542. }
  3543. return hr;
  3544. }
  3545. STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
  3546. {
  3547. HRESULT hr = S_OK;
  3548. if (cchDest == 0)
  3549. {
  3550. // can not null terminate a zero-byte dest buffer
  3551. hr = STRSAFE_E_INVALID_PARAMETER;
  3552. }
  3553. else
  3554. {
  3555. while (cchDest && cchSrc && (*pszSrc != '\0'))
  3556. {
  3557. *pszDest++= *pszSrc++;
  3558. cchDest--;
  3559. cchSrc--;
  3560. }
  3561. if (cchDest == 0)
  3562. {
  3563. // we are going to truncate pszDest
  3564. pszDest--;
  3565. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3566. }
  3567. *pszDest= '\0';
  3568. }
  3569. return hr;
  3570. }
  3571. STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
  3572. {
  3573. HRESULT hr = S_OK;
  3574. if (cchDest == 0)
  3575. {
  3576. // can not null terminate a zero-byte dest buffer
  3577. hr = STRSAFE_E_INVALID_PARAMETER;
  3578. }
  3579. else
  3580. {
  3581. while (cchDest && cchSrc && (*pszSrc != L'\0'))
  3582. {
  3583. *pszDest++= *pszSrc++;
  3584. cchDest--;
  3585. cchSrc--;
  3586. }
  3587. if (cchDest == 0)
  3588. {
  3589. // we are going to truncate pszDest
  3590. pszDest--;
  3591. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3592. }
  3593. *pszDest= L'\0';
  3594. }
  3595. return hr;
  3596. }
  3597. STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3598. {
  3599. HRESULT hr = S_OK;
  3600. char* pszDestEnd = pszDest;
  3601. size_t cchRemaining = 0;
  3602. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  3603. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  3604. // only accept valid flags
  3605. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3606. {
  3607. hr = STRSAFE_E_INVALID_PARAMETER;
  3608. }
  3609. else
  3610. {
  3611. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3612. {
  3613. if (pszDest == NULL)
  3614. {
  3615. if ((cchDest != 0) || (cbDest != 0))
  3616. {
  3617. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3618. hr = STRSAFE_E_INVALID_PARAMETER;
  3619. }
  3620. }
  3621. if (pszSrc == NULL)
  3622. {
  3623. pszSrc = "";
  3624. }
  3625. }
  3626. if (SUCCEEDED(hr))
  3627. {
  3628. if (cchDest == 0)
  3629. {
  3630. pszDestEnd = pszDest;
  3631. cchRemaining = 0;
  3632. // only fail if there was actually src data to copy
  3633. if (*pszSrc != '\0')
  3634. {
  3635. if (pszDest == NULL)
  3636. {
  3637. hr = STRSAFE_E_INVALID_PARAMETER;
  3638. }
  3639. else
  3640. {
  3641. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3642. }
  3643. }
  3644. }
  3645. else
  3646. {
  3647. pszDestEnd = pszDest;
  3648. cchRemaining = cchDest;
  3649. while (cchRemaining && cchSrc && (*pszSrc != '\0'))
  3650. {
  3651. *pszDestEnd++= *pszSrc++;
  3652. cchRemaining--;
  3653. cchSrc--;
  3654. }
  3655. if (cchRemaining > 0)
  3656. {
  3657. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  3658. {
  3659. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  3660. }
  3661. }
  3662. else
  3663. {
  3664. // we are going to truncate pszDest
  3665. pszDestEnd--;
  3666. cchRemaining++;
  3667. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3668. }
  3669. *pszDestEnd = '\0';
  3670. }
  3671. }
  3672. }
  3673. if (FAILED(hr))
  3674. {
  3675. if (pszDest)
  3676. {
  3677. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3678. {
  3679. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3680. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3681. {
  3682. pszDestEnd = pszDest;
  3683. cchRemaining = cchDest;
  3684. }
  3685. else if (cchDest > 0)
  3686. {
  3687. pszDestEnd = pszDest + cchDest - 1;
  3688. cchRemaining = 1;
  3689. // null terminate the end of the string
  3690. *pszDestEnd = '\0';
  3691. }
  3692. }
  3693. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  3694. {
  3695. if (cchDest > 0)
  3696. {
  3697. pszDestEnd = pszDest;
  3698. cchRemaining = cchDest;
  3699. // null terminate the beginning of the string
  3700. *pszDestEnd = '\0';
  3701. }
  3702. }
  3703. }
  3704. }
  3705. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3706. {
  3707. if (ppszDestEnd)
  3708. {
  3709. *ppszDestEnd = pszDestEnd;
  3710. }
  3711. if (pcchRemaining)
  3712. {
  3713. *pcchRemaining = cchRemaining;
  3714. }
  3715. }
  3716. return hr;
  3717. }
  3718. 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)
  3719. {
  3720. HRESULT hr = S_OK;
  3721. wchar_t* pszDestEnd = pszDest;
  3722. size_t cchRemaining = 0;
  3723. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  3724. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  3725. // only accept valid flags
  3726. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3727. {
  3728. hr = STRSAFE_E_INVALID_PARAMETER;
  3729. }
  3730. else
  3731. {
  3732. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3733. {
  3734. if (pszDest == NULL)
  3735. {
  3736. if ((cchDest != 0) || (cbDest != 0))
  3737. {
  3738. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3739. hr = STRSAFE_E_INVALID_PARAMETER;
  3740. }
  3741. }
  3742. if (pszSrc == NULL)
  3743. {
  3744. pszSrc = L"";
  3745. }
  3746. }
  3747. if (SUCCEEDED(hr))
  3748. {
  3749. if (cchDest == 0)
  3750. {
  3751. pszDestEnd = pszDest;
  3752. cchRemaining = 0;
  3753. // only fail if there was actually src data to copy
  3754. if (*pszSrc != L'\0')
  3755. {
  3756. if (pszDest == NULL)
  3757. {
  3758. hr = STRSAFE_E_INVALID_PARAMETER;
  3759. }
  3760. else
  3761. {
  3762. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3763. }
  3764. }
  3765. }
  3766. else
  3767. {
  3768. pszDestEnd = pszDest;
  3769. cchRemaining = cchDest;
  3770. while (cchRemaining && cchSrc && (*pszSrc != L'\0'))
  3771. {
  3772. *pszDestEnd++= *pszSrc++;
  3773. cchRemaining--;
  3774. cchSrc--;
  3775. }
  3776. if (cchRemaining > 0)
  3777. {
  3778. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  3779. {
  3780. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  3781. }
  3782. }
  3783. else
  3784. {
  3785. // we are going to truncate pszDest
  3786. pszDestEnd--;
  3787. cchRemaining++;
  3788. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3789. }
  3790. *pszDestEnd = L'\0';
  3791. }
  3792. }
  3793. }
  3794. if (FAILED(hr))
  3795. {
  3796. if (pszDest)
  3797. {
  3798. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3799. {
  3800. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3801. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3802. {
  3803. pszDestEnd = pszDest;
  3804. cchRemaining = cchDest;
  3805. }
  3806. else if (cchDest > 0)
  3807. {
  3808. pszDestEnd = pszDest + cchDest - 1;
  3809. cchRemaining = 1;
  3810. // null terminate the end of the string
  3811. *pszDestEnd = L'\0';
  3812. }
  3813. }
  3814. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  3815. {
  3816. if (cchDest > 0)
  3817. {
  3818. pszDestEnd = pszDest;
  3819. cchRemaining = cchDest;
  3820. // null terminate the beginning of the string
  3821. *pszDestEnd = L'\0';
  3822. }
  3823. }
  3824. }
  3825. }
  3826. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3827. {
  3828. if (ppszDestEnd)
  3829. {
  3830. *ppszDestEnd = pszDestEnd;
  3831. }
  3832. if (pcchRemaining)
  3833. {
  3834. *pcchRemaining = cchRemaining;
  3835. }
  3836. }
  3837. return hr;
  3838. }
  3839. STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
  3840. {
  3841. HRESULT hr;
  3842. size_t cchDestCurrent;
  3843. hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3844. if (SUCCEEDED(hr))
  3845. {
  3846. hr = StringCopyWorkerA(pszDest + cchDestCurrent,
  3847. cchDest - cchDestCurrent,
  3848. pszSrc);
  3849. }
  3850. return hr;
  3851. }
  3852. STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  3853. {
  3854. HRESULT hr;
  3855. size_t cchDestCurrent;
  3856. hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  3857. if (SUCCEEDED(hr))
  3858. {
  3859. hr = StringCopyWorkerW(pszDest + cchDestCurrent,
  3860. cchDest - cchDestCurrent,
  3861. pszSrc);
  3862. }
  3863. return hr;
  3864. }
  3865. STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3866. {
  3867. HRESULT hr = S_OK;
  3868. char* pszDestEnd = pszDest;
  3869. size_t cchRemaining = 0;
  3870. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  3871. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  3872. // only accept valid flags
  3873. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3874. {
  3875. hr = STRSAFE_E_INVALID_PARAMETER;
  3876. }
  3877. else
  3878. {
  3879. size_t cchDestCurrent;
  3880. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3881. {
  3882. if (pszDest == NULL)
  3883. {
  3884. if ((cchDest == 0) && (cbDest == 0))
  3885. {
  3886. cchDestCurrent = 0;
  3887. }
  3888. else
  3889. {
  3890. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3891. hr = STRSAFE_E_INVALID_PARAMETER;
  3892. }
  3893. }
  3894. else
  3895. {
  3896. hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3897. if (SUCCEEDED(hr))
  3898. {
  3899. pszDestEnd = pszDest + cchDestCurrent;
  3900. cchRemaining = cchDest - cchDestCurrent;
  3901. }
  3902. }
  3903. if (pszSrc == NULL)
  3904. {
  3905. pszSrc = "";
  3906. }
  3907. }
  3908. else
  3909. {
  3910. hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3911. if (SUCCEEDED(hr))
  3912. {
  3913. pszDestEnd = pszDest + cchDestCurrent;
  3914. cchRemaining = cchDest - cchDestCurrent;
  3915. }
  3916. }
  3917. if (SUCCEEDED(hr))
  3918. {
  3919. if (cchDest == 0)
  3920. {
  3921. // only fail if there was actually src data to append
  3922. if (*pszSrc != '\0')
  3923. {
  3924. if (pszDest == NULL)
  3925. {
  3926. hr = STRSAFE_E_INVALID_PARAMETER;
  3927. }
  3928. else
  3929. {
  3930. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  3931. }
  3932. }
  3933. }
  3934. else
  3935. {
  3936. // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  3937. // those flags through
  3938. hr = StringCopyExWorkerA(pszDestEnd,
  3939. cchRemaining,
  3940. (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
  3941. pszSrc,
  3942. &pszDestEnd,
  3943. &cchRemaining,
  3944. dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  3945. }
  3946. }
  3947. }
  3948. if (FAILED(hr))
  3949. {
  3950. if (pszDest)
  3951. {
  3952. // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerA()
  3953. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3954. {
  3955. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3956. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3957. {
  3958. pszDestEnd = pszDest;
  3959. cchRemaining = cchDest;
  3960. }
  3961. else
  3962. if (cchDest > 0)
  3963. {
  3964. pszDestEnd = pszDest + cchDest - 1;
  3965. cchRemaining = 1;
  3966. // null terminate the end of the string
  3967. *pszDestEnd = '\0';
  3968. }
  3969. }
  3970. if (dwFlags & STRSAFE_NULL_ON_FAILURE)
  3971. {
  3972. if (cchDest > 0)
  3973. {
  3974. pszDestEnd = pszDest;
  3975. cchRemaining = cchDest;
  3976. // null terminate the beginning of the string
  3977. *pszDestEnd = '\0';
  3978. }
  3979. }
  3980. }
  3981. }
  3982. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3983. {
  3984. if (ppszDestEnd)
  3985. {
  3986. *ppszDestEnd = pszDestEnd;
  3987. }
  3988. if (pcchRemaining)
  3989. {
  3990. *pcchRemaining = cchRemaining;
  3991. }
  3992. }
  3993. return hr;
  3994. }
  3995. STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3996. {
  3997. HRESULT hr = S_OK;
  3998. wchar_t* pszDestEnd = pszDest;
  3999. size_t cchRemaining = 0;
  4000. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  4001. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4002. // only accept valid flags
  4003. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4004. {
  4005. hr = STRSAFE_E_INVALID_PARAMETER;
  4006. }
  4007. else
  4008. {
  4009. size_t cchDestCurrent;
  4010. if (dwFlags & STRSAFE_IGNORE_NULLS)
  4011. {
  4012. if (pszDest == NULL)
  4013. {
  4014. if ((cchDest == 0) && (cbDest == 0))
  4015. {
  4016. cchDestCurrent = 0;
  4017. }
  4018. else
  4019. {
  4020. // NULL pszDest and non-zero cchDest/cbDest is invalid
  4021. hr = STRSAFE_E_INVALID_PARAMETER;
  4022. }
  4023. }
  4024. else
  4025. {
  4026. hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  4027. if (SUCCEEDED(hr))
  4028. {
  4029. pszDestEnd = pszDest + cchDestCurrent;
  4030. cchRemaining = cchDest - cchDestCurrent;
  4031. }
  4032. }
  4033. if (pszSrc == NULL)
  4034. {
  4035. pszSrc = L"";
  4036. }
  4037. }
  4038. else
  4039. {
  4040. hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  4041. if (SUCCEEDED(hr))
  4042. {
  4043. pszDestEnd = pszDest + cchDestCurrent;
  4044. cchRemaining = cchDest - cchDestCurrent;
  4045. }
  4046. }
  4047. if (SUCCEEDED(hr))
  4048. {
  4049. if (cchDest == 0)
  4050. {
  4051. // only fail if there was actually src data to append
  4052. if (*pszSrc != L'\0')
  4053. {
  4054. if (pszDest == NULL)
  4055. {
  4056. hr = STRSAFE_E_INVALID_PARAMETER;
  4057. }
  4058. else
  4059. {
  4060. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4061. }
  4062. }
  4063. }
  4064. else
  4065. {
  4066. // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  4067. // those flags through
  4068. hr = StringCopyExWorkerW(pszDestEnd,
  4069. cchRemaining,
  4070. (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
  4071. pszSrc,
  4072. &pszDestEnd,
  4073. &cchRemaining,
  4074. dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  4075. }
  4076. }
  4077. }
  4078. if (FAILED(hr))
  4079. {
  4080. if (pszDest)
  4081. {
  4082. // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerW()
  4083. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4084. {
  4085. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4086. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4087. {
  4088. pszDestEnd = pszDest;
  4089. cchRemaining = cchDest;
  4090. }
  4091. else if (cchDest > 0)
  4092. {
  4093. pszDestEnd = pszDest + cchDest - 1;
  4094. cchRemaining = 1;
  4095. // null terminate the end of the string
  4096. *pszDestEnd = L'\0';
  4097. }
  4098. }
  4099. if (dwFlags & STRSAFE_NULL_ON_FAILURE)
  4100. {
  4101. if (cchDest > 0)
  4102. {
  4103. pszDestEnd = pszDest;
  4104. cchRemaining = cchDest;
  4105. // null terminate the beginning of the string
  4106. *pszDestEnd = L'\0';
  4107. }
  4108. }
  4109. }
  4110. }
  4111. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4112. {
  4113. if (ppszDestEnd)
  4114. {
  4115. *ppszDestEnd = pszDestEnd;
  4116. }
  4117. if (pcchRemaining)
  4118. {
  4119. *pcchRemaining = cchRemaining;
  4120. }
  4121. }
  4122. return hr;
  4123. }
  4124. STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
  4125. {
  4126. HRESULT hr;
  4127. size_t cchDestCurrent;
  4128. hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  4129. if (SUCCEEDED(hr))
  4130. {
  4131. hr = StringCopyNWorkerA(pszDest + cchDestCurrent,
  4132. cchDest - cchDestCurrent,
  4133. pszSrc,
  4134. cchMaxAppend);
  4135. }
  4136. return hr;
  4137. }
  4138. STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
  4139. {
  4140. HRESULT hr;
  4141. size_t cchDestCurrent;
  4142. hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  4143. if (SUCCEEDED(hr))
  4144. {
  4145. hr = StringCopyNWorkerW(pszDest + cchDestCurrent,
  4146. cchDest - cchDestCurrent,
  4147. pszSrc,
  4148. cchMaxAppend);
  4149. }
  4150. return hr;
  4151. }
  4152. STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  4153. {
  4154. HRESULT hr = S_OK;
  4155. char* pszDestEnd = pszDest;
  4156. size_t cchRemaining = 0;
  4157. size_t cchDestCurrent = 0;
  4158. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  4159. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  4160. // only accept valid flags
  4161. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4162. {
  4163. hr = STRSAFE_E_INVALID_PARAMETER;
  4164. }
  4165. else
  4166. {
  4167. if (dwFlags & STRSAFE_IGNORE_NULLS)
  4168. {
  4169. if (pszDest == NULL)
  4170. {
  4171. if ((cchDest == 0) && (cbDest == 0))
  4172. {
  4173. cchDestCurrent = 0;
  4174. }
  4175. else
  4176. {
  4177. // NULL pszDest and non-zero cchDest/cbDest is invalid
  4178. hr = STRSAFE_E_INVALID_PARAMETER;
  4179. }
  4180. }
  4181. else
  4182. {
  4183. hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  4184. if (SUCCEEDED(hr))
  4185. {
  4186. pszDestEnd = pszDest + cchDestCurrent;
  4187. cchRemaining = cchDest - cchDestCurrent;
  4188. }
  4189. }
  4190. if (pszSrc == NULL)
  4191. {
  4192. pszSrc = "";
  4193. }
  4194. }
  4195. else
  4196. {
  4197. hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  4198. if (SUCCEEDED(hr))
  4199. {
  4200. pszDestEnd = pszDest + cchDestCurrent;
  4201. cchRemaining = cchDest - cchDestCurrent;
  4202. }
  4203. }
  4204. if (SUCCEEDED(hr))
  4205. {
  4206. if (cchDest == 0)
  4207. {
  4208. // only fail if there was actually src data to append
  4209. if (*pszSrc != '\0')
  4210. {
  4211. if (pszDest == NULL)
  4212. {
  4213. hr = STRSAFE_E_INVALID_PARAMETER;
  4214. }
  4215. else
  4216. {
  4217. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4218. }
  4219. }
  4220. }
  4221. else
  4222. {
  4223. // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  4224. // those flags through
  4225. hr = StringCopyNExWorkerA(pszDestEnd,
  4226. cchRemaining,
  4227. (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
  4228. pszSrc,
  4229. cchMaxAppend,
  4230. &pszDestEnd,
  4231. &cchRemaining,
  4232. dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  4233. }
  4234. }
  4235. }
  4236. if (FAILED(hr))
  4237. {
  4238. if (pszDest)
  4239. {
  4240. // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerA()
  4241. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4242. {
  4243. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4244. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4245. {
  4246. pszDestEnd = pszDest;
  4247. cchRemaining = cchDest;
  4248. }
  4249. else if (cchDest > 0)
  4250. {
  4251. pszDestEnd = pszDest + cchDest - 1;
  4252. cchRemaining = 1;
  4253. // null terminate the end of the string
  4254. *pszDestEnd = '\0';
  4255. }
  4256. }
  4257. if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
  4258. {
  4259. if (cchDest > 0)
  4260. {
  4261. pszDestEnd = pszDest;
  4262. cchRemaining = cchDest;
  4263. // null terminate the beginning of the string
  4264. *pszDestEnd = '\0';
  4265. }
  4266. }
  4267. }
  4268. }
  4269. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4270. {
  4271. if (ppszDestEnd)
  4272. {
  4273. *ppszDestEnd = pszDestEnd;
  4274. }
  4275. if (pcchRemaining)
  4276. {
  4277. *pcchRemaining = cchRemaining;
  4278. }
  4279. }
  4280. return hr;
  4281. }
  4282. 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)
  4283. {
  4284. HRESULT hr = S_OK;
  4285. wchar_t* pszDestEnd = pszDest;
  4286. size_t cchRemaining = 0;
  4287. size_t cchDestCurrent = 0;
  4288. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  4289. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4290. // only accept valid flags
  4291. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4292. {
  4293. hr = STRSAFE_E_INVALID_PARAMETER;
  4294. }
  4295. else
  4296. {
  4297. if (dwFlags & STRSAFE_IGNORE_NULLS)
  4298. {
  4299. if (pszDest == NULL)
  4300. {
  4301. if ((cchDest == 0) && (cbDest == 0))
  4302. {
  4303. cchDestCurrent = 0;
  4304. }
  4305. else
  4306. {
  4307. // NULL pszDest and non-zero cchDest/cbDest is invalid
  4308. hr = STRSAFE_E_INVALID_PARAMETER;
  4309. }
  4310. }
  4311. else
  4312. {
  4313. hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  4314. if (SUCCEEDED(hr))
  4315. {
  4316. pszDestEnd = pszDest + cchDestCurrent;
  4317. cchRemaining = cchDest - cchDestCurrent;
  4318. }
  4319. }
  4320. if (pszSrc == NULL)
  4321. {
  4322. pszSrc = L"";
  4323. }
  4324. }
  4325. else
  4326. {
  4327. hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  4328. if (SUCCEEDED(hr))
  4329. {
  4330. pszDestEnd = pszDest + cchDestCurrent;
  4331. cchRemaining = cchDest - cchDestCurrent;
  4332. }
  4333. }
  4334. if (SUCCEEDED(hr))
  4335. {
  4336. if (cchDest == 0)
  4337. {
  4338. // only fail if there was actually src data to append
  4339. if (*pszSrc != L'\0')
  4340. {
  4341. if (pszDest == NULL)
  4342. {
  4343. hr = STRSAFE_E_INVALID_PARAMETER;
  4344. }
  4345. else
  4346. {
  4347. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4348. }
  4349. }
  4350. }
  4351. else
  4352. {
  4353. // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  4354. // those flags through
  4355. hr = StringCopyNExWorkerW(pszDestEnd,
  4356. cchRemaining,
  4357. (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
  4358. pszSrc,
  4359. cchMaxAppend,
  4360. &pszDestEnd,
  4361. &cchRemaining,
  4362. dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  4363. }
  4364. }
  4365. }
  4366. if (FAILED(hr))
  4367. {
  4368. if (pszDest)
  4369. {
  4370. // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerW()
  4371. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4372. {
  4373. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4374. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4375. {
  4376. pszDestEnd = pszDest;
  4377. cchRemaining = cchDest;
  4378. }
  4379. else if (cchDest > 0)
  4380. {
  4381. pszDestEnd = pszDest + cchDest - 1;
  4382. cchRemaining = 1;
  4383. // null terminate the end of the string
  4384. *pszDestEnd = L'\0';
  4385. }
  4386. }
  4387. if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
  4388. {
  4389. if (cchDest > 0)
  4390. {
  4391. pszDestEnd = pszDest;
  4392. cchRemaining = cchDest;
  4393. // null terminate the beginning of the string
  4394. *pszDestEnd = L'\0';
  4395. }
  4396. }
  4397. }
  4398. }
  4399. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4400. {
  4401. if (ppszDestEnd)
  4402. {
  4403. *ppszDestEnd = pszDestEnd;
  4404. }
  4405. if (pcchRemaining)
  4406. {
  4407. *pcchRemaining = cchRemaining;
  4408. }
  4409. }
  4410. return hr;
  4411. }
  4412. STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
  4413. {
  4414. HRESULT hr = S_OK;
  4415. if (cchDest == 0)
  4416. {
  4417. // can not null terminate a zero-byte dest buffer
  4418. hr = STRSAFE_E_INVALID_PARAMETER;
  4419. }
  4420. else
  4421. {
  4422. int iRet;
  4423. size_t cchMax;
  4424. // leave the last space for the null terminator
  4425. cchMax = cchDest - 1;
  4426. iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
  4427. // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  4428. if ((iRet < 0) || (((size_t)iRet) > cchMax))
  4429. {
  4430. // need to null terminate the string
  4431. pszDest += cchMax;
  4432. *pszDest = '\0';
  4433. // we have truncated pszDest
  4434. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4435. }
  4436. else if (((size_t)iRet) == cchMax)
  4437. {
  4438. // need to null terminate the string
  4439. pszDest += cchMax;
  4440. *pszDest = '\0';
  4441. }
  4442. }
  4443. return hr;
  4444. }
  4445. STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
  4446. {
  4447. HRESULT hr = S_OK;
  4448. if (cchDest == 0)
  4449. {
  4450. // can not null terminate a zero-byte dest buffer
  4451. hr = STRSAFE_E_INVALID_PARAMETER;
  4452. }
  4453. else
  4454. {
  4455. int iRet;
  4456. size_t cchMax;
  4457. // leave the last space for the null terminator
  4458. cchMax = cchDest - 1;
  4459. iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
  4460. // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  4461. if ((iRet < 0) || (((size_t)iRet) > cchMax))
  4462. {
  4463. // need to null terminate the string
  4464. pszDest += cchMax;
  4465. *pszDest = L'\0';
  4466. // we have truncated pszDest
  4467. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4468. }
  4469. else if (((size_t)iRet) == cchMax)
  4470. {
  4471. // need to null terminate the string
  4472. pszDest += cchMax;
  4473. *pszDest = L'\0';
  4474. }
  4475. }
  4476. return hr;
  4477. }
  4478. STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  4479. {
  4480. HRESULT hr = S_OK;
  4481. char* pszDestEnd = pszDest;
  4482. size_t cchRemaining = 0;
  4483. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  4484. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  4485. // only accept valid flags
  4486. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4487. {
  4488. hr = STRSAFE_E_INVALID_PARAMETER;
  4489. }
  4490. else
  4491. {
  4492. if (dwFlags & STRSAFE_IGNORE_NULLS)
  4493. {
  4494. if (pszDest == NULL)
  4495. {
  4496. if ((cchDest != 0) || (cbDest != 0))
  4497. {
  4498. // NULL pszDest and non-zero cchDest/cbDest is invalid
  4499. hr = STRSAFE_E_INVALID_PARAMETER;
  4500. }
  4501. }
  4502. if (pszFormat == NULL)
  4503. {
  4504. pszFormat = "";
  4505. }
  4506. }
  4507. if (SUCCEEDED(hr))
  4508. {
  4509. if (cchDest == 0)
  4510. {
  4511. pszDestEnd = pszDest;
  4512. cchRemaining = 0;
  4513. // only fail if there was actually a non-empty format string
  4514. if (*pszFormat != '\0')
  4515. {
  4516. if (pszDest == NULL)
  4517. {
  4518. hr = STRSAFE_E_INVALID_PARAMETER;
  4519. }
  4520. else
  4521. {
  4522. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4523. }
  4524. }
  4525. }
  4526. else
  4527. {
  4528. int iRet;
  4529. size_t cchMax;
  4530. // leave the last space for the null terminator
  4531. cchMax = cchDest - 1;
  4532. iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
  4533. // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  4534. if ((iRet < 0) || (((size_t)iRet) > cchMax))
  4535. {
  4536. // we have truncated pszDest
  4537. pszDestEnd = pszDest + cchMax;
  4538. cchRemaining = 1;
  4539. // need to null terminate the string
  4540. *pszDestEnd = '\0';
  4541. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4542. }
  4543. else if (((size_t)iRet) == cchMax)
  4544. {
  4545. // string fit perfectly
  4546. pszDestEnd = pszDest + cchMax;
  4547. cchRemaining = 1;
  4548. // need to null terminate the string
  4549. *pszDestEnd = '\0';
  4550. }
  4551. else if (((size_t)iRet) < cchMax)
  4552. {
  4553. // there is extra room
  4554. pszDestEnd = pszDest + iRet;
  4555. cchRemaining = cchDest - iRet;
  4556. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4557. {
  4558. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  4559. }
  4560. }
  4561. }
  4562. }
  4563. }
  4564. if (FAILED(hr))
  4565. {
  4566. if (pszDest)
  4567. {
  4568. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4569. {
  4570. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4571. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4572. {
  4573. pszDestEnd = pszDest;
  4574. cchRemaining = cchDest;
  4575. }
  4576. else if (cchDest > 0)
  4577. {
  4578. pszDestEnd = pszDest + cchDest - 1;
  4579. cchRemaining = 1;
  4580. // null terminate the end of the string
  4581. *pszDestEnd = '\0';
  4582. }
  4583. }
  4584. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4585. {
  4586. if (cchDest > 0)
  4587. {
  4588. pszDestEnd = pszDest;
  4589. cchRemaining = cchDest;
  4590. // null terminate the beginning of the string
  4591. *pszDestEnd = '\0';
  4592. }
  4593. }
  4594. }
  4595. }
  4596. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4597. {
  4598. if (ppszDestEnd)
  4599. {
  4600. *ppszDestEnd = pszDestEnd;
  4601. }
  4602. if (pcchRemaining)
  4603. {
  4604. *pcchRemaining = cchRemaining;
  4605. }
  4606. }
  4607. return hr;
  4608. }
  4609. 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)
  4610. {
  4611. HRESULT hr = S_OK;
  4612. wchar_t* pszDestEnd = pszDest;
  4613. size_t cchRemaining = 0;
  4614. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  4615. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4616. // only accept valid flags
  4617. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4618. {
  4619. hr = STRSAFE_E_INVALID_PARAMETER;
  4620. }
  4621. else
  4622. {
  4623. if (dwFlags & STRSAFE_IGNORE_NULLS)
  4624. {
  4625. if (pszDest == NULL)
  4626. {
  4627. if ((cchDest != 0) || (cbDest != 0))
  4628. {
  4629. // NULL pszDest and non-zero cchDest/cbDest is invalid
  4630. hr = STRSAFE_E_INVALID_PARAMETER;
  4631. }
  4632. }
  4633. if (pszFormat == NULL)
  4634. {
  4635. pszFormat = L"";
  4636. }
  4637. }
  4638. if (SUCCEEDED(hr))
  4639. {
  4640. if (cchDest == 0)
  4641. {
  4642. pszDestEnd = pszDest;
  4643. cchRemaining = 0;
  4644. // only fail if there was actually a non-empty format string
  4645. if (*pszFormat != L'\0')
  4646. {
  4647. if (pszDest == NULL)
  4648. {
  4649. hr = STRSAFE_E_INVALID_PARAMETER;
  4650. }
  4651. else
  4652. {
  4653. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4654. }
  4655. }
  4656. }
  4657. else
  4658. {
  4659. int iRet;
  4660. size_t cchMax;
  4661. // leave the last space for the null terminator
  4662. cchMax = cchDest - 1;
  4663. iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
  4664. // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  4665. if ((iRet < 0) || (((size_t)iRet) > cchMax))
  4666. {
  4667. // we have truncated pszDest
  4668. pszDestEnd = pszDest + cchMax;
  4669. cchRemaining = 1;
  4670. // need to null terminate the string
  4671. *pszDestEnd = L'\0';
  4672. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4673. }
  4674. else if (((size_t)iRet) == cchMax)
  4675. {
  4676. // string fit perfectly
  4677. pszDestEnd = pszDest + cchMax;
  4678. cchRemaining = 1;
  4679. // need to null terminate the string
  4680. *pszDestEnd = L'\0';
  4681. }
  4682. else if (((size_t)iRet) < cchMax)
  4683. {
  4684. // there is extra room
  4685. pszDestEnd = pszDest + iRet;
  4686. cchRemaining = cchDest - iRet;
  4687. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4688. {
  4689. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4690. }
  4691. }
  4692. }
  4693. }
  4694. }
  4695. if (FAILED(hr))
  4696. {
  4697. if (pszDest)
  4698. {
  4699. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4700. {
  4701. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4702. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4703. {
  4704. pszDestEnd = pszDest;
  4705. cchRemaining = cchDest;
  4706. }
  4707. else if (cchDest > 0)
  4708. {
  4709. pszDestEnd = pszDest + cchDest - 1;
  4710. cchRemaining = 1;
  4711. // null terminate the end of the string
  4712. *pszDestEnd = L'\0';
  4713. }
  4714. }
  4715. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4716. {
  4717. if (cchDest > 0)
  4718. {
  4719. pszDestEnd = pszDest;
  4720. cchRemaining = cchDest;
  4721. // null terminate the beginning of the string
  4722. *pszDestEnd = L'\0';
  4723. }
  4724. }
  4725. }
  4726. }
  4727. if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4728. {
  4729. if (ppszDestEnd)
  4730. {
  4731. *ppszDestEnd = pszDestEnd;
  4732. }
  4733. if (pcchRemaining)
  4734. {
  4735. *pcchRemaining = cchRemaining;
  4736. }
  4737. }
  4738. return hr;
  4739. }
  4740. STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch)
  4741. {
  4742. HRESULT hr = S_OK;
  4743. size_t cchMaxPrev = cchMax;
  4744. while (cchMax && (*psz != '\0'))
  4745. {
  4746. psz++;
  4747. cchMax--;
  4748. }
  4749. if (cchMax == 0)
  4750. {
  4751. // the string is longer than cchMax
  4752. hr = STRSAFE_E_INVALID_PARAMETER;
  4753. }
  4754. if (SUCCEEDED(hr) && pcch)
  4755. {
  4756. *pcch = cchMaxPrev - cchMax;
  4757. }
  4758. return hr;
  4759. }
  4760. STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch)
  4761. {
  4762. HRESULT hr = S_OK;
  4763. size_t cchMaxPrev = cchMax;
  4764. while (cchMax && (*psz != L'\0'))
  4765. {
  4766. psz++;
  4767. cchMax--;
  4768. }
  4769. if (cchMax == 0)
  4770. {
  4771. // the string is longer than cchMax
  4772. hr = STRSAFE_E_INVALID_PARAMETER;
  4773. }
  4774. if (SUCCEEDED(hr) && pcch)
  4775. {
  4776. *pcch = cchMaxPrev - cchMax;
  4777. }
  4778. return hr;
  4779. }
  4780. #endif // STRSAFE_INLINE
  4781. #ifndef STRSAFE_LIB_IMPL
  4782. STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  4783. {
  4784. HRESULT hr = S_OK;
  4785. char* pszDestEnd = pszDest;
  4786. size_t cchRemaining = 0;
  4787. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  4788. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  4789. // only accept valid flags
  4790. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4791. {
  4792. hr = STRSAFE_E_INVALID_PARAMETER;
  4793. }
  4794. else
  4795. {
  4796. if (dwFlags & STRSAFE_IGNORE_NULLS)
  4797. {
  4798. if (pszDest == NULL)
  4799. {
  4800. if ((cchDest != 0) || (cbDest != 0))
  4801. {
  4802. // NULL pszDest and non-zero cchDest/cbDest is invalid
  4803. hr = STRSAFE_E_INVALID_PARAMETER;
  4804. }
  4805. }
  4806. }
  4807. if (SUCCEEDED(hr))
  4808. {
  4809. if (cchDest <= 1)
  4810. {
  4811. pszDestEnd = pszDest;
  4812. cchRemaining = cchDest;
  4813. if (cchDest == 1)
  4814. {
  4815. *pszDestEnd = '\0';
  4816. }
  4817. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4818. }
  4819. else
  4820. {
  4821. char ch;
  4822. pszDestEnd = pszDest;
  4823. cchRemaining = cchDest;
  4824. while ((cchRemaining > 1) && (ch = (char)getc(stdin)) != '\n')
  4825. {
  4826. if (ch == EOF)
  4827. {
  4828. if (pszDestEnd == pszDest)
  4829. {
  4830. // we failed to read anything from stdin
  4831. hr = STRSAFE_E_END_OF_FILE;
  4832. }
  4833. break;
  4834. }
  4835. *pszDestEnd = ch;
  4836. pszDestEnd++;
  4837. cchRemaining--;
  4838. }
  4839. if (cchRemaining > 0)
  4840. {
  4841. // there is extra room
  4842. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4843. {
  4844. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  4845. }
  4846. }
  4847. *pszDestEnd = '\0';
  4848. }
  4849. }
  4850. }
  4851. if (FAILED(hr))
  4852. {
  4853. if (pszDest)
  4854. {
  4855. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4856. {
  4857. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4858. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4859. {
  4860. pszDestEnd = pszDest;
  4861. cchRemaining = cchDest;
  4862. }
  4863. else if (cchDest > 0)
  4864. {
  4865. pszDestEnd = pszDest + cchDest - 1;
  4866. cchRemaining = 1;
  4867. // null terminate the end of the string
  4868. *pszDestEnd = '\0';
  4869. }
  4870. }
  4871. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4872. {
  4873. if (cchDest > 0)
  4874. {
  4875. pszDestEnd = pszDest;
  4876. cchRemaining = cchDest;
  4877. // null terminate the beginning of the string
  4878. *pszDestEnd = '\0';
  4879. }
  4880. }
  4881. }
  4882. }
  4883. if (SUCCEEDED(hr) ||
  4884. (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
  4885. (hr == STRSAFE_E_END_OF_FILE))
  4886. {
  4887. if (ppszDestEnd)
  4888. {
  4889. *ppszDestEnd = pszDestEnd;
  4890. }
  4891. if (pcchRemaining)
  4892. {
  4893. *pcchRemaining = cchRemaining;
  4894. }
  4895. }
  4896. return hr;
  4897. }
  4898. STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  4899. {
  4900. HRESULT hr = S_OK;
  4901. wchar_t* pszDestEnd = pszDest;
  4902. size_t cchRemaining = 0;
  4903. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  4904. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  4905. // only accept valid flags
  4906. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4907. {
  4908. hr = STRSAFE_E_INVALID_PARAMETER;
  4909. }
  4910. else
  4911. {
  4912. if (dwFlags & STRSAFE_IGNORE_NULLS)
  4913. {
  4914. if (pszDest == NULL)
  4915. {
  4916. if ((cchDest != 0) || (cbDest != 0))
  4917. {
  4918. // NULL pszDest and non-zero cchDest/cbDest is invalid
  4919. hr = STRSAFE_E_INVALID_PARAMETER;
  4920. }
  4921. }
  4922. }
  4923. if (SUCCEEDED(hr))
  4924. {
  4925. if (cchDest <= 1)
  4926. {
  4927. pszDestEnd = pszDest;
  4928. cchRemaining = cchDest;
  4929. if (cchDest == 1)
  4930. {
  4931. *pszDestEnd = L'\0';
  4932. }
  4933. hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4934. }
  4935. else
  4936. {
  4937. wchar_t ch;
  4938. pszDestEnd = pszDest;
  4939. cchRemaining = cchDest;
  4940. while ((cchRemaining > 1) && (ch = (wchar_t)getwc(stdin)) != L'\n')
  4941. {
  4942. if (ch == EOF)
  4943. {
  4944. if (pszDestEnd == pszDest)
  4945. {
  4946. // we failed to read anything from stdin
  4947. hr = STRSAFE_E_END_OF_FILE;
  4948. }
  4949. break;
  4950. }
  4951. *pszDestEnd = ch;
  4952. pszDestEnd++;
  4953. cchRemaining--;
  4954. }
  4955. if (cchRemaining > 0)
  4956. {
  4957. // there is extra room
  4958. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4959. {
  4960. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4961. }
  4962. }
  4963. *pszDestEnd = L'\0';
  4964. }
  4965. }
  4966. }
  4967. if (FAILED(hr))
  4968. {
  4969. if (pszDest)
  4970. {
  4971. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4972. {
  4973. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4974. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4975. {
  4976. pszDestEnd = pszDest;
  4977. cchRemaining = cchDest;
  4978. }
  4979. else if (cchDest > 0)
  4980. {
  4981. pszDestEnd = pszDest + cchDest - 1;
  4982. cchRemaining = 1;
  4983. // null terminate the end of the string
  4984. *pszDestEnd = L'\0';
  4985. }
  4986. }
  4987. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4988. {
  4989. if (cchDest > 0)
  4990. {
  4991. pszDestEnd = pszDest;
  4992. cchRemaining = cchDest;
  4993. // null terminate the beginning of the string
  4994. *pszDestEnd = L'\0';
  4995. }
  4996. }
  4997. }
  4998. }
  4999. if (SUCCEEDED(hr) ||
  5000. (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
  5001. (hr == STRSAFE_E_END_OF_FILE))
  5002. {
  5003. if (ppszDestEnd)
  5004. {
  5005. *ppszDestEnd = pszDestEnd;
  5006. }
  5007. if (pcchRemaining)
  5008. {
  5009. *pcchRemaining = cchRemaining;
  5010. }
  5011. }
  5012. return hr;
  5013. }
  5014. #endif // !STRSAFE_LIB_IMPL
  5015. // Do not call these functions, they are worker functions for internal use within this file
  5016. #ifdef DEPRECATE_SUPPORTED
  5017. #pragma deprecated(StringCopyWorkerA)
  5018. #pragma deprecated(StringCopyWorkerW)
  5019. #pragma deprecated(StringCopyExWorkerA)
  5020. #pragma deprecated(StringCopyExWorkerW)
  5021. #pragma deprecated(StringCatWorkerA)
  5022. #pragma deprecated(StringCatWorkerW)
  5023. #pragma deprecated(StringCatExWorkerA)
  5024. #pragma deprecated(StringCatExWorkerW)
  5025. #pragma deprecated(StringCatNWorkerA)
  5026. #pragma deprecated(StringCatNWorkerW)
  5027. #pragma deprecated(StringCatNExWorkerA)
  5028. #pragma deprecated(StringCatNExWorkerW)
  5029. #pragma deprecated(StringVPrintfWorkerA)
  5030. #pragma deprecated(StringVPrintfWorkerW)
  5031. #pragma deprecated(StringVPrintfExWorkerA)
  5032. #pragma deprecated(StringVPrintfExWorkerW)
  5033. #pragma deprecated(StringLengthWorkerA)
  5034. #pragma deprecated(StringLengthWorkerW)
  5035. #else
  5036. #define StringCopyWorkerA StringCopyWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
  5037. #define StringCopyWorkerW StringCopyWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
  5038. #define StringCopyExWorkerA StringCopyExWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
  5039. #define StringCopyExWorkerW StringCopyExWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
  5040. #define StringCatWorkerA StringCatWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
  5041. #define StringCatWorkerW StringCatWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
  5042. #define StringCatExWorkerA StringCatExWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
  5043. #define StringCatExWorkerW StringCatExWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
  5044. #define StringCatNWorkerA StringCatNWorkerA_instead_use_StringCchCatNA_or_StrincCbCatNA;
  5045. #define StringCatNWorkerW StringCatNWorkerW_instead_use_StringCchCatNW_or_StringCbCatNW;
  5046. #define StringCatNExWorkerA StringCatNExWorkerA_instead_use_StringCchCatNExA_or_StringCbCatNExA;
  5047. #define StringCatNExWorkerW StringCatNExWorkerW_instead_use_StringCchCatNExW_or_StringCbCatNExW;
  5048. #define StringVPrintfWorkerA StringVPrintfWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
  5049. #define StringVPrintfWorkerW StringVPrintfWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
  5050. #define StringVPrintfExWorkerA StringVPrintfExWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
  5051. #define StringVPrintfExWorkerW StringVPrintfExWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
  5052. #define StringLengthWorkerA StringLengthWorkerA_instead_use_StringCchLengthA_or_StringCbLengthA;
  5053. #define StringLengthWorkerW StringLengthWorkerW_instead_use_StringCchLengthW_or_StringCbLengthW;
  5054. #endif // !DEPRECATE_SUPPORTED
  5055. #ifndef STRSAFE_NO_DEPRECATE
  5056. // Deprecate all of the unsafe functions to generate compiletime errors. If you do not want
  5057. // this then you can #define STRSAFE_NO_DEPRECATE before including this file.
  5058. #ifdef DEPRECATE_SUPPORTED
  5059. // First all the names that are a/w variants (or shouldn't be #defined by now anyway).
  5060. #pragma deprecated(lstrcpyA)
  5061. #pragma deprecated(lstrcpyW)
  5062. #pragma deprecated(lstrcatA)
  5063. #pragma deprecated(lstrcatW)
  5064. #pragma deprecated(wsprintfA)
  5065. #pragma deprecated(wsprintfW)
  5066. #pragma deprecated(StrCpyW)
  5067. #pragma deprecated(StrCatW)
  5068. #pragma deprecated(StrNCatA)
  5069. #pragma deprecated(StrNCatW)
  5070. #pragma deprecated(StrCatNA)
  5071. #pragma deprecated(StrCatNW)
  5072. #pragma deprecated(wvsprintfA)
  5073. #pragma deprecated(wvsprintfW)
  5074. #pragma deprecated(strcpy)
  5075. #pragma deprecated(wcscpy)
  5076. #pragma deprecated(strcat)
  5077. #pragma deprecated(wcscat)
  5078. #pragma deprecated(sprintf)
  5079. #pragma deprecated(swprintf)
  5080. #pragma deprecated(vsprintf)
  5081. #pragma deprecated(vswprintf)
  5082. #pragma deprecated(_snprintf)
  5083. #pragma deprecated(_snwprintf)
  5084. #pragma deprecated(_vsnprintf)
  5085. #pragma deprecated(_vsnwprintf)
  5086. #pragma deprecated(gets)
  5087. #pragma deprecated(_getws)
  5088. // Then all the windows.h names - we need to undef and redef based on UNICODE setting
  5089. #undef lstrcpy
  5090. #undef lstrcat
  5091. #undef wsprintf
  5092. #undef wvsprintf
  5093. #pragma deprecated(lstrcpy)
  5094. #pragma deprecated(lstrcat)
  5095. #pragma deprecated(wsprintf)
  5096. #pragma deprecated(wvsprintf)
  5097. #ifdef UNICODE
  5098. #define lstrcpy lstrcpyW
  5099. #define lstrcat lstrcatW
  5100. #define wsprintf wsprintfW
  5101. #define wvsprintf wvsprintfW
  5102. #else
  5103. #define lstrcpy lstrcpyA
  5104. #define lstrcat lstrcatA
  5105. #define wsprintf wsprintfA
  5106. #define wvsprintf wvsprintfA
  5107. #endif
  5108. // Then the shlwapi names - they key off UNICODE also.
  5109. #undef StrCpyA
  5110. #undef StrCpy
  5111. #undef StrCatA
  5112. #undef StrCat
  5113. #undef StrNCat
  5114. #undef StrCatN
  5115. #pragma deprecated(StrCpyA)
  5116. #pragma deprecated(StrCatA)
  5117. #pragma deprecated(StrCatN)
  5118. #pragma deprecated(StrCpy)
  5119. #pragma deprecated(StrCat)
  5120. #pragma deprecated(StrNCat)
  5121. #define StrCpyA lstrcpyA
  5122. #define StrCatA lstrcatA
  5123. #define StrCatN StrNCat
  5124. #ifdef UNICODE
  5125. #define StrCpy StrCpyW
  5126. #define StrCat StrCatW
  5127. #define StrNCat StrNCatW
  5128. #else
  5129. #define StrCpy lstrcpyA
  5130. #define StrCat lstrcatA
  5131. #define StrNCat StrNCatA
  5132. #endif
  5133. // Then all the CRT names - we need to undef/redef based on _UNICODE value.
  5134. #undef _tcscpy
  5135. #undef _ftcscpy
  5136. #undef _tcscat
  5137. #undef _ftcscat
  5138. #undef _stprintf
  5139. #undef _sntprintf
  5140. #undef _vstprintf
  5141. #undef _vsntprintf
  5142. #undef _getts
  5143. #pragma deprecated(_tcscpy)
  5144. #pragma deprecated(_ftcscpy)
  5145. #pragma deprecated(_tcscat)
  5146. #pragma deprecated(_ftcscat)
  5147. #pragma deprecated(_stprintf)
  5148. #pragma deprecated(_sntprintf)
  5149. #pragma deprecated(_vstprintf)
  5150. #pragma deprecated(_vsntprintf)
  5151. #pragma deprecated(_getts)
  5152. #ifdef _UNICODE
  5153. #define _tcscpy wcscpy
  5154. #define _ftcscpy wcscpy
  5155. #define _tcscat wcscat
  5156. #define _ftcscat wcscat
  5157. #define _stprintf swprintf
  5158. #define _sntprintf _snwprintf
  5159. #define _vstprintf vswprintf
  5160. #define _vsntprintf _vsnwprintf
  5161. #define _getts _getws
  5162. #else
  5163. #define _tcscpy strcpy
  5164. #define _ftcscpy strcpy
  5165. #define _tcscat strcat
  5166. #define _ftcscat strcat
  5167. #define _stprintf sprintf
  5168. #define _sntprintf _snprintf
  5169. #define _vstprintf vsprintf
  5170. #define _vsntprintf _vsnprintf
  5171. #define _getts gets
  5172. #endif
  5173. #else // DEPRECATE_SUPPORTED
  5174. #undef strcpy
  5175. #define strcpy strcpy_instead_use_StringCbCopyA_or_StringCchCopyA;
  5176. #undef wcscpy
  5177. #define wcscpy wcscpy_instead_use_StringCbCopyW_or_StringCchCopyW;
  5178. #undef strcat
  5179. #define strcat strcat_instead_use_StringCbCatA_or_StringCchCatA;
  5180. #undef wcscat
  5181. #define wcscat wcscat_instead_use_StringCbCatW_or_StringCchCatW;
  5182. #undef sprintf
  5183. #define sprintf sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA;
  5184. #undef swprintf
  5185. #define swprintf swprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW;
  5186. #undef vsprintf
  5187. #define vsprintf vsprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
  5188. #undef vswprintf
  5189. #define vswprintf vswprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
  5190. #undef _snprintf
  5191. #define _snprintf _snprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA;
  5192. #undef _snwprintf
  5193. #define _snwprintf _snwprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW;
  5194. #undef _vsnprintf
  5195. #define _vsnprintf _vsnprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
  5196. #undef _vsnwprintf
  5197. #define _vsnwprintf _vsnwprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
  5198. #undef strcpyA
  5199. #define strcpyA strcpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
  5200. #undef strcpyW
  5201. #define strcpyW strcpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
  5202. #undef lstrcpy
  5203. #define lstrcpy lstrcpy_instead_use_StringCbCopy_or_StringCchCopy;
  5204. #undef lstrcpyA
  5205. #define lstrcpyA lstrcpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
  5206. #undef lstrcpyW
  5207. #define lstrcpyW lstrcpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
  5208. #undef StrCpy
  5209. #define StrCpy StrCpy_instead_use_StringCbCopy_or_StringCchCopy;
  5210. #undef StrCpyA
  5211. #define StrCpyA StrCpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
  5212. #undef StrCpyW
  5213. #define StrCpyW StrCpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
  5214. #undef _tcscpy
  5215. #define _tcscpy _tcscpy_instead_use_StringCbCopy_or_StringCchCopy;
  5216. #undef _ftcscpy
  5217. #define _ftcscpy _ftcscpy_instead_use_StringCbCopy_or_StringCchCopy;
  5218. #undef lstrcat
  5219. #define lstrcat lstrcat_instead_use_StringCbCat_or_StringCchCat;
  5220. #undef lstrcatA
  5221. #define lstrcatA lstrcatA_instead_use_StringCbCatA_or_StringCchCatA;
  5222. #undef lstrcatW
  5223. #define lstrcatW lstrcatW_instead_use_StringCbCatW_or_StringCchCatW;
  5224. #undef StrCat
  5225. #define StrCat StrCat_instead_use_StringCbCat_or_StringCchCat;
  5226. #undef StrCatA
  5227. #define StrCatA StrCatA_instead_use_StringCbCatA_or_StringCchCatA;
  5228. #undef StrCatW
  5229. #define StrCatW StrCatW_instead_use_StringCbCatW_or_StringCchCatW;
  5230. #undef StrNCat
  5231. #define StrNCat StrNCat_instead_use_StringCbCatN_or_StringCchCatN;
  5232. #undef StrNCatA
  5233. #define StrNCatA StrNCatA_instead_use_StringCbCatNA_or_StringCchCatNA;
  5234. #undef StrNCatW
  5235. #define StrNCatW StrNCatW_instead_use_StringCbCatNW_or_StringCchCatNW;
  5236. #undef StrCatN
  5237. #define StrCatN StrCatN_instead_use_StringCbCatN_or_StringCchCatN;
  5238. #undef StrCatNA
  5239. #define StrCatNA StrCatNA_instead_use_StringCbCatNA_or_StringCchCatNA;
  5240. #undef StrCatNW
  5241. #define StrCatNW StrCatNW_instead_use_StringCbCatNW_or_StringCchCatNW;
  5242. #undef _tcscat
  5243. #define _tcscat _tcscat_instead_use_StringCbCat_or_StringCchCat;
  5244. #undef _ftcscat
  5245. #define _ftcscat _ftcscat_instead_use_StringCbCat_or_StringCchCat;
  5246. #undef wsprintf
  5247. #define wsprintf wsprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
  5248. #undef wsprintfA
  5249. #define wsprintfA wsprintfA_instead_use_StringCbPrintfA_or_StringCchPrintfA;
  5250. #undef wsprintfW
  5251. #define wsprintfW wsprintfW_instead_use_StringCbPrintfW_or_StringCchPrintfW;
  5252. #undef wvsprintf
  5253. #define wvsprintf wvsprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
  5254. #undef wvsprintfA
  5255. #define wvsprintfA wvsprintfA_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
  5256. #undef wvsprintfW
  5257. #define wvsprintfW wvsprintfW_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
  5258. #undef _vstprintf
  5259. #define _vstprintf _vstprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
  5260. #undef _vsntprintf
  5261. #define _vsntprintf _vsntprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
  5262. #undef _stprintf
  5263. #define _stprintf _stprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
  5264. #undef _sntprintf
  5265. #define _sntprintf _sntprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
  5266. #undef _getts
  5267. #define _getts _getts_instead_use_StringCbGets_or_StringCchGets;
  5268. #undef gets
  5269. #define gets _gets_instead_use_StringCbGetsA_or_StringCchGetsA;
  5270. #undef _getws
  5271. #define _getws _getws_instead_use_StringCbGetsW_or_StringCchGetsW;
  5272. #endif // !DEPRECATE_SUPPORTED
  5273. #endif // !STRSAFE_NO_DEPRECATE
  5274. #ifdef _NTSTRSAFE_H_INCLUDED_
  5275. #pragma warning(pop)
  5276. #endif // _NTSTRSAFE_H_INCLUDED_
  5277. #endif // _STRSAFE_H_INCLUDED_