xref: /reactos/sdk/include/ddk/ntstrsafe.h (revision ea6e7740)
1 /**
2  * This file has no copyright assigned and is placed in the Public Domain.
3  * This file is part of the w64 mingw-runtime package.
4  * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5  */
6 #ifndef _NTSTRSAFE_H_INCLUDED_
7 #define _NTSTRSAFE_H_INCLUDED_
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdarg.h>
12 
13 #ifdef _MSC_VER
14 #pragma warning(push)
15 #pragma warning(disable:28719) /* disable banned api usage warning */
16 #endif /* _MSC_VER */
17 
18 #define NTSTRSAFEAPI static __inline NTSTATUS NTAPI
19 #define NTSTRSAFEVAPI static __inline NTSTATUS __cdecl
20 #define NTSTRSAFE_INLINE_API static __inline NTSTATUS NTAPI
21 
22 #ifndef NTSTRSAFE_MAX_CCH
23 #define NTSTRSAFE_MAX_CCH 2147483647
24 #endif
25 
26 #ifndef NTSTRSAFE_UNICODE_STRING_MAX_CCH
27 #define NTSTRSAFE_UNICODE_STRING_MAX_CCH 32767
28 #endif
29 
30 #ifndef _STRSAFE_H_INCLUDED_
31 #define STRSAFE_IGNORE_NULLS 0x00000100
32 #define STRSAFE_FILL_BEHIND_NULL 0x00000200
33 #define STRSAFE_FILL_ON_FAILURE 0x00000400
34 #define STRSAFE_NULL_ON_FAILURE 0x00000800
35 #define STRSAFE_NO_TRUNCATION 0x00001000
36 #define STRSAFE_IGNORE_NULL_UNICODE_STRINGS 0x00010000
37 #define STRSAFE_UNICODE_STRING_DEST_NULL_TERMINATED 0x00020000
38 
39 #define STRSAFE_VALID_FLAGS (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)
40 #define STRSAFE_UNICODE_STRING_VALID_FLAGS (STRSAFE_VALID_FLAGS | STRSAFE_IGNORE_NULL_UNICODE_STRINGS | STRSAFE_UNICODE_STRING_DEST_NULL_TERMINATED)
41 
42 #define STRSAFE_FILL_BYTE(x) ((STRSAFE_DWORD)(((x) & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL))
43 #define STRSAFE_FAILURE_BYTE(x) ((STRSAFE_DWORD)(((x) & 0x000000FF) | STRSAFE_FILL_ON_FAILURE))
44 
45 #define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)((dwFlags) & 0x000000FF))
46 #endif
47 
48 #define STRSAFE_FILL_BEHIND                 STRSAFE_FILL_BEHIND_NULL
49 #define STRSAFE_ZERO_LENGTH_ON_FAILURE      STRSAFE_NULL_ON_FAILURE
50 
51 typedef char *STRSAFE_LPSTR;
52 typedef const char *STRSAFE_LPCSTR;
53 typedef wchar_t *STRSAFE_LPWSTR;
54 typedef const wchar_t *STRSAFE_LPCWSTR;
55 
56 typedef _Null_terminated_ char *NTSTRSAFE_PSTR;
57 typedef _Null_terminated_ const char *NTSTRSAFE_PCSTR;
58 typedef _Null_terminated_ wchar_t *NTSTRSAFE_PWSTR;
59 typedef _Null_terminated_ const wchar_t *NTSTRSAFE_PCWSTR;
60 
61 typedef ULONG STRSAFE_DWORD;
62 
63 NTSTRSAFEAPI RtlStringCopyWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc);
64 NTSTRSAFEAPI RtlStringCopyWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc);
65 NTSTRSAFEAPI RtlStringCopyExWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCSTR pszSrc, STRSAFE_LPSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
66 NTSTRSAFEAPI RtlStringCopyExWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
67 NTSTRSAFEAPI RtlStringCopyNWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc, size_t cchToCopy);
68 NTSTRSAFEAPI RtlStringCopyNWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc, size_t cchToCopy);
69 NTSTRSAFEAPI RtlStringCopyNExWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCSTR pszSrc, size_t cchToCopy, STRSAFE_LPSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
70 NTSTRSAFEAPI RtlStringCopyNExWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc, size_t cchToCopy, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
71 NTSTRSAFEAPI RtlStringCatWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc);
72 NTSTRSAFEAPI RtlStringCatWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc);
73 NTSTRSAFEAPI RtlStringCatExWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCSTR pszSrc, STRSAFE_LPSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
74 NTSTRSAFEAPI RtlStringCatExWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
75 NTSTRSAFEAPI RtlStringCatNWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc, size_t cchToAppend);
76 NTSTRSAFEAPI RtlStringCatNWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc, size_t cchToAppend);
77 NTSTRSAFEAPI RtlStringCatNExWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCSTR pszSrc, size_t cchToAppend, STRSAFE_LPSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
78 NTSTRSAFEAPI RtlStringCatNExWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc, size_t cchToAppend, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags);
79 NTSTRSAFEAPI RtlStringVPrintfWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszFormat, va_list argList);
80 NTSTRSAFEAPI RtlStringVPrintfWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat, va_list argList);
81 NTSTRSAFEAPI RtlStringVPrintfExWorkerA(STRSAFE_LPSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCSTR pszFormat, va_list argList);
82 NTSTRSAFEAPI RtlStringVPrintfExWorkerW(STRSAFE_LPWSTR pszDest, size_t cchDest, size_t cbDest, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcchRemaining, STRSAFE_DWORD dwFlags, STRSAFE_LPCWSTR pszFormat, va_list argList);
83 NTSTRSAFEAPI RtlUnicodeStringValidate(PCUNICODE_STRING SourceString);
84 
85 NTSTRSAFEAPI
86 RtlStringLengthWorkerA(
87     _In_reads_or_z_(cchMax) STRSAFE_LPCSTR psz,
88     _In_ _In_range_(<=, NTSTRSAFE_MAX_CCH) size_t cchMax,
89     _Out_opt_ _Deref_out_range_(<, cchMax) size_t *pcchLength);
90 
91 NTSTRSAFEAPI
92 RtlStringLengthWorkerW(
93     _In_reads_or_z_(cchMax) STRSAFE_LPCWSTR psz,
94     _In_ _In_range_(<=, NTSTRSAFE_MAX_CCH) size_t cchMax,
95     _Out_opt_ _Deref_out_range_(<, cchMax) size_t *pcchLength);
96 
97 NTSTRSAFEAPI
98 RtlStringCchCopyA(
99     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
100     _In_ size_t cchDest,
101     _In_ NTSTRSAFE_PCSTR pszSrc);
102 
103 NTSTRSAFEAPI
104 RtlStringCchCopyW(
105     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
106     _In_ size_t cchDest,
107     _In_ NTSTRSAFE_PCWSTR pszSrc);
108 
109 NTSTRSAFEAPI
110 RtlStringCchCopyA(
111     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
112     _In_ size_t cchDest,
113     _In_ NTSTRSAFE_PCSTR pszSrc)
114 {
115     if (cchDest > NTSTRSAFE_MAX_CCH)
116     {
117         if (cchDest > 0)
118             *pszDest = '\0';
119 
120         return STATUS_INVALID_PARAMETER;
121     }
122 
123     return RtlStringCopyWorkerA(pszDest, cchDest, pszSrc);
124 }
125 
126 NTSTRSAFEAPI
127 RtlStringCchCopyW(
128     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
129     _In_ size_t cchDest,
130     _In_ NTSTRSAFE_PCWSTR pszSrc)
131 {
132     if (cchDest > NTSTRSAFE_MAX_CCH)
133     {
134         if (cchDest > 0)
135             *pszDest = '\0';
136 
137         return STATUS_INVALID_PARAMETER;
138     }
139 
140     return RtlStringCopyWorkerW(pszDest, cchDest, pszSrc);
141 }
142 
143 NTSTRSAFEAPI
144 RtlStringCbCopyA(
145     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
146     _In_ size_t cbDest,
147     _In_ NTSTRSAFE_PCSTR pszSrc);
148 
149 NTSTRSAFEAPI
150 RtlStringCbCopyW(
151     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
152     _In_ size_t cbDest,
153     _In_ NTSTRSAFE_PCWSTR pszSrc);
154 
155 NTSTRSAFEAPI
156 RtlStringCbCopyA(
157     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
158     _In_ size_t cbDest,
159     _In_ NTSTRSAFE_PCSTR pszSrc)
160 {
161     size_t cchDest = cbDest / sizeof(char);
162 
163     if (cchDest > NTSTRSAFE_MAX_CCH)
164     {
165         if (cchDest > 0)
166             *pszDest = '\0';
167 
168         return STATUS_INVALID_PARAMETER;
169     }
170     return RtlStringCopyWorkerA(pszDest, cbDest, pszSrc);
171 }
172 
173 NTSTRSAFEAPI
174 RtlStringCbCopyW(
175     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
176     _In_ size_t cbDest,
177     _In_ NTSTRSAFE_PCWSTR pszSrc)
178 {
179     size_t cchDest = cbDest / sizeof(wchar_t);
180 
181     if (cchDest > NTSTRSAFE_MAX_CCH)
182     {
183         if (cchDest > 0)
184             *pszDest = '\0';
185 
186         return STATUS_INVALID_PARAMETER;
187     }
188     return RtlStringCopyWorkerW(pszDest, cchDest, pszSrc);
189 }
190 
191 NTSTRSAFEAPI
192 RtlStringCchCopyExA(
193     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
194     _In_ size_t cchDest,
195     _In_ NTSTRSAFE_PCSTR pszSrc,
196     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
197     _Out_opt_ size_t *pcchRemaining,
198     _In_ STRSAFE_DWORD dwFlags);
199 
200 NTSTRSAFEAPI
201 RtlStringCchCopyExW(
202     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
203     _In_ size_t cchDest,
204     _In_ NTSTRSAFE_PCWSTR pszSrc,
205     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
206     _Out_opt_ size_t *pcchRemaining,
207     _In_ STRSAFE_DWORD dwFlags);
208 
209 NTSTRSAFEAPI
210 RtlStringCchCopyExA(
211     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
212     _In_ size_t cchDest,
213     _In_ NTSTRSAFE_PCSTR pszSrc,
214     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
215     _Out_opt_ size_t *pcchRemaining,
216     _In_ STRSAFE_DWORD dwFlags)
217 {
218     if (cchDest > NTSTRSAFE_MAX_CCH)
219     {
220         if (cchDest > 0)
221             *pszDest = '\0';
222 
223         return STATUS_INVALID_PARAMETER;
224     }
225 
226     return RtlStringCopyExWorkerA(pszDest, cchDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
227 }
228 
229 NTSTRSAFEAPI
230 RtlStringCchCopyExW(
231     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
232     _In_ size_t cchDest,
233     _In_ NTSTRSAFE_PCWSTR pszSrc,
234     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
235     _Out_opt_ size_t *pcchRemaining,
236     _In_ STRSAFE_DWORD dwFlags)
237 {
238     size_t cbDest = cchDest * sizeof(wchar_t);
239 
240     if (cchDest > NTSTRSAFE_MAX_CCH)
241     {
242         if (cchDest > 0)
243             *pszDest = L'\0';
244 
245         return STATUS_INVALID_PARAMETER;
246     }
247 
248     return RtlStringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
249 }
250 
251 NTSTRSAFEAPI
252 RtlStringCbCopyExA(
253     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
254     _In_ size_t cbDest,
255     _In_ NTSTRSAFE_PCSTR pszSrc,
256     _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR *ppszDestEnd,
257     _Out_opt_ size_t *pcbRemaining,
258     _In_ STRSAFE_DWORD dwFlags);
259 
260 NTSTRSAFEAPI
261 RtlStringCbCopyExW(
262     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
263     _In_ size_t cbDest,
264     _In_ NTSTRSAFE_PCWSTR pszSrc,
265     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
266     _Out_opt_ size_t *pcbRemaining,
267     _In_ STRSAFE_DWORD dwFlags);
268 
269 NTSTRSAFEAPI
270 RtlStringCbCopyExA(
271     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
272     _In_ size_t cbDest,
273     _In_ NTSTRSAFE_PCSTR pszSrc,
274     _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR *ppszDestEnd,
275     _Out_opt_ size_t *pcbRemaining,
276     _In_ STRSAFE_DWORD dwFlags)
277 {
278     NTSTATUS Status;
279     size_t cchDest = cbDest / sizeof(char);
280     size_t cchRemaining = 0;
281 
282     if (cchDest > NTSTRSAFE_MAX_CCH)
283     {
284         if (cchDest > 0)
285             *pszDest = '\0';
286 
287         return STATUS_INVALID_PARAMETER;
288     }
289 
290     Status = RtlStringCopyExWorkerA(pszDest, cbDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
291     if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
292     {
293         if (pcbRemaining)
294             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
295     }
296     return Status;
297 }
298 
299 NTSTRSAFEAPI
300 RtlStringCbCopyExW(
301     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
302     _In_ size_t cbDest,
303     _In_ NTSTRSAFE_PCWSTR pszSrc,
304     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
305     _Out_opt_ size_t *pcbRemaining,
306     _In_ STRSAFE_DWORD dwFlags)
307 {
308     NTSTATUS Status;
309     size_t cchDest = cbDest / sizeof(wchar_t);
310     size_t cchRemaining = 0;
311 
312     if (cchDest > NTSTRSAFE_MAX_CCH)
313     {
314         if (cchDest > 0)
315             *pszDest = L'\0';
316 
317         return STATUS_INVALID_PARAMETER;
318     }
319 
320     Status = RtlStringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
321     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
322     {
323         if (pcbRemaining)
324             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
325     }
326     return Status;
327 }
328 
329 NTSTRSAFEAPI
330 RtlStringCchCopyNA(
331     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
332     _In_ size_t cchDest,
333     _In_reads_or_z_(cchToCopy) STRSAFE_LPCSTR pszSrc,
334     _In_ size_t cchToCopy);
335 
336 NTSTRSAFEAPI
337 RtlStringCchCopyNW(
338     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
339     _In_ size_t cchDest,
340     _In_reads_or_z_(cchToCopy) STRSAFE_LPCWSTR pszSrc,
341     _In_ size_t cchToCopy);
342 
343 
344 NTSTRSAFEAPI
345 RtlStringCchCopyNA(
346     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
347     _In_ size_t cchDest,
348     _In_reads_or_z_(cchToCopy) STRSAFE_LPCSTR pszSrc,
349     _In_ size_t cchToCopy)
350 {
351     if (cchDest > NTSTRSAFE_MAX_CCH || cchToCopy > NTSTRSAFE_MAX_CCH)
352     {
353         if (cchDest > 0)
354             *pszDest = '\0';
355 
356         return STATUS_INVALID_PARAMETER;
357     }
358 
359     return RtlStringCopyNWorkerA(pszDest, cchDest, pszSrc, cchToCopy);
360 }
361 
362 NTSTRSAFEAPI
363 RtlStringCchCopyNW(
364     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
365     _In_ size_t cchDest,
366     _In_reads_or_z_(cchToCopy) STRSAFE_LPCWSTR pszSrc,
367     _In_ size_t cchToCopy)
368 {
369     if (cchDest > NTSTRSAFE_MAX_CCH || cchToCopy > NTSTRSAFE_MAX_CCH)
370     {
371         if (cchDest > 0)
372             *pszDest = L'\0';
373 
374         return STATUS_INVALID_PARAMETER;
375     }
376 
377     return RtlStringCopyNWorkerW(pszDest, cchDest, pszSrc, cchToCopy);
378 }
379 
380 NTSTRSAFEAPI
381 RtlStringCbCopyNA(
382     _Out_writes_bytes_(cbDest) NTSTRSAFE_PSTR pszDest,
383     _In_ size_t cbDest,
384     _In_reads_bytes_(cbToCopy) STRSAFE_LPCSTR pszSrc,
385     _In_ size_t cbToCopy);
386 
387 NTSTRSAFEAPI
388 RtlStringCbCopyNW(
389     _Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest,
390     _In_ size_t cbDest,
391     _In_reads_bytes_(cbToCopy) STRSAFE_LPCWSTR pszSrc,
392     _In_ size_t cbToCopy);
393 
394 NTSTRSAFEAPI
395 RtlStringCbCopyNA(
396     _Out_writes_bytes_(cbDest) NTSTRSAFE_PSTR pszDest,
397     _In_ size_t cbDest,
398     _In_reads_bytes_(cbToCopy) STRSAFE_LPCSTR pszSrc,
399     _In_ size_t cbToCopy)
400 {
401     size_t cchDest = cbDest / sizeof(char);
402     size_t cchToCopy = cbToCopy / sizeof(char);
403 
404     if (cchDest > NTSTRSAFE_MAX_CCH || cchToCopy > NTSTRSAFE_MAX_CCH)
405     {
406         if (cchDest > 0)
407             *pszDest = '\0';
408 
409         return STATUS_INVALID_PARAMETER;
410     }
411 
412     return RtlStringCopyNWorkerA(pszDest, cchDest, pszSrc, cchToCopy);
413 }
414 
415 NTSTRSAFEAPI
416 RtlStringCbCopyNW(
417     _Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest,
418     _In_ size_t cbDest,
419     _In_reads_bytes_(cbToCopy) STRSAFE_LPCWSTR pszSrc,
420     _In_ size_t cbToCopy)
421 {
422     size_t cchDest = cbDest / sizeof(wchar_t);
423     size_t cchToCopy = cbToCopy / sizeof(wchar_t);
424 
425     if (cchDest > NTSTRSAFE_MAX_CCH || cchToCopy > NTSTRSAFE_MAX_CCH)
426     {
427         if (cchDest > 0)
428             *pszDest = L'\0';
429 
430         return STATUS_INVALID_PARAMETER;
431     }
432 
433     return RtlStringCopyNWorkerW(pszDest, cchDest, pszSrc, cchToCopy);
434 }
435 
436 NTSTRSAFEAPI
437 RtlStringCchCopyNExA(
438     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
439     _In_ size_t cchDest,
440     _In_reads_or_z_(cchToCopy) STRSAFE_LPCSTR pszSrc,
441     _In_ size_t cchToCopy,
442     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
443     _Out_opt_ size_t *pcchRemaining,
444     _In_ STRSAFE_DWORD dwFlags);
445 
446 NTSTRSAFEAPI
447 RtlStringCchCopyNExW(
448     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
449     _In_ size_t cchDest,
450     _In_reads_or_z_(cchToCopy) STRSAFE_LPCWSTR pszSrc,
451     _In_ size_t cchToCopy,
452     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
453     _Out_opt_ size_t *pcchRemaining,
454     _In_ STRSAFE_DWORD dwFlags);
455 
456 NTSTRSAFEAPI
457 RtlStringCchCopyNExA(
458     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
459     _In_ size_t cchDest,
460     _In_reads_or_z_(cchToCopy) STRSAFE_LPCSTR pszSrc,
461     _In_ size_t cchToCopy,
462     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
463     _Out_opt_ size_t *pcchRemaining,
464     _In_ STRSAFE_DWORD dwFlags)
465 {
466     if (cchDest > NTSTRSAFE_MAX_CCH)
467     {
468         if (cchDest > 0)
469             *pszDest = '\0';
470 
471         return STATUS_INVALID_PARAMETER;
472     }
473 
474     return RtlStringCopyNExWorkerA(pszDest, cchDest, cchDest, pszSrc, cchToCopy, ppszDestEnd, pcchRemaining, dwFlags);
475 }
476 
477 NTSTRSAFEAPI
478 RtlStringCchCopyNExW(
479     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
480     _In_ size_t cchDest,
481     _In_reads_or_z_(cchToCopy) STRSAFE_LPCWSTR pszSrc,
482     _In_ size_t cchToCopy,
483     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
484     _Out_opt_ size_t *pcchRemaining,
485     _In_ STRSAFE_DWORD dwFlags)
486 {
487     if (cchDest > NTSTRSAFE_MAX_CCH)
488     {
489         if (cchDest > 0)
490             *pszDest = L'\0';
491 
492         return STATUS_INVALID_PARAMETER;
493     }
494 
495     return RtlStringCopyNExWorkerW(pszDest, cchDest, cchDest * sizeof(wchar_t), pszSrc, cchToCopy, ppszDestEnd, pcchRemaining, dwFlags);
496 }
497 
498 NTSTRSAFEAPI
499 RtlStringCbCopyNExA(
500     _Out_writes_bytes_(cbDest) NTSTRSAFE_PSTR pszDest,
501     _In_ size_t cbDest,
502     _In_reads_bytes_(cbToCopy) STRSAFE_LPCSTR pszSrc,
503     _In_ size_t cbToCopy,
504     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
505     _Out_opt_ size_t *pcbRemaining,
506     _In_ STRSAFE_DWORD dwFlags);
507 
508 NTSTRSAFEAPI
509 RtlStringCbCopyNExW(
510     _Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest,
511     _In_ size_t cbDest,
512     _In_reads_bytes_(cbToCopy) STRSAFE_LPCWSTR pszSrc,
513     _In_ size_t cbToCopy,
514     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
515     _Out_opt_ size_t *pcbRemaining,
516     _In_ STRSAFE_DWORD dwFlags);
517 
518 NTSTRSAFEAPI
519 RtlStringCbCopyNExA(
520     _Out_writes_bytes_(cbDest) STRSAFE_LPSTR pszDest,
521     _In_ size_t cbDest,
522     _In_reads_bytes_(cbToCopy) STRSAFE_LPCSTR pszSrc,
523     _In_ size_t cbToCopy,
524     _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR *ppszDestEnd,
525     _Out_opt_ size_t *pcbRemaining,
526     _In_ STRSAFE_DWORD dwFlags)
527 {
528     NTSTATUS Status;
529     size_t cchRemaining = 0;
530 
531     if (cbDest > NTSTRSAFE_MAX_CCH)
532     {
533         if ((pszDest != NULL) && (cbDest > 0))
534             *pszDest = L'\0';
535 
536         return STATUS_INVALID_PARAMETER;
537     }
538 
539     Status = RtlStringCopyNExWorkerA(pszDest, cbDest, cbDest, pszSrc, cbToCopy, ppszDestEnd, &cchRemaining, dwFlags);
540     if ((NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) && pcbRemaining)
541         *pcbRemaining = cchRemaining;
542 
543     return Status;
544 }
545 
546 NTSTRSAFEAPI
547 RtlStringCbCopyNExW(
548     _Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest,
549     _In_ size_t cbDest,
550     _In_reads_bytes_(cbToCopy) STRSAFE_LPCWSTR pszSrc,
551     _In_ size_t cbToCopy,
552     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
553     _Out_opt_ size_t *pcbRemaining,
554     _In_ STRSAFE_DWORD dwFlags)
555 {
556     NTSTATUS Status;
557     size_t cchDest = cbDest / sizeof(wchar_t);
558     size_t cchToCopy = cbToCopy / sizeof(wchar_t);
559     size_t cchRemaining = 0;
560 
561     if (cchDest > NTSTRSAFE_MAX_CCH)
562     {
563         if ((pszDest != NULL) && (cbDest > 0))
564             *pszDest = L'\0';
565 
566         return STATUS_INVALID_PARAMETER;
567     }
568 
569     Status = RtlStringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchToCopy, ppszDestEnd, &cchRemaining, dwFlags);
570     if ((NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) && pcbRemaining)
571         *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
572 
573     return Status;
574 }
575 
576 NTSTRSAFEAPI
577 RtlStringCchCatA(
578     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
579     _In_ size_t cchDest,
580     _In_ NTSTRSAFE_PCSTR pszSrc);
581 
582 NTSTRSAFEAPI
583 RtlStringCchCatW(
584     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
585     _In_ size_t cchDest,
586     _In_ NTSTRSAFE_PCWSTR pszSrc);
587 
588 NTSTRSAFEAPI
589 RtlStringCchCatA(
590     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
591     _In_ size_t cchDest,
592     _In_ NTSTRSAFE_PCSTR pszSrc)
593 {
594     if (cchDest > NTSTRSAFE_MAX_CCH)
595         return STATUS_INVALID_PARAMETER;
596 
597     return RtlStringCatWorkerA(pszDest, cchDest, pszSrc);
598 }
599 
600 NTSTRSAFEAPI
601 RtlStringCchCatW(
602     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
603     _In_ size_t cchDest,
604     _In_ NTSTRSAFE_PCWSTR pszSrc)
605 {
606     if (cchDest > NTSTRSAFE_MAX_CCH)
607         return STATUS_INVALID_PARAMETER;
608 
609     return RtlStringCatWorkerW(pszDest, cchDest, pszSrc);
610 }
611 
612 NTSTRSAFEAPI
613 RtlStringCbCatA(
614     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
615     _In_ size_t cbDest,
616     _In_ NTSTRSAFE_PCSTR pszSrc);
617 
618 NTSTRSAFEAPI
619 RtlStringCbCatW(
620     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
621     _In_ size_t cbDest,
622     _In_ NTSTRSAFE_PCWSTR pszSrc);
623 
624 NTSTRSAFEAPI
625 RtlStringCbCatA(
626     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
627     _In_ size_t cbDest,
628     _In_ NTSTRSAFE_PCSTR pszSrc)
629 {
630     if (cbDest > NTSTRSAFE_MAX_CCH)
631         return STATUS_INVALID_PARAMETER;
632     return RtlStringCatWorkerA(pszDest, cbDest, pszSrc);
633 }
634 
635 NTSTRSAFEAPI
636 RtlStringCbCatW(
637     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
638     _In_ size_t cbDest,
639     _In_ NTSTRSAFE_PCWSTR pszSrc)
640 {
641     size_t cchDest = cbDest / sizeof(wchar_t);
642 
643     if (cchDest > NTSTRSAFE_MAX_CCH)
644         return STATUS_INVALID_PARAMETER;
645 
646     return RtlStringCatWorkerW(pszDest, cchDest, pszSrc);
647 }
648 
649 NTSTRSAFEAPI
650 RtlStringCchCatExA(
651     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
652     _In_ size_t cchDest,
653     _In_ NTSTRSAFE_PCSTR pszSrc,
654     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
655     _Out_opt_ size_t *pcchRemaining,
656     _In_ STRSAFE_DWORD dwFlags);
657 
658 NTSTRSAFEAPI
659 RtlStringCchCatExW(
660     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
661     _In_ size_t cchDest,
662     _In_ NTSTRSAFE_PCWSTR pszSrc,
663     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
664     _Out_opt_ size_t *pcchRemaining,
665     _In_ STRSAFE_DWORD dwFlags);
666 
667 NTSTRSAFEAPI
668 RtlStringCchCatExA(
669     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
670     _In_ size_t cchDest,
671     _In_ NTSTRSAFE_PCSTR pszSrc,
672     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
673     _Out_opt_ size_t *pcchRemaining,
674     _In_ STRSAFE_DWORD dwFlags)
675 {
676     if (cchDest > NTSTRSAFE_MAX_CCH)
677         return STATUS_INVALID_PARAMETER;
678 
679     return RtlStringCatExWorkerA(pszDest, cchDest, cchDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
680 }
681 
682 NTSTRSAFEAPI
683 RtlStringCchCatExW(
684     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
685     _In_ size_t cchDest,
686     _In_ NTSTRSAFE_PCWSTR pszSrc,
687     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
688     _Out_opt_ size_t *pcchRemaining,
689     _In_ STRSAFE_DWORD dwFlags)
690 {
691     size_t cbDest = cchDest * sizeof(wchar_t);
692 
693     if (cchDest > NTSTRSAFE_MAX_CCH)
694         return STATUS_INVALID_PARAMETER;
695 
696     return RtlStringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
697 }
698 
699 NTSTRSAFEAPI
700 RtlStringCbCatExA(
701     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
702     _In_ size_t cbDest,
703     _In_ NTSTRSAFE_PCSTR pszSrc,
704     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
705     _Out_opt_ size_t *pcbRemaining,
706     _In_ STRSAFE_DWORD dwFlags);
707 
708 NTSTRSAFEAPI
709 RtlStringCbCatExW(
710     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
711     _In_ size_t cbDest,
712     _In_ NTSTRSAFE_PCWSTR pszSrc,
713     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
714     _Out_opt_ size_t *pcbRemaining,
715     _In_ STRSAFE_DWORD dwFlags);
716 
717 NTSTRSAFEAPI
718 RtlStringCbCatExA(
719     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
720     _In_ size_t cbDest,
721     _In_ NTSTRSAFE_PCSTR pszSrc,
722     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
723     _Out_opt_ size_t *pcbRemaining,
724     _In_ STRSAFE_DWORD dwFlags)
725 {
726     NTSTATUS Status;
727     size_t cchRemaining = 0;
728 
729     if (cbDest > NTSTRSAFE_MAX_CCH)
730         Status = STATUS_INVALID_PARAMETER;
731     else
732         Status = RtlStringCatExWorkerA(pszDest, cbDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
733 
734     if ((NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) && pcbRemaining)
735         *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
736 
737     return Status;
738 }
739 
740 NTSTRSAFEAPI
741 RtlStringCbCatExW(
742     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
743     _In_ size_t cbDest,
744     _In_ NTSTRSAFE_PCWSTR pszSrc,
745     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
746     _Out_opt_ size_t *pcbRemaining,
747     _In_ STRSAFE_DWORD dwFlags)
748 {
749     NTSTATUS Status;
750     size_t cchDest = cbDest / sizeof(wchar_t);
751     size_t cchRemaining = 0;
752 
753     if (cchDest > NTSTRSAFE_MAX_CCH)
754         Status = STATUS_INVALID_PARAMETER;
755     else
756         Status = RtlStringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
757 
758     if ((NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) && pcbRemaining)
759         *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
760 
761     return Status;
762 }
763 
764 NTSTRSAFEAPI
765 RtlStringCchCatNA(
766     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
767     _In_ size_t cchDest,
768     _In_reads_or_z_(cchToAppend) STRSAFE_LPCSTR pszSrc,
769     _In_ size_t cchToAppend);
770 
771 NTSTRSAFEAPI
772 RtlStringCchCatNW(
773     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
774     _In_ size_t cchDest,
775     _In_reads_or_z_(cchToAppend) STRSAFE_LPCWSTR pszSrc,
776     _In_ size_t cchToAppend);
777 
778 NTSTRSAFEAPI
779 RtlStringCchCatNA(
780     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
781     _In_ size_t cchDest,
782     _In_reads_or_z_(cchToAppend) STRSAFE_LPCSTR pszSrc,
783     _In_ size_t cchToAppend)
784 {
785     if (cchDest > NTSTRSAFE_MAX_CCH)
786         return STATUS_INVALID_PARAMETER;
787 
788     return RtlStringCatNWorkerA(pszDest, cchDest, pszSrc, cchToAppend);
789 }
790 
791 NTSTRSAFEAPI
792 RtlStringCchCatNW(
793     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
794     _In_ size_t cchDest,
795     _In_reads_or_z_(cchToAppend) STRSAFE_LPCWSTR pszSrc,
796     _In_ size_t cchToAppend)
797 {
798     if (cchDest > NTSTRSAFE_MAX_CCH)
799         return STATUS_INVALID_PARAMETER;
800 
801     return RtlStringCatNWorkerW(pszDest, cchDest, pszSrc, cchToAppend);
802 }
803 
804 NTSTRSAFEAPI
805 RtlStringCbCatNA(
806     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
807     _In_ size_t cbDest,
808     _In_reads_bytes_(cbToAppend) STRSAFE_LPCSTR pszSrc,
809     _In_ size_t cbToAppend);
810 
811 NTSTRSAFEAPI
812 RtlStringCbCatNW(
813     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
814     _In_ size_t cbDest,
815     _In_reads_bytes_(cbToAppend) STRSAFE_LPCWSTR pszSrc,
816     _In_ size_t cbToAppend);
817 
818 NTSTRSAFEAPI
819 RtlStringCbCatNA(
820     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
821     _In_ size_t cbDest,
822     _In_reads_bytes_(cbToAppend) STRSAFE_LPCSTR pszSrc,
823     _In_ size_t cbToAppend)
824 {
825     if (cbDest > NTSTRSAFE_MAX_CCH)
826         return STATUS_INVALID_PARAMETER;
827 
828     return RtlStringCatNWorkerA(pszDest, cbDest, pszSrc, cbToAppend);
829 }
830 
831 NTSTRSAFEAPI
832 RtlStringCbCatNW(
833     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
834     _In_ size_t cbDest,
835     _In_reads_bytes_(cbToAppend) STRSAFE_LPCWSTR pszSrc,
836     _In_ size_t cbToAppend)
837 {
838     size_t cchDest = cbDest / sizeof(wchar_t);
839     size_t cchToAppend = cbToAppend / sizeof(wchar_t);
840 
841     if (cchDest > NTSTRSAFE_MAX_CCH)
842         return STATUS_INVALID_PARAMETER;
843 
844     return RtlStringCatNWorkerW(pszDest, cchDest, pszSrc, cchToAppend);
845 }
846 
847 NTSTRSAFEAPI
848 RtlStringCchCatNExA(
849     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
850     _In_ size_t cchDest,
851     _In_reads_or_z_(cchToAppend) STRSAFE_LPCSTR pszSrc,
852     _In_ size_t cchToAppend,
853     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
854     _Out_opt_ size_t *pcchRemaining,
855     _In_ STRSAFE_DWORD dwFlags);
856 
857 NTSTRSAFEAPI
858 RtlStringCchCatNExW(
859     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
860     _In_ size_t cchDest,
861     _In_reads_or_z_(cchToAppend) STRSAFE_LPCWSTR pszSrc,
862     _In_ size_t cchToAppend,
863     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
864     _Out_opt_ size_t *pcchRemaining,
865     _In_ STRSAFE_DWORD dwFlags);
866 
867 NTSTRSAFEAPI
868 RtlStringCchCatNExA(
869     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
870     _In_ size_t cchDest,
871     _In_reads_or_z_(cchToAppend) STRSAFE_LPCSTR pszSrc,
872     _In_ size_t cchToAppend,
873     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
874     _Out_opt_ size_t *pcchRemaining,
875     _In_ STRSAFE_DWORD dwFlags)
876 {
877     if (cchDest > NTSTRSAFE_MAX_CCH)
878         return STATUS_INVALID_PARAMETER;
879 
880     return RtlStringCatNExWorkerA(pszDest, cchDest, cchDest, pszSrc, cchToAppend, ppszDestEnd, pcchRemaining, dwFlags);
881 }
882 
883 NTSTRSAFEAPI
884 RtlStringCchCatNExW(
885     _Inout_updates_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
886     _In_ size_t cchDest,
887     _In_reads_or_z_(cchToAppend) STRSAFE_LPCWSTR pszSrc,
888     _In_ size_t cchToAppend,
889     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
890     _Out_opt_ size_t *pcchRemaining,
891     _In_ STRSAFE_DWORD dwFlags)
892 {
893     if (cchDest > NTSTRSAFE_MAX_CCH)
894         return STATUS_INVALID_PARAMETER;
895 
896     return RtlStringCatNExWorkerW(pszDest, cchDest, (cchDest * sizeof(wchar_t)), pszSrc, cchToAppend, ppszDestEnd, pcchRemaining, dwFlags);
897 }
898 
899 NTSTRSAFEAPI
900 RtlStringCbCatNExA(
901     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
902     _In_ size_t cbDest,
903     _In_reads_bytes_(cbToAppend) STRSAFE_LPCSTR pszSrc,
904     _In_ size_t cbToAppend,
905     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
906     _Out_opt_ size_t *pcbRemaining,
907     _In_ STRSAFE_DWORD dwFlags);
908 
909 NTSTRSAFEAPI
910 RtlStringCbCatNExW(
911     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
912     _In_ size_t cbDest,
913     _In_reads_bytes_(cbToAppend) STRSAFE_LPCWSTR pszSrc,
914     _In_ size_t cbToAppend,
915     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
916     _Out_opt_ size_t *pcbRemaining,
917     _In_ STRSAFE_DWORD dwFlags);
918 
919 NTSTRSAFEAPI
920 RtlStringCbCatNExA(
921     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
922     _In_ size_t cbDest,
923     _In_reads_bytes_(cbToAppend) STRSAFE_LPCSTR pszSrc,
924     _In_ size_t cbToAppend,
925     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
926     _Out_opt_ size_t *pcbRemaining,
927     _In_ STRSAFE_DWORD dwFlags)
928 {
929     NTSTATUS Status;
930     size_t cchRemaining = 0;
931 
932     if (cbDest > NTSTRSAFE_MAX_CCH)
933         Status = STATUS_INVALID_PARAMETER;
934     else
935         Status = RtlStringCatNExWorkerA(pszDest, cbDest, cbDest, pszSrc, cbToAppend, ppszDestEnd, &cchRemaining, dwFlags);
936 
937     if ((NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) && pcbRemaining)
938         *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
939 
940     return Status;
941 }
942 
943 NTSTRSAFEAPI
944 RtlStringCbCatNExW(
945     _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
946     _In_ size_t cbDest,
947     _In_reads_bytes_(cbToAppend) STRSAFE_LPCWSTR pszSrc,
948     _In_ size_t cbToAppend,
949     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
950     _Out_opt_ size_t *pcbRemaining,
951     _In_ STRSAFE_DWORD dwFlags)
952 {
953     NTSTATUS Status;
954     size_t cchDest = cbDest / sizeof(wchar_t);
955     size_t cchToAppend = cbToAppend / sizeof(wchar_t);
956     size_t cchRemaining = 0;
957 
958     if (cchDest > NTSTRSAFE_MAX_CCH)
959         Status = STATUS_INVALID_PARAMETER;
960     else
961         Status = RtlStringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchToAppend, ppszDestEnd, &cchRemaining, dwFlags);
962 
963     if ((NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) && pcbRemaining)
964         *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
965 
966     return Status;
967 }
968 
969 NTSTRSAFEAPI
970 RtlStringCchVPrintfA(
971     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
972     _In_ size_t cchDest,
973     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
974     _In_ va_list argList);
975 
976 NTSTRSAFEAPI
977 RtlStringCchVPrintfW(
978     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
979     _In_ size_t cchDest,
980     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
981     _In_ va_list argList);
982 
983 NTSTRSAFEAPI
984 RtlStringCchVPrintfA(
985     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
986     _In_ size_t cchDest,
987     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
988     _In_ va_list argList)
989 {
990     if (cchDest > NTSTRSAFE_MAX_CCH)
991     {
992         if (cchDest > 0)
993             *pszDest = '\0';
994 
995         return STATUS_INVALID_PARAMETER;
996     }
997 
998     return RtlStringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
999 }
1000 
1001 NTSTRSAFEAPI
1002 RtlStringCchVPrintfW(
1003     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1004     _In_ size_t cchDest,
1005     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1006     _In_ va_list argList)
1007 {
1008     if (cchDest > NTSTRSAFE_MAX_CCH)
1009     {
1010         if (cchDest > 0)
1011             *pszDest = L'\0';
1012 
1013         return STATUS_INVALID_PARAMETER;
1014     }
1015 
1016     return RtlStringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
1017 }
1018 
1019 NTSTRSAFEAPI
1020 RtlStringCbVPrintfA(
1021     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1022     _In_ size_t cbDest,
1023     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1024     _In_ va_list argList);
1025 
1026 NTSTRSAFEAPI
1027 RtlStringCbVPrintfW(
1028     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1029     _In_ size_t cbDest,
1030     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1031     _In_ va_list argList);
1032 
1033 NTSTRSAFEAPI
1034 RtlStringCbVPrintfA(
1035     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1036     _In_ size_t cbDest,
1037     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1038     _In_ va_list argList)
1039 {
1040     if (cbDest > NTSTRSAFE_MAX_CCH)
1041     {
1042         if (cbDest > 0)
1043             *pszDest = '\0';
1044 
1045         return STATUS_INVALID_PARAMETER;
1046     }
1047 
1048     return RtlStringVPrintfWorkerA(pszDest, cbDest, pszFormat, argList);
1049 }
1050 
1051 NTSTRSAFEAPI
1052 RtlStringCbVPrintfW(
1053     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1054     _In_ size_t cbDest,
1055     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1056     _In_ va_list argList)
1057 {
1058     size_t cchDest = cbDest / sizeof(wchar_t);
1059 
1060     if (cchDest > NTSTRSAFE_MAX_CCH)
1061     {
1062         if (cchDest > 0)
1063             *pszDest = L'\0';
1064         return STATUS_INVALID_PARAMETER;
1065     }
1066 
1067     return RtlStringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
1068 }
1069 
1070 NTSTRSAFEVAPI
1071 RtlStringCchPrintfA(
1072     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1073     _In_ size_t cchDest,
1074     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1075     ...);
1076 
1077 NTSTRSAFEVAPI
1078 RtlStringCchPrintfW(
1079     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1080     _In_ size_t cchDest,
1081     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1082     ...);
1083 
1084 NTSTRSAFEVAPI
1085 RtlStringCchPrintfA(
1086     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1087     _In_ size_t cchDest,
1088     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1089     ...)
1090 {
1091     NTSTATUS Status;
1092     va_list argList;
1093 
1094     if (cchDest > NTSTRSAFE_MAX_CCH)
1095     {
1096         if (cchDest > 0)
1097             *pszDest = '\0';
1098 
1099         return STATUS_INVALID_PARAMETER;
1100     }
1101 
1102     va_start(argList, pszFormat);
1103     Status = RtlStringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
1104     va_end(argList);
1105 
1106     return Status;
1107 }
1108 
1109 NTSTRSAFEVAPI
1110 RtlStringCchPrintfW(
1111     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1112     _In_ size_t cchDest,
1113     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1114     ...)
1115 {
1116     NTSTATUS Status;
1117     va_list argList;
1118 
1119     if (cchDest > NTSTRSAFE_MAX_CCH)
1120     {
1121         if (cchDest > 0)
1122             *pszDest = L'\0';
1123         return STATUS_INVALID_PARAMETER;
1124     }
1125 
1126     va_start(argList, pszFormat);
1127     Status = RtlStringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
1128     va_end(argList);
1129 
1130     return Status;
1131 }
1132 
1133 NTSTRSAFEVAPI
1134 RtlStringCbPrintfA(
1135     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1136     _In_ size_t cbDest,
1137     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1138     ...);
1139 
1140 NTSTRSAFEVAPI
1141 RtlStringCbPrintfW(
1142     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1143     _In_ size_t cbDest,
1144     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1145     ...);
1146 
1147 NTSTRSAFEVAPI
1148 RtlStringCbPrintfA(
1149     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1150     _In_ size_t cbDest,
1151     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1152     ...)
1153 {
1154     NTSTATUS Status;
1155     va_list argList;
1156 
1157     if (cbDest > NTSTRSAFE_MAX_CCH)
1158     {
1159         if (cbDest > 0)
1160             *pszDest = '\0';
1161 
1162         return STATUS_INVALID_PARAMETER;
1163     }
1164 
1165     va_start(argList, pszFormat);
1166     Status = RtlStringVPrintfWorkerA(pszDest, cbDest, pszFormat, argList);
1167     va_end(argList);
1168 
1169     return Status;
1170 }
1171 
1172 NTSTRSAFEVAPI
1173 RtlStringCbPrintfW(
1174     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1175     _In_ size_t cbDest,
1176     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1177     ...)
1178 {
1179     NTSTATUS Status;
1180     va_list argList;
1181     size_t cchDest = cbDest / sizeof(wchar_t);
1182 
1183     if (cchDest > NTSTRSAFE_MAX_CCH)
1184     {
1185         if (cchDest > 0)
1186             *pszDest = L'\0';
1187         return STATUS_INVALID_PARAMETER;
1188     }
1189 
1190     va_start(argList, pszFormat);
1191     Status = RtlStringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
1192     va_end(argList);
1193 
1194     return Status;
1195 }
1196 
1197 NTSTRSAFEVAPI
1198 RtlStringCchPrintfExA(
1199     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1200     _In_ size_t cchDest,
1201     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
1202     _Out_opt_ size_t *pcchRemaining,
1203     _In_ STRSAFE_DWORD dwFlags,
1204     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1205     ...);
1206 
1207 NTSTRSAFEVAPI
1208 RtlStringCchPrintfExW(
1209     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1210     _In_ size_t cchDest,
1211     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
1212     _Out_opt_ size_t *pcchRemaining,
1213     _In_ STRSAFE_DWORD dwFlags,
1214     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1215     ...);
1216 
1217 NTSTRSAFEVAPI
1218 RtlStringCchPrintfExA(
1219     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1220     _In_ size_t cchDest,
1221     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
1222     _Out_opt_ size_t *pcchRemaining,
1223     _In_ STRSAFE_DWORD dwFlags,
1224     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1225     ...)
1226 {
1227     NTSTATUS Status;
1228     va_list argList;
1229 
1230     if (cchDest > NTSTRSAFE_MAX_CCH)
1231     {
1232         if (cchDest > 0)
1233             *pszDest = '\0';
1234 
1235         return STATUS_INVALID_PARAMETER;
1236     }
1237 
1238     va_start(argList, pszFormat);
1239     Status = RtlStringVPrintfExWorkerA(pszDest, cchDest, cchDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
1240     va_end(argList);
1241 
1242     return Status;
1243 }
1244 
1245 NTSTRSAFEVAPI
1246 RtlStringCchPrintfExW(
1247     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1248     _In_ size_t cchDest,
1249     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
1250     _Out_opt_ size_t *pcchRemaining,
1251     _In_ STRSAFE_DWORD dwFlags,
1252     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1253     ...)
1254 {
1255     NTSTATUS Status;
1256     size_t cbDest = cchDest * sizeof(wchar_t);
1257     va_list argList;
1258 
1259     if (cchDest > NTSTRSAFE_MAX_CCH)
1260     {
1261         if (cchDest > 0)
1262             *pszDest = L'\0';
1263         return STATUS_INVALID_PARAMETER;
1264     }
1265 
1266     va_start(argList, pszFormat);
1267     Status = RtlStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
1268     va_end(argList);
1269 
1270     return Status;
1271 }
1272 
1273 NTSTRSAFEVAPI
1274 RtlStringCbPrintfExA(
1275     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1276     _In_ size_t cbDest,
1277     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
1278     _Out_opt_ size_t *pcbRemaining,
1279     _In_ STRSAFE_DWORD dwFlags,
1280     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1281     ...);
1282 
1283 NTSTRSAFEVAPI
1284 RtlStringCbPrintfExW(
1285     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1286     _In_ size_t cbDest,
1287     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
1288     _Out_opt_ size_t *pcbRemaining,
1289     _In_ STRSAFE_DWORD dwFlags,
1290     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1291     ...);
1292 
1293 NTSTRSAFEVAPI
1294 RtlStringCbPrintfExA(
1295     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1296     _In_ size_t cbDest,
1297     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
1298     _Out_opt_ size_t *pcbRemaining,
1299     _In_ STRSAFE_DWORD dwFlags,
1300     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1301     ...)
1302 {
1303     NTSTATUS Status;
1304     size_t cchDest;
1305     size_t cchRemaining = 0;
1306 
1307     cchDest = cbDest / sizeof(char);
1308     if (cchDest > NTSTRSAFE_MAX_CCH)
1309     {
1310         if (cchDest > 0)
1311             *pszDest = '\0';
1312 
1313         return STATUS_INVALID_PARAMETER;
1314     }
1315 
1316     {
1317         va_list argList;
1318         va_start(argList, pszFormat);
1319         Status = RtlStringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
1320         va_end(argList);
1321     }
1322 
1323     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
1324     {
1325         if (pcbRemaining)
1326         {
1327             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
1328         }
1329     }
1330 
1331     return Status;
1332 }
1333 
1334 NTSTRSAFEVAPI
1335 RtlStringCbPrintfExW(
1336     _Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1337     _In_ size_t cbDest,
1338     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
1339     _Out_opt_ size_t *pcbRemaining,
1340     _In_ STRSAFE_DWORD dwFlags,
1341     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1342     ...)
1343 {
1344     NTSTATUS Status;
1345     size_t cchDest;
1346     size_t cchRemaining = 0;
1347     cchDest = cbDest / sizeof(wchar_t);
1348 
1349     if (cchDest > NTSTRSAFE_MAX_CCH)
1350     {
1351         if (cchDest > 0)
1352             *pszDest = L'\0';
1353 
1354         return STATUS_INVALID_PARAMETER;
1355     }
1356 
1357     {
1358         va_list argList;
1359         va_start(argList, pszFormat);
1360         Status = RtlStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
1361         va_end(argList);
1362     }
1363 
1364     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
1365     {
1366         if (pcbRemaining)
1367         {
1368             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
1369         }
1370     }
1371     return Status;
1372 }
1373 
1374 NTSTRSAFEAPI
1375 RtlStringCchVPrintfExA(
1376     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1377     _In_ size_t cchDest,
1378     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
1379     _Out_opt_ size_t *pcchRemaining,
1380     _In_ STRSAFE_DWORD dwFlags,
1381     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1382     _In_ va_list argList);
1383 
1384 NTSTRSAFEAPI
1385 RtlStringCchVPrintfExW(
1386     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1387     _In_ size_t cchDest,
1388     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
1389     _Out_opt_ size_t *pcchRemaining,
1390     _In_ STRSAFE_DWORD dwFlags,
1391     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1392     _In_ va_list argList);
1393 
1394 NTSTRSAFEAPI
1395 RtlStringCchVPrintfExA(
1396     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PSTR pszDest,
1397     _In_ size_t cchDest,
1398     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
1399     _Out_opt_ size_t *pcchRemaining,
1400     _In_ STRSAFE_DWORD dwFlags,
1401     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1402     _In_ va_list argList)
1403 {
1404     NTSTATUS Status;
1405 
1406     if (cchDest > NTSTRSAFE_MAX_CCH)
1407     {
1408         if (cchDest > 0)
1409             *pszDest = '\0';
1410 
1411         return STATUS_INVALID_PARAMETER;
1412     }
1413 
1414     {
1415         size_t cbDest;
1416         cbDest = cchDest * sizeof(char);
1417         Status = RtlStringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
1418     }
1419 
1420     return Status;
1421 }
1422 
1423 NTSTRSAFEAPI
1424 RtlStringCchVPrintfExW(
1425     _Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest,
1426     _In_ size_t cchDest,
1427     _Outptr_opt_result_buffer_(*pcchRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
1428     _Out_opt_ size_t *pcchRemaining,
1429     _In_ STRSAFE_DWORD dwFlags,
1430     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1431     _In_ va_list argList)
1432 {
1433     NTSTATUS Status;
1434 
1435     if (cchDest > NTSTRSAFE_MAX_CCH)
1436     {
1437         if (cchDest > 0)
1438             *pszDest = L'\0';
1439 
1440         return STATUS_INVALID_PARAMETER;
1441     }
1442 
1443     {
1444         size_t cbDest;
1445         cbDest = cchDest * sizeof(wchar_t);
1446         Status = RtlStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
1447     }
1448 
1449     return Status;
1450 }
1451 
1452 NTSTRSAFEAPI
1453 RtlStringCbVPrintfExA(
1454     _Out_writes_bytes_(cbDest) NTSTRSAFE_PSTR pszDest,
1455     _In_ size_t cbDest,
1456     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
1457     _Out_opt_ size_t *pcbRemaining,
1458     _In_ STRSAFE_DWORD dwFlags,
1459     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1460     _In_ va_list argList);
1461 
1462 NTSTRSAFEAPI
1463 RtlStringCbVPrintfExW(
1464     _Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest,
1465     _In_ size_t cbDest,
1466     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
1467     _Out_opt_ size_t *pcbRemaining,
1468     _In_ STRSAFE_DWORD dwFlags,
1469     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1470     _In_ va_list argList);
1471 
1472 NTSTRSAFEAPI
1473 RtlStringCbVPrintfExA(
1474     _Out_writes_bytes_(cbDest) NTSTRSAFE_PSTR pszDest,
1475     _In_ size_t cbDest,
1476     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PSTR *ppszDestEnd,
1477     _Out_opt_ size_t *pcbRemaining,
1478     _In_ STRSAFE_DWORD dwFlags,
1479     _In_ _Printf_format_string_ NTSTRSAFE_PCSTR pszFormat,
1480     _In_ va_list argList)
1481 {
1482     NTSTATUS Status;
1483     size_t cchDest;
1484     size_t cchRemaining = 0;
1485     cchDest = cbDest / sizeof(char);
1486 
1487     if (cchDest > NTSTRSAFE_MAX_CCH)
1488         Status = STATUS_INVALID_PARAMETER;
1489     else
1490         Status = RtlStringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
1491 
1492     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
1493     {
1494         if (pcbRemaining)
1495         {
1496             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
1497         }
1498     }
1499 
1500     return Status;
1501 }
1502 
1503 NTSTRSAFEAPI
1504 RtlStringCbVPrintfExW(
1505     _Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest,
1506     _In_ size_t cbDest,
1507     _Outptr_opt_result_bytebuffer_(*pcbRemaining) NTSTRSAFE_PWSTR *ppszDestEnd,
1508     _Out_opt_ size_t *pcbRemaining,
1509     _In_ STRSAFE_DWORD dwFlags,
1510     _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,
1511     _In_ va_list argList)
1512 {
1513     NTSTATUS Status;
1514     size_t cchDest;
1515     size_t cchRemaining = 0;
1516     cchDest = cbDest / sizeof(wchar_t);
1517 
1518     if (cchDest > NTSTRSAFE_MAX_CCH)
1519         Status = STATUS_INVALID_PARAMETER;
1520     else
1521         Status = RtlStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
1522 
1523     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
1524     {
1525         if (pcbRemaining)
1526         {
1527             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
1528         }
1529     }
1530 
1531     return Status;
1532 }
1533 
1534 
1535 _Must_inspect_result_
1536 NTSTRSAFEAPI
1537 RtlStringCchLengthA(
1538     _In_reads_or_z_(cchMax) STRSAFE_LPCSTR psz,
1539     _In_ _In_range_(1, NTSTRSAFE_MAX_CCH) size_t cchMax,
1540     _Out_opt_ _Deref_out_range_(< , cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t *pcchLength);
1541 
1542 _Must_inspect_result_
1543 NTSTRSAFEAPI
1544 RtlStringCchLengthW(
1545     _In_reads_or_z_(cchMax) STRSAFE_LPCWSTR psz,
1546     _In_ _In_range_(1, NTSTRSAFE_MAX_CCH) size_t cchMax,
1547     _Out_opt_ _Deref_out_range_(< , cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t *pcchLength);
1548 
1549 _Must_inspect_result_
1550 NTSTRSAFEAPI
1551 RtlStringCchLengthA(
1552     _In_reads_or_z_(cchMax) STRSAFE_LPCSTR psz,
1553     _In_ _In_range_(1, NTSTRSAFE_MAX_CCH) size_t cchMax,
1554     _Out_opt_ _Deref_out_range_(< , cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t *pcchLength)
1555 {
1556     NTSTATUS Status;
1557 
1558     if (!psz || (cchMax > NTSTRSAFE_MAX_CCH))
1559         Status = STATUS_INVALID_PARAMETER;
1560     else
1561         Status = RtlStringLengthWorkerA(psz, cchMax, pcchLength);
1562 
1563     if (!NT_SUCCESS(Status) && pcchLength)
1564     {
1565         *pcchLength = 0;
1566     }
1567 
1568     return Status;
1569 }
1570 
1571 _Must_inspect_result_
1572 NTSTRSAFEAPI
1573 RtlStringCchLengthW(
1574     _In_reads_or_z_(cchMax) STRSAFE_LPCWSTR psz,
1575     _In_ _In_range_(1, NTSTRSAFE_MAX_CCH) size_t cchMax,
1576     _Out_opt_ _Deref_out_range_(< , cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t *pcchLength)
1577 {
1578     NTSTATUS Status;
1579 
1580     if (!psz || (cchMax > NTSTRSAFE_MAX_CCH))
1581         Status = STATUS_INVALID_PARAMETER;
1582     else
1583         Status = RtlStringLengthWorkerW(psz, cchMax, pcchLength);
1584 
1585     if (!NT_SUCCESS(Status) && pcchLength)
1586     {
1587         *pcchLength = 0;
1588     }
1589 
1590     return Status;
1591 }
1592 
1593 _Must_inspect_result_
1594 NTSTRSAFEAPI
1595 RtlStringCbLengthA(
1596     _In_reads_or_z_(cbMax) STRSAFE_LPCSTR psz,
1597     _In_ _In_range_(1, NTSTRSAFE_MAX_CCH * sizeof(char)) size_t cbMax,
1598     _Out_opt_ _Deref_out_range_(< , cbMax) size_t *pcbLength);
1599 
1600 _Must_inspect_result_
1601 NTSTRSAFEAPI
1602 RtlStringCbLengthW(
1603     _In_reads_or_z_(cbMax / sizeof(wchar_t)) STRSAFE_LPCWSTR psz,
1604     _In_ _In_range_(1, NTSTRSAFE_MAX_CCH * sizeof(wchar_t)) size_t cbMax,
1605     _Out_opt_ _Deref_out_range_(< , cbMax - 1) size_t *pcbLength);
1606 
1607 _Must_inspect_result_
1608 NTSTRSAFEAPI
1609 RtlStringCbLengthA(
1610     _In_reads_or_z_(cbMax) STRSAFE_LPCSTR psz,
1611     _In_ _In_range_(1, NTSTRSAFE_MAX_CCH * sizeof(char)) size_t cbMax,
1612     _Out_opt_ _Deref_out_range_(< , cbMax) size_t *pcbLength)
1613 {
1614     NTSTATUS Status;
1615     size_t cchMax;
1616     size_t cchLength = 0;
1617     cchMax = cbMax / sizeof(char);
1618 
1619     if (!psz || (cchMax > NTSTRSAFE_MAX_CCH))
1620         Status = STATUS_INVALID_PARAMETER;
1621     else
1622         Status = RtlStringLengthWorkerA(psz, cchMax, &cchLength);
1623 
1624     if (pcbLength)
1625     {
1626         if (NT_SUCCESS(Status))
1627         {
1628             *pcbLength = cchLength * sizeof(char);
1629         }
1630         else
1631         {
1632             *pcbLength = 0;
1633         }
1634     }
1635 
1636     return Status;
1637 }
1638 
1639 _Must_inspect_result_
1640 NTSTRSAFEAPI
1641 RtlStringCbLengthW(
1642     _In_reads_or_z_(cbMax / sizeof(wchar_t)) STRSAFE_LPCWSTR psz,
1643     _In_ _In_range_(1, NTSTRSAFE_MAX_CCH * sizeof(wchar_t)) size_t cbMax,
1644     _Out_opt_ _Deref_out_range_(< , cbMax - 1) size_t *pcbLength)
1645 {
1646     NTSTATUS Status;
1647     size_t cchMax;
1648     size_t cchLength = 0;
1649     cchMax = cbMax / sizeof(wchar_t);
1650 
1651     if (!psz || (cchMax > NTSTRSAFE_MAX_CCH))
1652         Status = STATUS_INVALID_PARAMETER;
1653     else
1654         Status = RtlStringLengthWorkerW(psz, cchMax, &cchLength);
1655 
1656     if (pcbLength)
1657     {
1658         if (NT_SUCCESS(Status))
1659         {
1660             *pcbLength = cchLength * sizeof(wchar_t);
1661         }
1662         else
1663         {
1664             *pcbLength = 0;
1665         }
1666     }
1667 
1668     return Status;
1669 }
1670 
1671 NTSTRSAFEAPI RtlStringCopyWorkerA(
1672     STRSAFE_LPSTR pszDest,
1673     size_t cchDest,
1674     STRSAFE_LPCSTR pszSrc)
1675 {
1676     NTSTATUS Status = STATUS_SUCCESS;
1677 
1678     if (cchDest == 0)
1679     {
1680         Status = STATUS_INVALID_PARAMETER;
1681     }
1682     else
1683     {
1684         while (cchDest && (*pszSrc != '\0'))
1685         {
1686             *pszDest++ = *pszSrc++;
1687             cchDest--;
1688         }
1689 
1690         if (cchDest == 0)
1691         {
1692             pszDest--;
1693             Status = STATUS_BUFFER_OVERFLOW;
1694         }
1695 
1696         *pszDest = '\0';
1697     }
1698 
1699     return Status;
1700 }
1701 
1702 NTSTRSAFEAPI RtlStringCopyWorkerW(
1703     STRSAFE_LPWSTR pszDest,
1704     size_t cchDest,
1705     STRSAFE_LPCWSTR pszSrc)
1706 {
1707     NTSTATUS Status = STATUS_SUCCESS;
1708 
1709     if (cchDest == 0)
1710     {
1711         Status = STATUS_INVALID_PARAMETER;
1712     }
1713     else
1714     {
1715         while (cchDest && (*pszSrc != L'\0'))
1716         {
1717             *pszDest++ = *pszSrc++;
1718             cchDest--;
1719         }
1720 
1721         if (cchDest == 0)
1722         {
1723             pszDest--;
1724             Status = STATUS_BUFFER_OVERFLOW;
1725         }
1726 
1727         *pszDest = L'\0';
1728     }
1729 
1730     return Status;
1731 }
1732 
1733 NTSTRSAFEAPI RtlStringCopyExWorkerA(
1734     STRSAFE_LPSTR pszDest,
1735     size_t cchDest,
1736     size_t cbDest,
1737     STRSAFE_LPCSTR pszSrc,
1738     STRSAFE_LPSTR *ppszDestEnd,
1739     size_t *pcchRemaining,
1740     STRSAFE_DWORD dwFlags)
1741 {
1742     NTSTATUS Status = STATUS_SUCCESS;
1743     STRSAFE_LPSTR pszDestEnd = pszDest;
1744     size_t cchRemaining = 0;
1745 
1746     if (dwFlags & (~STRSAFE_VALID_FLAGS))
1747     {
1748         Status = STATUS_INVALID_PARAMETER;
1749     }
1750     else
1751     {
1752         if (dwFlags & STRSAFE_IGNORE_NULLS)
1753         {
1754             if (!pszDest)
1755             {
1756                 if ((cchDest != 0) || (cbDest != 0))
1757                     Status = STATUS_INVALID_PARAMETER;
1758             }
1759 
1760             if (!pszSrc)
1761                 pszSrc = "";
1762         }
1763 
1764         if (NT_SUCCESS(Status))
1765         {
1766             if (cchDest == 0)
1767             {
1768                 pszDestEnd = pszDest;
1769                 cchRemaining = 0;
1770 
1771                 if (*pszSrc != '\0')
1772                 {
1773                     if (!pszDest)
1774                         Status = STATUS_INVALID_PARAMETER;
1775                     else
1776                         Status = STATUS_BUFFER_OVERFLOW;
1777                 }
1778             }
1779             else
1780             {
1781                 pszDestEnd = pszDest;
1782                 cchRemaining = cchDest;
1783 
1784                 while (cchRemaining && (*pszSrc != '\0'))
1785                 {
1786                     *pszDestEnd++ = *pszSrc++;
1787                     cchRemaining--;
1788                 }
1789 
1790                 if (cchRemaining > 0)
1791                 {
1792                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
1793                     {
1794                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
1795                     }
1796                 }
1797                 else
1798                 {
1799                     pszDestEnd--;
1800                     cchRemaining++;
1801                     Status = STATUS_BUFFER_OVERFLOW;
1802                 }
1803 
1804                 *pszDestEnd = '\0';
1805             }
1806         }
1807     }
1808 
1809     if (!NT_SUCCESS(Status))
1810     {
1811         if (pszDest)
1812         {
1813             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
1814             {
1815                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
1816                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
1817                 {
1818                     pszDestEnd = pszDest;
1819                     cchRemaining = cchDest;
1820                 }
1821                 else if (cchDest > 0)
1822                 {
1823                     pszDestEnd = pszDest + cchDest - 1;
1824                     cchRemaining = 1;
1825                     *pszDestEnd = '\0';
1826                 }
1827             }
1828 
1829             if ((dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) && cchDest > 0)
1830             {
1831                 pszDestEnd = pszDest;
1832                 cchRemaining = cchDest;
1833                 *pszDestEnd = '\0';
1834             }
1835         }
1836     }
1837 
1838     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
1839     {
1840         if (ppszDestEnd)
1841             *ppszDestEnd = pszDestEnd;
1842 
1843         if (pcchRemaining)
1844             *pcchRemaining = cchRemaining;
1845     }
1846 
1847     return Status;
1848 }
1849 
1850 NTSTRSAFEAPI RtlStringCopyExWorkerW(
1851     STRSAFE_LPWSTR pszDest,
1852     size_t cchDest,
1853     size_t cbDest,
1854     STRSAFE_LPCWSTR pszSrc,
1855     STRSAFE_LPWSTR *ppszDestEnd,
1856     size_t *pcchRemaining,
1857     STRSAFE_DWORD dwFlags)
1858 {
1859     NTSTATUS Status = STATUS_SUCCESS;
1860     STRSAFE_LPWSTR pszDestEnd = pszDest;
1861     size_t cchRemaining = 0;
1862 
1863     if (dwFlags & (~STRSAFE_VALID_FLAGS))
1864     {
1865         Status = STATUS_INVALID_PARAMETER;
1866     }
1867     else
1868     {
1869         if (dwFlags & STRSAFE_IGNORE_NULLS)
1870         {
1871             if (!pszDest)
1872             {
1873                 if ((cchDest != 0) || (cbDest != 0))
1874                     Status = STATUS_INVALID_PARAMETER;
1875             }
1876 
1877             if (!pszSrc)
1878                 pszSrc = L"";
1879         }
1880 
1881         if (NT_SUCCESS(Status))
1882         {
1883             if (cchDest == 0)
1884             {
1885                 pszDestEnd = pszDest;
1886                 cchRemaining = 0;
1887 
1888                 if (*pszSrc != L'\0')
1889                 {
1890                     if (!pszDest)
1891                         Status = STATUS_INVALID_PARAMETER;
1892                     else
1893                         Status = STATUS_BUFFER_OVERFLOW;
1894                 }
1895             }
1896             else
1897             {
1898                 pszDestEnd = pszDest;
1899                 cchRemaining = cchDest;
1900 
1901                 while (cchRemaining && (*pszSrc != L'\0'))
1902                 {
1903                     *pszDestEnd++ = *pszSrc++;
1904                     cchRemaining--;
1905                 }
1906 
1907                 if (cchRemaining > 0)
1908                 {
1909                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
1910                     {
1911                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
1912                     }
1913                 }
1914                 else
1915                 {
1916                     pszDestEnd--;
1917                     cchRemaining++;
1918                     Status = STATUS_BUFFER_OVERFLOW;
1919                 }
1920 
1921                 *pszDestEnd = L'\0';
1922             }
1923         }
1924     }
1925 
1926     if (!NT_SUCCESS(Status))
1927     {
1928         if (pszDest)
1929         {
1930             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
1931             {
1932                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
1933 
1934                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
1935                 {
1936                     pszDestEnd = pszDest;
1937                     cchRemaining = cchDest;
1938                 }
1939                 else if (cchDest > 0)
1940                 {
1941                     pszDestEnd = pszDest + cchDest - 1;
1942                     cchRemaining = 1;
1943                     *pszDestEnd = L'\0';
1944                 }
1945             }
1946 
1947             if ((dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)) && cchDest > 0)
1948             {
1949                 pszDestEnd = pszDest;
1950                 cchRemaining = cchDest;
1951                 *pszDestEnd = L'\0';
1952             }
1953         }
1954     }
1955 
1956     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
1957     {
1958         if (ppszDestEnd)
1959             *ppszDestEnd = pszDestEnd;
1960 
1961         if (pcchRemaining)
1962             *pcchRemaining = cchRemaining;
1963     }
1964 
1965     return Status;
1966 }
1967 
1968 NTSTRSAFEAPI RtlStringCopyNWorkerA(
1969     STRSAFE_LPSTR pszDest,
1970     size_t cchDest,
1971     STRSAFE_LPCSTR pszSrc,
1972     size_t cchSrc)
1973 {
1974     NTSTATUS Status = STATUS_SUCCESS;
1975 
1976     if (cchDest == 0)
1977     {
1978         Status = STATUS_INVALID_PARAMETER;
1979     }
1980     else
1981     {
1982         while (cchDest && cchSrc && (*pszSrc != '\0'))
1983         {
1984             *pszDest++ = *pszSrc++;
1985             cchDest--;
1986             cchSrc--;
1987         }
1988 
1989         if (cchDest == 0)
1990         {
1991             pszDest--;
1992             Status = STATUS_BUFFER_OVERFLOW;
1993         }
1994 
1995         *pszDest = '\0';
1996     }
1997 
1998     return Status;
1999 }
2000 
2001 NTSTRSAFEAPI RtlStringCopyNWorkerW(
2002     STRSAFE_LPWSTR pszDest,
2003     size_t cchDest,
2004     STRSAFE_LPCWSTR pszSrc,
2005     size_t cchToCopy)
2006 {
2007     NTSTATUS Status = STATUS_SUCCESS;
2008 
2009     if (cchDest == 0)
2010     {
2011         Status = STATUS_INVALID_PARAMETER;
2012     }
2013     else
2014     {
2015         while (cchDest && cchToCopy && (*pszSrc != L'\0'))
2016         {
2017             *pszDest++ = *pszSrc++;
2018             cchDest--;
2019             cchToCopy--;
2020         }
2021 
2022         if (cchDest == 0)
2023         {
2024             pszDest--;
2025             Status = STATUS_BUFFER_OVERFLOW;
2026         }
2027 
2028         *pszDest = L'\0';
2029     }
2030 
2031     return Status;
2032 }
2033 
2034 NTSTRSAFEAPI RtlStringCopyNExWorkerA(
2035     STRSAFE_LPSTR pszDest,
2036     size_t cchDest,
2037     size_t cbDest,
2038     STRSAFE_LPCSTR pszSrc,
2039     size_t cchToCopy,
2040     STRSAFE_LPSTR *ppszDestEnd,
2041     size_t *pcchRemaining,
2042     STRSAFE_DWORD dwFlags)
2043 {
2044     NTSTATUS Status = STATUS_SUCCESS;
2045     STRSAFE_LPSTR pszDestEnd = pszDest;
2046     size_t cchRemaining = 0;
2047 
2048     if (dwFlags & (~STRSAFE_VALID_FLAGS))
2049     {
2050         Status = STATUS_INVALID_PARAMETER;
2051     }
2052     else if (cchToCopy > NTSTRSAFE_MAX_CCH)
2053     {
2054         Status = STATUS_INVALID_PARAMETER;
2055     }
2056     else
2057     {
2058         if (dwFlags & STRSAFE_IGNORE_NULLS)
2059         {
2060             if (!pszDest)
2061             {
2062                 if ((cchDest != 0) || (cbDest != 0))
2063                     Status = STATUS_INVALID_PARAMETER;
2064             }
2065 
2066             if (!pszSrc)
2067                 pszSrc = "";
2068         }
2069 
2070         if (NT_SUCCESS(Status))
2071         {
2072             if (cchDest == 0)
2073             {
2074                 pszDestEnd = pszDest;
2075                 cchRemaining = 0;
2076 
2077                 if ((cchToCopy != 0) && (*pszSrc != '\0'))
2078                 {
2079                     if (!pszDest)
2080                         Status = STATUS_INVALID_PARAMETER;
2081                     else
2082                         Status = STATUS_BUFFER_OVERFLOW;
2083                 }
2084             }
2085             else
2086             {
2087                 pszDestEnd = pszDest;
2088                 cchRemaining = cchDest;
2089 
2090                 while (cchRemaining && cchToCopy && (*pszSrc != '\0'))
2091                 {
2092                     *pszDestEnd++ = *pszSrc++;
2093                     cchRemaining--;
2094                     cchToCopy--;
2095                 }
2096 
2097                 if (cchRemaining > 0)
2098                 {
2099                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
2100                     {
2101                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
2102                     }
2103                 }
2104                 else
2105                 {
2106                     pszDestEnd--;
2107                     cchRemaining++;
2108                     Status = STATUS_BUFFER_OVERFLOW;
2109                 }
2110 
2111                 *pszDestEnd = '\0';
2112             }
2113         }
2114     }
2115 
2116     if (!NT_SUCCESS(Status))
2117     {
2118         if (pszDest)
2119         {
2120             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
2121             {
2122                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
2123                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
2124                 {
2125                     pszDestEnd = pszDest;
2126                     cchRemaining = cchDest;
2127                 }
2128                 else if (cchDest > 0)
2129                 {
2130                     pszDestEnd = pszDest + cchDest - 1;
2131                     cchRemaining = 1;
2132                     *pszDestEnd = '\0';
2133                 }
2134             }
2135 
2136             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
2137             {
2138                 if (cchDest > 0)
2139                 {
2140                     pszDestEnd = pszDest;
2141                     cchRemaining = cchDest;
2142                     *pszDestEnd = '\0';
2143                 }
2144             }
2145         }
2146     }
2147 
2148     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
2149     {
2150         if (ppszDestEnd)
2151             *ppszDestEnd = pszDestEnd;
2152 
2153         if (pcchRemaining)
2154             *pcchRemaining = cchRemaining;
2155     }
2156 
2157     return Status;
2158 }
2159 
2160 NTSTRSAFEAPI RtlStringCopyNExWorkerW(
2161     STRSAFE_LPWSTR pszDest,
2162     size_t cchDest,
2163     size_t cbDest,
2164     STRSAFE_LPCWSTR pszSrc,
2165     size_t cchToCopy,
2166     STRSAFE_LPWSTR *ppszDestEnd,
2167     size_t *pcchRemaining,
2168     STRSAFE_DWORD dwFlags)
2169 {
2170     NTSTATUS Status = STATUS_SUCCESS;
2171     STRSAFE_LPWSTR pszDestEnd = pszDest;
2172     size_t cchRemaining = 0;
2173 
2174     if (dwFlags & (~STRSAFE_VALID_FLAGS))
2175     {
2176         Status = STATUS_INVALID_PARAMETER;
2177     }
2178     else if (cchToCopy > NTSTRSAFE_MAX_CCH)
2179     {
2180         Status = STATUS_INVALID_PARAMETER;
2181     }
2182     else
2183     {
2184         if (dwFlags & STRSAFE_IGNORE_NULLS)
2185         {
2186             if (!pszDest)
2187             {
2188                 if ((cchDest != 0) || (cbDest != 0))
2189                     Status = STATUS_INVALID_PARAMETER;
2190             }
2191 
2192             if (!pszSrc)
2193                 pszSrc = L"";
2194         }
2195 
2196         if (NT_SUCCESS(Status))
2197         {
2198             if (cchDest == 0)
2199             {
2200                 pszDestEnd = pszDest;
2201                 cchRemaining = 0;
2202 
2203                 if ((cchToCopy != 0) && (*pszSrc != L'\0'))
2204                 {
2205                     if (!pszDest)
2206                         Status = STATUS_INVALID_PARAMETER;
2207                     else
2208                         Status = STATUS_BUFFER_OVERFLOW;
2209                 }
2210             }
2211             else
2212             {
2213                 pszDestEnd = pszDest;
2214                 cchRemaining = cchDest;
2215 
2216                 while (cchRemaining && cchToCopy && (*pszSrc != L'\0'))
2217                 {
2218                     *pszDestEnd++ = *pszSrc++;
2219                     cchRemaining--;
2220                     cchToCopy--;
2221                 }
2222 
2223                 if (cchRemaining > 0)
2224                 {
2225                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
2226                     {
2227                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
2228                     }
2229                 }
2230                 else
2231                 {
2232                     pszDestEnd--;
2233                     cchRemaining++;
2234                     Status = STATUS_BUFFER_OVERFLOW;
2235                 }
2236 
2237                 *pszDestEnd = L'\0';
2238             }
2239         }
2240     }
2241 
2242     if (!NT_SUCCESS(Status))
2243     {
2244         if (pszDest)
2245         {
2246             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
2247             {
2248                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
2249                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
2250                 {
2251                     pszDestEnd = pszDest;
2252                     cchRemaining = cchDest;
2253                 }
2254                 else if (cchDest > 0)
2255                 {
2256                     pszDestEnd = pszDest + cchDest - 1;
2257                     cchRemaining = 1;
2258                     *pszDestEnd = L'\0';
2259                 }
2260             }
2261             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
2262             {
2263                 if (cchDest > 0)
2264                 {
2265                     pszDestEnd = pszDest;
2266                     cchRemaining = cchDest;
2267                     *pszDestEnd = L'\0';
2268                 }
2269             }
2270         }
2271     }
2272 
2273     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
2274     {
2275         if (ppszDestEnd)
2276             *ppszDestEnd = pszDestEnd;
2277 
2278         if (pcchRemaining)
2279             *pcchRemaining = cchRemaining;
2280     }
2281 
2282     return Status;
2283 }
2284 
2285 NTSTRSAFEAPI RtlStringCatWorkerA(
2286     STRSAFE_LPSTR pszDest,
2287     size_t cchDest,
2288     STRSAFE_LPCSTR pszSrc)
2289 {
2290     size_t cchDestLength;
2291     NTSTATUS Status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestLength);
2292     if (NT_SUCCESS(Status))
2293         Status = RtlStringCopyWorkerA(pszDest + cchDestLength, cchDest - cchDestLength, pszSrc);
2294 
2295     return Status;
2296 }
2297 
2298 NTSTRSAFEAPI RtlStringCatWorkerW(
2299     STRSAFE_LPWSTR pszDest,
2300     size_t cchDest,
2301     STRSAFE_LPCWSTR pszSrc)
2302 {
2303     size_t cchDestLength;
2304     NTSTATUS Status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestLength);
2305     if (NT_SUCCESS(Status))
2306         Status = RtlStringCopyWorkerW(pszDest + cchDestLength, cchDest - cchDestLength, pszSrc);
2307 
2308     return Status;
2309 }
2310 
2311 NTSTRSAFEAPI RtlStringCatExWorkerA(
2312     STRSAFE_LPSTR pszDest,
2313     size_t cchDest,
2314     size_t cbDest,
2315     STRSAFE_LPCSTR pszSrc,
2316     STRSAFE_LPSTR *ppszDestEnd,
2317     size_t *pcchRemaining,
2318     STRSAFE_DWORD dwFlags)
2319 {
2320     NTSTATUS Status = STATUS_SUCCESS;
2321     STRSAFE_LPSTR pszDestEnd = pszDest;
2322     size_t cchRemaining = 0;
2323 
2324     if (dwFlags & (~STRSAFE_VALID_FLAGS))
2325     {
2326         Status = STATUS_INVALID_PARAMETER;
2327     }
2328     else
2329     {
2330         size_t cchDestLength;
2331         if (dwFlags & STRSAFE_IGNORE_NULLS)
2332         {
2333             if (!pszDest)
2334             {
2335                 if ((cchDest == 0) && (cbDest == 0))
2336                     cchDestLength = 0;
2337                 else
2338                     Status = STATUS_INVALID_PARAMETER;
2339             }
2340             else
2341             {
2342                 Status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestLength);
2343                 if (NT_SUCCESS(Status))
2344                 {
2345                     pszDestEnd = pszDest + cchDestLength;
2346                     cchRemaining = cchDest - cchDestLength;
2347                 }
2348             }
2349 
2350             if (!pszSrc)
2351                 pszSrc = "";
2352         }
2353         else
2354         {
2355             Status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestLength);
2356             if (NT_SUCCESS(Status))
2357             {
2358                 pszDestEnd = pszDest + cchDestLength;
2359                 cchRemaining = cchDest - cchDestLength;
2360             }
2361         }
2362 
2363         if (NT_SUCCESS(Status))
2364         {
2365             if (cchDest == 0)
2366             {
2367                 if (*pszSrc != '\0')
2368                 {
2369                     if (!pszDest)
2370                         Status = STATUS_INVALID_PARAMETER;
2371                     else
2372                         Status = STATUS_BUFFER_OVERFLOW;
2373                 }
2374             }
2375             else
2376             {
2377                 Status = RtlStringCopyExWorkerA(pszDestEnd, cchRemaining, (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)), pszSrc, &pszDestEnd, &cchRemaining, dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
2378             }
2379         }
2380     }
2381 
2382     if (!NT_SUCCESS(Status))
2383     {
2384         if (pszDest)
2385         {
2386             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
2387             {
2388                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
2389                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
2390                 {
2391                     pszDestEnd = pszDest;
2392                     cchRemaining = cchDest;
2393                 }
2394                 else if (cchDest > 0)
2395                 {
2396                     pszDestEnd = pszDest + cchDest - 1;
2397                     cchRemaining = 1;
2398                     *pszDestEnd = '\0';
2399                 }
2400             }
2401 
2402             if ((dwFlags & STRSAFE_NULL_ON_FAILURE) && cchDest > 0)
2403             {
2404                 pszDestEnd = pszDest;
2405                 cchRemaining = cchDest;
2406                 *pszDestEnd = '\0';
2407             }
2408         }
2409     }
2410 
2411     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
2412     {
2413         if (ppszDestEnd)
2414             *ppszDestEnd = pszDestEnd;
2415 
2416         if (pcchRemaining)
2417             *pcchRemaining = cchRemaining;
2418     }
2419 
2420     return Status;
2421 }
2422 
2423 NTSTRSAFEAPI RtlStringCatExWorkerW(
2424     STRSAFE_LPWSTR pszDest,
2425     size_t cchDest,
2426     size_t cbDest,
2427     STRSAFE_LPCWSTR pszSrc,
2428     STRSAFE_LPWSTR *ppszDestEnd,
2429     size_t *pcchRemaining,
2430     STRSAFE_DWORD dwFlags)
2431 {
2432     NTSTATUS Status = STATUS_SUCCESS;
2433     STRSAFE_LPWSTR pszDestEnd = pszDest;
2434     size_t cchRemaining = 0;
2435 
2436     if (dwFlags & (~STRSAFE_VALID_FLAGS))
2437     {
2438         Status = STATUS_INVALID_PARAMETER;
2439     }
2440     else
2441     {
2442         size_t cchDestLength;
2443         if (dwFlags & STRSAFE_IGNORE_NULLS)
2444         {
2445             if (!pszDest)
2446             {
2447                 if ((cchDest == 0) && (cbDest == 0))
2448                     cchDestLength = 0;
2449                 else
2450                     Status = STATUS_INVALID_PARAMETER;
2451             }
2452             else
2453             {
2454                 Status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestLength);
2455                 if (NT_SUCCESS(Status))
2456                 {
2457                     pszDestEnd = pszDest + cchDestLength;
2458                     cchRemaining = cchDest - cchDestLength;
2459                 }
2460             }
2461 
2462             if (!pszSrc)
2463                 pszSrc = L"";
2464         }
2465         else
2466         {
2467             Status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestLength);
2468             if (NT_SUCCESS(Status))
2469             {
2470                 pszDestEnd = pszDest + cchDestLength;
2471                 cchRemaining = cchDest - cchDestLength;
2472             }
2473         }
2474 
2475         if (NT_SUCCESS(Status))
2476         {
2477             if (cchDest == 0)
2478             {
2479                 if (*pszSrc != L'\0')
2480                 {
2481                     if (!pszDest)
2482                         Status = STATUS_INVALID_PARAMETER;
2483                     else
2484                         Status = STATUS_BUFFER_OVERFLOW;
2485                 }
2486             }
2487             else
2488             {
2489                 Status = RtlStringCopyExWorkerW(pszDestEnd, cchRemaining, (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)), pszSrc, &pszDestEnd, &cchRemaining, dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
2490             }
2491         }
2492     }
2493 
2494     if (!NT_SUCCESS(Status))
2495     {
2496         if (pszDest)
2497         {
2498             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
2499             {
2500                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
2501                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
2502                 {
2503                     pszDestEnd = pszDest;
2504                     cchRemaining = cchDest;
2505                 }
2506                 else if (cchDest > 0)
2507                 {
2508                     pszDestEnd = pszDest + cchDest - 1;
2509                     cchRemaining = 1;
2510                     *pszDestEnd = L'\0';
2511                 }
2512             }
2513 
2514             if ((dwFlags & STRSAFE_NULL_ON_FAILURE) && cchDest > 0)
2515             {
2516                 pszDestEnd = pszDest;
2517                 cchRemaining = cchDest;
2518                 *pszDestEnd = L'\0';
2519             }
2520         }
2521     }
2522 
2523     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
2524     {
2525         if (ppszDestEnd)
2526             *ppszDestEnd = pszDestEnd;
2527         if (pcchRemaining)
2528             *pcchRemaining = cchRemaining;
2529     }
2530 
2531     return Status;
2532 }
2533 
2534 NTSTRSAFEAPI RtlStringCatNWorkerA(
2535     STRSAFE_LPSTR pszDest,
2536     size_t cchDest,
2537     STRSAFE_LPCSTR pszSrc,
2538     size_t cchToAppend)
2539 {
2540     size_t cchDestLength;
2541     NTSTATUS Status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestLength);
2542     if (NT_SUCCESS(Status))
2543         Status = RtlStringCopyNWorkerA(pszDest + cchDestLength, cchDest - cchDestLength, pszSrc, cchToAppend);
2544 
2545     return Status;
2546 }
2547 
2548 NTSTRSAFEAPI RtlStringCatNWorkerW(
2549     STRSAFE_LPWSTR pszDest,
2550     size_t cchDest,
2551     STRSAFE_LPCWSTR pszSrc,
2552     size_t cchToAppend)
2553 {
2554     size_t cchDestLength;
2555     NTSTATUS Status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestLength);
2556     if (NT_SUCCESS(Status))
2557         Status = RtlStringCopyNWorkerW(pszDest + cchDestLength, cchDest - cchDestLength, pszSrc, cchToAppend);
2558 
2559     return Status;
2560 }
2561 
2562 NTSTRSAFEAPI RtlStringCatNExWorkerA(
2563     STRSAFE_LPSTR pszDest,
2564     size_t cchDest,
2565     size_t cbDest,
2566     STRSAFE_LPCSTR pszSrc,
2567     size_t cchToAppend,
2568     STRSAFE_LPSTR *ppszDestEnd,
2569     size_t *pcchRemaining,
2570     STRSAFE_DWORD dwFlags)
2571 {
2572     NTSTATUS Status = STATUS_SUCCESS;
2573     STRSAFE_LPSTR pszDestEnd = pszDest;
2574     size_t cchRemaining = 0;
2575     size_t cchDestLength = 0;
2576 
2577     if (dwFlags & (~STRSAFE_VALID_FLAGS))
2578     {
2579         Status = STATUS_INVALID_PARAMETER;
2580     }
2581     else if (cchToAppend > NTSTRSAFE_MAX_CCH)
2582     {
2583         Status = STATUS_INVALID_PARAMETER;
2584     }
2585     else
2586     {
2587         if (dwFlags & STRSAFE_IGNORE_NULLS)
2588         {
2589             if (!pszDest)
2590             {
2591                 if ((cchDest == 0) && (cbDest == 0))
2592                     cchDestLength = 0;
2593                 else
2594                     Status = STATUS_INVALID_PARAMETER;
2595             }
2596             else
2597             {
2598                 Status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestLength);
2599                 if (NT_SUCCESS(Status))
2600                 {
2601                     pszDestEnd = pszDest + cchDestLength;
2602                     cchRemaining = cchDest - cchDestLength;
2603                 }
2604             }
2605 
2606             if (!pszSrc)
2607                 pszSrc = "";
2608         }
2609         else
2610         {
2611             Status = RtlStringLengthWorkerA(pszDest, cchDest, &cchDestLength);
2612             if (NT_SUCCESS(Status))
2613             {
2614                 pszDestEnd = pszDest + cchDestLength;
2615                 cchRemaining = cchDest - cchDestLength;
2616             }
2617         }
2618 
2619         if (NT_SUCCESS(Status))
2620         {
2621             if (cchDest == 0)
2622             {
2623                 if ((cchToAppend != 0) && (*pszSrc != '\0'))
2624                 {
2625                     if (!pszDest)
2626                         Status = STATUS_INVALID_PARAMETER;
2627                     else
2628                         Status = STATUS_BUFFER_OVERFLOW;
2629                 }
2630             }
2631             else
2632             {
2633                 Status = RtlStringCopyNExWorkerA(pszDestEnd, cchRemaining, (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)), pszSrc, cchToAppend, &pszDestEnd, &cchRemaining, dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
2634             }
2635         }
2636     }
2637 
2638     if (!NT_SUCCESS(Status))
2639     {
2640         if (pszDest)
2641         {
2642             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
2643             {
2644                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
2645                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
2646                 {
2647                     pszDestEnd = pszDest;
2648                     cchRemaining = cchDest;
2649                 }
2650                 else if (cchDest > 0)
2651                 {
2652                     pszDestEnd = pszDest + cchDest - 1;
2653                     cchRemaining = 1;
2654                     *pszDestEnd = '\0';
2655                 }
2656             }
2657 
2658             if ((dwFlags & STRSAFE_NULL_ON_FAILURE) && cchDest > 0)
2659             {
2660                 pszDestEnd = pszDest;
2661                 cchRemaining = cchDest;
2662                 *pszDestEnd = '\0';
2663             }
2664         }
2665     }
2666 
2667     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
2668     {
2669         if (ppszDestEnd)
2670             *ppszDestEnd = pszDestEnd;
2671 
2672         if (pcchRemaining)
2673             *pcchRemaining = cchRemaining;
2674     }
2675 
2676     return Status;
2677 }
2678 
2679 NTSTRSAFEAPI RtlStringCatNExWorkerW(
2680     STRSAFE_LPWSTR pszDest,
2681     size_t cchDest,
2682     size_t cbDest,
2683     STRSAFE_LPCWSTR pszSrc,
2684     size_t cchToAppend,
2685     STRSAFE_LPWSTR *ppszDestEnd,
2686     size_t *pcchRemaining,
2687     STRSAFE_DWORD dwFlags)
2688 {
2689     NTSTATUS Status = STATUS_SUCCESS;
2690     STRSAFE_LPWSTR pszDestEnd = pszDest;
2691     size_t cchRemaining = 0;
2692     size_t cchDestLength = 0;
2693 
2694     if (dwFlags & (~STRSAFE_VALID_FLAGS))
2695     {
2696         Status = STATUS_INVALID_PARAMETER;
2697     }
2698     else if (cchToAppend > NTSTRSAFE_MAX_CCH)
2699     {
2700         Status = STATUS_INVALID_PARAMETER;
2701     }
2702     else
2703     {
2704         if (dwFlags & STRSAFE_IGNORE_NULLS)
2705         {
2706             if (!pszDest)
2707             {
2708                 if ((cchDest == 0) && (cbDest == 0))
2709                     cchDestLength = 0;
2710                 else
2711                     Status = STATUS_INVALID_PARAMETER;
2712             }
2713             else
2714             {
2715                 Status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestLength);
2716                 if (NT_SUCCESS(Status))
2717                 {
2718                     pszDestEnd = pszDest + cchDestLength;
2719                     cchRemaining = cchDest - cchDestLength;
2720                 }
2721             }
2722 
2723             if (!pszSrc)
2724                 pszSrc = L"";
2725         }
2726         else
2727         {
2728             Status = RtlStringLengthWorkerW(pszDest, cchDest, &cchDestLength);
2729             if (NT_SUCCESS(Status))
2730             {
2731                 pszDestEnd = pszDest + cchDestLength;
2732                 cchRemaining = cchDest - cchDestLength;
2733             }
2734         }
2735 
2736         if (NT_SUCCESS(Status))
2737         {
2738             if (cchDest == 0)
2739             {
2740                 if ((cchToAppend != 0) && (*pszSrc != L'\0'))
2741                 {
2742                     if (!pszDest)
2743                         Status = STATUS_INVALID_PARAMETER;
2744                     else
2745                         Status = STATUS_BUFFER_OVERFLOW;
2746                 }
2747             }
2748             else
2749             {
2750                 Status = RtlStringCopyNExWorkerW(pszDestEnd, cchRemaining, (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)), pszSrc, cchToAppend, &pszDestEnd, &cchRemaining, dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
2751             }
2752         }
2753     }
2754 
2755     if (!NT_SUCCESS(Status))
2756     {
2757         if (pszDest)
2758         {
2759             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
2760             {
2761                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
2762 
2763                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
2764                 {
2765                     pszDestEnd = pszDest;
2766                     cchRemaining = cchDest;
2767                 }
2768                 else if (cchDest > 0)
2769                 {
2770                     pszDestEnd = pszDest + cchDest - 1;
2771                     cchRemaining = 1;
2772                     *pszDestEnd = L'\0';
2773                 }
2774             }
2775 
2776             if ((dwFlags & STRSAFE_NULL_ON_FAILURE) && cchDest > 0)
2777             {
2778                 pszDestEnd = pszDest;
2779                 cchRemaining = cchDest;
2780                 *pszDestEnd = L'\0';
2781             }
2782         }
2783     }
2784 
2785     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
2786     {
2787         if (ppszDestEnd)
2788             *ppszDestEnd = pszDestEnd;
2789 
2790         if (pcchRemaining)
2791             *pcchRemaining = cchRemaining;
2792     }
2793 
2794     return Status;
2795 }
2796 
2797 NTSTRSAFEAPI RtlStringVPrintfWorkerA(
2798     STRSAFE_LPSTR pszDest,
2799     size_t cchDest,
2800     STRSAFE_LPCSTR pszFormat,
2801     va_list argList)
2802 {
2803     NTSTATUS Status = STATUS_SUCCESS;
2804 
2805     if (cchDest == 0)
2806     {
2807         Status = STATUS_INVALID_PARAMETER;
2808     }
2809     else
2810     {
2811         size_t cchMax = cchDest - 1;
2812         int iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
2813 
2814         if ((iRet < 0) || (((size_t)iRet) > cchMax))
2815         {
2816             pszDest += cchMax;
2817             *pszDest = '\0';
2818             Status = STATUS_BUFFER_OVERFLOW;
2819         }
2820         else if (((size_t)iRet) == cchMax)
2821         {
2822             pszDest += cchMax;
2823             *pszDest = '\0';
2824         }
2825     }
2826 
2827     return Status;
2828 }
2829 
2830 NTSTRSAFEAPI RtlpArrayVPrintfWorkerW(
2831     STRSAFE_LPWSTR pszDest,
2832     size_t cchDest,
2833     STRSAFE_LPCWSTR pszFormat,
2834     size_t* pcchDestNewLen,
2835     va_list argList)
2836 {
2837     NTSTATUS Status = STATUS_SUCCESS;
2838     int iRet = _vsnwprintf(pszDest, cchDest, pszFormat, argList);
2839 
2840     if ((iRet < 0) || (((size_t)iRet) > cchDest))
2841     {
2842         Status = STATUS_BUFFER_OVERFLOW;
2843         *pcchDestNewLen = cchDest;
2844     }
2845     else
2846     {
2847         *pcchDestNewLen = iRet;
2848     }
2849 
2850     return Status;
2851 }
2852 
2853 NTSTRSAFEAPI RtlpStringVPrintfWorkerW(
2854     STRSAFE_LPWSTR pszDest,
2855     size_t cchDest,
2856     STRSAFE_LPCWSTR pszFormat,
2857     size_t* pcchDestNewLen,
2858     va_list argList)
2859 {
2860     NTSTATUS Status = STATUS_SUCCESS;
2861     size_t cchMax = cchDest - 1;
2862     int iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
2863 
2864     if ((iRet < 0) || (((size_t)iRet) > cchMax))
2865     {
2866         pszDest += cchMax;
2867         *pszDest = L'\0';
2868         Status = STATUS_BUFFER_OVERFLOW;
2869     }
2870     else if (((size_t)iRet) == cchMax)
2871     {
2872         pszDest += cchMax;
2873         *pszDest = L'\0';
2874     }
2875 
2876     if (pcchDestNewLen)
2877         *pcchDestNewLen = (iRet == -1) ? cchDest : iRet;
2878 
2879     return Status;
2880 }
2881 
2882 NTSTRSAFEAPI RtlStringVPrintfWorkerW(
2883     STRSAFE_LPWSTR pszDest,
2884     size_t cchDest,
2885     STRSAFE_LPCWSTR pszFormat,
2886     va_list argList)
2887 {
2888     if (cchDest == 0)
2889         return STATUS_INVALID_PARAMETER;
2890 
2891     return RtlpStringVPrintfWorkerW(pszDest, cchDest, pszFormat, NULL, argList);
2892 }
2893 
2894 NTSTRSAFEAPI RtlStringVPrintfExWorkerA(
2895     STRSAFE_LPSTR pszDest,
2896     size_t cchDest,
2897     size_t cbDest,
2898     STRSAFE_LPSTR *ppszDestEnd,
2899     size_t *pcchRemaining,
2900     STRSAFE_DWORD dwFlags,
2901     STRSAFE_LPCSTR pszFormat,
2902     va_list argList)
2903 {
2904     NTSTATUS Status = STATUS_SUCCESS;
2905     STRSAFE_LPSTR pszDestEnd = pszDest;
2906     size_t cchRemaining = 0;
2907 
2908     if (dwFlags & (~STRSAFE_VALID_FLAGS))
2909     {
2910         Status = STATUS_INVALID_PARAMETER;
2911     }
2912     else
2913     {
2914         if (dwFlags & STRSAFE_IGNORE_NULLS)
2915         {
2916             if (!pszDest)
2917             {
2918                 if ((cchDest != 0) || (cbDest != 0))
2919                     Status = STATUS_INVALID_PARAMETER;
2920             }
2921 
2922             if (!pszFormat)
2923                 pszFormat = "";
2924         }
2925         if (NT_SUCCESS(Status))
2926         {
2927             if (cchDest == 0)
2928             {
2929                 pszDestEnd = pszDest;
2930                 cchRemaining = 0;
2931 
2932                 if (*pszFormat != '\0')
2933                 {
2934                     if (!pszDest)
2935                         Status = STATUS_INVALID_PARAMETER;
2936                     else
2937                         Status = STATUS_BUFFER_OVERFLOW;
2938                 }
2939             }
2940             else
2941             {
2942                 int iRet;
2943                 size_t cchMax;
2944                 cchMax = cchDest - 1;
2945                 iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
2946                 if ((iRet < 0) || (((size_t)iRet) > cchMax))
2947                 {
2948                     pszDestEnd = pszDest + cchMax;
2949                     cchRemaining = 1;
2950                     *pszDestEnd = '\0';
2951                     Status = STATUS_BUFFER_OVERFLOW;
2952                 }
2953                 else if (((size_t)iRet) == cchMax)
2954                 {
2955                     pszDestEnd = pszDest + cchMax;
2956                     cchRemaining = 1;
2957                     *pszDestEnd = '\0';
2958                 }
2959                 else if (((size_t)iRet) < cchMax)
2960                 {
2961                     pszDestEnd = pszDest + iRet;
2962                     cchRemaining = cchDest - iRet;
2963 
2964                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
2965                     {
2966                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
2967                     }
2968                 }
2969             }
2970         }
2971     }
2972 
2973     if (!NT_SUCCESS(Status))
2974     {
2975         if (pszDest)
2976         {
2977             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
2978             {
2979                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
2980                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
2981                 {
2982                     pszDestEnd = pszDest;
2983                     cchRemaining = cchDest;
2984                 }
2985                 else if (cchDest > 0)
2986                 {
2987                     pszDestEnd = pszDest + cchDest - 1;
2988                     cchRemaining = 1;
2989                     *pszDestEnd = '\0';
2990                 }
2991             }
2992 
2993             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
2994             {
2995                 if (cchDest > 0)
2996                 {
2997                     pszDestEnd = pszDest;
2998                     cchRemaining = cchDest;
2999                     *pszDestEnd = '\0';
3000                 }
3001             }
3002         }
3003     }
3004 
3005     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
3006     {
3007         if (ppszDestEnd)
3008             *ppszDestEnd = pszDestEnd;
3009 
3010         if (pcchRemaining)
3011             *pcchRemaining = cchRemaining;
3012     }
3013 
3014     return Status;
3015 }
3016 
3017 NTSTRSAFEAPI RtlpStringVPrintfExWorkerW(
3018     STRSAFE_LPWSTR pszDest,
3019     size_t cchDest,
3020     size_t cbDest,
3021     STRSAFE_LPWSTR *ppszDestEnd,
3022     size_t *pcchRemaining,
3023     STRSAFE_DWORD dwFlags,
3024     STRSAFE_LPCWSTR pszFormat,
3025     size_t* pcchDestNewLen,
3026     va_list argList)
3027 {
3028     NTSTATUS Status = STATUS_SUCCESS;
3029     STRSAFE_LPWSTR pszDestEnd = pszDest;
3030     size_t cchRemaining = 0;
3031 
3032     if (dwFlags & (~STRSAFE_VALID_FLAGS))
3033     {
3034         Status = STATUS_INVALID_PARAMETER;
3035     }
3036     else
3037     {
3038         if (dwFlags & STRSAFE_IGNORE_NULLS)
3039         {
3040             if (!pszDest)
3041             {
3042                 if ((cchDest != 0) || (cbDest != 0))
3043                     Status = STATUS_INVALID_PARAMETER;
3044             }
3045 
3046             if (!pszFormat)
3047                 pszFormat = L"";
3048         }
3049 
3050         if (NT_SUCCESS(Status))
3051         {
3052             if (cchDest == 0)
3053             {
3054                 pszDestEnd = pszDest;
3055                 cchRemaining = 0;
3056                 if (*pszFormat != L'\0')
3057                 {
3058                     if (!pszDest)
3059                         Status = STATUS_INVALID_PARAMETER;
3060                     else
3061                         Status = STATUS_BUFFER_OVERFLOW;
3062                 }
3063             }
3064             else
3065             {
3066                 size_t cchDestNewLen = 0;
3067 
3068                 Status = RtlpArrayVPrintfWorkerW(pszDest, cchDest, pszFormat, &cchDestNewLen, argList);
3069                 pszDestEnd = pszDest + cchDestNewLen;
3070                 cchRemaining = cchDest - cchDestNewLen;
3071 
3072                 if (NT_SUCCESS(Status) && (dwFlags & STRSAFE_FILL_BEHIND) && cchRemaining)
3073                 {
3074                     memset(pszDestEnd, STRSAFE_GET_FILL_PATTERN(dwFlags), (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
3075                 }
3076 
3077                 if (pcchDestNewLen)
3078                     *pcchDestNewLen = cchDestNewLen;
3079             }
3080         }
3081     }
3082 
3083     if (!NT_SUCCESS(Status))
3084     {
3085         if (pszDest)
3086         {
3087             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
3088             {
3089                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
3090                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
3091                 {
3092                     pszDestEnd = pszDest;
3093                     cchRemaining = cchDest;
3094                 }
3095                 else if (cchDest > 0)
3096                 {
3097                     pszDestEnd = pszDest + cchDest - 1;
3098                     cchRemaining = 1;
3099                     *pszDestEnd = L'\0';
3100                 }
3101             }
3102 
3103             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
3104             {
3105                 if (cchDest > 0)
3106                 {
3107                     pszDestEnd = pszDest;
3108                     cchRemaining = cchDest;
3109                     *pszDestEnd = L'\0';
3110                 }
3111             }
3112         }
3113     }
3114 
3115     if (NT_SUCCESS(Status) || (Status == STATUS_BUFFER_OVERFLOW))
3116     {
3117         if (ppszDestEnd)
3118             *ppszDestEnd = pszDestEnd;
3119 
3120         if (pcchRemaining)
3121             *pcchRemaining = cchRemaining;
3122     }
3123 
3124     return Status;
3125 }
3126 
3127 NTSTRSAFEAPI RtlStringVPrintfExWorkerW(
3128     STRSAFE_LPWSTR pszDest,
3129     size_t cchDest,
3130     size_t cbDest,
3131     STRSAFE_LPWSTR *ppszDestEnd,
3132     size_t *pcchRemaining,
3133     STRSAFE_DWORD dwFlags,
3134     STRSAFE_LPCWSTR pszFormat,
3135     va_list argList)
3136 {
3137     return RtlpStringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, NULL, argList);
3138 }
3139 
3140 NTSTRSAFEAPI
3141 RtlStringLengthWorkerA(
3142     _In_reads_or_z_(cchMax) STRSAFE_LPCSTR psz,
3143     _In_ _In_range_(<=, NTSTRSAFE_MAX_CCH) size_t cchMax,
3144     _Out_opt_ _Deref_out_range_(<, cchMax) size_t *pcchLength)
3145 {
3146     NTSTATUS Status = STATUS_SUCCESS;
3147     size_t cchMaxPrev = cchMax;
3148 
3149     while (cchMax && (*psz != '\0'))
3150     {
3151         psz++;
3152         cchMax--;
3153     }
3154 
3155     if (cchMax == 0)
3156         Status = STATUS_INVALID_PARAMETER;
3157 
3158     if (pcchLength)
3159     {
3160         if (NT_SUCCESS(Status))
3161             *pcchLength = cchMaxPrev - cchMax;
3162         else
3163             *pcchLength = 0;
3164     }
3165 
3166     return Status;
3167 }
3168 
3169 NTSTRSAFEAPI
3170 RtlStringLengthWorkerW(
3171     _In_reads_or_z_(cchMax) STRSAFE_LPCWSTR psz,
3172     _In_ _In_range_(<=, NTSTRSAFE_MAX_CCH) size_t cchMax,
3173     _Out_opt_ _Deref_out_range_(<, cchMax) size_t *pcchLength)
3174 {
3175     NTSTATUS Status = STATUS_SUCCESS;
3176     size_t cchMaxPrev = cchMax;
3177 
3178     while (cchMax && (*psz != L'\0'))
3179     {
3180         psz++;
3181         cchMax--;
3182     }
3183 
3184     if (cchMax == 0)
3185         Status = STATUS_INVALID_PARAMETER;
3186 
3187     if (pcchLength)
3188     {
3189         if (NT_SUCCESS(Status))
3190             *pcchLength = cchMaxPrev - cchMax;
3191         else
3192             *pcchLength = 0;
3193     }
3194 
3195     return Status;
3196 }
3197 
3198 NTSTRSAFEAPI
3199 RtlpUnicodeStringValidate(
3200     _In_opt_ PCUNICODE_STRING SourceString,
3201     _In_ STRSAFE_DWORD dwFlags)
3202 {
3203     if (SourceString)
3204     {
3205         if (SourceString->Length % sizeof(WCHAR) != 0 ||
3206             SourceString->MaximumLength % sizeof(WCHAR) != 0 ||
3207             SourceString->Length > SourceString->MaximumLength ||
3208             SourceString->MaximumLength > NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR) ||
3209             (SourceString->Buffer == NULL && (SourceString->Length != 0 || SourceString->MaximumLength != 0)))
3210         {
3211             return STATUS_INVALID_PARAMETER;
3212         }
3213     }
3214     else
3215     {
3216         if (!(dwFlags & STRSAFE_IGNORE_NULLS))
3217             return STATUS_INVALID_PARAMETER;
3218     }
3219 
3220     return STATUS_SUCCESS;
3221 }
3222 
3223 NTSTRSAFEAPI
3224 RtlUnicodeStringValidate(_In_opt_ PCUNICODE_STRING SourceString)
3225 {
3226     return RtlpUnicodeStringValidate(SourceString, 0);
3227 }
3228 
3229 NTSTRSAFEAPI
3230 RtlUnicodeStringValidateEx(
3231     _In_opt_ PCUNICODE_STRING SourceString,
3232     _In_ STRSAFE_DWORD dwFlags)
3233 {
3234     if (dwFlags & ~(STRSAFE_UNICODE_STRING_VALID_FLAGS))
3235         return STATUS_INVALID_PARAMETER;
3236 
3237     return RtlpUnicodeStringValidate(SourceString, dwFlags);
3238 }
3239 
3240 NTSTRSAFEVAPI
3241 RtlUnicodeStringPrintf(
3242     _In_ PUNICODE_STRING DestinationString,
3243     _In_ NTSTRSAFE_PCWSTR pszFormat,
3244     ...)
3245 {
3246     NTSTATUS Status;
3247     size_t   cchFinalLength;
3248     va_list  argList;
3249 
3250     if (DestinationString == NULL || pszFormat == NULL)
3251     {
3252         Status = STATUS_INVALID_PARAMETER;
3253     }
3254     else
3255     {
3256         Status = RtlUnicodeStringValidate(DestinationString);
3257         if (NT_SUCCESS(Status))
3258         {
3259             va_start(argList, pszFormat);
3260 
3261             Status = RtlpArrayVPrintfWorkerW(DestinationString->Buffer,
3262                 DestinationString->MaximumLength / sizeof(WCHAR),
3263                 pszFormat,
3264                 &cchFinalLength,
3265                 argList);
3266 
3267             if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
3268             {
3269                 DestinationString->Length = (USHORT)(cchFinalLength * sizeof(WCHAR));
3270             }
3271 
3272             va_end(argList);
3273         }
3274     }
3275 
3276     return Status;
3277 }
3278 
3279 NTSTRSAFEVAPI
3280 RtlUnicodeStringPrintfEx(
3281     _In_opt_ PUNICODE_STRING DestinationString,
3282     _In_opt_  PUNICODE_STRING RemainingString,
3283     _In_ STRSAFE_DWORD dwFlags,
3284     _In_ NTSTRSAFE_PCWSTR pszFormat, ...)
3285 {
3286     NTSTATUS Status;
3287     size_t cchFinalLength;
3288     size_t cchRemaining;
3289     va_list argList;
3290 
3291     va_start(argList, pszFormat);
3292 
3293     Status = RtlpStringVPrintfExWorkerW(DestinationString->Buffer,
3294         DestinationString->MaximumLength / sizeof(WCHAR),
3295         DestinationString->MaximumLength,
3296         &RemainingString->Buffer,
3297         &cchRemaining,
3298         dwFlags,
3299         pszFormat,
3300         &cchFinalLength,
3301         argList);
3302 
3303     va_end(argList);
3304 
3305     if (Status == STATUS_BUFFER_OVERFLOW || NT_SUCCESS(Status))
3306     {
3307         DestinationString->Length = (USHORT)(cchFinalLength * sizeof(WCHAR));
3308 
3309         if (RemainingString)
3310         {
3311             RemainingString->Length = 0;
3312             RemainingString->MaximumLength = (USHORT)cchRemaining * sizeof(WCHAR);
3313         }
3314     }
3315 
3316     return Status;
3317 }
3318 
3319 #define RtlStringCopyWorkerA RtlStringCopyWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
3320 #define RtlStringCopyWorkerW RtlStringCopyWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
3321 #define RtlStringCopyExWorkerA RtlStringCopyExWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
3322 #define RtlStringCopyExWorkerW RtlStringCopyExWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
3323 #define RtlStringCatWorkerA RtlStringCatWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
3324 #define RtlStringCatWorkerW RtlStringCatWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
3325 #define RtlStringCatExWorkerA RtlStringCatExWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
3326 #define RtlStringCatExWorkerW RtlStringCatExWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
3327 #define RtlStringCatNWorkerA RtlStringCatNWorkerA_instead_use_StringCchCatNA_or_StrincCbCatNA;
3328 #define RtlStringCatNWorkerW RtlStringCatNWorkerW_instead_use_StringCchCatNW_or_StringCbCatNW;
3329 #define RtlStringCatNExWorkerA RtlStringCatNExWorkerA_instead_use_StringCchCatNExA_or_StringCbCatNExA;
3330 #define RtlStringCatNExWorkerW RtlStringCatNExWorkerW_instead_use_StringCchCatNExW_or_StringCbCatNExW;
3331 #define RtlStringVPrintfWorkerA RtlStringVPrintfWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
3332 #define RtlStringVPrintfWorkerW RtlStringVPrintfWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
3333 #define RtlStringVPrintfExWorkerA RtlStringVPrintfExWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
3334 #define RtlStringVPrintfExWorkerW RtlStringVPrintfExWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
3335 #define RtlStringLengthWorkerA RtlStringLengthWorkerA_instead_use_StringCchLengthA_or_StringCbLengthA;
3336 #define RtlStringLengthWorkerW RtlStringLengthWorkerW_instead_use_StringCchLengthW_or_StringCbLengthW;
3337 
3338 #ifdef _MSC_VER
3339 #pragma warning(pop)
3340 #endif /* _MSC_VER */
3341 
3342 #endif /* _NTSTRSAFE_H_INCLUDED_ */
3343