Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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