Leaked source code of windows server 2003
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.

6820 lines
222 KiB

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