Source code of Windows XP (NT5)
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.

5424 lines
180 KiB

  1. /******************************************************************
  2. * *
  3. * ntstrsafe.h -- This module defines safer C library string *
  4. * routine replacements for drivers. These are *
  5. * meant to make C a bit more safe in reference *
  6. * to security and robustness. A similar file, *
  7. * strsafe.h, is available for applications. *
  8. * *
  9. * Copyright (c) Microsoft Corp. All rights reserved. *
  10. * *
  11. ******************************************************************/
  12. #ifndef _NTSTRSAFE_H_INCLUDED_
  13. #define _NTSTRSAFE_H_INCLUDED_
  14. #pragma once
  15. #include <stdio.h> // for _vsnprintf, _vsnwprintf, getc, getwc
  16. #include <string.h> // for memset
  17. #include <stdarg.h> // for va_start, etc.
  18. #ifdef __cplusplus
  19. #define _NTSTRSAFE_EXTERN_C extern "C"
  20. #else
  21. #define _NTSTRSAFE_EXTERN_C extern
  22. #endif
  23. // If you do not want to use these functions inline (and instead want to link w/ ntstrsafe.lib), then
  24. // #define NTSTRSAFE_LIB before including this header file.
  25. #if defined(NTSTRSAFE_LIB)
  26. #define NTSTRSAFEDDI _NTSTRSAFE_EXTERN_C NTSTATUS __stdcall
  27. #pragma comment(lib, "ntstrsafe.lib")
  28. #elif defined(NTSTRSAFE_LIB_IMPL)
  29. #define NTSTRSAFEDDI _NTSTRSAFE_EXTERN_C NTSTATUS __stdcall
  30. #else
  31. #define NTSTRSAFEDDI __inline NTSTATUS __stdcall
  32. #define NTSTRSAFE_INLINE
  33. #endif
  34. // Some functions always run inline because they use stdin and we want to avoid building multiple
  35. // versions of strsafe lib depending on if you use msvcrt, libcmt, etc.
  36. #define NTSTRSAFE_INLINE_API __inline NTSTATUS __stdcall
  37. // The user can request no "Cb" or no "Cch" fuctions, but not both!
  38. #if defined(NTSTRSAFE_NO_CB_FUNCTIONS) && defined(NTSTRSAFE_NO_CCH_FUNCTIONS)
  39. #error cannot specify both NTSTRSAFE_NO_CB_FUNCTIONS and NTSTRSAFE_NO_CCH_FUNCTIONS !!
  40. #endif
  41. // This should only be defined when we are building ntstrsafe.lib
  42. #ifdef NTSTRSAFE_LIB_IMPL
  43. #define NTSTRSAFE_INLINE
  44. #endif
  45. // If both strsafe.h and ntstrsafe.h are included, only use definitions from one.
  46. #ifndef _STRSAFE_H_INCLUDED_
  47. #define STRSAFE_MAX_CCH 2147483647 // max # of characters we support (same as INT_MAX)
  48. // Flags for controling the Ex functions
  49. //
  50. // STRSAFE_FILL_BYTE(0xFF) 0x000000FF // bottom byte specifies fill pattern
  51. #define STRSAFE_IGNORE_NULLS 0x00000100 // treat null as TEXT("") -- don't fault on NULL buffers
  52. #define STRSAFE_FILL_BEHIND_NULL 0x00000200 // fill in extra space behind the null terminator
  53. #define STRSAFE_FILL_ON_FAILURE 0x00000400 // on failure, overwrite pszDest with fill pattern and null terminate it
  54. #define STRSAFE_NULL_ON_FAILURE 0x00000800 // on failure, set *pszDest = TEXT('\0')
  55. #define STRSAFE_NO_TRUNCATION 0x00001000 // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it
  56. #define STRSAFE_VALID_FLAGS (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)
  57. // helper macro to set the fill character and specify buffer filling
  58. #define STRSAFE_FILL_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL))
  59. #define STRSAFE_FAILURE_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE))
  60. #define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)(dwFlags & 0x000000FF))
  61. #endif // _STRSAFE_H_INCLUDED_
  62. // prototypes for the worker functions
  63. #ifdef NTSTRSAFE_INLINE
  64. NTSTRSAFEDDI RtlStringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
  65. NTSTRSAFEDDI RtlStringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  66. NTSTRSAFEDDI RtlStringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  67. NTSTRSAFEDDI RtlStringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  68. NTSTRSAFEDDI RtlStringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
  69. NTSTRSAFEDDI RtlStringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
  70. NTSTRSAFEDDI RtlStringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  71. NTSTRSAFEDDI RtlStringCopyNExWorkerW(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);
  72. NTSTRSAFEDDI RtlStringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
  73. NTSTRSAFEDDI RtlStringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  74. NTSTRSAFEDDI RtlStringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  75. NTSTRSAFEDDI RtlStringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  76. NTSTRSAFEDDI RtlStringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
  77. NTSTRSAFEDDI RtlStringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
  78. NTSTRSAFEDDI RtlStringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  79. NTSTRSAFEDDI RtlStringCatNExWorkerW(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);
  80. NTSTRSAFEDDI RtlStringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
  81. NTSTRSAFEDDI RtlStringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
  82. NTSTRSAFEDDI RtlStringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  83. NTSTRSAFEDDI RtlStringVPrintfExWorkerW(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);
  84. NTSTRSAFEDDI RtlStringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch);
  85. NTSTRSAFEDDI RtlStringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  86. #endif // NTSTRSAFE_INLINE
  87. #ifdef _STRSAFE_H_INCLUDED_
  88. #pragma warning(push)
  89. #pragma warning(disable : 4995)
  90. #endif // _STRSAFE_H_INCLUDED_
  91. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  92. /*++
  93. NTSTATUS
  94. RtlStringCchCopy(
  95. OUT LPTSTR pszDest,
  96. IN size_t cchDest,
  97. IN LPCTSTR pszSrc
  98. );
  99. Routine Description:
  100. This routine is a safer version of the C built-in function 'strcpy'.
  101. The size of the destination buffer (in characters) is a parameter and
  102. this function will not write past the end of this buffer and it will
  103. ALWAYS null terminate the destination buffer (unless it is zero length).
  104. This routine is not a replacement for strncpy. That function will pad the
  105. destination string with extra null termination characters if the count is
  106. greater than the length of the source string, and it will fail to null
  107. terminate the destination string if the source string length is greater
  108. than or equal to the count. You can not blindly use this instead of strncpy:
  109. it is common for code to use it to "patch" strings and you would introduce
  110. errors if the code started null terminating in the middle of the string.
  111. This function returns an NTSTATUS value, and not a pointer. It returns
  112. STATUS_SUCCESS if the string was copied without truncation and null terminated,
  113. otherwise it will return a failure code. In failure cases as much of
  114. pszSrc will be copied to pszDest as possible, and pszDest will be null
  115. terminated.
  116. Arguments:
  117. pszDest - destination string
  118. cchDest - size of destination buffer in characters.
  119. length must be = (_tcslen(src) + 1) to hold all of the
  120. source including the null terminator
  121. pszSrc - source string which must be null terminated
  122. Notes:
  123. Behavior is undefined if source and destination strings overlap.
  124. pszDest and pszSrc should not be NULL. See RtlStringCchCopyEx if you require
  125. the handling of NULL values.
  126. Return Value:
  127. STATUS_SUCCESS - if there was source data and it was all copied and the
  128. resultant dest string was null terminated
  129. failure - the operation did not succeed.
  130. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  131. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  132. - this return value is an indication that the copy
  133. operation failed due to insufficient space. When this
  134. error occurs, the destination buffer is modified to
  135. contain a truncated version of the ideal result and is
  136. null terminated. This is useful for situations where
  137. truncation is ok
  138. It is strongly recommended to use the NT_SUCCESS() macro to test the
  139. return value of this function.
  140. --*/
  141. NTSTRSAFEDDI RtlStringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc);
  142. NTSTRSAFEDDI RtlStringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  143. #ifdef NTSTRSAFE_INLINE
  144. NTSTRSAFEDDI RtlStringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc)
  145. {
  146. NTSTATUS status;
  147. if (cchDest > STRSAFE_MAX_CCH)
  148. {
  149. status = STATUS_INVALID_PARAMETER;
  150. }
  151. else
  152. {
  153. status = RtlStringCopyWorkerA(pszDest, cchDest, pszSrc);
  154. }
  155. return status;
  156. }
  157. NTSTRSAFEDDI RtlStringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  158. {
  159. NTSTATUS status;
  160. if (cchDest > STRSAFE_MAX_CCH)
  161. {
  162. status = STATUS_INVALID_PARAMETER;
  163. }
  164. else
  165. {
  166. status = RtlStringCopyWorkerW(pszDest, cchDest, pszSrc);
  167. }
  168. return status;
  169. }
  170. #endif // NTSTRSAFE_INLINE
  171. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  172. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  173. /*++
  174. NTSTATUS
  175. RtlStringCbCopy(
  176. OUT LPTSTR pszDest,
  177. IN size_t cbDest,
  178. IN LPCTSTR pszSrc
  179. );
  180. Routine Description:
  181. This routine is a safer version of the C built-in function 'strcpy'.
  182. The size of the destination buffer (in bytes) is a parameter and this
  183. function will not write past the end of this buffer and it will ALWAYS
  184. null terminate the destination buffer (unless it is zero length).
  185. This routine is not a replacement for strncpy. That function will pad the
  186. destination string with extra null termination characters if the count is
  187. greater than the length of the source string, and it will fail to null
  188. terminate the destination string if the source string length is greater
  189. than or equal to the count. You can not blindly use this instead of strncpy:
  190. it is common for code to use it to "patch" strings and you would introduce
  191. errors if the code started null terminating in the middle of the string.
  192. This function returns an NTSTATUS value, and not a pointer. It returns
  193. STATUS_SUCCESS if the string was copied without truncation and null terminated,
  194. otherwise it will return a failure code. In failure cases as much of pszSrc
  195. will be copied to pszDest as possible, and pszDest will be null terminated.
  196. Arguments:
  197. pszDest - destination string
  198. cbDest - size of destination buffer in bytes.
  199. length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
  200. hold all of the source including the null terminator
  201. pszSrc - source string which must be null terminated
  202. Notes:
  203. Behavior is undefined if source and destination strings overlap.
  204. pszDest and pszSrc should not be NULL. See RtlStringCbCopyEx if you require
  205. the handling of NULL values.
  206. Return Value:
  207. STATUS_SUCCESS - if there was source data and it was all copied and the
  208. resultant dest string was null terminated
  209. failure - the operation did not succeed.
  210. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  211. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  212. - this return value is an indication that the copy
  213. operation failed due to insufficient space. When this
  214. error occurs, the destination buffer is modified to
  215. contain a truncated version of the ideal result and is
  216. null terminated. This is useful for situations where
  217. truncation is ok
  218. It is strongly recommended to use the NT_SUCCESS() macro to test the
  219. return value of this function.
  220. --*/
  221. NTSTRSAFEDDI RtlStringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc);
  222. NTSTRSAFEDDI RtlStringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
  223. #ifdef NTSTRSAFE_INLINE
  224. NTSTRSAFEDDI RtlStringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc)
  225. {
  226. NTSTATUS status;
  227. size_t cchDest;
  228. // convert to count of characters
  229. cchDest = cbDest / sizeof(char);
  230. if (cchDest > STRSAFE_MAX_CCH)
  231. {
  232. status = STATUS_INVALID_PARAMETER;
  233. }
  234. else
  235. {
  236. status = RtlStringCopyWorkerA(pszDest, cchDest, pszSrc);
  237. }
  238. return status;
  239. }
  240. NTSTRSAFEDDI RtlStringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
  241. {
  242. NTSTATUS status;
  243. size_t cchDest;
  244. // convert to count of characters
  245. cchDest = cbDest / sizeof(wchar_t);
  246. if (cchDest > STRSAFE_MAX_CCH)
  247. {
  248. status = STATUS_INVALID_PARAMETER;
  249. }
  250. else
  251. {
  252. status = RtlStringCopyWorkerW(pszDest, cchDest, pszSrc);
  253. }
  254. return status;
  255. }
  256. #endif // NTSTRSAFE_INLINE
  257. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  258. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  259. /*++
  260. NTSTATUS
  261. RtlStringCchCopyEx(
  262. OUT LPTSTR pszDest OPTIONAL,
  263. IN size_t cchDest,
  264. IN LPCTSTR pszSrc OPTIONAL,
  265. OUT LPTSTR* ppszDestEnd OPTIONAL,
  266. OUT size_t* pcchRemaining OPTIONAL,
  267. IN DWORD dwFlags
  268. );
  269. Routine Description:
  270. This routine is a safer version of the C built-in function 'strcpy' with
  271. some additional parameters. In addition to functionality provided by
  272. RtlStringCchCopy, this routine also returns a pointer to the end of the
  273. destination string and the number of characters left in the destination string
  274. including the null terminator. The flags parameter allows additional controls.
  275. Arguments:
  276. pszDest - destination string
  277. cchDest - size of destination buffer in characters.
  278. length must be = (_tcslen(pszSrc) + 1) to hold all of
  279. the source including the null terminator
  280. pszSrc - source string which must be null terminated
  281. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  282. pointer to the end of the destination string. If the
  283. function copied any data, the result will point to the
  284. null termination character
  285. pcchRemaining - if pcchRemaining is non-null, the function will return the
  286. number of characters left in the destination string,
  287. including the null terminator
  288. dwFlags - controls some details of the string copy:
  289. STRSAFE_FILL_BEHIND_NULL
  290. if the function succeeds, the low byte of dwFlags will be
  291. used to fill the uninitialize part of destination buffer
  292. behind the null terminator
  293. STRSAFE_IGNORE_NULLS
  294. treat NULL string pointers like empty strings (TEXT("")).
  295. this flag is useful for emulating functions like lstrcpy
  296. STRSAFE_FILL_ON_FAILURE
  297. if the function fails, the low byte of dwFlags will be
  298. used to fill all of the destination buffer, and it will
  299. be null terminated. This will overwrite any truncated
  300. string returned when the failure is
  301. STATUS_BUFFER_OVERFLOW
  302. STRSAFE_NO_TRUNCATION /
  303. STRSAFE_NULL_ON_FAILURE
  304. if the function fails, the destination buffer will be set
  305. to the empty string. This will overwrite any truncated string
  306. returned when the failure is STATUS_BUFFER_OVERFLOW.
  307. Notes:
  308. Behavior is undefined if source and destination strings overlap.
  309. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  310. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  311. may be NULL. An error may still be returned even though NULLS are ignored
  312. due to insufficient space.
  313. Return Value:
  314. STATUS_SUCCESS - if there was source data and it was all copied and the
  315. resultant dest string was null terminated
  316. failure - the operation did not succeed.
  317. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  318. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  319. - this return value is an indication that the copy
  320. operation failed due to insufficient space. When this
  321. error occurs, the destination buffer is modified to
  322. contain a truncated version of the ideal result and is
  323. null terminated. This is useful for situations where
  324. truncation is ok.
  325. It is strongly recommended to use the NT_SUCCESS() macro to test the
  326. return value of this function
  327. --*/
  328. NTSTRSAFEDDI RtlStringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  329. NTSTRSAFEDDI RtlStringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  330. #ifdef NTSTRSAFE_INLINE
  331. NTSTRSAFEDDI RtlStringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  332. {
  333. NTSTATUS status;
  334. if (cchDest > STRSAFE_MAX_CCH)
  335. {
  336. status = STATUS_INVALID_PARAMETER;
  337. }
  338. else
  339. {
  340. size_t cbDest;
  341. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  342. cbDest = cchDest * sizeof(char);
  343. status = RtlStringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  344. }
  345. return status;
  346. }
  347. NTSTRSAFEDDI RtlStringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  348. {
  349. NTSTATUS status;
  350. if (cchDest > STRSAFE_MAX_CCH)
  351. {
  352. status = STATUS_INVALID_PARAMETER;
  353. }
  354. else
  355. {
  356. size_t cbDest;
  357. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  358. cbDest = cchDest * sizeof(wchar_t);
  359. status = RtlStringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  360. }
  361. return status;
  362. }
  363. #endif // NTSTRSAFE_INLINE
  364. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  365. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  366. /*++
  367. NTSTATUS
  368. RtlStringCbCopyEx(
  369. OUT LPTSTR pszDest OPTIONAL,
  370. IN size_t cbDest,
  371. IN LPCTSTR pszSrc OPTIONAL,
  372. OUT LPTSTR* ppszDestEnd OPTIONAL,
  373. OUT size_t* pcbRemaining OPTIONAL,
  374. IN DWORD dwFlags
  375. );
  376. Routine Description:
  377. This routine is a safer version of the C built-in function 'strcpy' with
  378. some additional parameters. In addition to functionality provided by
  379. RtlStringCbCopy, this routine also returns a pointer to the end of the
  380. destination string and the number of bytes left in the destination string
  381. including the null terminator. The flags parameter allows additional controls.
  382. Arguments:
  383. pszDest - destination string
  384. cbDest - size of destination buffer in bytes.
  385. length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
  386. hold all of the source including the null terminator
  387. pszSrc - source string which must be null terminated
  388. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  389. pointer to the end of the destination string. If the
  390. function copied any data, the result will point to the
  391. null termination character
  392. pcbRemaining - pcbRemaining is non-null,the function will return the
  393. number of bytes left in the destination string,
  394. including the null terminator
  395. dwFlags - controls some details of the string copy:
  396. STRSAFE_FILL_BEHIND_NULL
  397. if the function succeeds, the low byte of dwFlags will be
  398. used to fill the uninitialize part of destination buffer
  399. behind the null terminator
  400. STRSAFE_IGNORE_NULLS
  401. treat NULL string pointers like empty strings (TEXT("")).
  402. this flag is useful for emulating functions like lstrcpy
  403. STRSAFE_FILL_ON_FAILURE
  404. if the function fails, the low byte of dwFlags will be
  405. used to fill all of the destination buffer, and it will
  406. be null terminated. This will overwrite any truncated
  407. string returned when the failure is
  408. STATUS_BUFFER_OVERFLOW
  409. STRSAFE_NO_TRUNCATION /
  410. STRSAFE_NULL_ON_FAILURE
  411. if the function fails, the destination buffer will be set
  412. to the empty string. This will overwrite any truncated string
  413. returned when the failure is STATUS_BUFFER_OVERFLOW.
  414. Notes:
  415. Behavior is undefined if source and destination strings overlap.
  416. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  417. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  418. may be NULL. An error may still be returned even though NULLS are ignored
  419. due to insufficient space.
  420. Return Value:
  421. STATUS_SUCCESS - if there was source data and it was all copied and the
  422. resultant dest string was null terminated
  423. failure - the operation did not succeed.
  424. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  425. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  426. - this return value is an indication that the copy
  427. operation failed due to insufficient space. When this
  428. error occurs, the destination buffer is modified to
  429. contain a truncated version of the ideal result and is
  430. null terminated. This is useful for situations where
  431. truncation is ok.
  432. It is strongly recommended to use the NT_SUCCESS() macro to test the
  433. return value of this function
  434. --*/
  435. NTSTRSAFEDDI RtlStringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  436. NTSTRSAFEDDI RtlStringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  437. #ifdef NTSTRSAFE_INLINE
  438. NTSTRSAFEDDI RtlStringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  439. {
  440. NTSTATUS status;
  441. size_t cchDest;
  442. size_t cchRemaining = 0;
  443. cchDest = cbDest / sizeof(char);
  444. if (cchDest > STRSAFE_MAX_CCH)
  445. {
  446. status = STATUS_INVALID_PARAMETER;
  447. }
  448. else
  449. {
  450. status = RtlStringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  451. }
  452. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  453. {
  454. if (pcbRemaining)
  455. {
  456. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  457. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  458. }
  459. }
  460. return status;
  461. }
  462. NTSTRSAFEDDI RtlStringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  463. {
  464. NTSTATUS status;
  465. size_t cchDest;
  466. size_t cchRemaining = 0;
  467. cchDest = cbDest / sizeof(wchar_t);
  468. if (cchDest > STRSAFE_MAX_CCH)
  469. {
  470. status = STATUS_INVALID_PARAMETER;
  471. }
  472. else
  473. {
  474. status = RtlStringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  475. }
  476. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  477. {
  478. if (pcbRemaining)
  479. {
  480. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  481. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  482. }
  483. }
  484. return status;
  485. }
  486. #endif // NTSTRSAFE_INLINE
  487. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  488. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  489. /*++
  490. NTSTATUS
  491. RtlStringCchCopyN(
  492. OUT LPTSTR pszDest,
  493. IN size_t cchDest,
  494. IN LPCTSTR pszSrc,
  495. IN size_t cchSrc
  496. );
  497. Routine Description:
  498. This routine is a safer version of the C built-in function 'strncpy'.
  499. The size of the destination buffer (in characters) is a parameter and
  500. this function will not write past the end of this buffer and it will
  501. ALWAYS null terminate the destination buffer (unless it is zero length).
  502. This routine is meant as a replacement for strncpy, but it does behave
  503. differently. This function will not pad the destination buffer with extra
  504. null termination characters if cchSrc is greater than the length of pszSrc.
  505. This function returns an NTSTATUS value, and not a pointer. It returns
  506. STATUS_SUCCESS if the entire string or the first cchSrc characters were copied
  507. without truncation and the resultant destination string was null terminated,
  508. otherwise it will return a failure code. In failure cases as much of pszSrc
  509. will be copied to pszDest as possible, and pszDest will be null terminated.
  510. Arguments:
  511. pszDest - destination string
  512. cchDest - size of destination buffer in characters.
  513. length must be = (_tcslen(src) + 1) to hold all of the
  514. source including the null terminator
  515. pszSrc - source string
  516. cchSrc - maximum number of characters to copy from source string,
  517. not including the null terminator.
  518. Notes:
  519. Behavior is undefined if source and destination strings overlap.
  520. pszDest and pszSrc should not be NULL. See RtlStringCchCopyNEx if you require
  521. the handling of NULL values.
  522. Return Value:
  523. STATUS_SUCCESS - if there was source data and it was all copied and the
  524. resultant dest string was null terminated
  525. failure - the operation did not succeed.
  526. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  527. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  528. - this return value is an indication that the copy
  529. operation failed due to insufficient space. When this
  530. error occurs, the destination buffer is modified to
  531. contain a truncated version of the ideal result and is
  532. null terminated. This is useful for situations where
  533. truncation is ok
  534. It is strongly recommended to use the NT_SUCCESS() macro to test the
  535. return value of this function.
  536. --*/
  537. NTSTRSAFEDDI RtlStringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
  538. NTSTRSAFEDDI RtlStringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
  539. #ifdef NTSTRSAFE_INLINE
  540. NTSTRSAFEDDI RtlStringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
  541. {
  542. NTSTATUS status;
  543. if ((cchDest > STRSAFE_MAX_CCH) ||
  544. (cchSrc > STRSAFE_MAX_CCH))
  545. {
  546. status = STATUS_INVALID_PARAMETER;
  547. }
  548. else
  549. {
  550. status = RtlStringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
  551. }
  552. return status;
  553. }
  554. NTSTRSAFEDDI RtlStringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
  555. {
  556. NTSTATUS status;
  557. if ((cchDest > STRSAFE_MAX_CCH) ||
  558. (cchSrc > STRSAFE_MAX_CCH))
  559. {
  560. status = STATUS_INVALID_PARAMETER;
  561. }
  562. else
  563. {
  564. status = RtlStringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
  565. }
  566. return status;
  567. }
  568. #endif // NTSTRSAFE_INLINE
  569. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  570. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  571. /*++
  572. NTSTATUS
  573. RtlStringCbCopyN(
  574. OUT LPTSTR pszDest,
  575. IN size_t cbDest,
  576. IN LPCTSTR pszSrc,
  577. IN size_t cbSrc
  578. );
  579. Routine Description:
  580. This routine is a safer version of the C built-in function 'strncpy'.
  581. The size of the destination buffer (in bytes) is a parameter and this
  582. function will not write past the end of this buffer and it will ALWAYS
  583. null terminate the destination buffer (unless it is zero length).
  584. This routine is meant as a replacement for strncpy, but it does behave
  585. differently. This function will not pad the destination buffer with extra
  586. null termination characters if cbSrc is greater than the size of pszSrc.
  587. This function returns an NTSTATUS value, and not a pointer. It returns
  588. STATUS_SUCCESS if the entire string or the first cbSrc characters were
  589. copied without truncation and the resultant destination string was null
  590. terminated, otherwise it will return a failure code. In failure cases as
  591. much of pszSrc will be copied to pszDest as possible, and pszDest will be
  592. null terminated.
  593. Arguments:
  594. pszDest - destination string
  595. cbDest - size of destination buffer in bytes.
  596. length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
  597. hold all of the source including the null terminator
  598. pszSrc - source string
  599. cbSrc - maximum number of bytes to copy from source string,
  600. not including the null terminator.
  601. Notes:
  602. Behavior is undefined if source and destination strings overlap.
  603. pszDest and pszSrc should not be NULL. See RtlStringCbCopyEx if you require
  604. the handling of NULL values.
  605. Return Value:
  606. STATUS_SUCCESS - if there was source data and it was all copied and the
  607. resultant dest string was null terminated
  608. failure - the operation did not succeed.
  609. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  610. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  611. - this return value is an indication that the copy
  612. operation failed due to insufficient space. When this
  613. error occurs, the destination buffer is modified to
  614. contain a truncated version of the ideal result and is
  615. null terminated. This is useful for situations where
  616. truncation is ok
  617. It is strongly recommended to use the NT_SUCCESS() macro to test the
  618. return value of this function.
  619. --*/
  620. NTSTRSAFEDDI RtlStringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc);
  621. NTSTRSAFEDDI RtlStringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc);
  622. #ifdef NTSTRSAFE_INLINE
  623. NTSTRSAFEDDI RtlStringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc)
  624. {
  625. NTSTATUS status;
  626. size_t cchDest;
  627. size_t cchSrc;
  628. // convert to count of characters
  629. cchDest = cbDest / sizeof(char);
  630. cchSrc = cbSrc / sizeof(char);
  631. if ((cchDest > STRSAFE_MAX_CCH) ||
  632. (cchSrc > STRSAFE_MAX_CCH))
  633. {
  634. status = STATUS_INVALID_PARAMETER;
  635. }
  636. else
  637. {
  638. status = RtlStringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
  639. }
  640. return status;
  641. }
  642. NTSTRSAFEDDI RtlStringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc)
  643. {
  644. NTSTATUS status;
  645. size_t cchDest;
  646. size_t cchSrc;
  647. // convert to count of characters
  648. cchDest = cbDest / sizeof(wchar_t);
  649. cchSrc = cbSrc / sizeof(wchar_t);
  650. if ((cchDest > STRSAFE_MAX_CCH) ||
  651. (cchSrc > STRSAFE_MAX_CCH))
  652. {
  653. status = STATUS_INVALID_PARAMETER;
  654. }
  655. else
  656. {
  657. status = RtlStringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
  658. }
  659. return status;
  660. }
  661. #endif // NTSTRSAFE_INLINE
  662. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  663. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  664. /*++
  665. NTSTATUS
  666. RtlStringCchCopyNEx(
  667. OUT LPTSTR pszDest OPTIONAL,
  668. IN size_t cchDest,
  669. IN LPCTSTR pszSrc OPTIONAL,
  670. IN size_t cchSrc,
  671. OUT LPTSTR* ppszDestEnd OPTIONAL,
  672. OUT size_t* pcchRemaining OPTIONAL,
  673. IN DWORD dwFlags
  674. );
  675. Routine Description:
  676. This routine is a safer version of the C built-in function 'strncpy' with
  677. some additional parameters. In addition to functionality provided by
  678. RtlStringCchCopyN, this routine also returns a pointer to the end of the
  679. destination string and the number of characters left in the destination
  680. string including the null terminator. The flags parameter allows
  681. additional controls.
  682. This routine is meant as a replacement for strncpy, but it does behave
  683. differently. This function will not pad the destination buffer with extra
  684. null termination characters if cchSrc is greater than the length of pszSrc.
  685. Arguments:
  686. pszDest - destination string
  687. cchDest - size of destination buffer in characters.
  688. length must be = (_tcslen(pszSrc) + 1) to hold all of
  689. the source including the null terminator
  690. pszSrc - source string
  691. cchSrc - maximum number of characters to copy from the source
  692. string
  693. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  694. pointer to the end of the destination string. If the
  695. function copied any data, the result will point to the
  696. null termination character
  697. pcchRemaining - if pcchRemaining is non-null, the function will return the
  698. number of characters left in the destination string,
  699. including the null terminator
  700. dwFlags - controls some details of the string copy:
  701. STRSAFE_FILL_BEHIND_NULL
  702. if the function succeeds, the low byte of dwFlags will be
  703. used to fill the uninitialize part of destination buffer
  704. behind the null terminator
  705. STRSAFE_IGNORE_NULLS
  706. treat NULL string pointers like empty strings (TEXT("")).
  707. this flag is useful for emulating functions like lstrcpy
  708. STRSAFE_FILL_ON_FAILURE
  709. if the function fails, the low byte of dwFlags will be
  710. used to fill all of the destination buffer, and it will
  711. be null terminated. This will overwrite any truncated
  712. string returned when the failure is
  713. STATUS_BUFFER_OVERFLOW
  714. STRSAFE_NO_TRUNCATION /
  715. STRSAFE_NULL_ON_FAILURE
  716. if the function fails, the destination buffer will be set
  717. to the empty string. This will overwrite any truncated string
  718. returned when the failure is STATUS_BUFFER_OVERFLOW.
  719. Notes:
  720. Behavior is undefined if source and destination strings overlap.
  721. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  722. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  723. may be NULL. An error may still be returned even though NULLS are ignored
  724. due to insufficient space.
  725. Return Value:
  726. STATUS_SUCCESS - if there was source data and it was all copied and the
  727. resultant dest string was null terminated
  728. failure - the operation did not succeed.
  729. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  730. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  731. - this return value is an indication that the copy
  732. operation failed due to insufficient space. When this
  733. error occurs, the destination buffer is modified to
  734. contain a truncated version of the ideal result and is
  735. null terminated. This is useful for situations where
  736. truncation is ok.
  737. It is strongly recommended to use the NT_SUCCESS() macro to test the
  738. return value of this function
  739. --*/
  740. NTSTRSAFEDDI RtlStringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  741. NTSTRSAFEDDI RtlStringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  742. #ifdef NTSTRSAFE_INLINE
  743. NTSTRSAFEDDI RtlStringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  744. {
  745. NTSTATUS status;
  746. if ((cchDest > STRSAFE_MAX_CCH) ||
  747. (cchSrc > STRSAFE_MAX_CCH))
  748. {
  749. status = STATUS_INVALID_PARAMETER;
  750. }
  751. else
  752. {
  753. size_t cbDest;
  754. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  755. cbDest = cchDest * sizeof(char);
  756. status = RtlStringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
  757. }
  758. return status;
  759. }
  760. NTSTRSAFEDDI RtlStringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  761. {
  762. NTSTATUS status;
  763. if ((cchDest > STRSAFE_MAX_CCH) ||
  764. (cchSrc > STRSAFE_MAX_CCH))
  765. {
  766. status = STATUS_INVALID_PARAMETER;
  767. }
  768. else
  769. {
  770. size_t cbDest;
  771. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  772. cbDest = cchDest * sizeof(wchar_t);
  773. status = RtlStringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
  774. }
  775. return status;
  776. }
  777. #endif // NTSTRSAFE_INLINE
  778. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  779. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  780. /*++
  781. NTSTATUS
  782. RtlStringCbCopyNEx(
  783. OUT LPTSTR pszDest OPTIONAL,
  784. IN size_t cbDest,
  785. IN LPCTSTR pszSrc OPTIONAL,
  786. IN size_t cbSrc,
  787. OUT LPTSTR* ppszDestEnd OPTIONAL,
  788. OUT size_t* pcbRemaining OPTIONAL,
  789. IN DWORD dwFlags
  790. );
  791. Routine Description:
  792. This routine is a safer version of the C built-in function 'strncpy' with
  793. some additional parameters. In addition to functionality provided by
  794. RtlStringCbCopyN, this routine also returns a pointer to the end of the
  795. destination string and the number of bytes left in the destination string
  796. including the null terminator. The flags parameter allows additional controls.
  797. This routine is meant as a replacement for strncpy, but it does behave
  798. differently. This function will not pad the destination buffer with extra
  799. null termination characters if cbSrc is greater than the size of pszSrc.
  800. Arguments:
  801. pszDest - destination string
  802. cbDest - size of destination buffer in bytes.
  803. length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
  804. hold all of the source including the null terminator
  805. pszSrc - source string
  806. cbSrc - maximum number of bytes to copy from source string
  807. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  808. pointer to the end of the destination string. If the
  809. function copied any data, the result will point to the
  810. null termination character
  811. pcbRemaining - pcbRemaining is non-null,the function will return the
  812. number of bytes left in the destination string,
  813. including the null terminator
  814. dwFlags - controls some details of the string copy:
  815. STRSAFE_FILL_BEHIND_NULL
  816. if the function succeeds, the low byte of dwFlags will be
  817. used to fill the uninitialize part of destination buffer
  818. behind the null terminator
  819. STRSAFE_IGNORE_NULLS
  820. treat NULL string pointers like empty strings (TEXT("")).
  821. this flag is useful for emulating functions like lstrcpy
  822. STRSAFE_FILL_ON_FAILURE
  823. if the function fails, the low byte of dwFlags will be
  824. used to fill all of the destination buffer, and it will
  825. be null terminated. This will overwrite any truncated
  826. string returned when the failure is
  827. STATUS_BUFFER_OVERFLOW
  828. STRSAFE_NO_TRUNCATION /
  829. STRSAFE_NULL_ON_FAILURE
  830. if the function fails, the destination buffer will be set
  831. to the empty string. This will overwrite any truncated string
  832. returned when the failure is STATUS_BUFFER_OVERFLOW.
  833. Notes:
  834. Behavior is undefined if source and destination strings overlap.
  835. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  836. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  837. may be NULL. An error may still be returned even though NULLS are ignored
  838. due to insufficient space.
  839. Return Value:
  840. STATUS_SUCCESS - if there was source data and it was all copied and the
  841. resultant dest string was null terminated
  842. failure - the operation did not succeed.
  843. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  844. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  845. - this return value is an indication that the copy
  846. operation failed due to insufficient space. When this
  847. error occurs, the destination buffer is modified to
  848. contain a truncated version of the ideal result and is
  849. null terminated. This is useful for situations where
  850. truncation is ok.
  851. It is strongly recommended to use the NT_SUCCESS() macro to test the
  852. return value of this function
  853. --*/
  854. NTSTRSAFEDDI RtlStringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  855. NTSTRSAFEDDI RtlStringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  856. #ifdef NTSTRSAFE_INLINE
  857. NTSTRSAFEDDI RtlStringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  858. {
  859. NTSTATUS status;
  860. size_t cchDest;
  861. size_t cchSrc;
  862. size_t cchRemaining = 0;
  863. cchDest = cbDest / sizeof(char);
  864. cchSrc = cbSrc / sizeof(char);
  865. if ((cchDest > STRSAFE_MAX_CCH) ||
  866. (cchSrc > STRSAFE_MAX_CCH))
  867. {
  868. status = STATUS_INVALID_PARAMETER;
  869. }
  870. else
  871. {
  872. status = RtlStringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
  873. }
  874. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  875. {
  876. if (pcbRemaining)
  877. {
  878. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  879. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  880. }
  881. }
  882. return status;
  883. }
  884. NTSTRSAFEDDI RtlStringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  885. {
  886. NTSTATUS status;
  887. size_t cchDest;
  888. size_t cchSrc;
  889. size_t cchRemaining = 0;
  890. cchDest = cbDest / sizeof(wchar_t);
  891. cchSrc = cbSrc / sizeof(wchar_t);
  892. if ((cchDest > STRSAFE_MAX_CCH) ||
  893. (cchSrc > STRSAFE_MAX_CCH))
  894. {
  895. status = STATUS_INVALID_PARAMETER;
  896. }
  897. else
  898. {
  899. status = RtlStringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
  900. }
  901. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  902. {
  903. if (pcbRemaining)
  904. {
  905. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  906. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  907. }
  908. }
  909. return status;
  910. }
  911. #endif // NTSTRSAFE_INLINE
  912. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  913. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  914. /*++
  915. NTSTATUS
  916. RtlStringCchCat(
  917. IN OUT LPTSTR pszDest,
  918. IN size_t cchDest,
  919. IN LPCTSTR pszSrc
  920. );
  921. Routine Description:
  922. This routine is a safer version of the C built-in function 'strcat'.
  923. The size of the destination buffer (in characters) is a parameter and this
  924. function will not write past the end of this buffer and it will ALWAYS
  925. null terminate the destination buffer (unless it is zero length).
  926. This function returns an NTSTATUS value, and not a pointer. It returns
  927. STATUS_SUCCESS if the string was concatenated without truncation and null terminated,
  928. otherwise it will return a failure code. In failure cases as much of pszSrc
  929. will be appended to pszDest as possible, and pszDest will be null
  930. terminated.
  931. Arguments:
  932. pszDest - destination string which must be null terminated
  933. cchDest - size of destination buffer in characters.
  934. length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
  935. to hold all of the combine string plus the null
  936. terminator
  937. pszSrc - source string which must be null terminated
  938. Notes:
  939. Behavior is undefined if source and destination strings overlap.
  940. pszDest and pszSrc should not be NULL. See RtlStringCchCatEx if you require
  941. the handling of NULL values.
  942. Return Value:
  943. STATUS_SUCCESS - if there was source data and it was all concatenated and
  944. the resultant dest string was null terminated
  945. failure - the operation did not succeed.
  946. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  947. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  948. - this return value is an indication that the operation
  949. failed due to insufficient space. When this error occurs,
  950. the destination buffer is modified to contain a truncated
  951. version of the ideal result and is null terminated. This
  952. is useful for situations where truncation is ok.
  953. It is strongly recommended to use the NT_SUCCESS() macro to test the
  954. return value of this function
  955. --*/
  956. NTSTRSAFEDDI RtlStringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc);
  957. NTSTRSAFEDDI RtlStringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  958. #ifdef NTSTRSAFE_INLINE
  959. NTSTRSAFEDDI RtlStringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc)
  960. {
  961. NTSTATUS status;
  962. if (cchDest > STRSAFE_MAX_CCH)
  963. {
  964. status = STATUS_INVALID_PARAMETER;
  965. }
  966. else
  967. {
  968. status = RtlStringCatWorkerA(pszDest, cchDest, pszSrc);
  969. }
  970. return status;
  971. }
  972. NTSTRSAFEDDI RtlStringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  973. {
  974. NTSTATUS status;
  975. if (cchDest > STRSAFE_MAX_CCH)
  976. {
  977. status = STATUS_INVALID_PARAMETER;
  978. }
  979. else
  980. {
  981. status = RtlStringCatWorkerW(pszDest, cchDest, pszSrc);
  982. }
  983. return status;
  984. }
  985. #endif // NTSTRSAFE_INLINE
  986. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  987. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  988. /*++
  989. NTSTATUS
  990. RtlStringCbCat(
  991. IN OUT LPTSTR pszDest,
  992. IN size_t cbDest,
  993. IN LPCTSTR pszSrc
  994. );
  995. Routine Description:
  996. This routine is a safer version of the C built-in function 'strcat'.
  997. The size of the destination buffer (in bytes) is a parameter and this
  998. function will not write past the end of this buffer and it will ALWAYS
  999. null terminate the destination buffer (unless it is zero length).
  1000. This function returns an NTSTATUS value, and not a pointer. It returns
  1001. STATUS_SUCCESS if the string was concatenated without truncation and null terminated,
  1002. otherwise it will return a failure code. In failure cases as much of pszSrc
  1003. will be appended to pszDest as possible, and pszDest will be null
  1004. terminated.
  1005. Arguments:
  1006. pszDest - destination string which must be null terminated
  1007. cbDest - size of destination buffer in bytes.
  1008. length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
  1009. to hold all of the combine string plus the null
  1010. terminator
  1011. pszSrc - source string which must be null terminated
  1012. Notes:
  1013. Behavior is undefined if source and destination strings overlap.
  1014. pszDest and pszSrc should not be NULL. See RtlStringCbCatEx if you require
  1015. the handling of NULL values.
  1016. Return Value:
  1017. STATUS_SUCCESS - if there was source data and it was all concatenated and
  1018. the resultant dest string was null terminated
  1019. failure - the operation did not succeed.
  1020. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1021. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1022. - this return value is an indication that the operation
  1023. failed due to insufficient space. When this error occurs,
  1024. the destination buffer is modified to contain a truncated
  1025. version of the ideal result and is null terminated. This
  1026. is useful for situations where truncation is ok.
  1027. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1028. return value of this function
  1029. --*/
  1030. NTSTRSAFEDDI RtlStringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc);
  1031. NTSTRSAFEDDI RtlStringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
  1032. #ifdef NTSTRSAFE_INLINE
  1033. NTSTRSAFEDDI RtlStringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc)
  1034. {
  1035. NTSTATUS status;
  1036. size_t cchDest;
  1037. cchDest = cbDest / sizeof(char);
  1038. if (cchDest > STRSAFE_MAX_CCH)
  1039. {
  1040. status = STATUS_INVALID_PARAMETER;
  1041. }
  1042. else
  1043. {
  1044. status = RtlStringCatWorkerA(pszDest, cchDest, pszSrc);
  1045. }
  1046. return status;
  1047. }
  1048. NTSTRSAFEDDI RtlStringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
  1049. {
  1050. NTSTATUS status;
  1051. size_t cchDest;
  1052. cchDest = cbDest / sizeof(wchar_t);
  1053. if (cchDest > STRSAFE_MAX_CCH)
  1054. {
  1055. status = STATUS_INVALID_PARAMETER;
  1056. }
  1057. else
  1058. {
  1059. status = RtlStringCatWorkerW(pszDest, cchDest, pszSrc);
  1060. }
  1061. return status;
  1062. }
  1063. #endif // NTSTRSAFE_INLINE
  1064. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  1065. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  1066. /*++
  1067. NTSTATUS
  1068. RtlStringCchCatEx(
  1069. IN OUT LPTSTR pszDest OPTIONAL,
  1070. IN size_t cchDest,
  1071. IN LPCTSTR pszSrc OPTIONAL,
  1072. OUT LPTSTR* ppszDestEnd OPTIONAL,
  1073. OUT size_t* pcchRemaining OPTIONAL,
  1074. IN DWORD dwFlags
  1075. );
  1076. Routine Description:
  1077. This routine is a safer version of the C built-in function 'strcat' with
  1078. some additional parameters. In addition to functionality provided by
  1079. RtlStringCchCat, this routine also returns a pointer to the end of the
  1080. destination string and the number of characters left in the destination string
  1081. including the null terminator. The flags parameter allows additional controls.
  1082. Arguments:
  1083. pszDest - destination string which must be null terminated
  1084. cchDest - size of destination buffer in characters
  1085. length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
  1086. to hold all of the combine string plus the null
  1087. terminator.
  1088. pszSrc - source string which must be null terminated
  1089. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  1090. pointer to the end of the destination string. If the
  1091. function appended any data, the result will point to the
  1092. null termination character
  1093. pcchRemaining - if pcchRemaining is non-null, the function will return the
  1094. number of characters left in the destination string,
  1095. including the null terminator
  1096. dwFlags - controls some details of the string copy:
  1097. STRSAFE_FILL_BEHIND_NULL
  1098. if the function succeeds, the low byte of dwFlags will be
  1099. used to fill the uninitialize part of destination buffer
  1100. behind the null terminator
  1101. STRSAFE_IGNORE_NULLS
  1102. treat NULL string pointers like empty strings (TEXT("")).
  1103. this flag is useful for emulating functions like lstrcat
  1104. STRSAFE_FILL_ON_FAILURE
  1105. if the function fails, the low byte of dwFlags will be
  1106. used to fill all of the destination buffer, and it will
  1107. be null terminated. This will overwrite any pre-existing
  1108. or truncated string
  1109. STRSAFE_NULL_ON_FAILURE
  1110. if the function fails, the destination buffer will be set
  1111. to the empty string. This will overwrite any pre-existing or
  1112. truncated string
  1113. STRSAFE_NO_TRUNCATION
  1114. if the function returns STATUS_BUFFER_OVERFLOW, pszDest
  1115. will not contain a truncated string, it will remain unchanged.
  1116. Notes:
  1117. Behavior is undefined if source and destination strings overlap.
  1118. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1119. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1120. may be NULL. An error may still be returned even though NULLS are ignored
  1121. due to insufficient space.
  1122. Return Value:
  1123. STATUS_SUCCESS - if there was source data and it was all concatenated and
  1124. the resultant dest string was null terminated
  1125. failure - the operation did not succeed.
  1126. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1127. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1128. - this return value is an indication that the operation
  1129. failed due to insufficient space. When this error
  1130. occurs, the destination buffer is modified to contain
  1131. a truncated version of the ideal result and is null
  1132. terminated. This is useful for situations where
  1133. truncation is ok.
  1134. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1135. return value of this function
  1136. --*/
  1137. NTSTRSAFEDDI RtlStringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1138. NTSTRSAFEDDI RtlStringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1139. #ifdef NTSTRSAFE_INLINE
  1140. NTSTRSAFEDDI RtlStringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1141. {
  1142. NTSTATUS status;
  1143. if (cchDest > STRSAFE_MAX_CCH)
  1144. {
  1145. status = STATUS_INVALID_PARAMETER;
  1146. }
  1147. else
  1148. {
  1149. size_t cbDest;
  1150. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  1151. cbDest = cchDest * sizeof(char);
  1152. status = RtlStringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  1153. }
  1154. return status;
  1155. }
  1156. NTSTRSAFEDDI RtlStringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1157. {
  1158. NTSTATUS status;
  1159. if (cchDest > STRSAFE_MAX_CCH)
  1160. {
  1161. status = STATUS_INVALID_PARAMETER;
  1162. }
  1163. else
  1164. {
  1165. size_t cbDest;
  1166. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1167. cbDest = cchDest * sizeof(wchar_t);
  1168. status = RtlStringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  1169. }
  1170. return status;
  1171. }
  1172. #endif // NTSTRSAFE_INLINE
  1173. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  1174. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  1175. /*++
  1176. NTSTATUS
  1177. RtlStringCbCatEx(
  1178. IN OUT LPTSTR pszDest OPTIONAL,
  1179. IN size_t cbDest,
  1180. IN LPCTSTR pszSrc OPTIONAL,
  1181. OUT LPTSTR* ppszDestEnd OPTIONAL,
  1182. OUT size_t* pcbRemaining OPTIONAL,
  1183. IN DWORD dwFlags
  1184. );
  1185. Routine Description:
  1186. This routine is a safer version of the C built-in function 'strcat' with
  1187. some additional parameters. In addition to functionality provided by
  1188. RtlStringCbCat, this routine also returns a pointer to the end of the
  1189. destination string and the number of bytes left in the destination string
  1190. including the null terminator. The flags parameter allows additional controls.
  1191. Arguments:
  1192. pszDest - destination string which must be null terminated
  1193. cbDest - size of destination buffer in bytes.
  1194. length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
  1195. to hold all of the combine string plus the null
  1196. terminator.
  1197. pszSrc - source string which must be null terminated
  1198. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  1199. pointer to the end of the destination string. If the
  1200. function appended any data, the result will point to the
  1201. null termination character
  1202. pcbRemaining - if pcbRemaining is non-null, the function will return
  1203. the number of bytes left in the destination string,
  1204. including the null terminator
  1205. dwFlags - controls some details of the string copy:
  1206. STRSAFE_FILL_BEHIND_NULL
  1207. if the function succeeds, the low byte of dwFlags will be
  1208. used to fill the uninitialize part of destination buffer
  1209. behind the null terminator
  1210. STRSAFE_IGNORE_NULLS
  1211. treat NULL string pointers like empty strings (TEXT("")).
  1212. this flag is useful for emulating functions like lstrcat
  1213. STRSAFE_FILL_ON_FAILURE
  1214. if the function fails, the low byte of dwFlags will be
  1215. used to fill all of the destination buffer, and it will
  1216. be null terminated. This will overwrite any pre-existing
  1217. or truncated string
  1218. STRSAFE_NULL_ON_FAILURE
  1219. if the function fails, the destination buffer will be set
  1220. to the empty string. This will overwrite any pre-existing or
  1221. truncated string
  1222. STRSAFE_NO_TRUNCATION
  1223. if the function returns STATUS_BUFFER_OVERFLOW, pszDest
  1224. will not contain a truncated string, it will remain unchanged.
  1225. Notes:
  1226. Behavior is undefined if source and destination strings overlap.
  1227. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1228. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1229. may be NULL. An error may still be returned even though NULLS are ignored
  1230. due to insufficient space.
  1231. Return Value:
  1232. STATUS_SUCCESS - if there was source data and it was all concatenated
  1233. and the resultant dest string was null terminated
  1234. failure - the operation did not succeed.
  1235. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1236. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1237. - this return value is an indication that the operation
  1238. failed due to insufficient space. When this error
  1239. occurs, the destination buffer is modified to contain
  1240. a truncated version of the ideal result and is null
  1241. terminated. This is useful for situations where
  1242. truncation is ok.
  1243. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1244. return value of this function
  1245. --*/
  1246. NTSTRSAFEDDI RtlStringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1247. NTSTRSAFEDDI RtlStringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1248. #ifdef NTSTRSAFE_INLINE
  1249. NTSTRSAFEDDI RtlStringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1250. {
  1251. NTSTATUS status;
  1252. size_t cchDest;
  1253. size_t cchRemaining = 0;
  1254. cchDest = cbDest / sizeof(char);
  1255. if (cchDest > STRSAFE_MAX_CCH)
  1256. {
  1257. status = STATUS_INVALID_PARAMETER;
  1258. }
  1259. else
  1260. {
  1261. status = RtlStringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  1262. }
  1263. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  1264. {
  1265. if (pcbRemaining)
  1266. {
  1267. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  1268. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  1269. }
  1270. }
  1271. return status;
  1272. }
  1273. NTSTRSAFEDDI RtlStringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1274. {
  1275. NTSTATUS status;
  1276. size_t cchDest;
  1277. size_t cchRemaining = 0;
  1278. cchDest = cbDest / sizeof(wchar_t);
  1279. if (cchDest > STRSAFE_MAX_CCH)
  1280. {
  1281. status = STATUS_INVALID_PARAMETER;
  1282. }
  1283. else
  1284. {
  1285. status = RtlStringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  1286. }
  1287. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  1288. {
  1289. if (pcbRemaining)
  1290. {
  1291. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1292. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  1293. }
  1294. }
  1295. return status;
  1296. }
  1297. #endif // NTSTRSAFE_INLINE
  1298. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  1299. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  1300. /*++
  1301. NTSTATUS
  1302. RtlStringCchCatN(
  1303. IN OUT LPTSTR pszDest,
  1304. IN size_t cchDest,
  1305. IN LPCTSTR pszSrc,
  1306. IN size_t cchMaxAppend
  1307. );
  1308. Routine Description:
  1309. This routine is a safer version of the C built-in function 'strncat'.
  1310. The size of the destination buffer (in characters) is a parameter as well as
  1311. the maximum number of characters to append, excluding the null terminator.
  1312. This function will not write past the end of the destination buffer and it will
  1313. ALWAYS null terminate pszDest (unless it is zero length).
  1314. This function returns an NTSTATUS value, and not a pointer. It returns
  1315. STATUS_SUCCESS if all of pszSrc or the first cchMaxAppend characters were appended
  1316. to the destination string and it was null terminated, otherwise it will
  1317. return a failure code. In failure cases as much of pszSrc will be appended
  1318. to pszDest as possible, and pszDest will be null terminated.
  1319. Arguments:
  1320. pszDest - destination string which must be null terminated
  1321. cchDest - size of destination buffer in characters.
  1322. length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
  1323. to hold all of the combine string plus the null
  1324. terminator.
  1325. pszSrc - source string
  1326. cchMaxAppend - maximum number of characters to append
  1327. Notes:
  1328. Behavior is undefined if source and destination strings overlap.
  1329. pszDest and pszSrc should not be NULL. See RtlStringCchCatNEx if you require
  1330. the handling of NULL values.
  1331. Return Value:
  1332. STATUS_SUCCESS - if all of pszSrc or the first cchMaxAppend characters
  1333. were concatenated to pszDest and the resultant dest
  1334. string was null terminated
  1335. failure - the operation did not succeed.
  1336. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1337. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1338. - this return value is an indication that the operation
  1339. failed due to insufficient space. When this error
  1340. occurs, the destination buffer is modified to contain
  1341. a truncated version of the ideal result and is null
  1342. terminated. This is useful for situations where
  1343. truncation is ok.
  1344. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1345. return value of this function
  1346. --*/
  1347. NTSTRSAFEDDI RtlStringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
  1348. NTSTRSAFEDDI RtlStringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
  1349. #ifdef NTSTRSAFE_INLINE
  1350. NTSTRSAFEDDI RtlStringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
  1351. {
  1352. NTSTATUS status;
  1353. if (cchDest > STRSAFE_MAX_CCH)
  1354. {
  1355. status = STATUS_INVALID_PARAMETER;
  1356. }
  1357. else
  1358. {
  1359. status = RtlStringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
  1360. }
  1361. return status;
  1362. }
  1363. NTSTRSAFEDDI RtlStringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
  1364. {
  1365. NTSTATUS status;
  1366. if (cchDest > STRSAFE_MAX_CCH)
  1367. {
  1368. status = STATUS_INVALID_PARAMETER;
  1369. }
  1370. else
  1371. {
  1372. status = RtlStringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
  1373. }
  1374. return status;
  1375. }
  1376. #endif // NTSTRSAFE_INLINE
  1377. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  1378. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  1379. /*++
  1380. NTSTATUS
  1381. RtlStringCbCatN(
  1382. IN OUT LPTSTR pszDest,
  1383. IN size_t cbDest,
  1384. IN LPCTSTR pszSrc,
  1385. IN size_t cbMaxAppend
  1386. );
  1387. Routine Description:
  1388. This routine is a safer version of the C built-in function 'strncat'.
  1389. The size of the destination buffer (in bytes) is a parameter as well as
  1390. the maximum number of bytes to append, excluding the null terminator.
  1391. This function will not write past the end of the destination buffer and it will
  1392. ALWAYS null terminate pszDest (unless it is zero length).
  1393. This function returns an NTSTATUS value, and not a pointer. It returns
  1394. STATUS_SUCCESS if all of pszSrc or the first cbMaxAppend bytes were appended
  1395. to the destination string and it was null terminated, otherwise it will
  1396. return a failure code. In failure cases as much of pszSrc will be appended
  1397. to pszDest as possible, and pszDest will be null terminated.
  1398. Arguments:
  1399. pszDest - destination string which must be null terminated
  1400. cbDest - size of destination buffer in bytes.
  1401. length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
  1402. to hold all of the combine string plus the null
  1403. terminator.
  1404. pszSrc - source string
  1405. cbMaxAppend - maximum number of bytes to append
  1406. Notes:
  1407. Behavior is undefined if source and destination strings overlap.
  1408. pszDest and pszSrc should not be NULL. See RtlStringCbCatNEx if you require
  1409. the handling of NULL values.
  1410. Return Value:
  1411. STATUS_SUCCESS - if all of pszSrc or the first cbMaxAppend bytes were
  1412. concatenated to pszDest and the resultant dest string
  1413. was null terminated
  1414. failure - the operation did not succeed.
  1415. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1416. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1417. - this return value is an indication that the operation
  1418. failed due to insufficient space. When this error
  1419. occurs, the destination buffer is modified to contain
  1420. a truncated version of the ideal result and is null
  1421. terminated. This is useful for situations where
  1422. truncation is ok.
  1423. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1424. return value of this function
  1425. --*/
  1426. NTSTRSAFEDDI RtlStringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend);
  1427. NTSTRSAFEDDI RtlStringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend);
  1428. #ifdef NTSTRSAFE_INLINE
  1429. NTSTRSAFEDDI RtlStringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend)
  1430. {
  1431. NTSTATUS status;
  1432. size_t cchDest;
  1433. cchDest = cbDest / sizeof(char);
  1434. if (cchDest > STRSAFE_MAX_CCH)
  1435. {
  1436. status = STATUS_INVALID_PARAMETER;
  1437. }
  1438. else
  1439. {
  1440. size_t cchMaxAppend;
  1441. cchMaxAppend = cbMaxAppend / sizeof(char);
  1442. status = RtlStringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
  1443. }
  1444. return status;
  1445. }
  1446. NTSTRSAFEDDI RtlStringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend)
  1447. {
  1448. NTSTATUS status;
  1449. size_t cchDest;
  1450. cchDest = cbDest / sizeof(wchar_t);
  1451. if (cchDest > STRSAFE_MAX_CCH)
  1452. {
  1453. status = STATUS_INVALID_PARAMETER;
  1454. }
  1455. else
  1456. {
  1457. size_t cchMaxAppend;
  1458. cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
  1459. status = RtlStringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
  1460. }
  1461. return status;
  1462. }
  1463. #endif // NTSTRSAFE_INLINE
  1464. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  1465. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  1466. /*++
  1467. NTSTATUS
  1468. RtlStringCchCatNEx(
  1469. IN OUT LPTSTR pszDest OPTIONAL,
  1470. IN size_t cchDest,
  1471. IN LPCTSTR pszSrc OPTIONAL,
  1472. IN size_t cchMaxAppend,
  1473. OUT LPTSTR* ppszDestEnd OPTIONAL,
  1474. OUT size_t* pcchRemaining OPTIONAL,
  1475. IN DWORD dwFlags
  1476. );
  1477. Routine Description:
  1478. This routine is a safer version of the C built-in function 'strncat', with
  1479. some additional parameters. In addition to functionality provided by
  1480. RtlStringCchCatN, this routine also returns a pointer to the end of the
  1481. destination string and the number of characters left in the destination string
  1482. including the null terminator. The flags parameter allows additional controls.
  1483. Arguments:
  1484. pszDest - destination string which must be null terminated
  1485. cchDest - size of destination buffer in characters.
  1486. length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
  1487. to hold all of the combine string plus the null
  1488. terminator.
  1489. pszSrc - source string
  1490. cchMaxAppend - maximum number of characters to append
  1491. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  1492. pointer to the end of the destination string. If the
  1493. function appended any data, the result will point to the
  1494. null termination character
  1495. pcchRemaining - if pcchRemaining is non-null, the function will return the
  1496. number of characters left in the destination string,
  1497. including the null terminator
  1498. dwFlags - controls some details of the string copy:
  1499. STRSAFE_FILL_BEHIND_NULL
  1500. if the function succeeds, the low byte of dwFlags will be
  1501. used to fill the uninitialize part of destination buffer
  1502. behind the null terminator
  1503. STRSAFE_IGNORE_NULLS
  1504. treat NULL string pointers like empty strings (TEXT(""))
  1505. STRSAFE_FILL_ON_FAILURE
  1506. if the function fails, the low byte of dwFlags will be
  1507. used to fill all of the destination buffer, and it will
  1508. be null terminated. This will overwrite any pre-existing
  1509. or truncated string
  1510. STRSAFE_NULL_ON_FAILURE
  1511. if the function fails, the destination buffer will be set
  1512. to the empty string. This will overwrite any pre-existing or
  1513. truncated string
  1514. STRSAFE_NO_TRUNCATION
  1515. if the function returns STATUS_BUFFER_OVERFLOW, pszDest
  1516. will not contain a truncated string, it will remain unchanged.
  1517. Notes:
  1518. Behavior is undefined if source and destination strings overlap.
  1519. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1520. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1521. may be NULL. An error may still be returned even though NULLS are ignored
  1522. due to insufficient space.
  1523. Return Value:
  1524. STATUS_SUCCESS - if all of pszSrc or the first cchMaxAppend characters
  1525. were concatenated to pszDest and the resultant dest
  1526. string was null terminated
  1527. failure - the operation did not succeed.
  1528. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1529. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1530. - this return value is an indication that the operation
  1531. failed due to insufficient space. When this error
  1532. occurs, the destination buffer is modified to contain
  1533. a truncated version of the ideal result and is null
  1534. terminated. This is useful for situations where
  1535. truncation is ok.
  1536. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1537. return value of this function
  1538. --*/
  1539. NTSTRSAFEDDI RtlStringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1540. NTSTRSAFEDDI RtlStringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1541. #ifdef NTSTRSAFE_INLINE
  1542. NTSTRSAFEDDI RtlStringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1543. {
  1544. NTSTATUS status;
  1545. if (cchDest > STRSAFE_MAX_CCH)
  1546. {
  1547. status = STATUS_INVALID_PARAMETER;
  1548. }
  1549. else
  1550. {
  1551. size_t cbDest;
  1552. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  1553. cbDest = cchDest * sizeof(char);
  1554. status = RtlStringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
  1555. }
  1556. return status;
  1557. }
  1558. NTSTRSAFEDDI RtlStringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1559. {
  1560. NTSTATUS status;
  1561. if (cchDest > STRSAFE_MAX_CCH)
  1562. {
  1563. status = STATUS_INVALID_PARAMETER;
  1564. }
  1565. else
  1566. {
  1567. size_t cbDest;
  1568. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1569. cbDest = cchDest * sizeof(wchar_t);
  1570. status = RtlStringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
  1571. }
  1572. return status;
  1573. }
  1574. #endif // NTSTRSAFE_INLINE
  1575. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  1576. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  1577. /*++
  1578. NTSTATUS
  1579. RtlStringCbCatNEx(
  1580. IN OUT LPTSTR pszDest OPTIONAL,
  1581. IN size_t cbDest,
  1582. IN LPCTSTR pszSrc OPTIONAL,
  1583. IN size_t cbMaxAppend,
  1584. OUT LPTSTR* ppszDestEnd OPTIONAL,
  1585. OUT size_t* pcchRemaining OPTIONAL,
  1586. IN DWORD dwFlags
  1587. );
  1588. Routine Description:
  1589. This routine is a safer version of the C built-in function 'strncat', with
  1590. some additional parameters. In addition to functionality provided by
  1591. RtlStringCbCatN, this routine also returns a pointer to the end of the
  1592. destination string and the number of bytes left in the destination string
  1593. including the null terminator. The flags parameter allows additional controls.
  1594. Arguments:
  1595. pszDest - destination string which must be null terminated
  1596. cbDest - size of destination buffer in bytes.
  1597. length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
  1598. to hold all of the combine string plus the null
  1599. terminator.
  1600. pszSrc - source string
  1601. cbMaxAppend - maximum number of bytes to append
  1602. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  1603. pointer to the end of the destination string. If the
  1604. function appended any data, the result will point to the
  1605. null termination character
  1606. pcbRemaining - if pcbRemaining is non-null, the function will return the
  1607. number of bytes left in the destination string,
  1608. including the null terminator
  1609. dwFlags - controls some details of the string copy:
  1610. STRSAFE_FILL_BEHIND_NULL
  1611. if the function succeeds, the low byte of dwFlags will be
  1612. used to fill the uninitialize part of destination buffer
  1613. behind the null terminator
  1614. STRSAFE_IGNORE_NULLS
  1615. treat NULL string pointers like empty strings (TEXT(""))
  1616. STRSAFE_FILL_ON_FAILURE
  1617. if the function fails, the low byte of dwFlags will be
  1618. used to fill all of the destination buffer, and it will
  1619. be null terminated. This will overwrite any pre-existing
  1620. or truncated string
  1621. STRSAFE_NULL_ON_FAILURE
  1622. if the function fails, the destination buffer will be set
  1623. to the empty string. This will overwrite any pre-existing or
  1624. truncated string
  1625. STRSAFE_NO_TRUNCATION
  1626. if the function returns STATUS_BUFFER_OVERFLOW, pszDest
  1627. will not contain a truncated string, it will remain unchanged.
  1628. Notes:
  1629. Behavior is undefined if source and destination strings overlap.
  1630. pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1631. is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1632. may be NULL. An error may still be returned even though NULLS are ignored
  1633. due to insufficient space.
  1634. Return Value:
  1635. STATUS_SUCCESS - if all of pszSrc or the first cbMaxAppend bytes were
  1636. concatenated to pszDest and the resultant dest string
  1637. was null terminated
  1638. failure - the operation did not succeed.
  1639. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1640. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1641. - this return value is an indication that the operation
  1642. failed due to insufficient space. When this error
  1643. occurs, the destination buffer is modified to contain
  1644. a truncated version of the ideal result and is null
  1645. terminated. This is useful for situations where
  1646. truncation is ok.
  1647. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1648. return value of this function
  1649. --*/
  1650. NTSTRSAFEDDI RtlStringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1651. NTSTRSAFEDDI RtlStringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1652. #ifdef NTSTRSAFE_INLINE
  1653. NTSTRSAFEDDI RtlStringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1654. {
  1655. NTSTATUS status;
  1656. size_t cchDest;
  1657. size_t cchRemaining = 0;
  1658. cchDest = cbDest / sizeof(char);
  1659. if (cchDest > STRSAFE_MAX_CCH)
  1660. {
  1661. status = STATUS_INVALID_PARAMETER;
  1662. }
  1663. else
  1664. {
  1665. size_t cchMaxAppend;
  1666. cchMaxAppend = cbMaxAppend / sizeof(char);
  1667. status = RtlStringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
  1668. }
  1669. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  1670. {
  1671. if (pcbRemaining)
  1672. {
  1673. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  1674. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  1675. }
  1676. }
  1677. return status;
  1678. }
  1679. NTSTRSAFEDDI RtlStringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1680. {
  1681. NTSTATUS status;
  1682. size_t cchDest;
  1683. size_t cchRemaining = 0;
  1684. cchDest = cbDest / sizeof(wchar_t);
  1685. if (cchDest > STRSAFE_MAX_CCH)
  1686. {
  1687. status = STATUS_INVALID_PARAMETER;
  1688. }
  1689. else
  1690. {
  1691. size_t cchMaxAppend;
  1692. cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
  1693. status = RtlStringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
  1694. }
  1695. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  1696. {
  1697. if (pcbRemaining)
  1698. {
  1699. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1700. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  1701. }
  1702. }
  1703. return status;
  1704. }
  1705. #endif // NTSTRSAFE_INLINE
  1706. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  1707. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  1708. /*++
  1709. NTSTATUS
  1710. RtlStringCchVPrintf(
  1711. OUT LPTSTR pszDest,
  1712. IN size_t cchDest,
  1713. IN LPCTSTR pszFormat,
  1714. IN va_list argList
  1715. );
  1716. Routine Description:
  1717. This routine is a safer version of the C built-in function 'vsprintf'.
  1718. The size of the destination buffer (in characters) is a parameter and
  1719. this function will not write past the end of this buffer and it will
  1720. ALWAYS null terminate the destination buffer (unless it is zero length).
  1721. This function returns an NTSTATUS value, and not a pointer. It returns
  1722. STATUS_SUCCESS if the string was printed without truncation and null terminated,
  1723. otherwise it will return a failure code. In failure cases it will return
  1724. a truncated version of the ideal result.
  1725. Arguments:
  1726. pszDest - destination string
  1727. cchDest - size of destination buffer in characters
  1728. length must be sufficient to hold the resulting formatted
  1729. string, including the null terminator.
  1730. pszFormat - format string which must be null terminated
  1731. argList - va_list from the variable arguments according to the
  1732. stdarg.h convention
  1733. Notes:
  1734. Behavior is undefined if destination, format strings or any arguments
  1735. strings overlap.
  1736. pszDest and pszFormat should not be NULL. See RtlStringCchVPrintfEx if you
  1737. require the handling of NULL values.
  1738. Return Value:
  1739. STATUS_SUCCESS - if there was sufficient space in the dest buffer for
  1740. the resultant string and it was null terminated.
  1741. failure - the operation did not succeed.
  1742. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1743. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1744. - this return value is an indication that the print
  1745. operation failed due to insufficient space. When this
  1746. error occurs, the destination buffer is modified to
  1747. contain a truncated version of the ideal result and is
  1748. null terminated. This is useful for situations where
  1749. truncation is ok.
  1750. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1751. return value of this function
  1752. --*/
  1753. NTSTRSAFEDDI RtlStringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
  1754. NTSTRSAFEDDI RtlStringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
  1755. #ifdef NTSTRSAFE_INLINE
  1756. NTSTRSAFEDDI RtlStringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
  1757. {
  1758. NTSTATUS status;
  1759. if (cchDest > STRSAFE_MAX_CCH)
  1760. {
  1761. status = STATUS_INVALID_PARAMETER;
  1762. }
  1763. else
  1764. {
  1765. status = RtlStringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  1766. }
  1767. return status;
  1768. }
  1769. NTSTRSAFEDDI RtlStringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
  1770. {
  1771. NTSTATUS status;
  1772. if (cchDest > STRSAFE_MAX_CCH)
  1773. {
  1774. status = STATUS_INVALID_PARAMETER;
  1775. }
  1776. else
  1777. {
  1778. status = RtlStringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  1779. }
  1780. return status;
  1781. }
  1782. #endif // NTSTRSAFE_INLINE
  1783. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  1784. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  1785. /*++
  1786. NTSTATUS
  1787. RtlStringCbVPrintf(
  1788. OUT LPTSTR pszDest,
  1789. IN size_t cbDest,
  1790. IN LPCTSTR pszFormat,
  1791. IN va_list argList
  1792. );
  1793. Routine Description:
  1794. This routine is a safer version of the C built-in function 'vsprintf'.
  1795. The size of the destination buffer (in bytes) is a parameter and
  1796. this function will not write past the end of this buffer and it will
  1797. ALWAYS null terminate the destination buffer (unless it is zero length).
  1798. This function returns an NTSTATUS value, and not a pointer. It returns
  1799. STATUS_SUCCESS if the string was printed without truncation and null terminated,
  1800. otherwise it will return a failure code. In failure cases it will return
  1801. a truncated version of the ideal result.
  1802. Arguments:
  1803. pszDest - destination string
  1804. cbDest - size of destination buffer in bytes
  1805. length must be sufficient to hold the resulting formatted
  1806. string, including the null terminator.
  1807. pszFormat - format string which must be null terminated
  1808. argList - va_list from the variable arguments according to the
  1809. stdarg.h convention
  1810. Notes:
  1811. Behavior is undefined if destination, format strings or any arguments
  1812. strings overlap.
  1813. pszDest and pszFormat should not be NULL. See RtlStringCbVPrintfEx if you
  1814. require the handling of NULL values.
  1815. Return Value:
  1816. STATUS_SUCCESS - if there was sufficient space in the dest buffer for
  1817. the resultant string and it was null terminated.
  1818. failure - the operation did not succeed.
  1819. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1820. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1821. - this return value is an indication that the print
  1822. operation failed due to insufficient space. When this
  1823. error occurs, the destination buffer is modified to
  1824. contain a truncated version of the ideal result and is
  1825. null terminated. This is useful for situations where
  1826. truncation is ok.
  1827. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1828. return value of this function
  1829. --*/
  1830. NTSTRSAFEDDI RtlStringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList);
  1831. NTSTRSAFEDDI RtlStringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList);
  1832. #ifdef NTSTRSAFE_INLINE
  1833. NTSTRSAFEDDI RtlStringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList)
  1834. {
  1835. NTSTATUS status;
  1836. size_t cchDest;
  1837. cchDest = cbDest / sizeof(char);
  1838. if (cchDest > STRSAFE_MAX_CCH)
  1839. {
  1840. status = STATUS_INVALID_PARAMETER;
  1841. }
  1842. else
  1843. {
  1844. status = RtlStringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  1845. }
  1846. return status;
  1847. }
  1848. NTSTRSAFEDDI RtlStringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList)
  1849. {
  1850. NTSTATUS status;
  1851. size_t cchDest;
  1852. cchDest = cbDest / sizeof(wchar_t);
  1853. if (cchDest > STRSAFE_MAX_CCH)
  1854. {
  1855. status = STATUS_INVALID_PARAMETER;
  1856. }
  1857. else
  1858. {
  1859. status = RtlStringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  1860. }
  1861. return status;
  1862. }
  1863. #endif // NTSTRSAFE_INLINE
  1864. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  1865. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  1866. /*++
  1867. NTSTATUS
  1868. RtlStringCchPrintf(
  1869. OUT LPTSTR pszDest,
  1870. IN size_t cchDest,
  1871. IN LPCTSTR pszFormat,
  1872. ...
  1873. );
  1874. Routine Description:
  1875. This routine is a safer version of the C built-in function 'sprintf'.
  1876. The size of the destination buffer (in characters) is a parameter and
  1877. this function will not write past the end of this buffer and it will
  1878. ALWAYS null terminate the destination buffer (unless it is zero length).
  1879. This function returns an NTSTATUS value, and not a pointer. It returns
  1880. STATUS_SUCCESS if the string was printed without truncation and null terminated,
  1881. otherwise it will return a failure code. In failure cases it will return
  1882. a truncated version of the ideal result.
  1883. Arguments:
  1884. pszDest - destination string
  1885. cchDest - size of destination buffer in characters
  1886. length must be sufficient to hold the resulting formatted
  1887. string, including the null terminator.
  1888. pszFormat - format string which must be null terminated
  1889. ... - additional parameters to be formatted according to
  1890. the format string
  1891. Notes:
  1892. Behavior is undefined if destination, format strings or any arguments
  1893. strings overlap.
  1894. pszDest and pszFormat should not be NULL. See RtlStringCchPrintfEx if you
  1895. require the handling of NULL values.
  1896. Return Value:
  1897. STATUS_SUCCESS - if there was sufficient space in the dest buffer for
  1898. the resultant string and it was null terminated.
  1899. failure - the operation did not succeed.
  1900. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1901. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1902. - this return value is an indication that the print
  1903. operation failed due to insufficient space. When this
  1904. error occurs, the destination buffer is modified to
  1905. contain a truncated version of the ideal result and is
  1906. null terminated. This is useful for situations where
  1907. truncation is ok.
  1908. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1909. return value of this function
  1910. --*/
  1911. NTSTRSAFEDDI RtlStringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...);
  1912. NTSTRSAFEDDI RtlStringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...);
  1913. #ifdef NTSTRSAFE_INLINE
  1914. NTSTRSAFEDDI RtlStringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...)
  1915. {
  1916. NTSTATUS status;
  1917. if (cchDest > STRSAFE_MAX_CCH)
  1918. {
  1919. status = STATUS_INVALID_PARAMETER;
  1920. }
  1921. else
  1922. {
  1923. va_list argList;
  1924. va_start(argList, pszFormat);
  1925. status = RtlStringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  1926. va_end(argList);
  1927. }
  1928. return status;
  1929. }
  1930. NTSTRSAFEDDI RtlStringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...)
  1931. {
  1932. NTSTATUS status;
  1933. if (cchDest > STRSAFE_MAX_CCH)
  1934. {
  1935. status = STATUS_INVALID_PARAMETER;
  1936. }
  1937. else
  1938. {
  1939. va_list argList;
  1940. va_start(argList, pszFormat);
  1941. status = RtlStringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  1942. va_end(argList);
  1943. }
  1944. return status;
  1945. }
  1946. #endif // NTSTRSAFE_INLINE
  1947. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  1948. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  1949. /*++
  1950. NTSTATUS
  1951. RtlStringCbPrintf(
  1952. OUT LPTSTR pszDest,
  1953. IN size_t cbDest,
  1954. IN LPCTSTR pszFormat,
  1955. ...
  1956. );
  1957. Routine Description:
  1958. This routine is a safer version of the C built-in function 'sprintf'.
  1959. The size of the destination buffer (in bytes) is a parameter and
  1960. this function will not write past the end of this buffer and it will
  1961. ALWAYS null terminate the destination buffer (unless it is zero length).
  1962. This function returns an NTSTATUS value, and not a pointer. It returns
  1963. STATUS_SUCCESS if the string was printed without truncation and null terminated,
  1964. otherwise it will return a failure code. In failure cases it will return
  1965. a truncated version of the ideal result.
  1966. Arguments:
  1967. pszDest - destination string
  1968. cbDest - size of destination buffer in bytes
  1969. length must be sufficient to hold the resulting formatted
  1970. string, including the null terminator.
  1971. pszFormat - format string which must be null terminated
  1972. ... - additional parameters to be formatted according to
  1973. the format string
  1974. Notes:
  1975. Behavior is undefined if destination, format strings or any arguments
  1976. strings overlap.
  1977. pszDest and pszFormat should not be NULL. See RtlStringCbPrintfEx if you
  1978. require the handling of NULL values.
  1979. Return Value:
  1980. STATUS_SUCCESS - if there was sufficient space in the dest buffer for
  1981. the resultant string and it was null terminated.
  1982. failure - the operation did not succeed.
  1983. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  1984. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  1985. - this return value is an indication that the print
  1986. operation failed due to insufficient space. When this
  1987. error occurs, the destination buffer is modified to
  1988. contain a truncated version of the ideal result and is
  1989. null terminated. This is useful for situations where
  1990. truncation is ok.
  1991. It is strongly recommended to use the NT_SUCCESS() macro to test the
  1992. return value of this function
  1993. --*/
  1994. NTSTRSAFEDDI RtlStringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...);
  1995. NTSTRSAFEDDI RtlStringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...);
  1996. #ifdef NTSTRSAFE_INLINE
  1997. NTSTRSAFEDDI RtlStringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...)
  1998. {
  1999. NTSTATUS status;
  2000. size_t cchDest;
  2001. cchDest = cbDest / sizeof(char);
  2002. if (cchDest > STRSAFE_MAX_CCH)
  2003. {
  2004. status = STATUS_INVALID_PARAMETER;
  2005. }
  2006. else
  2007. {
  2008. va_list argList;
  2009. va_start(argList, pszFormat);
  2010. status = RtlStringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  2011. va_end(argList);
  2012. }
  2013. return status;
  2014. }
  2015. NTSTRSAFEDDI RtlStringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...)
  2016. {
  2017. NTSTATUS status;
  2018. size_t cchDest;
  2019. cchDest = cbDest / sizeof(wchar_t);
  2020. if (cchDest > STRSAFE_MAX_CCH)
  2021. {
  2022. status = STATUS_INVALID_PARAMETER;
  2023. }
  2024. else
  2025. {
  2026. va_list argList;
  2027. va_start(argList, pszFormat);
  2028. status = RtlStringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  2029. va_end(argList);
  2030. }
  2031. return status;
  2032. }
  2033. #endif // NTSTRSAFE_INLINE
  2034. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  2035. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  2036. /*++
  2037. NTSTATUS
  2038. RtlStringCchPrintfEx(
  2039. OUT LPTSTR pszDest OPTIONAL,
  2040. IN size_t cchDest,
  2041. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2042. OUT size_t* pcchRemaining OPTIONAL,
  2043. IN DWORD dwFlags,
  2044. IN LPCTSTR pszFormat OPTIONAL,
  2045. ...
  2046. );
  2047. Routine Description:
  2048. This routine is a safer version of the C built-in function 'sprintf' with
  2049. some additional parameters. In addition to functionality provided by
  2050. RtlStringCchPrintf, this routine also returns a pointer to the end of the
  2051. destination string and the number of characters left in the destination string
  2052. including the null terminator. The flags parameter allows additional controls.
  2053. Arguments:
  2054. pszDest - destination string
  2055. cchDest - size of destination buffer in characters.
  2056. length must be sufficient to contain the resulting
  2057. formatted string plus the null terminator.
  2058. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  2059. pointer to the end of the destination string. If the
  2060. function printed any data, the result will point to the
  2061. null termination character
  2062. pcchRemaining - if pcchRemaining is non-null, the function will return
  2063. the number of characters left in the destination string,
  2064. including the null terminator
  2065. dwFlags - controls some details of the string copy:
  2066. STRSAFE_FILL_BEHIND_NULL
  2067. if the function succeeds, the low byte of dwFlags will be
  2068. used to fill the uninitialize part of destination buffer
  2069. behind the null terminator
  2070. STRSAFE_IGNORE_NULLS
  2071. treat NULL string pointers like empty strings (TEXT(""))
  2072. STRSAFE_FILL_ON_FAILURE
  2073. if the function fails, the low byte of dwFlags will be
  2074. used to fill all of the destination buffer, and it will
  2075. be null terminated. This will overwrite any truncated
  2076. string returned when the failure is
  2077. STATUS_BUFFER_OVERFLOW
  2078. STRSAFE_NO_TRUNCATION /
  2079. STRSAFE_NULL_ON_FAILURE
  2080. if the function fails, the destination buffer will be set
  2081. to the empty string. This will overwrite any truncated string
  2082. returned when the failure is STATUS_BUFFER_OVERFLOW.
  2083. pszFormat - format string which must be null terminated
  2084. ... - additional parameters to be formatted according to
  2085. the format string
  2086. Notes:
  2087. Behavior is undefined if destination, format strings or any arguments
  2088. strings overlap.
  2089. pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2090. flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2091. pszFormat may be NULL. An error may still be returned even though NULLS
  2092. are ignored due to insufficient space.
  2093. Return Value:
  2094. STATUS_SUCCESS - if there was source data and it was all concatenated and
  2095. the resultant dest string was null terminated
  2096. failure - the operation did not succeed.
  2097. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  2098. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  2099. - this return value is an indication that the print
  2100. operation failed due to insufficient space. When this
  2101. error occurs, the destination buffer is modified to
  2102. contain a truncated version of the ideal result and is
  2103. null terminated. This is useful for situations where
  2104. truncation is ok.
  2105. It is strongly recommended to use the NT_SUCCESS() macro to test the
  2106. return value of this function
  2107. --*/
  2108. NTSTRSAFEDDI RtlStringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...);
  2109. NTSTRSAFEDDI RtlStringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
  2110. #ifdef NTSTRSAFE_INLINE
  2111. NTSTRSAFEDDI RtlStringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...)
  2112. {
  2113. NTSTATUS status;
  2114. if (cchDest > STRSAFE_MAX_CCH)
  2115. {
  2116. status = STATUS_INVALID_PARAMETER;
  2117. }
  2118. else
  2119. {
  2120. size_t cbDest;
  2121. va_list argList;
  2122. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  2123. cbDest = cchDest * sizeof(char);
  2124. va_start(argList, pszFormat);
  2125. status = RtlStringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2126. va_end(argList);
  2127. }
  2128. return status;
  2129. }
  2130. NTSTRSAFEDDI RtlStringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
  2131. {
  2132. NTSTATUS status;
  2133. if (cchDest > STRSAFE_MAX_CCH)
  2134. {
  2135. status = STATUS_INVALID_PARAMETER;
  2136. }
  2137. else
  2138. {
  2139. size_t cbDest;
  2140. va_list argList;
  2141. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2142. cbDest = cchDest * sizeof(wchar_t);
  2143. va_start(argList, pszFormat);
  2144. status = RtlStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2145. va_end(argList);
  2146. }
  2147. return status;
  2148. }
  2149. #endif // NTSTRSAFE_INLINE
  2150. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  2151. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  2152. /*++
  2153. NTSTATUS
  2154. RtlStringCbPrintfEx(
  2155. OUT LPTSTR pszDest OPTIONAL,
  2156. IN size_t cbDest,
  2157. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2158. OUT size_t* pcbRemaining OPTIONAL,
  2159. IN DWORD dwFlags,
  2160. IN LPCTSTR pszFormat OPTIONAL,
  2161. ...
  2162. );
  2163. Routine Description:
  2164. This routine is a safer version of the C built-in function 'sprintf' with
  2165. some additional parameters. In addition to functionality provided by
  2166. RtlStringCbPrintf, this routine also returns a pointer to the end of the
  2167. destination string and the number of bytes left in the destination string
  2168. including the null terminator. The flags parameter allows additional controls.
  2169. Arguments:
  2170. pszDest - destination string
  2171. cbDest - size of destination buffer in bytes.
  2172. length must be sufficient to contain the resulting
  2173. formatted string plus the null terminator.
  2174. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  2175. pointer to the end of the destination string. If the
  2176. function printed any data, the result will point to the
  2177. null termination character
  2178. pcbRemaining - if pcbRemaining is non-null, the function will return
  2179. the number of bytes left in the destination string,
  2180. including the null terminator
  2181. dwFlags - controls some details of the string copy:
  2182. STRSAFE_FILL_BEHIND_NULL
  2183. if the function succeeds, the low byte of dwFlags will be
  2184. used to fill the uninitialize part of destination buffer
  2185. behind the null terminator
  2186. STRSAFE_IGNORE_NULLS
  2187. treat NULL string pointers like empty strings (TEXT(""))
  2188. STRSAFE_FILL_ON_FAILURE
  2189. if the function fails, the low byte of dwFlags will be
  2190. used to fill all of the destination buffer, and it will
  2191. be null terminated. This will overwrite any truncated
  2192. string returned when the failure is
  2193. STATUS_BUFFER_OVERFLOW
  2194. STRSAFE_NO_TRUNCATION /
  2195. STRSAFE_NULL_ON_FAILURE
  2196. if the function fails, the destination buffer will be set
  2197. to the empty string. This will overwrite any truncated string
  2198. returned when the failure is STATUS_BUFFER_OVERFLOW.
  2199. pszFormat - format string which must be null terminated
  2200. ... - additional parameters to be formatted according to
  2201. the format string
  2202. Notes:
  2203. Behavior is undefined if destination, format strings or any arguments
  2204. strings overlap.
  2205. pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2206. flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2207. pszFormat may be NULL. An error may still be returned even though NULLS
  2208. are ignored due to insufficient space.
  2209. Return Value:
  2210. STATUS_SUCCESS - if there was source data and it was all concatenated and
  2211. the resultant dest string was null terminated
  2212. failure - the operation did not succeed.
  2213. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  2214. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  2215. - this return value is an indication that the print
  2216. operation failed due to insufficient space. When this
  2217. error occurs, the destination buffer is modified to
  2218. contain a truncated version of the ideal result and is
  2219. null terminated. This is useful for situations where
  2220. truncation is ok.
  2221. It is strongly recommended to use the NT_SUCCESS() macro to test the
  2222. return value of this function
  2223. --*/
  2224. NTSTRSAFEDDI RtlStringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...);
  2225. NTSTRSAFEDDI RtlStringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
  2226. #ifdef NTSTRSAFE_INLINE
  2227. NTSTRSAFEDDI RtlStringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...)
  2228. {
  2229. NTSTATUS status;
  2230. size_t cchDest;
  2231. size_t cchRemaining = 0;
  2232. cchDest = cbDest / sizeof(char);
  2233. if (cchDest > STRSAFE_MAX_CCH)
  2234. {
  2235. status = STATUS_INVALID_PARAMETER;
  2236. }
  2237. else
  2238. {
  2239. va_list argList;
  2240. va_start(argList, pszFormat);
  2241. status = RtlStringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  2242. va_end(argList);
  2243. }
  2244. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  2245. {
  2246. if (pcbRemaining)
  2247. {
  2248. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  2249. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  2250. }
  2251. }
  2252. return status;
  2253. }
  2254. NTSTRSAFEDDI RtlStringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
  2255. {
  2256. NTSTATUS status;
  2257. size_t cchDest;
  2258. size_t cchRemaining = 0;
  2259. cchDest = cbDest / sizeof(wchar_t);
  2260. if (cchDest > STRSAFE_MAX_CCH)
  2261. {
  2262. status = STATUS_INVALID_PARAMETER;
  2263. }
  2264. else
  2265. {
  2266. va_list argList;
  2267. va_start(argList, pszFormat);
  2268. status = RtlStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  2269. va_end(argList);
  2270. }
  2271. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  2272. {
  2273. if (pcbRemaining)
  2274. {
  2275. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2276. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  2277. }
  2278. }
  2279. return status;
  2280. }
  2281. #endif // NTSTRSAFE_INLINE
  2282. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  2283. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  2284. /*++
  2285. NTSTATUS
  2286. RtlStringCchVPrintfEx(
  2287. OUT LPTSTR pszDest OPTIONAL,
  2288. IN size_t cchDest,
  2289. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2290. OUT size_t* pcchRemaining OPTIONAL,
  2291. IN DWORD dwFlags,
  2292. IN LPCTSTR pszFormat OPTIONAL,
  2293. IN va_list argList
  2294. );
  2295. Routine Description:
  2296. This routine is a safer version of the C built-in function 'vsprintf' with
  2297. some additional parameters. In addition to functionality provided by
  2298. RtlStringCchVPrintf, this routine also returns a pointer to the end of the
  2299. destination string and the number of characters left in the destination string
  2300. including the null terminator. The flags parameter allows additional controls.
  2301. Arguments:
  2302. pszDest - destination string
  2303. cchDest - size of destination buffer in characters.
  2304. length must be sufficient to contain the resulting
  2305. formatted string plus the null terminator.
  2306. ppszDestEnd - if ppszDestEnd is non-null, the function will return a
  2307. pointer to the end of the destination string. If the
  2308. function printed any data, the result will point to the
  2309. null termination character
  2310. pcchRemaining - if pcchRemaining is non-null, the function will return
  2311. the number of characters left in the destination string,
  2312. including the null terminator
  2313. dwFlags - controls some details of the string copy:
  2314. STRSAFE_FILL_BEHIND_NULL
  2315. if the function succeeds, the low byte of dwFlags will be
  2316. used to fill the uninitialize part of destination buffer
  2317. behind the null terminator
  2318. STRSAFE_IGNORE_NULLS
  2319. treat NULL string pointers like empty strings (TEXT(""))
  2320. STRSAFE_FILL_ON_FAILURE
  2321. if the function fails, the low byte of dwFlags will be
  2322. used to fill all of the destination buffer, and it will
  2323. be null terminated. This will overwrite any truncated
  2324. string returned when the failure is
  2325. STATUS_BUFFER_OVERFLOW
  2326. STRSAFE_NO_TRUNCATION /
  2327. STRSAFE_NULL_ON_FAILURE
  2328. if the function fails, the destination buffer will be set
  2329. to the empty string. This will overwrite any truncated string
  2330. returned when the failure is STATUS_BUFFER_OVERFLOW.
  2331. pszFormat - format string which must be null terminated
  2332. argList - va_list from the variable arguments according to the
  2333. stdarg.h convention
  2334. Notes:
  2335. Behavior is undefined if destination, format strings or any arguments
  2336. strings overlap.
  2337. pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2338. flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2339. pszFormat may be NULL. An error may still be returned even though NULLS
  2340. are ignored due to insufficient space.
  2341. Return Value:
  2342. STATUS_SUCCESS - if there was source data and it was all concatenated and
  2343. the resultant dest string was null terminated
  2344. failure - the operation did not succeed.
  2345. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  2346. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  2347. - this return value is an indication that the print
  2348. operation failed due to insufficient space. When this
  2349. error occurs, the destination buffer is modified to
  2350. contain a truncated version of the ideal result and is
  2351. null terminated. This is useful for situations where
  2352. truncation is ok.
  2353. It is strongly recommended to use the NT_SUCCESS() macro to test the
  2354. return value of this function
  2355. --*/
  2356. NTSTRSAFEDDI RtlStringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  2357. NTSTRSAFEDDI RtlStringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
  2358. #ifdef NTSTRSAFE_INLINE
  2359. NTSTRSAFEDDI RtlStringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  2360. {
  2361. NTSTATUS status;
  2362. if (cchDest > STRSAFE_MAX_CCH)
  2363. {
  2364. status = STATUS_INVALID_PARAMETER;
  2365. }
  2366. else
  2367. {
  2368. size_t cbDest;
  2369. // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  2370. cbDest = cchDest * sizeof(char);
  2371. status = RtlStringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2372. }
  2373. return status;
  2374. }
  2375. NTSTRSAFEDDI RtlStringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
  2376. {
  2377. NTSTATUS status;
  2378. if (cchDest > STRSAFE_MAX_CCH)
  2379. {
  2380. status = STATUS_INVALID_PARAMETER;
  2381. }
  2382. else
  2383. {
  2384. size_t cbDest;
  2385. // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2386. cbDest = cchDest * sizeof(wchar_t);
  2387. status = RtlStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2388. }
  2389. return status;
  2390. }
  2391. #endif // NTSTRSAFE_INLINE
  2392. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  2393. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  2394. /*++
  2395. NTSTATUS
  2396. RtlStringCbVPrintfEx(
  2397. OUT LPTSTR pszDest OPTIONAL,
  2398. IN size_t cbDest,
  2399. OUT LPTSTR* ppszDestEnd OPTIONAL,
  2400. OUT size_t* pcbRemaining OPTIONAL,
  2401. IN DWORD dwFlags,
  2402. IN LPCTSTR pszFormat OPTIONAL,
  2403. IN va_list argList
  2404. );
  2405. Routine Description:
  2406. This routine is a safer version of the C built-in function 'vsprintf' with
  2407. some additional parameters. In addition to functionality provided by
  2408. RtlStringCbVPrintf, this routine also returns a pointer to the end of the
  2409. destination string and the number of characters left in the destination string
  2410. including the null terminator. The flags parameter allows additional controls.
  2411. Arguments:
  2412. pszDest - destination string
  2413. cbDest - size of destination buffer in bytes.
  2414. length must be sufficient to contain the resulting
  2415. formatted string plus the null terminator.
  2416. ppszDestEnd - if ppszDestEnd is non-null, the function will return
  2417. a pointer to the end of the destination string. If the
  2418. function printed any data, the result will point to the
  2419. null termination character
  2420. pcbRemaining - if pcbRemaining is non-null, the function will return
  2421. the number of bytes left in the destination string,
  2422. including the null terminator
  2423. dwFlags - controls some details of the string copy:
  2424. STRSAFE_FILL_BEHIND_NULL
  2425. if the function succeeds, the low byte of dwFlags will be
  2426. used to fill the uninitialize part of destination buffer
  2427. behind the null terminator
  2428. STRSAFE_IGNORE_NULLS
  2429. treat NULL string pointers like empty strings (TEXT(""))
  2430. STRSAFE_FILL_ON_FAILURE
  2431. if the function fails, the low byte of dwFlags will be
  2432. used to fill all of the destination buffer, and it will
  2433. be null terminated. This will overwrite any truncated
  2434. string returned when the failure is
  2435. STATUS_BUFFER_OVERFLOW
  2436. STRSAFE_NO_TRUNCATION /
  2437. STRSAFE_NULL_ON_FAILURE
  2438. if the function fails, the destination buffer will be set
  2439. to the empty string. This will overwrite any truncated string
  2440. returned when the failure is STATUS_BUFFER_OVERFLOW.
  2441. pszFormat - format string which must be null terminated
  2442. argList - va_list from the variable arguments according to the
  2443. stdarg.h convention
  2444. Notes:
  2445. Behavior is undefined if destination, format strings or any arguments
  2446. strings overlap.
  2447. pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2448. flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2449. pszFormat may be NULL. An error may still be returned even though NULLS
  2450. are ignored due to insufficient space.
  2451. Return Value:
  2452. STATUS_SUCCESS - if there was source data and it was all concatenated and
  2453. the resultant dest string was null terminated
  2454. failure - the operation did not succeed.
  2455. STATUS_BUFFER_OVERFLOW (STRSAFE_E_INSUFFICIENT_BUFFER/ERROR_INSUFFICIENT_BUFFER to user mode apps)
  2456. Note: This status has the severity class Warning - IRPs completed with this status do have their data copied back to user mode
  2457. - this return value is an indication that the print
  2458. operation failed due to insufficient space. When this
  2459. error occurs, the destination buffer is modified to
  2460. contain a truncated version of the ideal result and is
  2461. null terminated. This is useful for situations where
  2462. truncation is ok.
  2463. It is strongly recommended to use the NT_SUCCESS() macro to test the
  2464. return value of this function
  2465. --*/
  2466. NTSTRSAFEDDI RtlStringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  2467. NTSTRSAFEDDI RtlStringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
  2468. #ifdef NTSTRSAFE_INLINE
  2469. NTSTRSAFEDDI RtlStringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  2470. {
  2471. NTSTATUS status;
  2472. size_t cchDest;
  2473. size_t cchRemaining = 0;
  2474. cchDest = cbDest / sizeof(char);
  2475. if (cchDest > STRSAFE_MAX_CCH)
  2476. {
  2477. status = STATUS_INVALID_PARAMETER;
  2478. }
  2479. else
  2480. {
  2481. status = RtlStringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  2482. }
  2483. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  2484. {
  2485. if (pcbRemaining)
  2486. {
  2487. // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  2488. *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  2489. }
  2490. }
  2491. return status;
  2492. }
  2493. NTSTRSAFEDDI RtlStringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
  2494. {
  2495. NTSTATUS status;
  2496. size_t cchDest;
  2497. size_t cchRemaining = 0;
  2498. cchDest = cbDest / sizeof(wchar_t);
  2499. if (cchDest > STRSAFE_MAX_CCH)
  2500. {
  2501. status = STATUS_INVALID_PARAMETER;
  2502. }
  2503. else
  2504. {
  2505. status = RtlStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  2506. }
  2507. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  2508. {
  2509. if (pcbRemaining)
  2510. {
  2511. // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2512. *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  2513. }
  2514. }
  2515. return status;
  2516. }
  2517. #endif // NTSTRSAFE_INLINE
  2518. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  2519. #ifndef NTSTRSAFE_NO_CCH_FUNCTIONS
  2520. /*++
  2521. NTSTATUS
  2522. RtlStringCchLength(
  2523. IN LPCTSTR psz,
  2524. IN size_t cchMax,
  2525. OUT size_t* pcch OPTIONAL
  2526. );
  2527. Routine Description:
  2528. This routine is a safer version of the C built-in function 'strlen'.
  2529. It is used to make sure a string is not larger than a given length, and
  2530. it optionally returns the current length in characters not including
  2531. the null terminator.
  2532. This function returns an NTSTATUS value, and not a pointer. It returns
  2533. STATUS_SUCCESS if the string is non-null and the length including the null
  2534. terminator is less than or equal to cchMax characters.
  2535. Arguments:
  2536. psz - string to check the length of
  2537. cchMax - maximum number of characters including the null terminator
  2538. that psz is allowed to contain
  2539. pcch - if the function succeeds and pcch is non-null, the current length
  2540. in characters of psz excluding the null terminator will be returned.
  2541. This out parameter is equivalent to the return value of strlen(psz)
  2542. Notes:
  2543. psz can be null but the function will fail
  2544. cchMax should be greater than zero or the function will fail
  2545. Return Value:
  2546. STATUS_SUCCESS - psz is non-null and the length including the null
  2547. terminator is less than or equal to cchMax characters
  2548. failure - the operation did not succeed.
  2549. It is strongly recommended to use the NT_SUCCESS() macro to test the
  2550. return value of this function.
  2551. --*/
  2552. NTSTRSAFEDDI RtlStringCchLengthA(const char* psz, size_t cchMax, size_t* pcch);
  2553. NTSTRSAFEDDI RtlStringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  2554. #ifdef NTSTRSAFE_INLINE
  2555. NTSTRSAFEDDI RtlStringCchLengthA(const char* psz, size_t cchMax, size_t* pcch)
  2556. {
  2557. NTSTATUS status;
  2558. if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  2559. {
  2560. status = STATUS_INVALID_PARAMETER;
  2561. }
  2562. else
  2563. {
  2564. status = RtlStringLengthWorkerA(psz, cchMax, pcch);
  2565. }
  2566. return status;
  2567. }
  2568. NTSTRSAFEDDI RtlStringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch)
  2569. {
  2570. NTSTATUS status;
  2571. if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  2572. {
  2573. status = STATUS_INVALID_PARAMETER;
  2574. }
  2575. else
  2576. {
  2577. status = RtlStringLengthWorkerW(psz, cchMax, pcch);
  2578. }
  2579. return status;
  2580. }
  2581. #endif // NTSTRSAFE_INLINE
  2582. #endif // !NTSTRSAFE_NO_CCH_FUNCTIONS
  2583. #ifndef NTSTRSAFE_NO_CB_FUNCTIONS
  2584. /*++
  2585. NTSTATUS
  2586. RtlStringCbLength(
  2587. IN LPCTSTR psz,
  2588. IN size_t cbMax,
  2589. OUT size_t* pcb OPTIONAL
  2590. );
  2591. Routine Description:
  2592. This routine is a safer version of the C built-in function 'strlen'.
  2593. It is used to make sure a string is not larger than a given length, and
  2594. it optionally returns the current length in bytes not including
  2595. the null terminator.
  2596. This function returns an NTSTATUS value, and not a pointer. It returns
  2597. STATUS_SUCCESS if the string is non-null and the length including the null
  2598. terminator is less than or equal to cbMax bytes.
  2599. Arguments:
  2600. psz - string to check the length of
  2601. cbMax - maximum number of bytes including the null terminator
  2602. that psz is allowed to contain
  2603. pcb - if the function succeeds and pcb is non-null, the current length
  2604. in bytes of psz excluding the null terminator will be returned.
  2605. This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR)
  2606. Notes:
  2607. psz can be null but the function will fail
  2608. cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail
  2609. Return Value:
  2610. STATUS_SUCCESS - psz is non-null and the length including the null
  2611. terminator is less than or equal to cbMax bytes
  2612. failure - the operation did not succeed.
  2613. It is strongly recommended to use the NT_SUCCESS() macro to test the
  2614. return value of this function.
  2615. --*/
  2616. NTSTRSAFEDDI RtlStringCbLengthA(const char* psz, size_t cchMax, size_t* pcch);
  2617. NTSTRSAFEDDI RtlStringCbLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  2618. #ifdef NTSTRSAFE_INLINE
  2619. NTSTRSAFEDDI RtlStringCbLengthA(const char* psz, size_t cbMax, size_t* pcb)
  2620. {
  2621. NTSTATUS status;
  2622. size_t cchMax;
  2623. size_t cch = 0;
  2624. cchMax = cbMax / sizeof(char);
  2625. if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  2626. {
  2627. status = STATUS_INVALID_PARAMETER;
  2628. }
  2629. else
  2630. {
  2631. status = RtlStringLengthWorkerA(psz, cchMax, &cch);
  2632. }
  2633. if (NT_SUCCESS(status) && pcb)
  2634. {
  2635. // safe to multiply cch * sizeof(char) since cch < STRSAFE_MAX_CCH and sizeof(char) is 1
  2636. *pcb = cch * sizeof(char);
  2637. }
  2638. return status;
  2639. }
  2640. NTSTRSAFEDDI RtlStringCbLengthW(const wchar_t* psz, size_t cbMax, size_t* pcb)
  2641. {
  2642. NTSTATUS status;
  2643. size_t cchMax;
  2644. size_t cch = 0;
  2645. cchMax = cbMax / sizeof(wchar_t);
  2646. if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  2647. {
  2648. status = STATUS_INVALID_PARAMETER;
  2649. }
  2650. else
  2651. {
  2652. status = RtlStringLengthWorkerW(psz, cchMax, &cch);
  2653. }
  2654. if (NT_SUCCESS(status) && pcb)
  2655. {
  2656. // safe to multiply cch * sizeof(wchar_t) since cch < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2657. *pcb = cch * sizeof(wchar_t);
  2658. }
  2659. return status;
  2660. }
  2661. #endif // NTSTRSAFE_INLINE
  2662. #endif // !NTSTRSAFE_NO_CB_FUNCTIONS
  2663. // these are the worker functions that actually do the work
  2664. #ifdef NTSTRSAFE_INLINE
  2665. NTSTRSAFEDDI RtlStringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
  2666. {
  2667. NTSTATUS status = STATUS_SUCCESS;
  2668. if (cchDest == 0)
  2669. {
  2670. // can not null terminate a zero-byte dest buffer
  2671. status = STATUS_INVALID_PARAMETER;
  2672. }
  2673. else
  2674. {
  2675. while (cchDest && (*pszSrc != '\0'))
  2676. {
  2677. *pszDest++ = *pszSrc++;
  2678. cchDest--;
  2679. }
  2680. if (cchDest == 0)
  2681. {
  2682. // we are going to truncate pszDest
  2683. pszDest--;
  2684. status = STATUS_BUFFER_OVERFLOW;
  2685. }
  2686. *pszDest= '\0';
  2687. }
  2688. return status;
  2689. }
  2690. NTSTRSAFEDDI RtlStringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  2691. {
  2692. NTSTATUS status = STATUS_SUCCESS;
  2693. if (cchDest == 0)
  2694. {
  2695. // can not null terminate a zero-byte dest buffer
  2696. status = STATUS_INVALID_PARAMETER;
  2697. }
  2698. else
  2699. {
  2700. while (cchDest && (*pszSrc != L'\0'))
  2701. {
  2702. *pszDest++ = *pszSrc++;
  2703. cchDest--;
  2704. }
  2705. if (cchDest == 0)
  2706. {
  2707. // we are going to truncate pszDest
  2708. pszDest--;
  2709. status = STATUS_BUFFER_OVERFLOW;
  2710. }
  2711. *pszDest= L'\0';
  2712. }
  2713. return status;
  2714. }
  2715. NTSTRSAFEDDI RtlStringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  2716. {
  2717. NTSTATUS status = STATUS_SUCCESS;
  2718. char* pszDestEnd = pszDest;
  2719. size_t cchRemaining = 0;
  2720. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  2721. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  2722. // only accept valid flags
  2723. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  2724. {
  2725. status = STATUS_INVALID_PARAMETER;
  2726. }
  2727. else
  2728. {
  2729. if (dwFlags & STRSAFE_IGNORE_NULLS)
  2730. {
  2731. if (pszDest == NULL)
  2732. {
  2733. if ((cchDest != 0) || (cbDest != 0))
  2734. {
  2735. // NULL pszDest and non-zero cchDest/cbDest is invalid
  2736. status = STATUS_INVALID_PARAMETER;
  2737. }
  2738. }
  2739. if (pszSrc == NULL)
  2740. {
  2741. pszSrc = "";
  2742. }
  2743. }
  2744. if (NT_SUCCESS(status))
  2745. {
  2746. if (cchDest == 0)
  2747. {
  2748. pszDestEnd = pszDest;
  2749. cchRemaining = 0;
  2750. // only fail if there was actually src data to copy
  2751. if (*pszSrc != '\0')
  2752. {
  2753. if (pszDest == NULL)
  2754. {
  2755. status = STATUS_INVALID_PARAMETER;
  2756. }
  2757. else
  2758. {
  2759. status = STATUS_BUFFER_OVERFLOW;
  2760. }
  2761. }
  2762. }
  2763. else
  2764. {
  2765. pszDestEnd = pszDest;
  2766. cchRemaining = cchDest;
  2767. while (cchRemaining && (*pszSrc != '\0'))
  2768. {
  2769. *pszDestEnd++= *pszSrc++;
  2770. cchRemaining--;
  2771. }
  2772. if (cchRemaining > 0)
  2773. {
  2774. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  2775. {
  2776. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  2777. }
  2778. }
  2779. else
  2780. {
  2781. // we are going to truncate pszDest
  2782. pszDestEnd--;
  2783. cchRemaining++;
  2784. status = STATUS_BUFFER_OVERFLOW;
  2785. }
  2786. *pszDestEnd = '\0';
  2787. }
  2788. }
  2789. }
  2790. if (!NT_SUCCESS(status))
  2791. {
  2792. if (pszDest)
  2793. {
  2794. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  2795. {
  2796. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  2797. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  2798. {
  2799. pszDestEnd = pszDest;
  2800. cchRemaining = cchDest;
  2801. }
  2802. else if (cchDest > 0)
  2803. {
  2804. pszDestEnd = pszDest + cchDest - 1;
  2805. cchRemaining = 1;
  2806. // null terminate the end of the string
  2807. *pszDestEnd = '\0';
  2808. }
  2809. }
  2810. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  2811. {
  2812. if (cchDest > 0)
  2813. {
  2814. pszDestEnd = pszDest;
  2815. cchRemaining = cchDest;
  2816. // null terminate the beginning of the string
  2817. *pszDestEnd = '\0';
  2818. }
  2819. }
  2820. }
  2821. }
  2822. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  2823. {
  2824. if (ppszDestEnd)
  2825. {
  2826. *ppszDestEnd = pszDestEnd;
  2827. }
  2828. if (pcchRemaining)
  2829. {
  2830. *pcchRemaining = cchRemaining;
  2831. }
  2832. }
  2833. return status;
  2834. }
  2835. NTSTRSAFEDDI RtlStringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  2836. {
  2837. NTSTATUS status = STATUS_SUCCESS;
  2838. wchar_t* pszDestEnd = pszDest;
  2839. size_t cchRemaining = 0;
  2840. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  2841. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  2842. // only accept valid flags
  2843. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  2844. {
  2845. status = STATUS_INVALID_PARAMETER;
  2846. }
  2847. else
  2848. {
  2849. if (dwFlags & STRSAFE_IGNORE_NULLS)
  2850. {
  2851. if (pszDest == NULL)
  2852. {
  2853. if ((cchDest != 0) || (cbDest != 0))
  2854. {
  2855. // NULL pszDest and non-zero cchDest/cbDest is invalid
  2856. status = STATUS_INVALID_PARAMETER;
  2857. }
  2858. }
  2859. if (pszSrc == NULL)
  2860. {
  2861. pszSrc = L"";
  2862. }
  2863. }
  2864. if (NT_SUCCESS(status))
  2865. {
  2866. if (cchDest == 0)
  2867. {
  2868. pszDestEnd = pszDest;
  2869. cchRemaining = 0;
  2870. // only fail if there was actually src data to copy
  2871. if (*pszSrc != L'\0')
  2872. {
  2873. if (pszDest == NULL)
  2874. {
  2875. status = STATUS_INVALID_PARAMETER;
  2876. }
  2877. else
  2878. {
  2879. status = STATUS_BUFFER_OVERFLOW;
  2880. }
  2881. }
  2882. }
  2883. else
  2884. {
  2885. pszDestEnd = pszDest;
  2886. cchRemaining = cchDest;
  2887. while (cchRemaining && (*pszSrc != L'\0'))
  2888. {
  2889. *pszDestEnd++= *pszSrc++;
  2890. cchRemaining--;
  2891. }
  2892. if (cchRemaining > 0)
  2893. {
  2894. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  2895. {
  2896. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  2897. }
  2898. }
  2899. else
  2900. {
  2901. // we are going to truncate pszDest
  2902. pszDestEnd--;
  2903. cchRemaining++;
  2904. status = STATUS_BUFFER_OVERFLOW;
  2905. }
  2906. *pszDestEnd = L'\0';
  2907. }
  2908. }
  2909. }
  2910. if (!NT_SUCCESS(status))
  2911. {
  2912. if (pszDest)
  2913. {
  2914. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  2915. {
  2916. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  2917. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  2918. {
  2919. pszDestEnd = pszDest;
  2920. cchRemaining = cchDest;
  2921. }
  2922. else if (cchDest > 0)
  2923. {
  2924. pszDestEnd = pszDest + cchDest - 1;
  2925. cchRemaining = 1;
  2926. // null terminate the end of the string
  2927. *pszDestEnd = L'\0';
  2928. }
  2929. }
  2930. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  2931. {
  2932. if (cchDest > 0)
  2933. {
  2934. pszDestEnd = pszDest;
  2935. cchRemaining = cchDest;
  2936. // null terminate the beginning of the string
  2937. *pszDestEnd = L'\0';
  2938. }
  2939. }
  2940. }
  2941. }
  2942. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  2943. {
  2944. if (ppszDestEnd)
  2945. {
  2946. *ppszDestEnd = pszDestEnd;
  2947. }
  2948. if (pcchRemaining)
  2949. {
  2950. *pcchRemaining = cchRemaining;
  2951. }
  2952. }
  2953. return status;
  2954. }
  2955. NTSTRSAFEDDI RtlStringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
  2956. {
  2957. NTSTATUS status = STATUS_SUCCESS;
  2958. if (cchDest == 0)
  2959. {
  2960. // can not null terminate a zero-byte dest buffer
  2961. status = STATUS_INVALID_PARAMETER;
  2962. }
  2963. else
  2964. {
  2965. while (cchDest && cchSrc && (*pszSrc != '\0'))
  2966. {
  2967. *pszDest++= *pszSrc++;
  2968. cchDest--;
  2969. cchSrc--;
  2970. }
  2971. if (cchDest == 0)
  2972. {
  2973. // we are going to truncate pszDest
  2974. pszDest--;
  2975. status = STATUS_BUFFER_OVERFLOW;
  2976. }
  2977. *pszDest= '\0';
  2978. }
  2979. return status;
  2980. }
  2981. NTSTRSAFEDDI RtlStringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
  2982. {
  2983. NTSTATUS status = STATUS_SUCCESS;
  2984. if (cchDest == 0)
  2985. {
  2986. // can not null terminate a zero-byte dest buffer
  2987. status = STATUS_INVALID_PARAMETER;
  2988. }
  2989. else
  2990. {
  2991. while (cchDest && cchSrc && (*pszSrc != L'\0'))
  2992. {
  2993. *pszDest++= *pszSrc++;
  2994. cchDest--;
  2995. cchSrc--;
  2996. }
  2997. if (cchDest == 0)
  2998. {
  2999. // we are going to truncate pszDest
  3000. pszDest--;
  3001. status = STATUS_BUFFER_OVERFLOW;
  3002. }
  3003. *pszDest= L'\0';
  3004. }
  3005. return status;
  3006. }
  3007. NTSTRSAFEDDI RtlStringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3008. {
  3009. NTSTATUS status = STATUS_SUCCESS;
  3010. char* pszDestEnd = pszDest;
  3011. size_t cchRemaining = 0;
  3012. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  3013. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  3014. // only accept valid flags
  3015. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3016. {
  3017. status = STATUS_INVALID_PARAMETER;
  3018. }
  3019. else
  3020. {
  3021. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3022. {
  3023. if (pszDest == NULL)
  3024. {
  3025. if ((cchDest != 0) || (cbDest != 0))
  3026. {
  3027. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3028. status = STATUS_INVALID_PARAMETER;
  3029. }
  3030. }
  3031. if (pszSrc == NULL)
  3032. {
  3033. pszSrc = "";
  3034. }
  3035. }
  3036. if (NT_SUCCESS(status))
  3037. {
  3038. if (cchDest == 0)
  3039. {
  3040. pszDestEnd = pszDest;
  3041. cchRemaining = 0;
  3042. // only fail if there was actually src data to copy
  3043. if (*pszSrc != '\0')
  3044. {
  3045. if (pszDest == NULL)
  3046. {
  3047. status = STATUS_INVALID_PARAMETER;
  3048. }
  3049. else
  3050. {
  3051. status = STATUS_BUFFER_OVERFLOW;
  3052. }
  3053. }
  3054. }
  3055. else
  3056. {
  3057. pszDestEnd = pszDest;
  3058. cchRemaining = cchDest;
  3059. while (cchRemaining && cchSrc && (*pszSrc != '\0'))
  3060. {
  3061. *pszDestEnd++= *pszSrc++;
  3062. cchRemaining--;
  3063. cchSrc--;
  3064. }
  3065. if (cchRemaining > 0)
  3066. {
  3067. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  3068. {
  3069. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  3070. }
  3071. }
  3072. else
  3073. {
  3074. // we are going to truncate pszDest
  3075. pszDestEnd--;
  3076. cchRemaining++;
  3077. status = STATUS_BUFFER_OVERFLOW;
  3078. }
  3079. *pszDestEnd = '\0';
  3080. }
  3081. }
  3082. }
  3083. if (!NT_SUCCESS(status))
  3084. {
  3085. if (pszDest)
  3086. {
  3087. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3088. {
  3089. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3090. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3091. {
  3092. pszDestEnd = pszDest;
  3093. cchRemaining = cchDest;
  3094. }
  3095. else if (cchDest > 0)
  3096. {
  3097. pszDestEnd = pszDest + cchDest - 1;
  3098. cchRemaining = 1;
  3099. // null terminate the end of the string
  3100. *pszDestEnd = '\0';
  3101. }
  3102. }
  3103. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  3104. {
  3105. if (cchDest > 0)
  3106. {
  3107. pszDestEnd = pszDest;
  3108. cchRemaining = cchDest;
  3109. // null terminate the beginning of the string
  3110. *pszDestEnd = '\0';
  3111. }
  3112. }
  3113. }
  3114. }
  3115. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  3116. {
  3117. if (ppszDestEnd)
  3118. {
  3119. *ppszDestEnd = pszDestEnd;
  3120. }
  3121. if (pcchRemaining)
  3122. {
  3123. *pcchRemaining = cchRemaining;
  3124. }
  3125. }
  3126. return status;
  3127. }
  3128. NTSTRSAFEDDI RtlStringCopyNExWorkerW(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)
  3129. {
  3130. NTSTATUS status = STATUS_SUCCESS;
  3131. wchar_t* pszDestEnd = pszDest;
  3132. size_t cchRemaining = 0;
  3133. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  3134. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  3135. // only accept valid flags
  3136. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3137. {
  3138. status = STATUS_INVALID_PARAMETER;
  3139. }
  3140. else
  3141. {
  3142. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3143. {
  3144. if (pszDest == NULL)
  3145. {
  3146. if ((cchDest != 0) || (cbDest != 0))
  3147. {
  3148. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3149. status = STATUS_INVALID_PARAMETER;
  3150. }
  3151. }
  3152. if (pszSrc == NULL)
  3153. {
  3154. pszSrc = L"";
  3155. }
  3156. }
  3157. if (NT_SUCCESS(status))
  3158. {
  3159. if (cchDest == 0)
  3160. {
  3161. pszDestEnd = pszDest;
  3162. cchRemaining = 0;
  3163. // only fail if there was actually src data to copy
  3164. if (*pszSrc != L'\0')
  3165. {
  3166. if (pszDest == NULL)
  3167. {
  3168. status = STATUS_INVALID_PARAMETER;
  3169. }
  3170. else
  3171. {
  3172. status = STATUS_BUFFER_OVERFLOW;
  3173. }
  3174. }
  3175. }
  3176. else
  3177. {
  3178. pszDestEnd = pszDest;
  3179. cchRemaining = cchDest;
  3180. while (cchRemaining && cchSrc && (*pszSrc != L'\0'))
  3181. {
  3182. *pszDestEnd++= *pszSrc++;
  3183. cchRemaining--;
  3184. cchSrc--;
  3185. }
  3186. if (cchRemaining > 0)
  3187. {
  3188. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  3189. {
  3190. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  3191. }
  3192. }
  3193. else
  3194. {
  3195. // we are going to truncate pszDest
  3196. pszDestEnd--;
  3197. cchRemaining++;
  3198. status = STATUS_BUFFER_OVERFLOW;
  3199. }
  3200. *pszDestEnd = L'\0';
  3201. }
  3202. }
  3203. }
  3204. if (!NT_SUCCESS(status))
  3205. {
  3206. if (pszDest)
  3207. {
  3208. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3209. {
  3210. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3211. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3212. {
  3213. pszDestEnd = pszDest;
  3214. cchRemaining = cchDest;
  3215. }
  3216. else if (cchDest > 0)
  3217. {
  3218. pszDestEnd = pszDest + cchDest - 1;
  3219. cchRemaining = 1;
  3220. // null terminate the end of the string
  3221. *pszDestEnd = L'\0';
  3222. }
  3223. }
  3224. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  3225. {
  3226. if (cchDest > 0)
  3227. {
  3228. pszDestEnd = pszDest;
  3229. cchRemaining = cchDest;
  3230. // null terminate the beginning of the string
  3231. *pszDestEnd = L'\0';
  3232. }
  3233. }
  3234. }
  3235. }
  3236. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  3237. {
  3238. if (ppszDestEnd)
  3239. {
  3240. *ppszDestEnd = pszDestEnd;
  3241. }
  3242. if (pcchRemaining)
  3243. {
  3244. *pcchRemaining = cchRemaining;
  3245. }
  3246. }
  3247. return status;
  3248. }
  3249. NTSTRSAFEDDI RtlStringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
  3250. {
  3251. NTSTATUS status;
  3252. size_t cchDestCurrent;
  3253. status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3254. if (NT_SUCCESS(status))
  3255. {
  3256. status = RtlStringCopyWorkerA(pszDest + cchDestCurrent,
  3257. cchDest - cchDestCurrent,
  3258. pszSrc);
  3259. }
  3260. return status;
  3261. }
  3262. NTSTRSAFEDDI RtlStringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  3263. {
  3264. NTSTATUS status;
  3265. size_t cchDestCurrent;
  3266. status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  3267. if (NT_SUCCESS(status))
  3268. {
  3269. status = RtlStringCopyWorkerW(pszDest + cchDestCurrent,
  3270. cchDest - cchDestCurrent,
  3271. pszSrc);
  3272. }
  3273. return status;
  3274. }
  3275. NTSTRSAFEDDI RtlStringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3276. {
  3277. NTSTATUS status = STATUS_SUCCESS;
  3278. char* pszDestEnd = pszDest;
  3279. size_t cchRemaining = 0;
  3280. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  3281. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  3282. // only accept valid flags
  3283. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3284. {
  3285. status = STATUS_INVALID_PARAMETER;
  3286. }
  3287. else
  3288. {
  3289. size_t cchDestCurrent;
  3290. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3291. {
  3292. if (pszDest == NULL)
  3293. {
  3294. if ((cchDest == 0) && (cbDest == 0))
  3295. {
  3296. cchDestCurrent = 0;
  3297. }
  3298. else
  3299. {
  3300. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3301. status = STATUS_INVALID_PARAMETER;
  3302. }
  3303. }
  3304. else
  3305. {
  3306. status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3307. if (NT_SUCCESS(status))
  3308. {
  3309. pszDestEnd = pszDest + cchDestCurrent;
  3310. cchRemaining = cchDest - cchDestCurrent;
  3311. }
  3312. }
  3313. if (pszSrc == NULL)
  3314. {
  3315. pszSrc = "";
  3316. }
  3317. }
  3318. else
  3319. {
  3320. status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3321. if (NT_SUCCESS(status))
  3322. {
  3323. pszDestEnd = pszDest + cchDestCurrent;
  3324. cchRemaining = cchDest - cchDestCurrent;
  3325. }
  3326. }
  3327. if (NT_SUCCESS(status))
  3328. {
  3329. if (cchDest == 0)
  3330. {
  3331. // only fail if there was actually src data to append
  3332. if (*pszSrc != '\0')
  3333. {
  3334. if (pszDest == NULL)
  3335. {
  3336. status = STATUS_INVALID_PARAMETER;
  3337. }
  3338. else
  3339. {
  3340. status = STATUS_BUFFER_OVERFLOW;
  3341. }
  3342. }
  3343. }
  3344. else
  3345. {
  3346. // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  3347. // those flags through
  3348. status = RtlStringCopyExWorkerA(pszDestEnd,
  3349. cchRemaining,
  3350. (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
  3351. pszSrc,
  3352. &pszDestEnd,
  3353. &cchRemaining,
  3354. dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  3355. }
  3356. }
  3357. }
  3358. if (!NT_SUCCESS(status))
  3359. {
  3360. if (pszDest)
  3361. {
  3362. // STRSAFE_NO_TRUNCATION is taken care of by RtlStringCopyExWorkerA()
  3363. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3364. {
  3365. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3366. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3367. {
  3368. pszDestEnd = pszDest;
  3369. cchRemaining = cchDest;
  3370. }
  3371. else
  3372. if (cchDest > 0)
  3373. {
  3374. pszDestEnd = pszDest + cchDest - 1;
  3375. cchRemaining = 1;
  3376. // null terminate the end of the string
  3377. *pszDestEnd = '\0';
  3378. }
  3379. }
  3380. if (dwFlags & STRSAFE_NULL_ON_FAILURE)
  3381. {
  3382. if (cchDest > 0)
  3383. {
  3384. pszDestEnd = pszDest;
  3385. cchRemaining = cchDest;
  3386. // null terminate the beginning of the string
  3387. *pszDestEnd = '\0';
  3388. }
  3389. }
  3390. }
  3391. }
  3392. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  3393. {
  3394. if (ppszDestEnd)
  3395. {
  3396. *ppszDestEnd = pszDestEnd;
  3397. }
  3398. if (pcchRemaining)
  3399. {
  3400. *pcchRemaining = cchRemaining;
  3401. }
  3402. }
  3403. return status;
  3404. }
  3405. NTSTRSAFEDDI RtlStringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3406. {
  3407. NTSTATUS status = STATUS_SUCCESS;
  3408. wchar_t* pszDestEnd = pszDest;
  3409. size_t cchRemaining = 0;
  3410. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  3411. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  3412. // only accept valid flags
  3413. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3414. {
  3415. status = STATUS_INVALID_PARAMETER;
  3416. }
  3417. else
  3418. {
  3419. size_t cchDestCurrent;
  3420. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3421. {
  3422. if (pszDest == NULL)
  3423. {
  3424. if ((cchDest == 0) && (cbDest == 0))
  3425. {
  3426. cchDestCurrent = 0;
  3427. }
  3428. else
  3429. {
  3430. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3431. status = STATUS_INVALID_PARAMETER;
  3432. }
  3433. }
  3434. else
  3435. {
  3436. status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  3437. if (NT_SUCCESS(status))
  3438. {
  3439. pszDestEnd = pszDest + cchDestCurrent;
  3440. cchRemaining = cchDest - cchDestCurrent;
  3441. }
  3442. }
  3443. if (pszSrc == NULL)
  3444. {
  3445. pszSrc = L"";
  3446. }
  3447. }
  3448. else
  3449. {
  3450. status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  3451. if (NT_SUCCESS(status))
  3452. {
  3453. pszDestEnd = pszDest + cchDestCurrent;
  3454. cchRemaining = cchDest - cchDestCurrent;
  3455. }
  3456. }
  3457. if (NT_SUCCESS(status))
  3458. {
  3459. if (cchDest == 0)
  3460. {
  3461. // only fail if there was actually src data to append
  3462. if (*pszSrc != L'\0')
  3463. {
  3464. if (pszDest == NULL)
  3465. {
  3466. status = STATUS_INVALID_PARAMETER;
  3467. }
  3468. else
  3469. {
  3470. status = STATUS_BUFFER_OVERFLOW;
  3471. }
  3472. }
  3473. }
  3474. else
  3475. {
  3476. // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  3477. // those flags through
  3478. status = RtlStringCopyExWorkerW(pszDestEnd,
  3479. cchRemaining,
  3480. (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
  3481. pszSrc,
  3482. &pszDestEnd,
  3483. &cchRemaining,
  3484. dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  3485. }
  3486. }
  3487. }
  3488. if (!NT_SUCCESS(status))
  3489. {
  3490. if (pszDest)
  3491. {
  3492. // STRSAFE_NO_TRUNCATION is taken care of by RtlStringCopyExWorkerW()
  3493. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3494. {
  3495. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3496. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3497. {
  3498. pszDestEnd = pszDest;
  3499. cchRemaining = cchDest;
  3500. }
  3501. else if (cchDest > 0)
  3502. {
  3503. pszDestEnd = pszDest + cchDest - 1;
  3504. cchRemaining = 1;
  3505. // null terminate the end of the string
  3506. *pszDestEnd = L'\0';
  3507. }
  3508. }
  3509. if (dwFlags & STRSAFE_NULL_ON_FAILURE)
  3510. {
  3511. if (cchDest > 0)
  3512. {
  3513. pszDestEnd = pszDest;
  3514. cchRemaining = cchDest;
  3515. // null terminate the beginning of the string
  3516. *pszDestEnd = L'\0';
  3517. }
  3518. }
  3519. }
  3520. }
  3521. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  3522. {
  3523. if (ppszDestEnd)
  3524. {
  3525. *ppszDestEnd = pszDestEnd;
  3526. }
  3527. if (pcchRemaining)
  3528. {
  3529. *pcchRemaining = cchRemaining;
  3530. }
  3531. }
  3532. return status;
  3533. }
  3534. NTSTRSAFEDDI RtlStringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
  3535. {
  3536. NTSTATUS status;
  3537. size_t cchDestCurrent;
  3538. status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3539. if (NT_SUCCESS(status))
  3540. {
  3541. status = RtlStringCopyNWorkerA(pszDest + cchDestCurrent,
  3542. cchDest - cchDestCurrent,
  3543. pszSrc,
  3544. cchMaxAppend);
  3545. }
  3546. return status;
  3547. }
  3548. NTSTRSAFEDDI RtlStringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
  3549. {
  3550. NTSTATUS status;
  3551. size_t cchDestCurrent;
  3552. status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  3553. if (NT_SUCCESS(status))
  3554. {
  3555. status = RtlStringCopyNWorkerW(pszDest + cchDestCurrent,
  3556. cchDest - cchDestCurrent,
  3557. pszSrc,
  3558. cchMaxAppend);
  3559. }
  3560. return status;
  3561. }
  3562. NTSTRSAFEDDI RtlStringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3563. {
  3564. NTSTATUS status = STATUS_SUCCESS;
  3565. char* pszDestEnd = pszDest;
  3566. size_t cchRemaining = 0;
  3567. size_t cchDestCurrent = 0;
  3568. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  3569. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  3570. // only accept valid flags
  3571. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3572. {
  3573. status = STATUS_INVALID_PARAMETER;
  3574. }
  3575. else
  3576. {
  3577. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3578. {
  3579. if (pszDest == NULL)
  3580. {
  3581. if ((cchDest == 0) && (cbDest == 0))
  3582. {
  3583. cchDestCurrent = 0;
  3584. }
  3585. else
  3586. {
  3587. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3588. status = STATUS_INVALID_PARAMETER;
  3589. }
  3590. }
  3591. else
  3592. {
  3593. status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3594. if (NT_SUCCESS(status))
  3595. {
  3596. pszDestEnd = pszDest + cchDestCurrent;
  3597. cchRemaining = cchDest - cchDestCurrent;
  3598. }
  3599. }
  3600. if (pszSrc == NULL)
  3601. {
  3602. pszSrc = "";
  3603. }
  3604. }
  3605. else
  3606. {
  3607. status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  3608. if (NT_SUCCESS(status))
  3609. {
  3610. pszDestEnd = pszDest + cchDestCurrent;
  3611. cchRemaining = cchDest - cchDestCurrent;
  3612. }
  3613. }
  3614. if (NT_SUCCESS(status))
  3615. {
  3616. if (cchDest == 0)
  3617. {
  3618. // only fail if there was actually src data to append
  3619. if (*pszSrc != '\0')
  3620. {
  3621. if (pszDest == NULL)
  3622. {
  3623. status = STATUS_INVALID_PARAMETER;
  3624. }
  3625. else
  3626. {
  3627. status = STATUS_BUFFER_OVERFLOW;
  3628. }
  3629. }
  3630. }
  3631. else
  3632. {
  3633. // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  3634. // those flags through
  3635. status = RtlStringCopyNExWorkerA(pszDestEnd,
  3636. cchRemaining,
  3637. (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
  3638. pszSrc,
  3639. cchMaxAppend,
  3640. &pszDestEnd,
  3641. &cchRemaining,
  3642. dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  3643. }
  3644. }
  3645. }
  3646. if (!NT_SUCCESS(status))
  3647. {
  3648. if (pszDest)
  3649. {
  3650. // STRSAFE_NO_TRUNCATION is taken care of by RtlStringCopyNExWorkerA()
  3651. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3652. {
  3653. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3654. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3655. {
  3656. pszDestEnd = pszDest;
  3657. cchRemaining = cchDest;
  3658. }
  3659. else if (cchDest > 0)
  3660. {
  3661. pszDestEnd = pszDest + cchDest - 1;
  3662. cchRemaining = 1;
  3663. // null terminate the end of the string
  3664. *pszDestEnd = '\0';
  3665. }
  3666. }
  3667. if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
  3668. {
  3669. if (cchDest > 0)
  3670. {
  3671. pszDestEnd = pszDest;
  3672. cchRemaining = cchDest;
  3673. // null terminate the beginning of the string
  3674. *pszDestEnd = '\0';
  3675. }
  3676. }
  3677. }
  3678. }
  3679. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  3680. {
  3681. if (ppszDestEnd)
  3682. {
  3683. *ppszDestEnd = pszDestEnd;
  3684. }
  3685. if (pcchRemaining)
  3686. {
  3687. *pcchRemaining = cchRemaining;
  3688. }
  3689. }
  3690. return status;
  3691. }
  3692. NTSTRSAFEDDI RtlStringCatNExWorkerW(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)
  3693. {
  3694. NTSTATUS status = STATUS_SUCCESS;
  3695. wchar_t* pszDestEnd = pszDest;
  3696. size_t cchRemaining = 0;
  3697. size_t cchDestCurrent = 0;
  3698. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  3699. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  3700. // only accept valid flags
  3701. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3702. {
  3703. status = STATUS_INVALID_PARAMETER;
  3704. }
  3705. else
  3706. {
  3707. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3708. {
  3709. if (pszDest == NULL)
  3710. {
  3711. if ((cchDest == 0) && (cbDest == 0))
  3712. {
  3713. cchDestCurrent = 0;
  3714. }
  3715. else
  3716. {
  3717. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3718. status = STATUS_INVALID_PARAMETER;
  3719. }
  3720. }
  3721. else
  3722. {
  3723. status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  3724. if (NT_SUCCESS(status))
  3725. {
  3726. pszDestEnd = pszDest + cchDestCurrent;
  3727. cchRemaining = cchDest - cchDestCurrent;
  3728. }
  3729. }
  3730. if (pszSrc == NULL)
  3731. {
  3732. pszSrc = L"";
  3733. }
  3734. }
  3735. else
  3736. {
  3737. status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  3738. if (NT_SUCCESS(status))
  3739. {
  3740. pszDestEnd = pszDest + cchDestCurrent;
  3741. cchRemaining = cchDest - cchDestCurrent;
  3742. }
  3743. }
  3744. if (NT_SUCCESS(status))
  3745. {
  3746. if (cchDest == 0)
  3747. {
  3748. // only fail if there was actually src data to append
  3749. if (*pszSrc != L'\0')
  3750. {
  3751. if (pszDest == NULL)
  3752. {
  3753. status = STATUS_INVALID_PARAMETER;
  3754. }
  3755. else
  3756. {
  3757. status = STATUS_BUFFER_OVERFLOW;
  3758. }
  3759. }
  3760. }
  3761. else
  3762. {
  3763. // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  3764. // those flags through
  3765. status = RtlStringCopyNExWorkerW(pszDestEnd,
  3766. cchRemaining,
  3767. (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
  3768. pszSrc,
  3769. cchMaxAppend,
  3770. &pszDestEnd,
  3771. &cchRemaining,
  3772. dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  3773. }
  3774. }
  3775. }
  3776. if (!NT_SUCCESS(status))
  3777. {
  3778. if (pszDest)
  3779. {
  3780. // STRSAFE_NO_TRUNCATION is taken care of by RtlStringCopyNExWorkerW()
  3781. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  3782. {
  3783. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  3784. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  3785. {
  3786. pszDestEnd = pszDest;
  3787. cchRemaining = cchDest;
  3788. }
  3789. else if (cchDest > 0)
  3790. {
  3791. pszDestEnd = pszDest + cchDest - 1;
  3792. cchRemaining = 1;
  3793. // null terminate the end of the string
  3794. *pszDestEnd = L'\0';
  3795. }
  3796. }
  3797. if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
  3798. {
  3799. if (cchDest > 0)
  3800. {
  3801. pszDestEnd = pszDest;
  3802. cchRemaining = cchDest;
  3803. // null terminate the beginning of the string
  3804. *pszDestEnd = L'\0';
  3805. }
  3806. }
  3807. }
  3808. }
  3809. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  3810. {
  3811. if (ppszDestEnd)
  3812. {
  3813. *ppszDestEnd = pszDestEnd;
  3814. }
  3815. if (pcchRemaining)
  3816. {
  3817. *pcchRemaining = cchRemaining;
  3818. }
  3819. }
  3820. return status;
  3821. }
  3822. NTSTRSAFEDDI RtlStringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
  3823. {
  3824. NTSTATUS status = STATUS_SUCCESS;
  3825. if (cchDest == 0)
  3826. {
  3827. // can not null terminate a zero-byte dest buffer
  3828. status = STATUS_INVALID_PARAMETER;
  3829. }
  3830. else
  3831. {
  3832. int iRet;
  3833. size_t cchMax;
  3834. // leave the last space for the null terminator
  3835. cchMax = cchDest - 1;
  3836. iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
  3837. // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  3838. if ((iRet < 0) || (((size_t)iRet) > cchMax))
  3839. {
  3840. // need to null terminate the string
  3841. pszDest += cchMax;
  3842. *pszDest = '\0';
  3843. // we have truncated pszDest
  3844. status = STATUS_BUFFER_OVERFLOW;
  3845. }
  3846. else if (((size_t)iRet) == cchMax)
  3847. {
  3848. // need to null terminate the string
  3849. pszDest += cchMax;
  3850. *pszDest = '\0';
  3851. }
  3852. }
  3853. return status;
  3854. }
  3855. NTSTRSAFEDDI RtlStringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
  3856. {
  3857. NTSTATUS status = STATUS_SUCCESS;
  3858. if (cchDest == 0)
  3859. {
  3860. // can not null terminate a zero-byte dest buffer
  3861. status = STATUS_INVALID_PARAMETER;
  3862. }
  3863. else
  3864. {
  3865. int iRet;
  3866. size_t cchMax;
  3867. // leave the last space for the null terminator
  3868. cchMax = cchDest - 1;
  3869. iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
  3870. // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  3871. if ((iRet < 0) || (((size_t)iRet) > cchMax))
  3872. {
  3873. // need to null terminate the string
  3874. pszDest += cchMax;
  3875. *pszDest = L'\0';
  3876. // we have truncated pszDest
  3877. status = STATUS_BUFFER_OVERFLOW;
  3878. }
  3879. else if (((size_t)iRet) == cchMax)
  3880. {
  3881. // need to null terminate the string
  3882. pszDest += cchMax;
  3883. *pszDest = L'\0';
  3884. }
  3885. }
  3886. return status;
  3887. }
  3888. NTSTRSAFEDDI RtlStringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  3889. {
  3890. NTSTATUS status = STATUS_SUCCESS;
  3891. char* pszDestEnd = pszDest;
  3892. size_t cchRemaining = 0;
  3893. // ASSERT(cbDest == (cchDest * sizeof(char)) ||
  3894. // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  3895. // only accept valid flags
  3896. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  3897. {
  3898. status = STATUS_INVALID_PARAMETER;
  3899. }
  3900. else
  3901. {
  3902. if (dwFlags & STRSAFE_IGNORE_NULLS)
  3903. {
  3904. if (pszDest == NULL)
  3905. {
  3906. if ((cchDest != 0) || (cbDest != 0))
  3907. {
  3908. // NULL pszDest and non-zero cchDest/cbDest is invalid
  3909. status = STATUS_INVALID_PARAMETER;
  3910. }
  3911. }
  3912. if (pszFormat == NULL)
  3913. {
  3914. pszFormat = "";
  3915. }
  3916. }
  3917. if (NT_SUCCESS(status))
  3918. {
  3919. if (cchDest == 0)
  3920. {
  3921. pszDestEnd = pszDest;
  3922. cchRemaining = 0;
  3923. // only fail if there was actually a non-empty format string
  3924. if (*pszFormat != '\0')
  3925. {
  3926. if (pszDest == NULL)
  3927. {
  3928. status = STATUS_INVALID_PARAMETER;
  3929. }
  3930. else
  3931. {
  3932. status = STATUS_BUFFER_OVERFLOW;
  3933. }
  3934. }
  3935. }
  3936. else
  3937. {
  3938. int iRet;
  3939. size_t cchMax;
  3940. // leave the last space for the null terminator
  3941. cchMax = cchDest - 1;
  3942. iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
  3943. // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  3944. if ((iRet < 0) || (((size_t)iRet) > cchMax))
  3945. {
  3946. // we have truncated pszDest
  3947. pszDestEnd = pszDest + cchMax;
  3948. cchRemaining = 1;
  3949. // need to null terminate the string
  3950. *pszDestEnd = '\0';
  3951. status = STATUS_BUFFER_OVERFLOW;
  3952. }
  3953. else if (((size_t)iRet) == cchMax)
  3954. {
  3955. // string fit perfectly
  3956. pszDestEnd = pszDest + cchMax;
  3957. cchRemaining = 1;
  3958. // need to null terminate the string
  3959. *pszDestEnd = '\0';
  3960. }
  3961. else if (((size_t)iRet) < cchMax)
  3962. {
  3963. // there is extra room
  3964. pszDestEnd = pszDest + iRet;
  3965. cchRemaining = cchDest - iRet;
  3966. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  3967. {
  3968. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  3969. }
  3970. }
  3971. }
  3972. }
  3973. }
  3974. if (!NT_SUCCESS(status))
  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 = '\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 = '\0';
  4002. }
  4003. }
  4004. }
  4005. }
  4006. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  4007. {
  4008. if (ppszDestEnd)
  4009. {
  4010. *ppszDestEnd = pszDestEnd;
  4011. }
  4012. if (pcchRemaining)
  4013. {
  4014. *pcchRemaining = cchRemaining;
  4015. }
  4016. }
  4017. return status;
  4018. }
  4019. NTSTRSAFEDDI RtlStringVPrintfExWorkerW(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)
  4020. {
  4021. NTSTATUS status = STATUS_SUCCESS;
  4022. wchar_t* pszDestEnd = pszDest;
  4023. size_t cchRemaining = 0;
  4024. // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  4025. // cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4026. // only accept valid flags
  4027. if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4028. {
  4029. status = STATUS_INVALID_PARAMETER;
  4030. }
  4031. else
  4032. {
  4033. if (dwFlags & STRSAFE_IGNORE_NULLS)
  4034. {
  4035. if (pszDest == NULL)
  4036. {
  4037. if ((cchDest != 0) || (cbDest != 0))
  4038. {
  4039. // NULL pszDest and non-zero cchDest/cbDest is invalid
  4040. status = STATUS_INVALID_PARAMETER;
  4041. }
  4042. }
  4043. if (pszFormat == NULL)
  4044. {
  4045. pszFormat = L"";
  4046. }
  4047. }
  4048. if (NT_SUCCESS(status))
  4049. {
  4050. if (cchDest == 0)
  4051. {
  4052. pszDestEnd = pszDest;
  4053. cchRemaining = 0;
  4054. // only fail if there was actually a non-empty format string
  4055. if (*pszFormat != L'\0')
  4056. {
  4057. if (pszDest == NULL)
  4058. {
  4059. status = STATUS_INVALID_PARAMETER;
  4060. }
  4061. else
  4062. {
  4063. status = STATUS_BUFFER_OVERFLOW;
  4064. }
  4065. }
  4066. }
  4067. else
  4068. {
  4069. int iRet;
  4070. size_t cchMax;
  4071. // leave the last space for the null terminator
  4072. cchMax = cchDest - 1;
  4073. iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
  4074. // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  4075. if ((iRet < 0) || (((size_t)iRet) > cchMax))
  4076. {
  4077. // we have truncated pszDest
  4078. pszDestEnd = pszDest + cchMax;
  4079. cchRemaining = 1;
  4080. // need to null terminate the string
  4081. *pszDestEnd = L'\0';
  4082. status = STATUS_BUFFER_OVERFLOW;
  4083. }
  4084. else if (((size_t)iRet) == cchMax)
  4085. {
  4086. // string fit perfectly
  4087. pszDestEnd = pszDest + cchMax;
  4088. cchRemaining = 1;
  4089. // need to null terminate the string
  4090. *pszDestEnd = L'\0';
  4091. }
  4092. else if (((size_t)iRet) < cchMax)
  4093. {
  4094. // there is extra room
  4095. pszDestEnd = pszDest + iRet;
  4096. cchRemaining = cchDest - iRet;
  4097. if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4098. {
  4099. memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4100. }
  4101. }
  4102. }
  4103. }
  4104. }
  4105. if (!NT_SUCCESS(status))
  4106. {
  4107. if (pszDest)
  4108. {
  4109. if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4110. {
  4111. memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4112. if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4113. {
  4114. pszDestEnd = pszDest;
  4115. cchRemaining = cchDest;
  4116. }
  4117. else if (cchDest > 0)
  4118. {
  4119. pszDestEnd = pszDest + cchDest - 1;
  4120. cchRemaining = 1;
  4121. // null terminate the end of the string
  4122. *pszDestEnd = L'\0';
  4123. }
  4124. }
  4125. if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4126. {
  4127. if (cchDest > 0)
  4128. {
  4129. pszDestEnd = pszDest;
  4130. cchRemaining = cchDest;
  4131. // null terminate the beginning of the string
  4132. *pszDestEnd = L'\0';
  4133. }
  4134. }
  4135. }
  4136. }
  4137. if (NT_SUCCESS(status) || (status == STATUS_BUFFER_OVERFLOW))
  4138. {
  4139. if (ppszDestEnd)
  4140. {
  4141. *ppszDestEnd = pszDestEnd;
  4142. }
  4143. if (pcchRemaining)
  4144. {
  4145. *pcchRemaining = cchRemaining;
  4146. }
  4147. }
  4148. return status;
  4149. }
  4150. NTSTRSAFEDDI RtlStringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch)
  4151. {
  4152. NTSTATUS status = STATUS_SUCCESS;
  4153. size_t cchMaxPrev = cchMax;
  4154. while (cchMax && (*psz != '\0'))
  4155. {
  4156. psz++;
  4157. cchMax--;
  4158. }
  4159. if (cchMax == 0)
  4160. {
  4161. // the string is longer than cchMax
  4162. status = STATUS_INVALID_PARAMETER;
  4163. }
  4164. if (NT_SUCCESS(status) && pcch)
  4165. {
  4166. *pcch = cchMaxPrev - cchMax;
  4167. }
  4168. return status;
  4169. }
  4170. NTSTRSAFEDDI RtlStringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch)
  4171. {
  4172. NTSTATUS status = STATUS_SUCCESS;
  4173. size_t cchMaxPrev = cchMax;
  4174. while (cchMax && (*psz != L'\0'))
  4175. {
  4176. psz++;
  4177. cchMax--;
  4178. }
  4179. if (cchMax == 0)
  4180. {
  4181. // the string is longer than cchMax
  4182. status = STATUS_INVALID_PARAMETER;
  4183. }
  4184. if (NT_SUCCESS(status) && pcch)
  4185. {
  4186. *pcch = cchMaxPrev - cchMax;
  4187. }
  4188. return status;
  4189. }
  4190. #endif // NTSTRSAFE_INLINE
  4191. // Do not call these functions, they are worker functions for internal use within this file
  4192. #ifdef DEPRECATE_SUPPORTED
  4193. #pragma deprecated(RtlStringCopyWorkerA)
  4194. #pragma deprecated(RtlStringCopyWorkerW)
  4195. #pragma deprecated(RtlStringCopyExWorkerA)
  4196. #pragma deprecated(RtlStringCopyExWorkerW)
  4197. #pragma deprecated(RtlStringCatWorkerA)
  4198. #pragma deprecated(RtlStringCatWorkerW)
  4199. #pragma deprecated(RtlStringCatExWorkerA)
  4200. #pragma deprecated(RtlStringCatExWorkerW)
  4201. #pragma deprecated(RtlStringCatNWorkerA)
  4202. #pragma deprecated(RtlStringCatNWorkerW)
  4203. #pragma deprecated(RtlStringCatNExWorkerA)
  4204. #pragma deprecated(RtlStringCatNExWorkerW)
  4205. #pragma deprecated(RtlStringVPrintfWorkerA)
  4206. #pragma deprecated(RtlStringVPrintfWorkerW)
  4207. #pragma deprecated(RtlStringVPrintfExWorkerA)
  4208. #pragma deprecated(RtlStringVPrintfExWorkerW)
  4209. #pragma deprecated(RtlStringLengthWorkerA)
  4210. #pragma deprecated(RtlStringLengthWorkerW)
  4211. #else
  4212. #define RtlStringCopyWorkerA RtlStringCopyWorkerA_instead_use_RtlStringCchCopyA_or_RtlStringCchCopyExA;
  4213. #define RtlStringCopyWorkerW RtlStringCopyWorkerW_instead_use_RtlStringCchCopyW_or_RtlStringCchCopyExW;
  4214. #define RtlStringCopyExWorkerA RtlStringCopyExWorkerA_instead_use_RtlStringCchCopyA_or_RtlStringCchCopyExA;
  4215. #define RtlStringCopyExWorkerW RtlStringCopyExWorkerW_instead_use_RtlStringCchCopyW_or_RtlStringCchCopyExW;
  4216. #define RtlStringCatWorkerA RtlStringCatWorkerA_instead_use_RtlStringCchCatA_or_RtlStringCchCatExA;
  4217. #define RtlStringCatWorkerW RtlStringCatWorkerW_instead_use_RtlStringCchCatW_or_RtlStringCchCatExW;
  4218. #define RtlStringCatExWorkerA RtlStringCatExWorkerA_instead_use_RtlStringCchCatA_or_RtlStringCchCatExA;
  4219. #define RtlStringCatExWorkerW RtlStringCatExWorkerW_instead_use_RtlStringCchCatW_or_RtlStringCchCatExW;
  4220. #define RtlStringCatNWorkerA RtlStringCatNWorkerA_instead_use_RtlStringCchCatNA_or_StrincCbCatNA;
  4221. #define RtlStringCatNWorkerW RtlStringCatNWorkerW_instead_use_RtlStringCchCatNW_or_RtlStringCbCatNW;
  4222. #define RtlStringCatNExWorkerA RtlStringCatNExWorkerA_instead_use_RtlStringCchCatNExA_or_RtlStringCbCatNExA;
  4223. #define RtlStringCatNExWorkerW RtlStringCatNExWorkerW_instead_use_RtlStringCchCatNExW_or_RtlStringCbCatNExW;
  4224. #define RtlStringVPrintfWorkerA RtlStringVPrintfWorkerA_instead_use_RtlStringCchVPrintfA_or_RtlStringCchVPrintfExA;
  4225. #define RtlStringVPrintfWorkerW RtlStringVPrintfWorkerW_instead_use_RtlStringCchVPrintfW_or_RtlStringCchVPrintfExW;
  4226. #define RtlStringVPrintfExWorkerA RtlStringVPrintfExWorkerA_instead_use_RtlStringCchVPrintfA_or_RtlStringCchVPrintfExA;
  4227. #define RtlStringVPrintfExWorkerW RtlStringVPrintfExWorkerW_instead_use_RtlStringCchVPrintfW_or_RtlStringCchVPrintfExW;
  4228. #define RtlStringLengthWorkerA RtlStringLengthWorkerA_instead_use_RtlStringCchLengthA_or_RtlStringCbLengthA;
  4229. #define RtlStringLengthWorkerW RtlStringLengthWorkerW_instead_use_RtlStringCchLengthW_or_RtlStringCbLengthW;
  4230. #endif // !DEPRECATE_SUPPORTED
  4231. #ifndef NTSTRSAFE_NO_DEPRECATE
  4232. // Deprecate all of the unsafe functions to generate compiletime errors. If you do not want
  4233. // this then you can #define NTSTRSAFE_NO_DEPRECATE before including this file.
  4234. #ifdef DEPRECATE_SUPPORTED
  4235. #pragma deprecated(strcpy)
  4236. #pragma deprecated(wcscpy)
  4237. #pragma deprecated(strcat)
  4238. #pragma deprecated(wcscat)
  4239. #pragma deprecated(sprintf)
  4240. #pragma deprecated(swprintf)
  4241. #pragma deprecated(vsprintf)
  4242. #pragma deprecated(vswprintf)
  4243. #pragma deprecated(_snprintf)
  4244. #pragma deprecated(_snwprintf)
  4245. #pragma deprecated(_vsnprintf)
  4246. #pragma deprecated(_vsnwprintf)
  4247. #else // DEPRECATE_SUPPORTED
  4248. #undef strcpy
  4249. #define strcpy strcpy_instead_use_RtlStringCbCopyA_or_RtlStringCchCopyA;
  4250. #undef wcscpy
  4251. #define wcscpy wcscpy_instead_use_RtlStringCbCopyW_or_RtlStringCchCopyW;
  4252. #undef strcat
  4253. #define strcat strcat_instead_use_RtlStringCbCatA_or_RtlStringCchCatA;
  4254. #undef wcscat
  4255. #define wcscat wcscat_instead_use_RtlStringCbCatW_or_RtlStringCchCatW;
  4256. #undef sprintf
  4257. #define sprintf sprintf_instead_use_RtlStringCbPrintfA_or_RtlStringCchPrintfA;
  4258. #undef swprintf
  4259. #define swprintf swprintf_instead_use_RtlStringCbPrintfW_or_RtlStringCchPrintfW;
  4260. #undef vsprintf
  4261. #define vsprintf vsprintf_instead_use_RtlStringCbVPrintfA_or_RtlStringCchVPrintfA;
  4262. #undef vswprintf
  4263. #define vswprintf vswprintf_instead_use_RtlStringCbVPrintfW_or_RtlStringCchVPrintfW;
  4264. #undef _snprintf
  4265. #define _snprintf _snprintf_instead_use_RtlStringCbPrintfA_or_RtlStringCchPrintfA;
  4266. #undef _snwprintf
  4267. #define _snwprintf _snwprintf_instead_use_RtlStringCbPrintfW_or_RtlStringCchPrintfW;
  4268. #undef _vsnprintf
  4269. #define _vsnprintf _vsnprintf_instead_use_RtlStringCbVPrintfA_or_RtlStringCchVPrintfA;
  4270. #undef _vsnwprintf
  4271. #define _vsnwprintf _vsnwprintf_instead_use_RtlStringCbVPrintfW_or_RtlStringCchVPrintfW;
  4272. #endif // !DEPRECATE_SUPPORTED
  4273. #endif // !NTSTRSAFE_NO_DEPRECATE
  4274. #ifdef _STRSAFE_H_INCLUDED_
  4275. #pragma warning(pop)
  4276. #endif // _STRSAFE_H_INCLUDED_
  4277. #endif // _NTSTRSAFE_H_INCLUDED_