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