comparison lib/legacy_dx/strsafe.h @ 0:9c0607679772

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