aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/strutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/strutil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/strutil.cpp2824
1 files changed, 2824 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/strutil.cpp b/src/libs/dutil/WixToolset.DUtil/strutil.cpp
new file mode 100644
index 00000000..550d6169
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/strutil.cpp
@@ -0,0 +1,2824 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5
6// Exit macros
7#define StrExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_STRUTIL, x, s, __VA_ARGS__)
8#define StrExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_STRUTIL, x, s, __VA_ARGS__)
9#define StrExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_STRUTIL, x, s, __VA_ARGS__)
10#define StrExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_STRUTIL, x, s, __VA_ARGS__)
11#define StrExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_STRUTIL, x, s, __VA_ARGS__)
12#define StrExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_STRUTIL, x, s, __VA_ARGS__)
13#define StrExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_STRUTIL, p, x, e, s, __VA_ARGS__)
14#define StrExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_STRUTIL, p, x, s, __VA_ARGS__)
15#define StrExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_STRUTIL, p, x, e, s, __VA_ARGS__)
16#define StrExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_STRUTIL, p, x, s, __VA_ARGS__)
17#define StrExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_STRUTIL, e, x, s, __VA_ARGS__)
18#define StrExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_STRUTIL, g, x, s, __VA_ARGS__)
19
20#define ARRAY_GROWTH_SIZE 5
21
22// Forward declarations.
23static HRESULT AllocHelper(
24 __deref_out_ecount_part(cch, 0) LPWSTR* ppwz,
25 __in SIZE_T cch,
26 __in BOOL fZeroOnRealloc
27 );
28static HRESULT AllocStringHelper(
29 __deref_out_ecount_z(cchSource + 1) LPWSTR* ppwz,
30 __in_z LPCWSTR wzSource,
31 __in SIZE_T cchSource,
32 __in BOOL fZeroOnRealloc
33 );
34static HRESULT AllocConcatHelper(
35 __deref_out_z LPWSTR* ppwz,
36 __in_z LPCWSTR wzSource,
37 __in SIZE_T cchSource,
38 __in BOOL fZeroOnRealloc
39 );
40static HRESULT AllocFormattedArgsHelper(
41 __deref_out_z LPWSTR* ppwz,
42 __in BOOL fZeroOnRealloc,
43 __in __format_string LPCWSTR wzFormat,
44 __in va_list args
45 );
46static HRESULT StrAllocStringMapInvariant(
47 __deref_out_z LPWSTR* pscz,
48 __in_z LPCWSTR wzSource,
49 __in SIZE_T cchSource,
50 __in DWORD dwMapFlags
51 );
52
53/********************************************************************
54StrAlloc - allocates or reuses dynamic string memory
55
56NOTE: caller is responsible for freeing ppwz even if function fails
57********************************************************************/
58extern "C" HRESULT DAPI StrAlloc(
59 __deref_out_ecount_part(cch, 0) LPWSTR* ppwz,
60 __in SIZE_T cch
61 )
62{
63 return AllocHelper(ppwz, cch, FALSE);
64}
65
66/********************************************************************
67StrAllocSecure - allocates or reuses dynamic string memory
68If the memory needs to reallocated, calls SecureZeroMemory on the
69original block of memory after it is moved.
70
71NOTE: caller is responsible for freeing ppwz even if function fails
72********************************************************************/
73extern "C" HRESULT DAPI StrAllocSecure(
74 __deref_out_ecount_part(cch, 0) LPWSTR* ppwz,
75 __in SIZE_T cch
76 )
77{
78 return AllocHelper(ppwz, cch, TRUE);
79}
80
81/********************************************************************
82AllocHelper - allocates or reuses dynamic string memory
83If fZeroOnRealloc is true and the memory needs to reallocated,
84calls SecureZeroMemory on original block of memory after it is moved.
85
86NOTE: caller is responsible for freeing ppwz even if function fails
87********************************************************************/
88static HRESULT AllocHelper(
89 __deref_out_ecount_part(cch, 0) LPWSTR* ppwz,
90 __in SIZE_T cch,
91 __in BOOL fZeroOnRealloc
92 )
93{
94 Assert(ppwz && cch);
95
96 HRESULT hr = S_OK;
97 LPWSTR pwz = NULL;
98
99 if (cch >= MAXDWORD / sizeof(WCHAR))
100 {
101 hr = E_OUTOFMEMORY;
102 StrExitOnFailure(hr, "Not enough memory to allocate string of size: %u", cch);
103 }
104
105 if (*ppwz)
106 {
107 if (fZeroOnRealloc)
108 {
109 LPVOID pvNew = NULL;
110 hr = MemReAllocSecure(*ppwz, sizeof(WCHAR)* cch, FALSE, &pvNew);
111 StrExitOnFailure(hr, "Failed to reallocate string");
112 pwz = static_cast<LPWSTR>(pvNew);
113 }
114 else
115 {
116 pwz = static_cast<LPWSTR>(MemReAlloc(*ppwz, sizeof(WCHAR)* cch, FALSE));
117 }
118 }
119 else
120 {
121 pwz = static_cast<LPWSTR>(MemAlloc(sizeof(WCHAR) * cch, TRUE));
122 }
123
124 StrExitOnNull(pwz, hr, E_OUTOFMEMORY, "failed to allocate string, len: %u", cch);
125
126 *ppwz = pwz;
127LExit:
128 return hr;
129}
130
131
132/********************************************************************
133StrTrimCapacity - Frees any unnecessary memory associated with a string.
134 Purely used for optimization, generally only when a string
135 has been changing size, and will no longer grow.
136
137NOTE: caller is responsible for freeing ppwz even if function fails
138********************************************************************/
139HRESULT DAPI StrTrimCapacity(
140 __deref_out_z LPWSTR* ppwz
141 )
142{
143 Assert(ppwz);
144
145 HRESULT hr = S_OK;
146 SIZE_T cchLen = 0;
147
148 hr = ::StringCchLengthW(*ppwz, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchLen));
149 StrExitOnRootFailure(hr, "Failed to calculate length of string");
150
151 ++cchLen; // Add 1 for null-terminator
152
153 hr = StrAlloc(ppwz, cchLen);
154 StrExitOnFailure(hr, "Failed to reallocate string");
155
156LExit:
157 return hr;
158}
159
160
161/********************************************************************
162StrTrimWhitespace - allocates or reuses dynamic string memory and copies
163 in an existing string, excluding whitespace
164
165NOTE: caller is responsible for freeing ppwz even if function fails
166********************************************************************/
167HRESULT DAPI StrTrimWhitespace(
168 __deref_out_z LPWSTR* ppwz,
169 __in_z LPCWSTR wzSource
170 )
171{
172 HRESULT hr = S_OK;
173 size_t i = 0;
174 LPWSTR sczResult = NULL;
175
176 // Ignore beginning whitespace
177 while (L' ' == *wzSource || L'\t' == *wzSource)
178 {
179 wzSource++;
180 }
181
182 hr = ::StringCchLengthW(wzSource, STRSAFE_MAX_CCH, &i);
183 StrExitOnRootFailure(hr, "Failed to get length of string");
184
185 // Overwrite ending whitespace with null characters
186 if (0 < i)
187 {
188 // start from the last non-null-terminator character in the array
189 for (i = i - 1; i > 0; --i)
190 {
191 if (L' ' != wzSource[i] && L'\t' != wzSource[i])
192 {
193 break;
194 }
195 }
196
197 ++i;
198 }
199
200 hr = StrAllocString(&sczResult, wzSource, i);
201 StrExitOnFailure(hr, "Failed to copy result string");
202
203 // Output result
204 *ppwz = sczResult;
205 sczResult = NULL;
206
207LExit:
208 ReleaseStr(sczResult);
209
210 return hr;
211}
212
213
214/********************************************************************
215StrAnsiAlloc - allocates or reuses dynamic ANSI string memory
216
217NOTE: caller is responsible for freeing ppsz even if function fails
218********************************************************************/
219extern "C" HRESULT DAPI StrAnsiAlloc(
220 __deref_out_ecount_part(cch, 0) LPSTR* ppsz,
221 __in SIZE_T cch
222 )
223{
224 Assert(ppsz && cch);
225
226 HRESULT hr = S_OK;
227 LPSTR psz = NULL;
228
229 if (cch >= MAXDWORD / sizeof(WCHAR))
230 {
231 hr = E_OUTOFMEMORY;
232 StrExitOnFailure(hr, "Not enough memory to allocate string of size: %u", cch);
233 }
234
235 if (*ppsz)
236 {
237 psz = static_cast<LPSTR>(MemReAlloc(*ppsz, sizeof(CHAR) * cch, FALSE));
238 }
239 else
240 {
241 psz = static_cast<LPSTR>(MemAlloc(sizeof(CHAR) * cch, TRUE));
242 }
243
244 StrExitOnNull(psz, hr, E_OUTOFMEMORY, "failed to allocate string, len: %u", cch);
245
246 *ppsz = psz;
247LExit:
248 return hr;
249}
250
251
252/********************************************************************
253StrAnsiTrimCapacity - Frees any unnecessary memory associated with a string.
254 Purely used for optimization, generally only when a string
255 has been changing size, and will no longer grow.
256
257NOTE: caller is responsible for freeing ppwz even if function fails
258********************************************************************/
259HRESULT DAPI StrAnsiTrimCapacity(
260 __deref_out_z LPSTR* ppz
261 )
262{
263 Assert(ppz);
264
265 HRESULT hr = S_OK;
266 SIZE_T cchLen = 0;
267
268#pragma prefast(push)
269#pragma prefast(disable:25068)
270 hr = ::StringCchLengthA(*ppz, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchLen));
271#pragma prefast(pop)
272 StrExitOnFailure(hr, "Failed to calculate length of string");
273
274 ++cchLen; // Add 1 for null-terminator
275
276 hr = StrAnsiAlloc(ppz, cchLen);
277 StrExitOnFailure(hr, "Failed to reallocate string");
278
279LExit:
280 return hr;
281}
282
283
284/********************************************************************
285StrAnsiTrimWhitespace - allocates or reuses dynamic string memory and copies
286 in an existing string, excluding whitespace
287
288NOTE: caller is responsible for freeing ppz even if function fails
289********************************************************************/
290HRESULT DAPI StrAnsiTrimWhitespace(
291 __deref_out_z LPSTR* ppz,
292 __in_z LPCSTR szSource
293 )
294{
295 HRESULT hr = S_OK;
296 size_t i = 0;
297 LPSTR sczResult = NULL;
298
299 // Ignore beginning whitespace
300 while (' ' == *szSource || '\t' == *szSource)
301 {
302 szSource++;
303 }
304
305 hr = ::StringCchLengthA(szSource, STRSAFE_MAX_CCH, &i);
306 StrExitOnRootFailure(hr, "Failed to get length of string");
307
308 // Overwrite ending whitespace with null characters
309 if (0 < i)
310 {
311 // start from the last non-null-terminator character in the array
312 for (i = i - 1; i > 0; --i)
313 {
314 if (L' ' != szSource[i] && L'\t' != szSource[i])
315 {
316 break;
317 }
318 }
319
320 ++i;
321 }
322
323 hr = StrAnsiAllocStringAnsi(&sczResult, szSource, i);
324 StrExitOnFailure(hr, "Failed to copy result string");
325
326 // Output result
327 *ppz = sczResult;
328 sczResult = NULL;
329
330LExit:
331 ReleaseStr(sczResult);
332
333 return hr;
334}
335
336/********************************************************************
337StrAllocString - allocates or reuses dynamic string memory and copies in an existing string
338
339NOTE: caller is responsible for freeing ppwz even if function fails
340NOTE: cchSource does not have to equal the length of wzSource
341NOTE: if cchSource == 0, length of wzSource is used instead
342********************************************************************/
343extern "C" HRESULT DAPI StrAllocString(
344 __deref_out_ecount_z(cchSource+1) LPWSTR* ppwz,
345 __in_z LPCWSTR wzSource,
346 __in SIZE_T cchSource
347 )
348{
349 return AllocStringHelper(ppwz, wzSource, cchSource, FALSE);
350}
351
352/********************************************************************
353StrAllocStringSecure - allocates or reuses dynamic string memory and
354copies in an existing string. If the memory needs to reallocated,
355calls SecureZeroMemory on original block of memory after it is moved.
356
357NOTE: caller is responsible for freeing ppwz even if function fails
358NOTE: cchSource does not have to equal the length of wzSource
359NOTE: if cchSource == 0, length of wzSource is used instead
360********************************************************************/
361extern "C" HRESULT DAPI StrAllocStringSecure(
362 __deref_out_ecount_z(cchSource + 1) LPWSTR* ppwz,
363 __in_z LPCWSTR wzSource,
364 __in SIZE_T cchSource
365 )
366{
367 return AllocStringHelper(ppwz, wzSource, cchSource, TRUE);
368}
369
370/********************************************************************
371AllocStringHelper - allocates or reuses dynamic string memory and copies in an existing string
372If fZeroOnRealloc is true and the memory needs to reallocated,
373calls SecureZeroMemory on original block of memory after it is moved.
374
375NOTE: caller is responsible for freeing ppwz even if function fails
376NOTE: cchSource does not have to equal the length of wzSource
377NOTE: if cchSource == 0, length of wzSource is used instead
378********************************************************************/
379static HRESULT AllocStringHelper(
380 __deref_out_ecount_z(cchSource + 1) LPWSTR* ppwz,
381 __in_z LPCWSTR wzSource,
382 __in SIZE_T cchSource,
383 __in BOOL fZeroOnRealloc
384 )
385{
386 Assert(ppwz && wzSource); // && *wzSource);
387
388 HRESULT hr = S_OK;
389 SIZE_T cch = 0;
390
391 if (*ppwz)
392 {
393 cch = MemSize(*ppwz); // get the count in bytes so we can check if it failed (returns -1)
394 if (-1 == cch)
395 {
396 hr = E_INVALIDARG;
397 StrExitOnFailure(hr, "failed to get size of destination string");
398 }
399 cch /= sizeof(WCHAR); //convert the count in bytes to count in characters
400 }
401
402 if (0 == cchSource && wzSource)
403 {
404 hr = ::StringCchLengthW(wzSource, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSource));
405 StrExitOnRootFailure(hr, "failed to get length of source string");
406 }
407
408 SIZE_T cchNeeded;
409 hr = ::ULongPtrAdd(cchSource, 1, &cchNeeded); // add one for the null terminator
410 StrExitOnRootFailure(hr, "source string is too long");
411
412 if (cch < cchNeeded)
413 {
414 cch = cchNeeded;
415 hr = AllocHelper(ppwz, cch, fZeroOnRealloc);
416 StrExitOnFailure(hr, "failed to allocate string from string.");
417 }
418
419 // copy everything (the NULL terminator will be included)
420 hr = ::StringCchCopyNExW(*ppwz, cch, wzSource, cchSource, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
421
422LExit:
423 return hr;
424}
425
426
427/********************************************************************
428StrAnsiAllocString - allocates or reuses dynamic ANSI string memory and copies in an existing string
429
430NOTE: caller is responsible for freeing ppsz even if function fails
431NOTE: cchSource must equal the length of wzSource (not including the NULL terminator)
432NOTE: if cchSource == 0, length of wzSource is used instead
433********************************************************************/
434extern "C" HRESULT DAPI StrAnsiAllocString(
435 __deref_out_ecount_z(cchSource+1) LPSTR* ppsz,
436 __in_z LPCWSTR wzSource,
437 __in SIZE_T cchSource,
438 __in UINT uiCodepage
439 )
440{
441 Assert(ppsz && wzSource);
442
443 HRESULT hr = S_OK;
444 LPSTR psz = NULL;
445 SIZE_T cch = 0;
446 SIZE_T cchDest = cchSource; // at least enough
447
448 if (*ppsz)
449 {
450 cch = MemSize(*ppsz); // get the count in bytes so we can check if it failed (returns -1)
451 if (-1 == cch)
452 {
453 hr = E_INVALIDARG;
454 StrExitOnFailure(hr, "failed to get size of destination string");
455 }
456 cch /= sizeof(CHAR); //convert the count in bytes to count in characters
457 }
458
459 if (0 == cchSource)
460 {
461 cchDest = ::WideCharToMultiByte(uiCodepage, 0, wzSource, -1, NULL, 0, NULL, NULL);
462 if (0 == cchDest)
463 {
464 StrExitWithLastError(hr, "failed to get required size for conversion to ANSI: %ls", wzSource);
465 }
466
467 --cchDest; // subtract one because WideChageToMultiByte includes space for the NULL terminator that we track below
468 }
469 else if (L'\0' == wzSource[cchSource - 1]) // if the source already had a null terminator, don't count that in the character count because we track it below
470 {
471 cchDest = cchSource - 1;
472 }
473
474 if (cch < cchDest + 1)
475 {
476 cch = cchDest + 1; // add one for the NULL terminator
477 if (cch >= MAXDWORD / sizeof(WCHAR))
478 {
479 hr = E_OUTOFMEMORY;
480 StrExitOnFailure(hr, "Not enough memory to allocate string of size: %u", cch);
481 }
482
483 if (*ppsz)
484 {
485 psz = static_cast<LPSTR>(MemReAlloc(*ppsz, sizeof(CHAR) * cch, TRUE));
486 }
487 else
488 {
489 psz = static_cast<LPSTR>(MemAlloc(sizeof(CHAR) * cch, TRUE));
490 }
491 StrExitOnNull(psz, hr, E_OUTOFMEMORY, "failed to allocate string, len: %u", cch);
492
493 *ppsz = psz;
494 }
495
496 if (0 == ::WideCharToMultiByte(uiCodepage, 0, wzSource, 0 == cchSource ? -1 : (int)cchSource, *ppsz, (int)cch, NULL, NULL))
497 {
498 StrExitWithLastError(hr, "failed to convert to ansi: %ls", wzSource);
499 }
500 (*ppsz)[cchDest] = L'\0';
501
502LExit:
503 return hr;
504}
505
506
507/********************************************************************
508StrAllocStringAnsi - allocates or reuses dynamic string memory and copies in an existing ANSI string
509
510NOTE: caller is responsible for freeing ppwz even if function fails
511NOTE: cchSource must equal the length of wzSource (not including the NULL terminator)
512NOTE: if cchSource == 0, length of wzSource is used instead
513********************************************************************/
514extern "C" HRESULT DAPI StrAllocStringAnsi(
515 __deref_out_ecount_z(cchSource+1) LPWSTR* ppwz,
516 __in_z LPCSTR szSource,
517 __in SIZE_T cchSource,
518 __in UINT uiCodepage
519 )
520{
521 Assert(ppwz && szSource);
522
523 HRESULT hr = S_OK;
524 LPWSTR pwz = NULL;
525 SIZE_T cch = 0;
526 SIZE_T cchDest = cchSource; // at least enough
527
528 if (*ppwz)
529 {
530 cch = MemSize(*ppwz); // get the count in bytes so we can check if it failed (returns -1)
531 if (-1 == cch)
532 {
533 hr = E_INVALIDARG;
534 StrExitOnFailure(hr, "failed to get size of destination string");
535 }
536 cch /= sizeof(WCHAR); //convert the count in bytes to count in characters
537 }
538
539 if (0 == cchSource)
540 {
541 cchDest = ::MultiByteToWideChar(uiCodepage, 0, szSource, -1, NULL, 0);
542 if (0 == cchDest)
543 {
544 StrExitWithLastError(hr, "failed to get required size for conversion to unicode: %s", szSource);
545 }
546
547 --cchDest; //subtract one because MultiByteToWideChar includes space for the NULL terminator that we track below
548 }
549 else if (L'\0' == szSource[cchSource - 1]) // if the source already had a null terminator, don't count that in the character count because we track it below
550 {
551 cchDest = cchSource - 1;
552 }
553
554 if (cch < cchDest + 1)
555 {
556 cch = cchDest + 1;
557 if (cch >= MAXDWORD / sizeof(WCHAR))
558 {
559 hr = E_OUTOFMEMORY;
560 StrExitOnFailure(hr, "Not enough memory to allocate string of size: %u", cch);
561 }
562
563 if (*ppwz)
564 {
565 pwz = static_cast<LPWSTR>(MemReAlloc(*ppwz, sizeof(WCHAR) * cch, TRUE));
566 }
567 else
568 {
569 pwz = static_cast<LPWSTR>(MemAlloc(sizeof(WCHAR) * cch, TRUE));
570 }
571
572 StrExitOnNull(pwz, hr, E_OUTOFMEMORY, "failed to allocate string, len: %u", cch);
573
574 *ppwz = pwz;
575 }
576
577 if (0 == ::MultiByteToWideChar(uiCodepage, 0, szSource, 0 == cchSource ? -1 : (int)cchSource, *ppwz, (int)cch))
578 {
579 StrExitWithLastError(hr, "failed to convert to unicode: %s", szSource);
580 }
581 (*ppwz)[cchDest] = L'\0';
582
583LExit:
584 return hr;
585}
586
587
588/********************************************************************
589StrAnsiAllocStringAnsi - allocates or reuses dynamic string memory and copies in an existing string
590
591NOTE: caller is responsible for freeing ppsz even if function fails
592NOTE: cchSource does not have to equal the length of wzSource
593NOTE: if cchSource == 0, length of wzSource is used instead
594********************************************************************/
595HRESULT DAPI StrAnsiAllocStringAnsi(
596 __deref_out_ecount_z(cchSource+1) LPSTR* ppsz,
597 __in_z LPCSTR szSource,
598 __in SIZE_T cchSource
599 )
600{
601 Assert(ppsz && szSource); // && *szSource);
602
603 HRESULT hr = S_OK;
604 SIZE_T cch = 0;
605
606 if (*ppsz)
607 {
608 cch = MemSize(*ppsz); // get the count in bytes so we can check if it failed (returns -1)
609 if (-1 == cch)
610 {
611 hr = E_INVALIDARG;
612 StrExitOnRootFailure(hr, "failed to get size of destination string");
613 }
614 cch /= sizeof(CHAR); //convert the count in bytes to count in characters
615 }
616
617 if (0 == cchSource && szSource)
618 {
619 hr = ::StringCchLengthA(szSource, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchSource));
620 StrExitOnRootFailure(hr, "failed to get length of source string");
621 }
622
623 SIZE_T cchNeeded;
624 hr = ::ULongPtrAdd(cchSource, 1, &cchNeeded); // add one for the null terminator
625 StrExitOnRootFailure(hr, "source string is too long");
626
627 if (cch < cchNeeded)
628 {
629 cch = cchNeeded;
630 hr = StrAnsiAlloc(ppsz, cch);
631 StrExitOnFailure(hr, "failed to allocate string from string.");
632 }
633
634 // copy everything (the NULL terminator will be included)
635#pragma prefast(push)
636#pragma prefast(disable:25068)
637 hr = ::StringCchCopyNExA(*ppsz, cch, szSource, cchSource, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
638#pragma prefast(pop)
639
640LExit:
641 return hr;
642}
643
644
645/********************************************************************
646StrAllocPrefix - allocates or reuses dynamic string memory and
647 prefixes a string
648
649NOTE: caller is responsible for freeing ppwz even if function fails
650NOTE: cchPrefix does not have to equal the length of wzPrefix
651NOTE: if cchPrefix == 0, length of wzPrefix is used instead
652********************************************************************/
653extern "C" HRESULT DAPI StrAllocPrefix(
654 __deref_out_z LPWSTR* ppwz,
655 __in_z LPCWSTR wzPrefix,
656 __in SIZE_T cchPrefix
657 )
658{
659 Assert(ppwz && wzPrefix);
660
661 HRESULT hr = S_OK;
662 SIZE_T cch = 0;
663 SIZE_T cchLen = 0;
664
665 if (*ppwz)
666 {
667 cch = MemSize(*ppwz); // get the count in bytes so we can check if it failed (returns -1)
668 if (-1 == cch)
669 {
670 hr = E_INVALIDARG;
671 StrExitOnFailure(hr, "failed to get size of destination string");
672 }
673 cch /= sizeof(WCHAR); //convert the count in bytes to count in characters
674
675 hr = ::StringCchLengthW(*ppwz, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchLen));
676 StrExitOnFailure(hr, "Failed to calculate length of string");
677 }
678
679 Assert(cchLen <= cch);
680
681 if (0 == cchPrefix)
682 {
683 hr = ::StringCchLengthW(wzPrefix, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchPrefix));
684 StrExitOnFailure(hr, "Failed to calculate length of string");
685 }
686
687 if (cch - cchLen < cchPrefix + 1)
688 {
689 cch = cchPrefix + cchLen + 1;
690 hr = StrAlloc(ppwz, cch);
691 StrExitOnFailure(hr, "failed to allocate string from string: %ls", wzPrefix);
692 }
693
694 if (*ppwz)
695 {
696 SIZE_T cb = cch * sizeof(WCHAR);
697 SIZE_T cbPrefix = cchPrefix * sizeof(WCHAR);
698
699 memmove(*ppwz + cchPrefix, *ppwz, cb - cbPrefix);
700 memcpy(*ppwz, wzPrefix, cbPrefix);
701 }
702 else
703 {
704 hr = E_UNEXPECTED;
705 StrExitOnFailure(hr, "for some reason our buffer is still null");
706 }
707
708LExit:
709 return hr;
710}
711
712
713/********************************************************************
714StrAllocConcat - allocates or reuses dynamic string memory and adds an existing string
715
716NOTE: caller is responsible for freeing ppwz even if function fails
717NOTE: cchSource does not have to equal the length of wzSource
718NOTE: if cchSource == 0, length of wzSource is used instead
719********************************************************************/
720extern "C" HRESULT DAPI StrAllocConcat(
721 __deref_out_z LPWSTR* ppwz,
722 __in_z LPCWSTR wzSource,
723 __in SIZE_T cchSource
724 )
725{
726 return AllocConcatHelper(ppwz, wzSource, cchSource, FALSE);
727}
728
729
730/********************************************************************
731StrAllocConcatSecure - allocates or reuses dynamic string memory and
732adds an existing string. If the memory needs to reallocated, calls
733SecureZeroMemory on the original block of memory after it is moved.
734
735NOTE: caller is responsible for freeing ppwz even if function fails
736NOTE: cchSource does not have to equal the length of wzSource
737NOTE: if cchSource == 0, length of wzSource is used instead
738********************************************************************/
739extern "C" HRESULT DAPI StrAllocConcatSecure(
740 __deref_out_z LPWSTR* ppwz,
741 __in_z LPCWSTR wzSource,
742 __in SIZE_T cchSource
743 )
744{
745 return AllocConcatHelper(ppwz, wzSource, cchSource, TRUE);
746}
747
748
749/********************************************************************
750AllocConcatHelper - allocates or reuses dynamic string memory and adds an existing string
751If fZeroOnRealloc is true and the memory needs to reallocated,
752calls SecureZeroMemory on original block of memory after it is moved.
753
754NOTE: caller is responsible for freeing ppwz even if function fails
755NOTE: cchSource does not have to equal the length of wzSource
756NOTE: if cchSource == 0, length of wzSource is used instead
757********************************************************************/
758static HRESULT AllocConcatHelper(
759 __deref_out_z LPWSTR* ppwz,
760 __in_z LPCWSTR wzSource,
761 __in SIZE_T cchSource,
762 __in BOOL fZeroOnRealloc
763 )
764{
765 Assert(ppwz && wzSource); // && *wzSource);
766
767 HRESULT hr = S_OK;
768 SIZE_T cch = 0;
769 SIZE_T cchLen = 0;
770
771 if (*ppwz)
772 {
773 cch = MemSize(*ppwz); // get the count in bytes so we can check if it failed (returns -1)
774 if (-1 == cch)
775 {
776 hr = E_INVALIDARG;
777 StrExitOnFailure(hr, "failed to get size of destination string");
778 }
779 cch /= sizeof(WCHAR); //convert the count in bytes to count in characters
780
781 hr = ::StringCchLengthW(*ppwz, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchLen));
782 StrExitOnFailure(hr, "Failed to calculate length of string");
783 }
784
785 Assert(cchLen <= cch);
786
787 if (0 == cchSource)
788 {
789 hr = ::StringCchLengthW(wzSource, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchSource));
790 StrExitOnFailure(hr, "Failed to calculate length of string");
791 }
792
793 if (cch - cchLen < cchSource + 1)
794 {
795 cch = (cchSource + cchLen + 1) * 2;
796 hr = AllocHelper(ppwz, cch, fZeroOnRealloc);
797 StrExitOnFailure(hr, "failed to allocate string from string: %ls", wzSource);
798 }
799
800 if (*ppwz)
801 {
802 hr = ::StringCchCatNExW(*ppwz, cch, wzSource, cchSource, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
803 }
804 else
805 {
806 hr = E_UNEXPECTED;
807 StrExitOnFailure(hr, "for some reason our buffer is still null");
808 }
809
810LExit:
811 return hr;
812}
813
814
815/********************************************************************
816StrAnsiAllocConcat - allocates or reuses dynamic string memory and adds an existing string
817
818NOTE: caller is responsible for freeing ppz even if function fails
819NOTE: cchSource does not have to equal the length of pzSource
820NOTE: if cchSource == 0, length of pzSource is used instead
821********************************************************************/
822extern "C" HRESULT DAPI StrAnsiAllocConcat(
823 __deref_out_z LPSTR* ppz,
824 __in_z LPCSTR pzSource,
825 __in SIZE_T cchSource
826 )
827{
828 Assert(ppz && pzSource); // && *pzSource);
829
830 HRESULT hr = S_OK;
831 SIZE_T cch = 0;
832 SIZE_T cchLen = 0;
833
834 if (*ppz)
835 {
836 cch = MemSize(*ppz); // get the count in bytes so we can check if it failed (returns -1)
837 if (-1 == cch)
838 {
839 hr = E_INVALIDARG;
840 StrExitOnFailure(hr, "failed to get size of destination string");
841 }
842 cch /= sizeof(CHAR); // convert the count in bytes to count in characters
843
844#pragma prefast(push)
845#pragma prefast(disable:25068)
846 hr = ::StringCchLengthA(*ppz, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchLen));
847#pragma prefast(pop)
848 StrExitOnFailure(hr, "Failed to calculate length of string");
849 }
850
851 Assert(cchLen <= cch);
852
853 if (0 == cchSource)
854 {
855#pragma prefast(push)
856#pragma prefast(disable:25068)
857 hr = ::StringCchLengthA(pzSource, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchSource));
858#pragma prefast(pop)
859 StrExitOnFailure(hr, "Failed to calculate length of string");
860 }
861
862 if (cch - cchLen < cchSource + 1)
863 {
864 cch = (cchSource + cchLen + 1) * 2;
865 hr = StrAnsiAlloc(ppz, cch);
866 StrExitOnFailure(hr, "failed to allocate string from string: %hs", pzSource);
867 }
868
869 if (*ppz)
870 {
871#pragma prefast(push)
872#pragma prefast(disable:25068)
873 hr = ::StringCchCatNExA(*ppz, cch, pzSource, cchSource, NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
874#pragma prefast(pop)
875 }
876 else
877 {
878 hr = E_UNEXPECTED;
879 StrExitOnFailure(hr, "for some reason our buffer is still null");
880 }
881
882LExit:
883 return hr;
884}
885
886
887/********************************************************************
888StrAllocFormatted - allocates or reuses dynamic string memory and formats it
889
890NOTE: caller is responsible for freeing ppwz even if function fails
891********************************************************************/
892extern "C" HRESULT __cdecl StrAllocFormatted(
893 __deref_out_z LPWSTR* ppwz,
894 __in __format_string LPCWSTR wzFormat,
895 ...
896 )
897{
898 Assert(ppwz && wzFormat && *wzFormat);
899
900 HRESULT hr = S_OK;
901 va_list args;
902
903 va_start(args, wzFormat);
904 hr = StrAllocFormattedArgs(ppwz, wzFormat, args);
905 va_end(args);
906
907 return hr;
908}
909
910
911/********************************************************************
912StrAllocConcatFormatted - allocates or reuses dynamic string memory
913and adds a formatted string
914
915NOTE: caller is responsible for freeing ppwz even if function fails
916********************************************************************/
917extern "C" HRESULT __cdecl StrAllocConcatFormatted(
918 __deref_out_z LPWSTR* ppwz,
919 __in __format_string LPCWSTR wzFormat,
920 ...
921 )
922{
923 Assert(ppwz && wzFormat && *wzFormat);
924
925 HRESULT hr = S_OK;
926 LPWSTR sczFormatted = NULL;
927 va_list args;
928
929 va_start(args, wzFormat);
930 hr = StrAllocFormattedArgs(&sczFormatted, wzFormat, args);
931 va_end(args);
932 StrExitOnFailure(hr, "Failed to allocate formatted string");
933
934 hr = StrAllocConcat(ppwz, sczFormatted, 0);
935
936LExit:
937 ReleaseStr(sczFormatted);
938
939 return hr;
940}
941
942
943/********************************************************************
944StrAllocConcatFormattedSecure - allocates or reuses dynamic string
945memory and adds a formatted string. If the memory needs to be
946reallocated, calls SecureZeroMemory on original block of memory after
947it is moved.
948
949NOTE: caller is responsible for freeing ppwz even if function fails
950********************************************************************/
951extern "C" HRESULT __cdecl StrAllocConcatFormattedSecure(
952 __deref_out_z LPWSTR* ppwz,
953 __in __format_string LPCWSTR wzFormat,
954 ...
955 )
956{
957 Assert(ppwz && wzFormat && *wzFormat);
958
959 HRESULT hr = S_OK;
960 LPWSTR sczFormatted = NULL;
961 va_list args;
962
963 va_start(args, wzFormat);
964 hr = StrAllocFormattedArgsSecure(&sczFormatted, wzFormat, args);
965 va_end(args);
966 StrExitOnFailure(hr, "Failed to allocate formatted string");
967
968 hr = StrAllocConcatSecure(ppwz, sczFormatted, 0);
969
970LExit:
971 ReleaseStr(sczFormatted);
972
973 return hr;
974}
975
976
977/********************************************************************
978StrAllocFormattedSecure - allocates or reuses dynamic string memory
979and formats it. If the memory needs to be reallocated,
980calls SecureZeroMemory on original block of memory after it is moved.
981
982NOTE: caller is responsible for freeing ppwz even if function fails
983********************************************************************/
984extern "C" HRESULT __cdecl StrAllocFormattedSecure(
985 __deref_out_z LPWSTR* ppwz,
986 __in __format_string LPCWSTR wzFormat,
987 ...
988 )
989{
990 Assert(ppwz && wzFormat && *wzFormat);
991
992 HRESULT hr = S_OK;
993 va_list args;
994
995 va_start(args, wzFormat);
996 hr = StrAllocFormattedArgsSecure(ppwz, wzFormat, args);
997 va_end(args);
998
999 return hr;
1000}
1001
1002
1003/********************************************************************
1004StrAnsiAllocFormatted - allocates or reuses dynamic ANSI string memory and formats it
1005
1006NOTE: caller is responsible for freeing ppsz even if function fails
1007********************************************************************/
1008extern "C" HRESULT DAPI StrAnsiAllocFormatted(
1009 __deref_out_z LPSTR* ppsz,
1010 __in __format_string LPCSTR szFormat,
1011 ...
1012 )
1013{
1014 Assert(ppsz && szFormat && *szFormat);
1015
1016 HRESULT hr = S_OK;
1017 va_list args;
1018
1019 va_start(args, szFormat);
1020 hr = StrAnsiAllocFormattedArgs(ppsz, szFormat, args);
1021 va_end(args);
1022
1023 return hr;
1024}
1025
1026
1027/********************************************************************
1028StrAllocFormattedArgs - allocates or reuses dynamic string memory
1029and formats it with the passed in args
1030
1031NOTE: caller is responsible for freeing ppwz even if function fails
1032********************************************************************/
1033extern "C" HRESULT DAPI StrAllocFormattedArgs(
1034 __deref_out_z LPWSTR* ppwz,
1035 __in __format_string LPCWSTR wzFormat,
1036 __in va_list args
1037 )
1038{
1039 return AllocFormattedArgsHelper(ppwz, FALSE, wzFormat, args);
1040}
1041
1042
1043/********************************************************************
1044StrAllocFormattedArgsSecure - allocates or reuses dynamic string memory
1045and formats it with the passed in args.
1046
1047If the memory needs to reallocated, calls SecureZeroMemory on the
1048original block of memory after it is moved.
1049
1050NOTE: caller is responsible for freeing ppwz even if function fails
1051********************************************************************/
1052extern "C" HRESULT DAPI StrAllocFormattedArgsSecure(
1053 __deref_out_z LPWSTR* ppwz,
1054 __in __format_string LPCWSTR wzFormat,
1055 __in va_list args
1056 )
1057{
1058 return AllocFormattedArgsHelper(ppwz, TRUE, wzFormat, args);
1059}
1060
1061
1062/********************************************************************
1063AllocFormattedArgsHelper - allocates or reuses dynamic string memory
1064and formats it with the passed in args.
1065
1066If fZeroOnRealloc is true and the memory needs to reallocated,
1067calls SecureZeroMemory on original block of memory after it is moved.
1068
1069NOTE: caller is responsible for freeing ppwz even if function fails
1070********************************************************************/
1071static HRESULT AllocFormattedArgsHelper(
1072 __deref_out_z LPWSTR* ppwz,
1073 __in BOOL fZeroOnRealloc,
1074 __in __format_string LPCWSTR wzFormat,
1075 __in va_list args
1076 )
1077{
1078 Assert(ppwz && wzFormat && *wzFormat);
1079
1080 HRESULT hr = S_OK;
1081 SIZE_T cch = 0;
1082 LPWSTR pwzOriginal = NULL;
1083 SIZE_T cbOriginal = 0;
1084 size_t cchOriginal = 0;
1085
1086 if (*ppwz)
1087 {
1088 cbOriginal = MemSize(*ppwz); // get the count in bytes so we can check if it failed (returns -1)
1089 if (-1 == cbOriginal)
1090 {
1091 hr = E_INVALIDARG;
1092 StrExitOnRootFailure(hr, "failed to get size of destination string");
1093 }
1094
1095 cch = cbOriginal / sizeof(WCHAR); //convert the count in bytes to count in characters
1096
1097 hr = ::StringCchLengthW(*ppwz, STRSAFE_MAX_CCH, &cchOriginal);
1098 StrExitOnRootFailure(hr, "failed to get length of original string");
1099 }
1100
1101 if (0 == cch) // if there is no space in the string buffer
1102 {
1103 cch = 256;
1104
1105 hr = AllocHelper(ppwz, cch, fZeroOnRealloc);
1106 StrExitOnFailure(hr, "failed to allocate string to format: %ls", wzFormat);
1107 }
1108
1109 // format the message (grow until it fits or there is a failure)
1110 do
1111 {
1112 hr = ::StringCchVPrintfW(*ppwz, cch, wzFormat, args);
1113 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
1114 {
1115 if (!pwzOriginal)
1116 {
1117 // this allows you to pass the original string as a formatting argument and not crash
1118 // save the original string and free it after the printf is complete
1119 pwzOriginal = *ppwz;
1120 *ppwz = NULL;
1121
1122 // StringCchVPrintfW starts writing to the string...
1123 // NOTE: this hack only works with sprintf(&pwz, "%s ...", pwz, ...);
1124 pwzOriginal[cchOriginal] = 0;
1125 }
1126
1127 cch *= 2;
1128
1129 hr = AllocHelper(ppwz, cch, fZeroOnRealloc);
1130 StrExitOnFailure(hr, "failed to allocate string to format: %ls", wzFormat);
1131
1132 hr = S_FALSE;
1133 }
1134 } while (S_FALSE == hr);
1135 StrExitOnRootFailure(hr, "failed to format string");
1136
1137LExit:
1138 if (pwzOriginal && fZeroOnRealloc)
1139 {
1140 SecureZeroMemory(pwzOriginal, cbOriginal);
1141 }
1142
1143 ReleaseStr(pwzOriginal);
1144
1145 return hr;
1146}
1147
1148
1149/********************************************************************
1150StrAnsiAllocFormattedArgs - allocates or reuses dynamic ANSI string memory
1151and formats it with the passed in args
1152
1153NOTE: caller is responsible for freeing ppsz even if function fails
1154********************************************************************/
1155extern "C" HRESULT DAPI StrAnsiAllocFormattedArgs(
1156 __deref_out_z LPSTR* ppsz,
1157 __in __format_string LPCSTR szFormat,
1158 __in va_list args
1159 )
1160{
1161 Assert(ppsz && szFormat && *szFormat);
1162
1163 HRESULT hr = S_OK;
1164 SIZE_T cch = *ppsz ? MemSize(*ppsz) / sizeof(CHAR) : 0;
1165 LPSTR pszOriginal = NULL;
1166 size_t cchOriginal = 0;
1167
1168 if (*ppsz)
1169 {
1170 cch = MemSize(*ppsz); // get the count in bytes so we can check if it failed (returns -1)
1171 if (-1 == cch)
1172 {
1173 hr = E_INVALIDARG;
1174 StrExitOnRootFailure(hr, "failed to get size of destination string");
1175 }
1176 cch /= sizeof(CHAR); //convert the count in bytes to count in characters
1177
1178 hr = ::StringCchLengthA(*ppsz, STRSAFE_MAX_CCH, &cchOriginal);
1179 StrExitOnRootFailure(hr, "failed to get length of original string");
1180 }
1181
1182 if (0 == cch) // if there is no space in the string buffer
1183 {
1184 cch = 256;
1185 hr = StrAnsiAlloc(ppsz, cch);
1186 StrExitOnFailure(hr, "failed to allocate string to format: %s", szFormat);
1187 }
1188
1189 // format the message (grow until it fits or there is a failure)
1190 do
1191 {
1192#pragma prefast(push)
1193#pragma prefast(disable:25068) // We intentionally don't use the unicode API here
1194 hr = ::StringCchVPrintfA(*ppsz, cch, szFormat, args);
1195#pragma prefast(pop)
1196 if (STRSAFE_E_INSUFFICIENT_BUFFER == hr)
1197 {
1198 if (!pszOriginal)
1199 {
1200 // this allows you to pass the original string as a formatting argument and not crash
1201 // save the original string and free it after the printf is complete
1202 pszOriginal = *ppsz;
1203 *ppsz = NULL;
1204 // StringCchVPrintfW starts writing to the string...
1205 // NOTE: this hack only works with sprintf(&pwz, "%s ...", pwz, ...);
1206 pszOriginal[cchOriginal] = 0;
1207 }
1208 cch *= 2;
1209 hr = StrAnsiAlloc(ppsz, cch);
1210 StrExitOnFailure(hr, "failed to allocate string to format: %hs", szFormat);
1211 hr = S_FALSE;
1212 }
1213 } while (S_FALSE == hr);
1214 StrExitOnRootFailure(hr, "failed to format string");
1215
1216LExit:
1217 ReleaseStr(pszOriginal);
1218
1219 return hr;
1220}
1221
1222
1223/********************************************************************
1224StrAllocFromError - returns the string for a particular error.
1225
1226********************************************************************/
1227extern "C" HRESULT DAPI StrAllocFromError(
1228 __inout LPWSTR *ppwzMessage,
1229 __in HRESULT hrError,
1230 __in_opt HMODULE hModule,
1231 ...
1232 )
1233{
1234 HRESULT hr = S_OK;
1235 DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_SYSTEM;
1236 LPVOID pvMessage = NULL;
1237 DWORD cchMessage = 0;
1238
1239 if (hModule)
1240 {
1241 dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
1242 }
1243
1244 va_list args;
1245 va_start(args, hModule);
1246 cchMessage = ::FormatMessageW(dwFlags, static_cast<LPCVOID>(hModule), hrError, 0, reinterpret_cast<LPWSTR>(&pvMessage), 0, &args);
1247 va_end(args);
1248
1249 if (0 == cchMessage)
1250 {
1251 StrExitWithLastError(hr, "Failed to format message for error: 0x%x", hrError);
1252 }
1253
1254 hr = StrAllocString(ppwzMessage, reinterpret_cast<LPCWSTR>(pvMessage), cchMessage);
1255 StrExitOnFailure(hr, "Failed to allocate string for message.");
1256
1257LExit:
1258 if (pvMessage)
1259 {
1260 ::LocalFree(pvMessage);
1261 }
1262
1263 return hr;
1264}
1265
1266
1267/********************************************************************
1268StrMaxLength - returns maximum number of characters that can be stored in dynamic string p
1269
1270NOTE: assumes Unicode string
1271********************************************************************/
1272extern "C" HRESULT DAPI StrMaxLength(
1273 __in LPCVOID p,
1274 __out SIZE_T* pcch
1275 )
1276{
1277 Assert(pcch);
1278
1279 HRESULT hr = S_OK;
1280
1281 if (p)
1282 {
1283 *pcch = MemSize(p); // get size of entire buffer
1284 if (-1 == *pcch)
1285 {
1286 ExitFunction1(hr = E_FAIL);
1287 }
1288
1289 *pcch /= sizeof(WCHAR); // reduce to count of characters
1290 }
1291 else
1292 {
1293 *pcch = 0;
1294 }
1295 Assert(S_OK == hr);
1296
1297LExit:
1298 return hr;
1299}
1300
1301
1302/********************************************************************
1303StrSize - returns count of bytes in dynamic string p
1304
1305********************************************************************/
1306extern "C" HRESULT DAPI StrSize(
1307 __in LPCVOID p,
1308 __out SIZE_T* pcb
1309 )
1310{
1311 Assert(p && pcb);
1312
1313 HRESULT hr = S_OK;
1314
1315 *pcb = MemSize(p);
1316 if (-1 == *pcb)
1317 {
1318 hr = E_FAIL;
1319 }
1320
1321 return hr;
1322}
1323
1324/********************************************************************
1325StrFree - releases dynamic string memory allocated by any StrAlloc*() functions
1326
1327********************************************************************/
1328extern "C" HRESULT DAPI StrFree(
1329 __in LPVOID p
1330 )
1331{
1332 Assert(p);
1333
1334 HRESULT hr = MemFree(p);
1335 StrExitOnFailure(hr, "failed to free string");
1336
1337LExit:
1338 return hr;
1339}
1340
1341
1342/****************************************************************************
1343StrReplaceStringAll - Replaces wzOldSubString in ppOriginal with a wzNewSubString.
1344Replaces all instances.
1345
1346****************************************************************************/
1347extern "C" HRESULT DAPI StrReplaceStringAll(
1348 __inout LPWSTR* ppwzOriginal,
1349 __in_z LPCWSTR wzOldSubString,
1350 __in_z LPCWSTR wzNewSubString
1351 )
1352{
1353 HRESULT hr = S_OK;
1354 DWORD dwStartIndex = 0;
1355
1356 do
1357 {
1358 hr = StrReplaceString(ppwzOriginal, &dwStartIndex, wzOldSubString, wzNewSubString);
1359 StrExitOnFailure(hr, "Failed to replace substring");
1360 }
1361 while (S_OK == hr);
1362
1363 hr = (0 == dwStartIndex) ? S_FALSE : S_OK;
1364
1365LExit:
1366 return hr;
1367}
1368
1369
1370/****************************************************************************
1371StrReplaceString - Replaces wzOldSubString in ppOriginal with a wzNewSubString.
1372Search for old substring starts at dwStartIndex. Does only 1 replace.
1373
1374****************************************************************************/
1375extern "C" HRESULT DAPI StrReplaceString(
1376 __inout LPWSTR* ppwzOriginal,
1377 __inout DWORD* pdwStartIndex,
1378 __in_z LPCWSTR wzOldSubString,
1379 __in_z LPCWSTR wzNewSubString
1380 )
1381{
1382 Assert(ppwzOriginal && wzOldSubString && wzNewSubString);
1383
1384 HRESULT hr = S_FALSE;
1385 LPCWSTR wzSubLocation = NULL;
1386 LPWSTR pwzBuffer = NULL;
1387 size_t cchOldSubString = 0;
1388 size_t cchNewSubString = 0;
1389
1390 if (!*ppwzOriginal)
1391 {
1392 ExitFunction();
1393 }
1394
1395 wzSubLocation = wcsstr(*ppwzOriginal + *pdwStartIndex, wzOldSubString);
1396 if (!wzSubLocation)
1397 {
1398 ExitFunction();
1399 }
1400
1401 if (wzOldSubString)
1402 {
1403 hr = ::StringCchLengthW(wzOldSubString, STRSAFE_MAX_CCH, &cchOldSubString);
1404 StrExitOnRootFailure(hr, "Failed to get old string length.");
1405 }
1406
1407 if (wzNewSubString)
1408 {
1409 hr = ::StringCchLengthW(wzNewSubString, STRSAFE_MAX_CCH, &cchNewSubString);
1410 StrExitOnRootFailure(hr, "Failed to get new string length.");
1411 }
1412
1413 hr = ::PtrdiffTToDWord(wzSubLocation - *ppwzOriginal, pdwStartIndex);
1414 StrExitOnRootFailure(hr, "Failed to diff pointers.");
1415
1416 hr = StrAllocString(&pwzBuffer, *ppwzOriginal, wzSubLocation - *ppwzOriginal);
1417 StrExitOnFailure(hr, "Failed to duplicate string.");
1418
1419 pwzBuffer[wzSubLocation - *ppwzOriginal] = '\0';
1420
1421 hr = StrAllocConcat(&pwzBuffer, wzNewSubString, 0);
1422 StrExitOnFailure(hr, "Failed to append new string.");
1423
1424 hr = StrAllocConcat(&pwzBuffer, wzSubLocation + cchOldSubString, 0);
1425 StrExitOnFailure(hr, "Failed to append post string.");
1426
1427 hr = StrFree(*ppwzOriginal);
1428 StrExitOnFailure(hr, "Failed to free original string.");
1429
1430 *ppwzOriginal = pwzBuffer;
1431 *pdwStartIndex = *pdwStartIndex + static_cast<DWORD>(cchNewSubString);
1432 hr = S_OK;
1433
1434LExit:
1435 return hr;
1436}
1437
1438
1439static inline BYTE HexCharToByte(
1440 __in WCHAR wc
1441 )
1442{
1443 Assert(L'0' <= wc && wc <= L'9' || L'a' <= wc && wc <= L'f' || L'A' <= wc && wc <= L'F'); // make sure wc is a hex character
1444
1445 BYTE b;
1446 if (L'0' <= wc && wc <= L'9')
1447 {
1448 b = (BYTE)(wc - L'0');
1449 }
1450 else if ('a' <= wc && wc <= 'f')
1451 {
1452 b = (BYTE)(wc - L'0' - (L'a' - L'9' - 1));
1453 }
1454 else // must be (L'A' <= wc && wc <= L'F')
1455 {
1456 b = (BYTE)(wc - L'0' - (L'A' - L'9' - 1));
1457 }
1458
1459 Assert(0 <= b && b <= 15);
1460 return b;
1461}
1462
1463
1464/****************************************************************************
1465StrHexEncode - converts an array of bytes to a text string
1466
1467NOTE: wzDest must have space for cbSource * 2 + 1 characters
1468****************************************************************************/
1469extern "C" HRESULT DAPI StrHexEncode(
1470 __in_ecount(cbSource) const BYTE* pbSource,
1471 __in SIZE_T cbSource,
1472 __out_ecount(cchDest) LPWSTR wzDest,
1473 __in SIZE_T cchDest
1474 )
1475{
1476 Assert(pbSource && wzDest);
1477
1478 HRESULT hr = S_OK;
1479 DWORD i;
1480 BYTE b;
1481
1482 if (cchDest < 2 * cbSource + 1)
1483 {
1484 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
1485 }
1486
1487 for (i = 0; i < cbSource; ++i)
1488 {
1489 b = (*pbSource) >> 4;
1490 *(wzDest++) = (WCHAR)(L'0' + b + ((b < 10) ? 0 : L'A'-L'9'-1));
1491 b = (*pbSource) & 0xF;
1492 *(wzDest++) = (WCHAR)(L'0' + b + ((b < 10) ? 0 : L'A'-L'9'-1));
1493
1494 ++pbSource;
1495 }
1496
1497 *wzDest = 0;
1498
1499LExit:
1500 return hr;
1501}
1502
1503
1504/****************************************************************************
1505StrAllocHexEncode - converts an array of bytes to an allocated text string
1506
1507****************************************************************************/
1508HRESULT DAPI StrAllocHexEncode(
1509 __in_ecount(cbSource) const BYTE* pbSource,
1510 __in SIZE_T cbSource,
1511 __deref_out_ecount_z(2*(cbSource+1)) LPWSTR* ppwzDest
1512 )
1513{
1514 HRESULT hr = S_OK;
1515 SIZE_T cchSource = sizeof(WCHAR) * (cbSource + 1);
1516
1517 hr = StrAlloc(ppwzDest, cchSource);
1518 StrExitOnFailure(hr, "Failed to allocate hex string.");
1519
1520 hr = StrHexEncode(pbSource, cbSource, *ppwzDest, cchSource);
1521 StrExitOnFailure(hr, "Failed to encode hex string.");
1522
1523LExit:
1524 return hr;
1525}
1526
1527
1528/****************************************************************************
1529StrHexDecode - converts a string of text to array of bytes
1530
1531NOTE: wzSource must contain even number of characters
1532****************************************************************************/
1533extern "C" HRESULT DAPI StrHexDecode(
1534 __in_z LPCWSTR wzSource,
1535 __out_bcount(cbDest) BYTE* pbDest,
1536 __in SIZE_T cbDest
1537 )
1538{
1539 Assert(wzSource && pbDest);
1540
1541 HRESULT hr = S_OK;
1542 size_t cchSource = 0;
1543 size_t i = 0;
1544 BYTE b = 0;
1545
1546 hr = ::StringCchLengthW(wzSource, STRSAFE_MAX_CCH, &cchSource);
1547 StrExitOnRootFailure(hr, "Failed to get length of hex string: %ls", wzSource);
1548
1549 Assert(0 == cchSource % 2);
1550 if (cbDest < cchSource / 2)
1551 {
1552 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
1553 StrExitOnRootFailure(hr, "Insufficient buffer to decode string '%ls' len: %Iu into %Iu bytes.", wzSource, cchSource, cbDest);
1554 }
1555
1556 for (i = 0; i < cchSource / 2; ++i)
1557 {
1558 b = HexCharToByte(*wzSource++);
1559 (*pbDest) = b << 4;
1560
1561 b = HexCharToByte(*wzSource++);
1562 (*pbDest) |= b & 0xF;
1563
1564 ++pbDest;
1565 }
1566
1567LExit:
1568 return hr;
1569}
1570
1571
1572/****************************************************************************
1573StrAllocHexDecode - allocates a byte array hex-converted from string of text
1574
1575NOTE: wzSource must contain even number of characters
1576****************************************************************************/
1577extern "C" HRESULT DAPI StrAllocHexDecode(
1578 __in_z LPCWSTR wzSource,
1579 __out_bcount(*pcbDest) BYTE** ppbDest,
1580 __out_opt DWORD* pcbDest
1581 )
1582{
1583 Assert(wzSource && *wzSource && ppbDest);
1584
1585 HRESULT hr = S_OK;
1586 size_t cch = 0;
1587 BYTE* pb = NULL;
1588 DWORD cb = 0;
1589
1590 hr = ::StringCchLengthW(wzSource, STRSAFE_MAX_CCH, &cch);
1591 StrExitOnFailure(hr, "Failed to calculate length of source string.");
1592
1593 if (cch % 2)
1594 {
1595 hr = E_INVALIDARG;
1596 StrExitOnFailure(hr, "Invalid source parameter, string must be even length or it cannot be decoded.");
1597 }
1598
1599 cb = static_cast<DWORD>(cch / 2);
1600 pb = static_cast<BYTE*>(MemAlloc(cb, TRUE));
1601 StrExitOnNull(pb, hr, E_OUTOFMEMORY, "Failed to allocate memory for hex decode.");
1602
1603 hr = StrHexDecode(wzSource, pb, cb);
1604 StrExitOnFailure(hr, "Failed to decode source string.");
1605
1606 *ppbDest = pb;
1607 pb = NULL;
1608
1609 if (pcbDest)
1610 {
1611 *pcbDest = cb;
1612 }
1613
1614LExit:
1615 ReleaseMem(pb);
1616
1617 return hr;
1618}
1619
1620
1621/****************************************************************************
1622Base85 encoding/decoding data
1623
1624****************************************************************************/
1625const WCHAR Base85EncodeTable[] = L"!%'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~";
1626
1627const BYTE Base85DecodeTable[256] =
1628{
1629 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1630 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1631 85, 0, 85, 85, 85, 1, 85, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1632 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 85, 85, 85, 23,
1633 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
1634 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 85, 52, 53, 54,
1635 85, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
1636 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
1637 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1638 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1639 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1640 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1641 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1642 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1643 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
1644 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85
1645};
1646
1647const UINT Base85PowerTable[4] = { 1, 85, 85*85, 85*85*85 };
1648
1649
1650/****************************************************************************
1651StrAllocBase85Encode - converts an array of bytes into an XML compatible string
1652
1653****************************************************************************/
1654extern "C" HRESULT DAPI StrAllocBase85Encode(
1655 __in_bcount_opt(cbSource) const BYTE* pbSource,
1656 __in SIZE_T cbSource,
1657 __deref_out_z LPWSTR* pwzDest
1658 )
1659{
1660 HRESULT hr = S_OK;
1661 SIZE_T cchDest = 0;
1662 LPWSTR wzDest;
1663 DWORD_PTR iSource = 0;
1664 DWORD_PTR iDest = 0;
1665
1666 if (!pwzDest || !pbSource)
1667 {
1668 return E_INVALIDARG;
1669 }
1670
1671 // calc actual size of output
1672 cchDest = cbSource / 4;
1673 cchDest += cchDest * 4;
1674 if (cbSource & 3)
1675 {
1676 cchDest += (cbSource & 3) + 1;
1677 }
1678 ++cchDest; // add room for null terminator
1679
1680 hr = StrAlloc(pwzDest, cchDest);
1681 StrExitOnFailure(hr, "failed to allocate destination string");
1682
1683 wzDest = *pwzDest;
1684
1685 // first, encode full words
1686 for (iSource = 0, iDest = 0; (iSource + 4 < cbSource) && (iDest + 5 < cchDest); iSource += 4, iDest += 5)
1687 {
1688 DWORD n = pbSource[iSource] + (pbSource[iSource + 1] << 8) + (pbSource[iSource + 2] << 16) + (pbSource[iSource + 3] << 24);
1689 DWORD k = n / 85;
1690
1691 //Assert(0 <= (n - k * 85) && (n - k * 85) < countof(Base85EncodeTable));
1692 wzDest[iDest] = Base85EncodeTable[n - k * 85];
1693 n = k / 85;
1694
1695 //Assert(0 <= (k - n * 85) && (k - n * 85) < countof(Base85EncodeTable));
1696 wzDest[iDest + 1] = Base85EncodeTable[k - n * 85];
1697 k = n / 85;
1698
1699 //Assert(0 <= (n - k * 85) && (n - k * 85) < countof(Base85EncodeTable));
1700 wzDest[iDest + 2] = Base85EncodeTable[n - k * 85];
1701 n = k / 85;
1702
1703 //Assert(0 <= (k - n * 85) && (k - n * 85) < countof(Base85EncodeTable));
1704 wzDest[iDest + 3] = Base85EncodeTable[k - n * 85];
1705
1706 __assume(n <= DWORD_MAX / 85 / 85 / 85 / 85);
1707
1708 //Assert(0 <= n && n < countof(Base85EncodeTable));
1709 wzDest[iDest + 4] = Base85EncodeTable[n];
1710 }
1711
1712 // encode any remaining bytes
1713 if (iSource < cbSource)
1714 {
1715 DWORD n = 0;
1716 for (DWORD i = 0; iSource + i < cbSource; ++i)
1717 {
1718 n += pbSource[iSource + i] << (i << 3);
1719 }
1720
1721 for (/* iSource already initialized */; iSource < cbSource && iDest < cchDest; ++iSource, ++iDest)
1722 {
1723 DWORD k = n / 85;
1724
1725 //Assert(0 <= (n - k * 85) && (n - k * 85) < countof(Base85EncodeTable));
1726 wzDest[iDest] = Base85EncodeTable[n - k * 85];
1727
1728 n = k;
1729 }
1730
1731 wzDest[iDest] = Base85EncodeTable[n];
1732 ++iDest;
1733 }
1734 Assert(iSource == cbSource);
1735 Assert(iDest == cchDest - 1);
1736
1737 wzDest[iDest] = L'\0';
1738 hr = S_OK;
1739
1740LExit:
1741 return hr;
1742}
1743
1744
1745/****************************************************************************
1746StrAllocBase85Decode - converts a string of text to array of bytes
1747
1748NOTE: Use MemFree() to release the allocated stream of bytes
1749****************************************************************************/
1750extern "C" HRESULT DAPI StrAllocBase85Decode(
1751 __in_z LPCWSTR wzSource,
1752 __deref_out_bcount(*pcbDest) BYTE** ppbDest,
1753 __out SIZE_T* pcbDest
1754 )
1755{
1756 HRESULT hr = S_OK;
1757 size_t cchSource = 0;
1758 DWORD_PTR i, n, k;
1759
1760 BYTE* pbDest = 0;
1761 SIZE_T cbDest = 0;
1762
1763 if (!wzSource || !ppbDest || !pcbDest)
1764 {
1765 ExitFunction1(hr = E_INVALIDARG);
1766 }
1767
1768 hr = ::StringCchLengthW(wzSource, STRSAFE_MAX_CCH, &cchSource);
1769 StrExitOnRootFailure(hr, "failed to get length of base 85 string: %ls", wzSource);
1770
1771 // evaluate size of output and check it
1772 k = cchSource / 5;
1773 cbDest = k << 2;
1774 k = cchSource - k * 5;
1775 if (k)
1776 {
1777 if (1 == k)
1778 {
1779 // decode error -- encoded size cannot equal 1 mod 5
1780 return E_UNEXPECTED;
1781 }
1782
1783 cbDest += k - 1;
1784 }
1785
1786 *ppbDest = static_cast<BYTE*>(MemAlloc(cbDest, FALSE));
1787 StrExitOnNull(*ppbDest, hr, E_OUTOFMEMORY, "failed allocate memory to decode the string");
1788
1789 pbDest = *ppbDest;
1790 *pcbDest = cbDest;
1791
1792 // decode full words first
1793 while (5 <= cchSource)
1794 {
1795 k = Base85DecodeTable[wzSource[0]];
1796 if (85 == k)
1797 {
1798 // illegal symbol
1799 return E_UNEXPECTED;
1800 }
1801 n = k;
1802
1803 k = Base85DecodeTable[wzSource[1]];
1804 if (85 == k)
1805 {
1806 // illegal symbol
1807 return E_UNEXPECTED;
1808 }
1809 n += k * 85;
1810
1811 k = Base85DecodeTable[wzSource[2]];
1812 if (85 == k)
1813 {
1814 // illegal symbol
1815 return E_UNEXPECTED;
1816 }
1817 n += k * (85 * 85);
1818
1819 k = Base85DecodeTable[wzSource[3]];
1820 if (85 == k)
1821 {
1822 // illegal symbol
1823 return E_UNEXPECTED;
1824 }
1825 n += k * (85 * 85 * 85);
1826
1827 k = Base85DecodeTable[wzSource[4]];
1828 if (85 == k)
1829 {
1830 // illegal symbol
1831 return E_UNEXPECTED;
1832 }
1833 k *= (85 * 85 * 85 * 85);
1834
1835 // if (k + n > (1u << 32)) <=> (k > ~n) then decode error
1836 if (k > ~n)
1837 {
1838 // overflow
1839 return E_UNEXPECTED;
1840 }
1841
1842 n += k;
1843
1844 pbDest[0] = (BYTE) n;
1845 pbDest[1] = (BYTE) (n >> 8);
1846 pbDest[2] = (BYTE) (n >> 16);
1847 pbDest[3] = (BYTE) (n >> 24);
1848
1849 wzSource += 5;
1850 pbDest += 4;
1851 cchSource -= 5;
1852 }
1853
1854 if (cchSource)
1855 {
1856 n = 0;
1857 for (i = 0; i < cchSource; ++i)
1858 {
1859 k = Base85DecodeTable[wzSource[i]];
1860 if (85 == k)
1861 {
1862 // illegal symbol
1863 return E_UNEXPECTED;
1864 }
1865
1866 n += k * Base85PowerTable[i];
1867 }
1868
1869 for (i = 1; i < cchSource; ++i)
1870 {
1871 *pbDest++ = (BYTE)n;
1872 n >>= 8;
1873 }
1874
1875 if (0 != n)
1876 {
1877 // decode error
1878 return E_UNEXPECTED;
1879 }
1880 }
1881
1882 hr = S_OK;
1883
1884LExit:
1885 return hr;
1886}
1887
1888
1889/****************************************************************************
1890MultiSzLen - calculates the length of a MULTISZ string including all nulls
1891including the double null terminator at the end of the MULTISZ.
1892
1893NOTE: returns 0 if the multisz in not properly terminated with two nulls
1894****************************************************************************/
1895extern "C" HRESULT DAPI MultiSzLen(
1896 __in_ecount(*pcch) __nullnullterminated LPCWSTR pwzMultiSz,
1897 __out SIZE_T* pcch
1898)
1899{
1900 Assert(pcch);
1901
1902 HRESULT hr = S_OK;
1903 LPCWSTR wz = pwzMultiSz;
1904 DWORD_PTR dwMaxSize = 0;
1905
1906 hr = StrMaxLength(pwzMultiSz, &dwMaxSize);
1907 StrExitOnFailure(hr, "failed to get the max size of a string while calculating MULTISZ length");
1908
1909 *pcch = 0;
1910 while (*pcch < dwMaxSize)
1911 {
1912 if (L'\0' == *wz && L'\0' == *(wz + 1))
1913 {
1914 break;
1915 }
1916
1917 ++wz;
1918 *pcch = *pcch + 1;
1919 }
1920
1921 // Add two for the last 2 NULLs (that we looked ahead at)
1922 *pcch = *pcch + 2;
1923
1924 // If we've walked off the end then the length is 0
1925 if (*pcch > dwMaxSize)
1926 {
1927 *pcch = 0;
1928 }
1929
1930LExit:
1931 return hr;
1932}
1933
1934
1935/****************************************************************************
1936MultiSzPrepend - prepends a string onto the front of a MUTLISZ
1937
1938****************************************************************************/
1939extern "C" HRESULT DAPI MultiSzPrepend(
1940 __deref_inout_ecount(*pcchMultiSz) __nullnullterminated LPWSTR* ppwzMultiSz,
1941 __inout_opt SIZE_T* pcchMultiSz,
1942 __in __nullnullterminated LPCWSTR pwzInsert
1943 )
1944{
1945 Assert(ppwzMultiSz && pwzInsert && *pwzInsert);
1946
1947 HRESULT hr =S_OK;
1948 LPWSTR pwzResult = NULL;
1949 SIZE_T cchResult = 0;
1950 SIZE_T cchInsert = 0;
1951 SIZE_T cchMultiSz = 0;
1952
1953 // Get the lengths of the MULTISZ (and prime it if it's not initialized)
1954 if (pcchMultiSz && 0 != *pcchMultiSz)
1955 {
1956 cchMultiSz = *pcchMultiSz;
1957 }
1958 else
1959 {
1960 hr = MultiSzLen(*ppwzMultiSz, &cchMultiSz);
1961 StrExitOnFailure(hr, "failed to get length of multisz");
1962 }
1963
1964 hr = ::StringCchLengthW(pwzInsert, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchInsert));
1965 StrExitOnRootFailure(hr, "failed to get length of insert string");
1966
1967 cchResult = cchInsert + cchMultiSz + 1;
1968
1969 // Allocate the result buffer
1970 hr = StrAlloc(&pwzResult, cchResult + 1);
1971 StrExitOnFailure(hr, "failed to allocate result string");
1972
1973 // Prepend
1974 hr = ::StringCchCopyW(pwzResult, cchResult, pwzInsert);
1975 StrExitOnRootFailure(hr, "failed to copy prepend string: %ls", pwzInsert);
1976
1977 // If there was no MULTISZ, double null terminate our result, otherwise, copy the MULTISZ in
1978 if (0 == cchMultiSz)
1979 {
1980 pwzResult[cchResult] = L'\0';
1981 ++cchResult;
1982 }
1983 else
1984 {
1985 // Copy the rest
1986 ::CopyMemory(pwzResult + cchInsert + 1, *ppwzMultiSz, cchMultiSz * sizeof(WCHAR));
1987
1988 // Free the old buffer
1989 ReleaseNullStr(*ppwzMultiSz);
1990 }
1991
1992 // Set the result
1993 *ppwzMultiSz = pwzResult;
1994
1995 if (pcchMultiSz)
1996 {
1997 *pcchMultiSz = cchResult;
1998 }
1999
2000 pwzResult = NULL;
2001
2002LExit:
2003 ReleaseNullStr(pwzResult);
2004
2005 return hr;
2006}
2007
2008/****************************************************************************
2009MultiSzFindSubstring - case insensitive find of a string in a MULTISZ that contains the
2010specified sub string and returns the index of the
2011string in the MULTISZ, the address, neither, or both
2012
2013NOTE: returns S_FALSE if the string is not found
2014****************************************************************************/
2015extern "C" HRESULT DAPI MultiSzFindSubstring(
2016 __in __nullnullterminated LPCWSTR pwzMultiSz,
2017 __in __nullnullterminated LPCWSTR pwzSubstring,
2018 __out_opt DWORD_PTR* pdwIndex,
2019 __deref_opt_out __nullnullterminated LPCWSTR* ppwzFoundIn
2020 )
2021{
2022 Assert(pwzMultiSz && *pwzMultiSz && pwzSubstring && *pwzSubstring);
2023
2024 HRESULT hr = S_FALSE; // Assume we won't find it (the glass is half empty)
2025 LPCWSTR wz = pwzMultiSz;
2026 DWORD_PTR dwIndex = 0;
2027 SIZE_T cchMultiSz = 0;
2028 SIZE_T cchProgress = 0;
2029
2030 hr = MultiSzLen(pwzMultiSz, &cchMultiSz);
2031 StrExitOnFailure(hr, "failed to get the length of a MULTISZ string");
2032
2033 // Find the string containing the sub string
2034 hr = S_OK;
2035 while (NULL == wcsistr(wz, pwzSubstring))
2036 {
2037 // Slide through to the end of the current string
2038 while (L'\0' != *wz && cchProgress < cchMultiSz)
2039 {
2040 ++wz;
2041 ++cchProgress;
2042 }
2043
2044 // If we're done, we're done
2045 if (L'\0' == *(wz + 1) || cchProgress >= cchMultiSz)
2046 {
2047 hr = S_FALSE;
2048 break;
2049 }
2050
2051 // Move on to the next string
2052 ++wz;
2053 ++dwIndex;
2054 }
2055 Assert(S_OK == hr || S_FALSE == hr);
2056
2057 // If we found it give them what they want
2058 if (S_OK == hr)
2059 {
2060 if (pdwIndex)
2061 {
2062 *pdwIndex = dwIndex;
2063 }
2064
2065 if (ppwzFoundIn)
2066 {
2067 *ppwzFoundIn = wz;
2068 }
2069 }
2070
2071LExit:
2072 return hr;
2073}
2074
2075/****************************************************************************
2076MultiSzFindString - finds a string in a MULTISZ and returns the index of
2077the string in the MULTISZ, the address or both
2078
2079NOTE: returns S_FALSE if the string is not found
2080****************************************************************************/
2081extern "C" HRESULT DAPI MultiSzFindString(
2082 __in __nullnullterminated LPCWSTR pwzMultiSz,
2083 __in __nullnullterminated LPCWSTR pwzString,
2084 __out_opt DWORD_PTR* pdwIndex,
2085 __deref_opt_out __nullnullterminated LPCWSTR* ppwzFound
2086 )
2087{
2088 Assert(pwzMultiSz && *pwzMultiSz && pwzString && *pwzString && (pdwIndex || ppwzFound));
2089
2090 HRESULT hr = S_FALSE; // Assume we won't find it
2091 LPCWSTR wz = pwzMultiSz;
2092 DWORD_PTR dwIndex = 0;
2093 SIZE_T cchMutliSz = 0;
2094 SIZE_T cchProgress = 0;
2095
2096 hr = MultiSzLen(pwzMultiSz, &cchMutliSz);
2097 StrExitOnFailure(hr, "failed to get the length of a MULTISZ string");
2098
2099 // Find the string
2100 hr = S_OK;
2101 while (0 != lstrcmpW(wz, pwzString))
2102 {
2103 // Slide through to the end of the current string
2104 while (L'\0' != *wz && cchProgress < cchMutliSz)
2105 {
2106 ++wz;
2107 ++cchProgress;
2108 }
2109
2110 // If we're done, we're done
2111 if (L'\0' == *(wz + 1) || cchProgress >= cchMutliSz)
2112 {
2113 hr = S_FALSE;
2114 break;
2115 }
2116
2117 // Move on to the next string
2118 ++wz;
2119 ++dwIndex;
2120 }
2121 Assert(S_OK == hr || S_FALSE == hr);
2122
2123 // If we found it give them what they want
2124 if (S_OK == hr)
2125 {
2126 if (pdwIndex)
2127 {
2128 *pdwIndex = dwIndex;
2129 }
2130
2131 if (ppwzFound)
2132 {
2133 *ppwzFound = wz;
2134 }
2135 }
2136
2137LExit:
2138 return hr;
2139}
2140
2141/****************************************************************************
2142MultiSzRemoveString - removes string from a MULTISZ at the specified
2143index
2144
2145NOTE: does an in place removal without shrinking the memory allocation
2146
2147NOTE: returns S_FALSE if the MULTISZ has fewer strings than dwIndex
2148****************************************************************************/
2149extern "C" HRESULT DAPI MultiSzRemoveString(
2150 __deref_inout __nullnullterminated LPWSTR* ppwzMultiSz,
2151 __in DWORD_PTR dwIndex
2152 )
2153{
2154 Assert(ppwzMultiSz && *ppwzMultiSz);
2155
2156 HRESULT hr = S_OK;
2157 LPCWSTR wz = *ppwzMultiSz;
2158 LPCWSTR wzNext = NULL;
2159 DWORD_PTR dwCurrentIndex = 0;
2160 SIZE_T cchMultiSz = 0;
2161 SIZE_T cchProgress = 0;
2162
2163 hr = MultiSzLen(*ppwzMultiSz, &cchMultiSz);
2164 StrExitOnFailure(hr, "failed to get the length of a MULTISZ string");
2165
2166 // Find the index we want to remove
2167 hr = S_OK;
2168 while (dwCurrentIndex < dwIndex)
2169 {
2170 // Slide through to the end of the current string
2171 while (L'\0' != *wz && cchProgress < cchMultiSz)
2172 {
2173 ++wz;
2174 ++cchProgress;
2175 }
2176
2177 // If we're done, we're done
2178 if (L'\0' == *(wz + 1) || cchProgress >= cchMultiSz)
2179 {
2180 hr = S_FALSE;
2181 break;
2182 }
2183
2184 // Move on to the next string
2185 ++wz;
2186 ++cchProgress;
2187 ++dwCurrentIndex;
2188 }
2189 Assert(S_OK == hr || S_FALSE == hr);
2190
2191 // If we found the index to be removed
2192 if (S_OK == hr)
2193 {
2194 wzNext = wz;
2195
2196 // Slide through to the end of the current string
2197 while (L'\0' != *wzNext && cchProgress < cchMultiSz)
2198 {
2199 ++wzNext;
2200 ++cchProgress;
2201 }
2202
2203 // Something weird has happened if we're past the end of the MULTISZ
2204 if (cchProgress > cchMultiSz)
2205 {
2206 hr = E_UNEXPECTED;
2207 StrExitOnFailure(hr, "failed to move past the string to be removed from MULTISZ");
2208 }
2209
2210 // Move on to the next character
2211 ++wzNext;
2212 ++cchProgress;
2213
2214 ::MoveMemory((LPVOID)wz, (LPVOID)wzNext, (cchMultiSz - cchProgress) * sizeof(WCHAR));
2215 }
2216
2217LExit:
2218 return hr;
2219}
2220
2221/****************************************************************************
2222MultiSzInsertString - inserts new string at the specified index
2223
2224****************************************************************************/
2225extern "C" HRESULT DAPI MultiSzInsertString(
2226 __deref_inout __nullnullterminated LPWSTR* ppwzMultiSz,
2227 __inout_opt SIZE_T* pcchMultiSz,
2228 __in DWORD_PTR dwIndex,
2229 __in_z LPCWSTR pwzInsert
2230 )
2231{
2232 Assert(ppwzMultiSz && pwzInsert && *pwzInsert);
2233
2234 HRESULT hr = S_OK;
2235 LPCWSTR wz = *ppwzMultiSz;
2236 DWORD_PTR dwCurrentIndex = 0;
2237 SIZE_T cchProgress = 0;
2238 LPWSTR pwzResult = NULL;
2239 SIZE_T cchResult = 0;
2240 SIZE_T cchString = 0;
2241 SIZE_T cchMultiSz = 0;
2242
2243 hr = ::StringCchLengthW(pwzInsert, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchString));
2244 StrExitOnRootFailure(hr, "failed to get length of insert string");
2245
2246 if (pcchMultiSz && 0 != *pcchMultiSz)
2247 {
2248 cchMultiSz = *pcchMultiSz;
2249 }
2250 else
2251 {
2252 hr = MultiSzLen(*ppwzMultiSz, &cchMultiSz);
2253 StrExitOnFailure(hr, "failed to get the length of a MULTISZ string");
2254 }
2255
2256 // Find the index we want to insert at
2257 hr = S_OK;
2258 while (dwCurrentIndex < dwIndex)
2259 {
2260 // Slide through to the end of the current string
2261 while (L'\0' != *wz && cchProgress < cchMultiSz)
2262 {
2263 ++wz;
2264 ++cchProgress;
2265 }
2266
2267 // If we're done, we're done
2268 if ((dwCurrentIndex + 1 != dwIndex && L'\0' == *(wz + 1)) || cchProgress >= cchMultiSz)
2269 {
2270 hr = HRESULT_FROM_WIN32(ERROR_OBJECT_NOT_FOUND);
2271 StrExitOnRootFailure(hr, "requested to insert into an invalid index: %u in a MULTISZ", dwIndex);
2272 }
2273
2274 // Move on to the next string
2275 ++wz;
2276 ++cchProgress;
2277 ++dwCurrentIndex;
2278 }
2279
2280 //
2281 // Insert the string
2282 //
2283 cchResult = cchMultiSz + cchString + 1;
2284
2285 hr = StrAlloc(&pwzResult, cchResult);
2286 StrExitOnFailure(hr, "failed to allocate result string for MULTISZ insert");
2287
2288 // Copy the part before the insert
2289 ::CopyMemory(pwzResult, *ppwzMultiSz, cchProgress * sizeof(WCHAR));
2290
2291 // Copy the insert part
2292 ::CopyMemory(pwzResult + cchProgress, pwzInsert, (cchString + 1) * sizeof(WCHAR));
2293
2294 // Copy the part after the insert
2295 ::CopyMemory(pwzResult + cchProgress + cchString + 1, wz, (cchMultiSz - cchProgress) * sizeof(WCHAR));
2296
2297 // Free the old buffer
2298 ReleaseNullStr(*ppwzMultiSz);
2299
2300 // Set the result
2301 *ppwzMultiSz = pwzResult;
2302
2303 // If they wanted the resulting length, let 'em have it
2304 if (pcchMultiSz)
2305 {
2306 *pcchMultiSz = cchResult;
2307 }
2308
2309 pwzResult = NULL;
2310
2311LExit:
2312 ReleaseStr(pwzResult);
2313
2314 return hr;
2315}
2316
2317/****************************************************************************
2318MultiSzReplaceString - replaces string at the specified index with a new one
2319
2320****************************************************************************/
2321extern "C" HRESULT DAPI MultiSzReplaceString(
2322 __deref_inout __nullnullterminated LPWSTR* ppwzMultiSz,
2323 __in DWORD_PTR dwIndex,
2324 __in_z LPCWSTR pwzString
2325 )
2326{
2327 Assert(ppwzMultiSz && pwzString && *pwzString);
2328
2329 HRESULT hr = S_OK;
2330
2331 hr = MultiSzRemoveString(ppwzMultiSz, dwIndex);
2332 StrExitOnFailure(hr, "failed to remove string from MULTISZ at the specified index: %u", dwIndex);
2333
2334 hr = MultiSzInsertString(ppwzMultiSz, NULL, dwIndex, pwzString);
2335 StrExitOnFailure(hr, "failed to insert string into MULTISZ at the specified index: %u", dwIndex);
2336
2337LExit:
2338 return hr;
2339}
2340
2341
2342/****************************************************************************
2343wcsistr - case insensitive find a substring
2344
2345****************************************************************************/
2346extern "C" LPCWSTR DAPI wcsistr(
2347 __in_z LPCWSTR wzString,
2348 __in_z LPCWSTR wzCharSet
2349 )
2350{
2351 LPCWSTR wzSource = wzString;
2352 LPCWSTR wzSearch = NULL;
2353 SIZE_T cchSourceIndex = 0;
2354
2355 // Walk through wzString (the source string) one character at a time
2356 while (*wzSource)
2357 {
2358 cchSourceIndex = 0;
2359 wzSearch = wzCharSet;
2360
2361 // Look ahead in the source string until we get a full match or we hit the end of the source
2362 while (L'\0' != wzSource[cchSourceIndex] && L'\0' != *wzSearch && towlower(wzSource[cchSourceIndex]) == towlower(*wzSearch))
2363 {
2364 ++cchSourceIndex;
2365 ++wzSearch;
2366 }
2367
2368 // If we found it, return the point that we found it at
2369 if (L'\0' == *wzSearch)
2370 {
2371 return wzSource;
2372 }
2373
2374 // Walk ahead one character
2375 ++wzSource;
2376 }
2377
2378 return NULL;
2379}
2380
2381/****************************************************************************
2382StrStringToInt16 - converts a string to a signed 16-bit integer.
2383
2384****************************************************************************/
2385extern "C" HRESULT DAPI StrStringToInt16(
2386 __in_z LPCWSTR wzIn,
2387 __in DWORD cchIn,
2388 __out SHORT* psOut
2389 )
2390{
2391 HRESULT hr = S_OK;
2392 LONGLONG ll = 0;
2393
2394 hr = StrStringToInt64(wzIn, cchIn, &ll);
2395 StrExitOnFailure(hr, "Failed to parse int64.");
2396
2397 if (SHORT_MAX < ll || SHORT_MIN > ll)
2398 {
2399 ExitFunction1(hr = DISP_E_OVERFLOW);
2400 }
2401 *psOut = (SHORT)ll;
2402
2403LExit:
2404 return hr;
2405}
2406
2407/****************************************************************************
2408StrStringToUInt16 - converts a string to an unsigned 16-bit integer.
2409
2410****************************************************************************/
2411extern "C" HRESULT DAPI StrStringToUInt16(
2412 __in_z LPCWSTR wzIn,
2413 __in DWORD cchIn,
2414 __out USHORT* pusOut
2415 )
2416{
2417 HRESULT hr = S_OK;
2418 ULONGLONG ull = 0;
2419
2420 hr = StrStringToUInt64(wzIn, cchIn, &ull);
2421 StrExitOnFailure(hr, "Failed to parse uint64.");
2422
2423 if (USHORT_MAX < ull)
2424 {
2425 ExitFunction1(hr = DISP_E_OVERFLOW);
2426 }
2427 *pusOut = (USHORT)ull;
2428
2429LExit:
2430 return hr;
2431}
2432
2433/****************************************************************************
2434StrStringToInt32 - converts a string to a signed 32-bit integer.
2435
2436****************************************************************************/
2437extern "C" HRESULT DAPI StrStringToInt32(
2438 __in_z LPCWSTR wzIn,
2439 __in DWORD cchIn,
2440 __out INT* piOut
2441 )
2442{
2443 HRESULT hr = S_OK;
2444 LONGLONG ll = 0;
2445
2446 hr = StrStringToInt64(wzIn, cchIn, &ll);
2447 StrExitOnFailure(hr, "Failed to parse int64.");
2448
2449 if (INT_MAX < ll || INT_MIN > ll)
2450 {
2451 ExitFunction1(hr = DISP_E_OVERFLOW);
2452 }
2453 *piOut = (INT)ll;
2454
2455LExit:
2456 return hr;
2457}
2458
2459/****************************************************************************
2460StrStringToUInt32 - converts a string to an unsigned 32-bit integer.
2461
2462****************************************************************************/
2463extern "C" HRESULT DAPI StrStringToUInt32(
2464 __in_z LPCWSTR wzIn,
2465 __in DWORD cchIn,
2466 __out UINT* puiOut
2467 )
2468{
2469 HRESULT hr = S_OK;
2470 ULONGLONG ull = 0;
2471
2472 hr = StrStringToUInt64(wzIn, cchIn, &ull);
2473 StrExitOnFailure(hr, "Failed to parse uint64.");
2474
2475 if (UINT_MAX < ull)
2476 {
2477 ExitFunction1(hr = DISP_E_OVERFLOW);
2478 }
2479 *puiOut = (UINT)ull;
2480
2481LExit:
2482 return hr;
2483}
2484
2485/****************************************************************************
2486StrStringToInt64 - converts a string to a signed 64-bit integer.
2487
2488****************************************************************************/
2489extern "C" HRESULT DAPI StrStringToInt64(
2490 __in_z LPCWSTR wzIn,
2491 __in DWORD cchIn,
2492 __out LONGLONG* pllOut
2493 )
2494{
2495 HRESULT hr = S_OK;
2496 DWORD i = 0;
2497 INT iSign = 1;
2498 INT nDigit = 0;
2499 LARGE_INTEGER liValue = { };
2500 size_t cchString = 0;
2501
2502 // get string length if not provided
2503 if (0 >= cchIn)
2504 {
2505 hr = ::StringCchLengthW(wzIn, STRSAFE_MAX_CCH, &cchString);
2506 StrExitOnRootFailure(hr, "Failed to get length of string.");
2507
2508 cchIn = (DWORD)cchString;
2509 if (0 >= cchIn)
2510 {
2511 ExitFunction1(hr = E_INVALIDARG);
2512 }
2513 }
2514
2515 // check sign
2516 if (L'-' == wzIn[0])
2517 {
2518 if (1 >= cchIn)
2519 {
2520 ExitFunction1(hr = E_INVALIDARG);
2521 }
2522 i = 1;
2523 iSign = -1;
2524 }
2525
2526 // read digits
2527 while (i < cchIn)
2528 {
2529 nDigit = wzIn[i] - L'0';
2530 if (0 > nDigit || 9 < nDigit)
2531 {
2532 ExitFunction1(hr = E_INVALIDARG);
2533 }
2534 liValue.QuadPart = liValue.QuadPart * 10 + nDigit * iSign;
2535
2536 if ((liValue.HighPart ^ iSign) & INT_MIN)
2537 {
2538 ExitFunction1(hr = DISP_E_OVERFLOW);
2539 }
2540 ++i;
2541 }
2542
2543 *pllOut = liValue.QuadPart;
2544
2545LExit:
2546 return hr;
2547}
2548
2549/****************************************************************************
2550StrStringToUInt64 - converts a string to an unsigned 64-bit integer.
2551
2552****************************************************************************/
2553extern "C" HRESULT DAPI StrStringToUInt64(
2554 __in_z LPCWSTR wzIn,
2555 __in DWORD cchIn,
2556 __out ULONGLONG* pullOut
2557 )
2558{
2559 HRESULT hr = S_OK;
2560 DWORD i = 0;
2561 DWORD nDigit = 0;
2562 ULONGLONG ullValue = 0;
2563 ULONGLONG ull = 0;
2564 size_t cchString = 0;
2565
2566 // get string length if not provided
2567 if (0 >= cchIn)
2568 {
2569 hr = ::StringCchLengthW(wzIn, STRSAFE_MAX_CCH, &cchString);
2570 StrExitOnRootFailure(hr, "Failed to get length of string.");
2571
2572 cchIn = (DWORD)cchString;
2573 if (0 >= cchIn)
2574 {
2575 ExitFunction1(hr = E_INVALIDARG);
2576 }
2577 }
2578
2579 // read digits
2580 while (i < cchIn)
2581 {
2582 nDigit = wzIn[i] - L'0';
2583 if (9 < nDigit)
2584 {
2585 ExitFunction1(hr = E_INVALIDARG);
2586 }
2587 ull = (ULONGLONG)(ullValue * 10 + nDigit);
2588
2589 if (ull < ullValue)
2590 {
2591 ExitFunction1(hr = DISP_E_OVERFLOW);
2592 }
2593 ullValue = ull;
2594 ++i;
2595 }
2596
2597 *pullOut = ullValue;
2598
2599LExit:
2600 return hr;
2601}
2602
2603/****************************************************************************
2604StrStringToUpper - alters the given string in-place to be entirely uppercase
2605
2606****************************************************************************/
2607void DAPI StrStringToUpper(
2608 __inout_z LPWSTR wzIn
2609 )
2610{
2611 ::CharUpperBuffW(wzIn, lstrlenW(wzIn));
2612}
2613
2614/****************************************************************************
2615StrStringToLower - alters the given string in-place to be entirely lowercase
2616
2617****************************************************************************/
2618void DAPI StrStringToLower(
2619 __inout_z LPWSTR wzIn
2620 )
2621{
2622 ::CharLowerBuffW(wzIn, lstrlenW(wzIn));
2623}
2624
2625/****************************************************************************
2626StrAllocStringToUpperInvariant - creates an upper-case copy of a string.
2627
2628****************************************************************************/
2629extern "C" HRESULT DAPI StrAllocStringToUpperInvariant(
2630 __deref_out_z LPWSTR* pscz,
2631 __in_z LPCWSTR wzSource,
2632 __in SIZE_T cchSource
2633 )
2634{
2635 return StrAllocStringMapInvariant(pscz, wzSource, cchSource, LCMAP_UPPERCASE);
2636}
2637
2638/****************************************************************************
2639StrAllocStringToLowerInvariant - creates an lower-case copy of a string.
2640
2641****************************************************************************/
2642extern "C" HRESULT DAPI StrAllocStringToLowerInvariant(
2643 __deref_out_z LPWSTR* pscz,
2644 __in_z LPCWSTR wzSource,
2645 __in SIZE_T cchSource
2646 )
2647{
2648 return StrAllocStringMapInvariant(pscz, wzSource, cchSource, LCMAP_LOWERCASE);
2649}
2650
2651/****************************************************************************
2652StrArrayAllocString - Allocates a string array.
2653
2654****************************************************************************/
2655extern "C" HRESULT DAPI StrArrayAllocString(
2656 __deref_inout_ecount_opt(*pcStrArray) LPWSTR **prgsczStrArray,
2657 __inout LPUINT pcStrArray,
2658 __in_z LPCWSTR wzSource,
2659 __in SIZE_T cchSource
2660 )
2661{
2662 HRESULT hr = S_OK;
2663 UINT cNewStrArray;
2664
2665 hr = ::UIntAdd(*pcStrArray, 1, &cNewStrArray);
2666 StrExitOnFailure(hr, "Failed to increment the string array element count.");
2667
2668 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgsczStrArray), cNewStrArray, sizeof(LPWSTR), ARRAY_GROWTH_SIZE);
2669 StrExitOnFailure(hr, "Failed to allocate memory for the string array.");
2670
2671 hr = StrAllocString(&(*prgsczStrArray)[*pcStrArray], wzSource, cchSource);
2672 StrExitOnFailure(hr, "Failed to allocate and assign the string.");
2673
2674 *pcStrArray = cNewStrArray;
2675
2676LExit:
2677 return hr;
2678}
2679
2680/****************************************************************************
2681StrArrayFree - Frees a string array.
2682
2683Use ReleaseNullStrArray to nullify the arguments.
2684
2685****************************************************************************/
2686extern "C" HRESULT DAPI StrArrayFree(
2687 __in_ecount(cStrArray) LPWSTR *rgsczStrArray,
2688 __in UINT cStrArray
2689 )
2690{
2691 HRESULT hr = S_OK;
2692
2693 for (UINT i = 0; i < cStrArray; ++i)
2694 {
2695 if (NULL != rgsczStrArray[i])
2696 {
2697 hr = StrFree(rgsczStrArray[i]);
2698 StrExitOnFailure(hr, "Failed to free the string at index %u.", i);
2699 }
2700 }
2701
2702 hr = MemFree(rgsczStrArray);
2703 StrExitOnFailure(hr, "Failed to free memory for the string array.");
2704
2705LExit:
2706 return hr;
2707}
2708
2709/****************************************************************************
2710StrSplitAllocArray - Splits a string into an array.
2711
2712****************************************************************************/
2713extern "C" HRESULT DAPI StrSplitAllocArray(
2714 __deref_inout_ecount_opt(*pcStrArray) LPWSTR **prgsczStrArray,
2715 __inout LPUINT pcStrArray,
2716 __in_z LPCWSTR wzSource,
2717 __in_z LPCWSTR wzDelim
2718 )
2719{
2720 HRESULT hr = S_OK;
2721 LPWSTR sczCopy = NULL;
2722 LPWSTR wzContext = NULL;
2723
2724 // Copy wzSource so it is not modified.
2725 hr = StrAllocString(&sczCopy, wzSource, 0);
2726 StrExitOnFailure(hr, "Failed to copy the source string.");
2727
2728 for (LPCWSTR wzToken = ::wcstok_s(sczCopy, wzDelim, &wzContext); wzToken; wzToken = ::wcstok_s(NULL, wzDelim, &wzContext))
2729 {
2730 hr = StrArrayAllocString(prgsczStrArray, pcStrArray, wzToken, 0);
2731 StrExitOnFailure(hr, "Failed to add the string to the string array.");
2732 }
2733
2734LExit:
2735 ReleaseStr(sczCopy);
2736
2737 return hr;
2738}
2739
2740/****************************************************************************
2741StrAllocStringMapInvariant - helper function for the ToUpper and ToLower.
2742
2743Note: Assumes source and destination buffers will be the same.
2744****************************************************************************/
2745static HRESULT StrAllocStringMapInvariant(
2746 __deref_out_z LPWSTR* pscz,
2747 __in_z LPCWSTR wzSource,
2748 __in SIZE_T cchSource,
2749 __in DWORD dwMapFlags
2750 )
2751{
2752 HRESULT hr = S_OK;
2753
2754 hr = StrAllocString(pscz, wzSource, cchSource);
2755 StrExitOnFailure(hr, "Failed to allocate a copy of the source string.");
2756
2757 if (0 == cchSource)
2758 {
2759 // Need the actual string size for LCMapString. This includes the null-terminator
2760 // but LCMapString doesn't care either way.
2761 hr = ::StringCchLengthW(*pscz, INT_MAX, reinterpret_cast<size_t*>(&cchSource));
2762 StrExitOnRootFailure(hr, "Failed to get the length of the string.");
2763 }
2764 else if (INT_MAX < cchSource)
2765 {
2766 StrExitOnRootFailure(hr = E_INVALIDARG, "Source string is too long: %Iu", cchSource);
2767 }
2768
2769 // Convert the copy of the string to upper or lower case in-place.
2770 if (0 == ::LCMapStringW(LOCALE_INVARIANT, dwMapFlags, *pscz, static_cast<int>(cchSource), *pscz, static_cast<int>(cchSource)))
2771 {
2772 StrExitWithLastError(hr, "Failed to convert the string case.");
2773 }
2774
2775LExit:
2776 return hr;
2777}
2778
2779/****************************************************************************
2780StrSecureZeroString - zeroes out string to the make sure the contents
2781don't remain in memory.
2782
2783****************************************************************************/
2784extern "C" DAPI_(HRESULT) StrSecureZeroString(
2785 __in LPWSTR pwz
2786 )
2787{
2788 HRESULT hr = S_OK;
2789 SIZE_T cch;
2790
2791 if (pwz)
2792 {
2793 cch = MemSize(pwz);
2794 if (-1 == cch)
2795 {
2796 hr = E_INVALIDARG;
2797 StrExitOnFailure(hr, "Failed to get size of string");
2798 }
2799 else
2800 {
2801 SecureZeroMemory(pwz, cch);
2802 }
2803 }
2804
2805LExit:
2806 return hr;
2807}
2808
2809/****************************************************************************
2810StrSecureZeroFreeString - zeroes out string to the make sure the contents
2811don't remain in memory, then frees the string.
2812
2813****************************************************************************/
2814extern "C" DAPI_(HRESULT) StrSecureZeroFreeString(
2815 __in LPWSTR pwz
2816 )
2817{
2818 HRESULT hr = S_OK;
2819
2820 hr = StrSecureZeroString(pwz);
2821 ReleaseStr(pwz);
2822
2823 return hr;
2824}