| Index: src/installer-ca/dutil/strutil.cpp |
| =================================================================== |
| new file mode 100644 |
| --- /dev/null |
| +++ b/src/installer-ca/dutil/strutil.cpp |
| @@ -0,0 +1,755 @@ |
| +//------------------------------------------------------------------------------------------------- |
| +// <copyright file="strutil.cpp" company="Outercurve Foundation"> |
| +// Copyright (c) 2004, Outercurve Foundation. |
| +// This software is released under Microsoft Reciprocal License (MS-RL). |
| +// The license and further copyright text can be found in the file |
| +// LICENSE.TXT at the root directory of the distribution. |
| +// </copyright> |
| +// |
| +// <summary> |
| +// String helper functions. |
| +// </summary> |
| +//------------------------------------------------------------------------------------------------- |
| + |
| +#include "../precomp.h" |
| + |
| +#define ARRAY_GROWTH_SIZE 5 |
| + |
| +// Forward declarations. |
| +static HRESULT StrAllocStringMapInvariant( |
| + __deref_out_z LPWSTR* pscz, |
| + __in_z LPCWSTR wzSource, |
| + __in int cchSource, |
| + __in DWORD dwMapFlags |
| + ); |
| + |
| +/******************************************************************** |
| +StrAlloc - allocates or reuses dynamic string memory |
| + |
| +NOTE: caller is responsible for freeing ppwz even if function fails |
| +********************************************************************/ |
| +extern "C" HRESULT DAPI DAPI StrAlloc( |
| + __deref_out_ecount_part(cch, 0) LPWSTR* ppwz, |
| + __in DWORD_PTR cch |
| + ) |
| +{ |
| + Assert(ppwz && cch); |
| + |
| + HRESULT hr = S_OK; |
| + LPWSTR pwz = NULL; |
| + |
| + if (cch >= MAXDWORD / sizeof(WCHAR)) |
| + { |
| + hr = E_OUTOFMEMORY; |
| + ExitOnFailure1(hr, "Not enough memory to allocate string of size: %u", cch); |
| + } |
| + |
| + if (*ppwz) |
| + { |
| + pwz = static_cast<LPWSTR>(MemReAlloc(*ppwz, sizeof(WCHAR) * cch, FALSE)); |
| + } |
| + else |
| + { |
| + pwz = static_cast<LPWSTR>(MemAlloc(sizeof(WCHAR) * cch, TRUE)); |
| + } |
| + |
| + ExitOnNull1(pwz, hr, E_OUTOFMEMORY, "failed to allocate string, len: %u", cch); |
| + |
| + *ppwz = pwz; |
| +LExit: |
| + return hr; |
| +} |
| + |
| + |
| +/******************************************************************** |
| +StrTrimCapacity - Frees any unnecessary memory associated with a string. |
| + Purely used for optimization, generally only when a string |
| + has been changing size, and will no longer grow. |
| + |
| +NOTE: caller is responsible for freeing ppwz even if function fails |
| +********************************************************************/ |
| +HRESULT DAPI StrTrimCapacity( |
| + __deref_out_z LPWSTR* ppwz |
| + ) |
| +{ |
| + Assert(ppwz); |
| + |
| + HRESULT hr = S_OK; |
| + DWORD_PTR cchLen = 0; |
| + |
| + hr = ::StringCchLengthW(*ppwz, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchLen)); |
| + ExitOnFailure(hr, "Failed to calculate length of string"); |
| + |
| + ++cchLen; // Add 1 for null-terminator |
| + |
| + hr = StrAlloc(ppwz, cchLen); |
| + ExitOnFailure(hr, "Failed to reallocate string"); |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| + |
| +/******************************************************************** |
| +StrTrimWhitespace - allocates or reuses dynamic string memory and copies |
| + in an existing string, excluding whitespace |
| + |
| +NOTE: caller is responsible for freeing ppwz even if function fails |
| +********************************************************************/ |
| +HRESULT DAPI StrTrimWhitespace( |
| + __deref_out_z LPWSTR* ppwz, |
| + __in_z LPCWSTR wzSource |
| + ) |
| +{ |
| + HRESULT hr = S_OK; |
| + int i = 0; |
| + LPWSTR sczResult = NULL; |
| + |
| + // Ignore beginning whitespace |
| + while (L' ' == *wzSource || L'\t' == *wzSource) |
| + { |
| + wzSource++; |
| + } |
| + |
| + i = lstrlenW(wzSource); |
| + // Overwrite ending whitespace with null characters |
| + if (0 < i) |
| + { |
| + // start from the last non-null-terminator character in the array |
| + for (i = i - 1; i > 0; --i) |
| + { |
| + if (L' ' != wzSource[i] && L'\t' != wzSource[i]) |
| + { |
| + break; |
| + } |
| + } |
| + |
| + ++i; |
| + } |
| + |
| + hr = StrAllocString(&sczResult, wzSource, i); |
| + ExitOnFailure(hr, "Failed to copy result string"); |
| + |
| + // Output result |
| + *ppwz = sczResult; |
| + sczResult = NULL; |
| + |
| +LExit: |
| + ReleaseStr(sczResult); |
| + |
| + return hr; |
| +} |
| + |
| + |
| + |
| + |
| + |
| +/******************************************************************** |
| +StrAllocString - allocates or reuses dynamic string memory and copies in an existing string |
| + |
| +NOTE: caller is responsible for freeing ppwz even if function fails |
| +NOTE: cchSource does not have to equal the length of wzSource |
| +NOTE: if cchSource == 0, length of wzSource is used instead |
| +********************************************************************/ |
| +extern "C" HRESULT DAPI StrAllocString( |
| + __deref_out_ecount_z(cchSource+1) LPWSTR* ppwz, |
| + __in_z LPCWSTR wzSource, |
| + __in DWORD_PTR cchSource |
| + ) |
| +{ |
| + Assert(ppwz && wzSource); // && *wzSource); |
| + |
| + HRESULT hr = S_OK; |
| + DWORD_PTR cch = 0; |
| + |
| + if (*ppwz) |
| + { |
| + cch = MemSize(*ppwz); // get the count in bytes so we can check if it failed (returns -1) |
| + if (-1 == cch) |
| + { |
| + hr = E_INVALIDARG; |
| + ExitOnFailure(hr, "failed to get size of destination string"); |
| + } |
| + cch /= sizeof(WCHAR); //convert the count in bytes to count in characters |
| + } |
| + |
| + if (0 == cchSource) |
| + { |
| + cchSource = lstrlenW(wzSource); |
| + } |
| + |
| + DWORD_PTR cchNeeded; |
| + hr = ::ULongPtrAdd(cchSource, 1, &cchNeeded); // add one for the null terminator |
| + ExitOnFailure(hr, "source string is too long"); |
| + |
| + if (cch < cchNeeded) |
| + { |
| + cch = cchNeeded; |
| + hr = StrAlloc(ppwz, cch); |
| + ExitOnFailure(hr, "failed to allocate string from string."); |
| + } |
| + |
| + // copy everything (the NULL terminator will be included) |
| + hr = ::StringCchCopyNExW(*ppwz, cch, wzSource, cchSource, NULL, NULL, STRSAFE_FILL_BEHIND_NULL); |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| + |
| + |
| + |
| + |
| +/******************************************************************** |
| +StrAllocConcat - allocates or reuses dynamic string memory and adds an existing string |
| + |
| +NOTE: caller is responsible for freeing ppwz even if function fails |
| +NOTE: cchSource does not have to equal the length of wzSource |
| +NOTE: if cchSource == 0, length of wzSource is used instead |
| +********************************************************************/ |
| +extern "C" HRESULT DAPI StrAllocConcat( |
| + __deref_out_z LPWSTR* ppwz, |
| + __in_z LPCWSTR wzSource, |
| + __in DWORD_PTR cchSource |
| + ) |
| +{ |
| + Assert(ppwz && wzSource); // && *wzSource); |
| + |
| + HRESULT hr = S_OK; |
| + DWORD_PTR cch = 0; |
| + DWORD_PTR cchLen = 0; |
| + |
| + if (*ppwz) |
| + { |
| + cch = MemSize(*ppwz); // get the count in bytes so we can check if it failed (returns -1) |
| + if (-1 == cch) |
| + { |
| + hr = E_INVALIDARG; |
| + ExitOnFailure(hr, "failed to get size of destination string"); |
| + } |
| + cch /= sizeof(WCHAR); //convert the count in bytes to count in characters |
| + |
| + hr = ::StringCchLengthW(*ppwz, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchLen)); |
| + ExitOnFailure(hr, "Failed to calculate length of string"); |
| + } |
| + |
| + Assert(cchLen <= cch); |
| + |
| + if (0 == cchSource) |
| + { |
| + hr = ::StringCchLengthW(wzSource, STRSAFE_MAX_CCH, reinterpret_cast<UINT_PTR*>(&cchSource)); |
| + ExitOnFailure(hr, "Failed to calculate length of string"); |
| + } |
| + |
| + if (cch - cchLen < cchSource + 1) |
| + { |
| + cch = (cchSource + cchLen + 1) * 2; |
| + hr = StrAlloc(ppwz, cch); |
| + ExitOnFailure1(hr, "failed to allocate string from string: %ls", wzSource); |
| + } |
| + |
| + if (*ppwz) |
| + { |
| + hr = ::StringCchCatNExW(*ppwz, cch, wzSource, cchSource, NULL, NULL, STRSAFE_FILL_BEHIND_NULL); |
| + } |
| + else |
| + { |
| + hr = E_UNEXPECTED; |
| + ExitOnFailure(hr, "for some reason our buffer is still null"); |
| + } |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| + |
| + |
| + |
| + |
| +/******************************************************************** |
| +StrAllocFormatted - allocates or reuses dynamic string memory and formats it |
| + |
| +NOTE: caller is responsible for freeing ppwz even if function fails |
| +********************************************************************/ |
| +extern "C" HRESULT DAPI StrAllocFormatted( |
| + __deref_out_z LPWSTR* ppwz, |
| + __in __format_string LPCWSTR wzFormat, |
| + ... |
| + ) |
| +{ |
| + Assert(ppwz && wzFormat && *wzFormat); |
| + |
| + HRESULT hr = S_OK; |
| + va_list args; |
| + |
| + va_start(args, wzFormat); |
| + hr = StrAllocFormattedArgs(ppwz, wzFormat, args); |
| + va_end(args); |
| + |
| + return hr; |
| +} |
| + |
| + |
| + |
| + |
| +/******************************************************************** |
| +StrAllocFormattedArgs - allocates or reuses dynamic string memory |
| +and formats it with the passed in args |
| + |
| +NOTE: caller is responsible for freeing ppwz even if function fails |
| +********************************************************************/ |
| +extern "C" HRESULT DAPI StrAllocFormattedArgs( |
| + __deref_out_z LPWSTR* ppwz, |
| + __in __format_string LPCWSTR wzFormat, |
| + __in va_list args |
| + ) |
| +{ |
| + Assert(ppwz && wzFormat && *wzFormat); |
| + |
| + HRESULT hr = S_OK; |
| + DWORD_PTR cch = 0; |
| + LPWSTR pwzOriginal = NULL; |
| + DWORD_PTR cchOriginal = 0; |
| + |
| + if (*ppwz) |
| + { |
| + cch = MemSize(*ppwz); // get the count in bytes so we can check if it failed (returns -1) |
| + if (-1 == cch) |
| + { |
| + hr = E_INVALIDARG; |
| + ExitOnFailure(hr, "failed to get size of destination string"); |
| + } |
| + cch /= sizeof(WCHAR); //convert the count in bytes to count in characters |
| + |
| + cchOriginal = lstrlenW(*ppwz); |
| + } |
| + |
| + if (0 == cch) // if there is no space in the string buffer |
| + { |
| + cch = 256; |
| + hr = StrAlloc(ppwz, cch); |
| + ExitOnFailure1(hr, "failed to allocate string to format: %ls", wzFormat); |
| + } |
| + |
| + // format the message (grow until it fits or there is a failure) |
| + do |
| + { |
| + hr = ::StringCchVPrintfW(*ppwz, cch, wzFormat, args); |
| + if (STRSAFE_E_INSUFFICIENT_BUFFER == hr) |
| + { |
| + if (!pwzOriginal) |
| + { |
| + // this allows you to pass the original string as a formatting argument and not crash |
| + // save the original string and free it after the printf is complete |
| + pwzOriginal = *ppwz; |
| + *ppwz = NULL; |
| + // StringCchVPrintfW starts writing to the string... |
| + // NOTE: this hack only works with sprintf(&pwz, "%s ...", pwz, ...); |
| + pwzOriginal[cchOriginal] = 0; |
| + } |
| + cch *= 2; |
| + hr = StrAlloc(ppwz, cch); |
| + ExitOnFailure1(hr, "failed to allocate string to format: %ls", wzFormat); |
| + hr = S_FALSE; |
| + } |
| + } while (S_FALSE == hr); |
| + ExitOnFailure(hr, "failed to format string"); |
| + |
| +LExit: |
| + ReleaseStr(pwzOriginal); |
| + |
| + return hr; |
| +} |
| + |
| + |
| + |
| + |
| + |
| + |
| +/******************************************************************** |
| +StrMaxLength - returns maximum number of characters that can be stored in dynamic string p |
| + |
| +NOTE: assumes Unicode string |
| +********************************************************************/ |
| +extern "C" HRESULT DAPI StrMaxLength( |
| + __in LPCVOID p, |
| + __out DWORD_PTR* pcch |
| + ) |
| +{ |
| + Assert(pcch); |
| + |
| + HRESULT hr = S_OK; |
| + |
| + if (p) |
| + { |
| + *pcch = MemSize(p); // get size of entire buffer |
| + if (-1 == *pcch) |
| + { |
| + ExitFunction1(hr = E_FAIL); |
| + } |
| + |
| + *pcch /= sizeof(WCHAR); // reduce to count of characters |
| + } |
| + else |
| + { |
| + *pcch = 0; |
| + } |
| + Assert(S_OK == hr); |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| + |
| +/******************************************************************** |
| +StrSize - returns count of bytes in dynamic string p |
| + |
| +********************************************************************/ |
| +extern "C" HRESULT DAPI StrSize( |
| + __in LPCVOID p, |
| + __out DWORD_PTR* pcb |
| + ) |
| +{ |
| + Assert(p && pcb); |
| + |
| + HRESULT hr = S_OK; |
| + |
| + *pcb = MemSize(p); |
| + if (-1 == *pcb) |
| + { |
| + hr = E_FAIL; |
| + } |
| + |
| + return hr; |
| +} |
| + |
| +/******************************************************************** |
| +StrFree - releases dynamic string memory allocated by any StrAlloc*() functions |
| + |
| +********************************************************************/ |
| +extern "C" HRESULT DAPI StrFree( |
| + __in LPVOID p |
| + ) |
| +{ |
| + Assert(p); |
| + |
| + HRESULT hr = MemFree(p); |
| + ExitOnFailure(hr, "failed to free string"); |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| + |
| +/**************************************************************************** |
| +wcsistr - case insensitive find a substring |
| + |
| +****************************************************************************/ |
| +extern "C" LPCWSTR wcsistr( |
| + __in_z LPCWSTR wzString, |
| + __in_z LPCWSTR wzCharSet |
| + ) |
| +{ |
| + LPCWSTR wzSource = wzString; |
| + LPCWSTR wzSearch = NULL; |
| + DWORD_PTR cchSourceIndex = 0; |
| + |
| + // Walk through wzString (the source string) one character at a time |
| + while (*wzSource) |
| + { |
| + cchSourceIndex = 0; |
| + wzSearch = wzCharSet; |
| + |
| + // Look ahead in the source string until we get a full match or we hit the end of the source |
| + while (L'\0' != wzSource[cchSourceIndex] && L'\0' != *wzSearch && towlower(wzSource[cchSourceIndex]) == towlower(*wzSearch)) |
| + { |
| + ++cchSourceIndex; |
| + ++wzSearch; |
| + } |
| + |
| + // If we found it, return the point that we found it at |
| + if (L'\0' == *wzSearch) |
| + { |
| + return wzSource; |
| + } |
| + |
| + // Walk ahead one character |
| + ++wzSource; |
| + } |
| + |
| + return NULL; |
| +} |
| + |
| +/**************************************************************************** |
| +StrStringToInt16 - converts a string to a signed 16-bit integer. |
| + |
| +****************************************************************************/ |
| +extern "C" HRESULT DAPI StrStringToInt16( |
| + __in_z LPCWSTR wzIn, |
| + __in DWORD cchIn, |
| + __out SHORT* psOut |
| + ) |
| +{ |
| + HRESULT hr = S_OK; |
| + LONGLONG ll = 0; |
| + |
| + hr = StrStringToInt64(wzIn, cchIn, &ll); |
| + ExitOnFailure(hr, "Failed to parse int64."); |
| + |
| + if (SHORT_MAX < ll || SHORT_MIN > ll) |
| + { |
| + ExitFunction1(hr = DISP_E_OVERFLOW); |
| + } |
| + *psOut = (SHORT)ll; |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| +/**************************************************************************** |
| +StrStringToUInt16 - converts a string to an unsigned 16-bit integer. |
| + |
| +****************************************************************************/ |
| +extern "C" HRESULT DAPI StrStringToUInt16( |
| + __in_z LPCWSTR wzIn, |
| + __in DWORD cchIn, |
| + __out USHORT* pusOut |
| + ) |
| +{ |
| + HRESULT hr = S_OK; |
| + ULONGLONG ull = 0; |
| + |
| + hr = StrStringToUInt64(wzIn, cchIn, &ull); |
| + ExitOnFailure(hr, "Failed to parse uint64."); |
| + |
| + if (USHORT_MAX < ull) |
| + { |
| + ExitFunction1(hr = DISP_E_OVERFLOW); |
| + } |
| + *pusOut = (USHORT)ull; |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| +/**************************************************************************** |
| +StrStringToInt32 - converts a string to a signed 32-bit integer. |
| + |
| +****************************************************************************/ |
| +extern "C" HRESULT DAPI StrStringToInt32( |
| + __in_z LPCWSTR wzIn, |
| + __in DWORD cchIn, |
| + __out INT* piOut |
| + ) |
| +{ |
| + HRESULT hr = S_OK; |
| + LONGLONG ll = 0; |
| + |
| + hr = StrStringToInt64(wzIn, cchIn, &ll); |
| + ExitOnFailure(hr, "Failed to parse int64."); |
| + |
| + if (INT_MAX < ll || INT_MIN > ll) |
| + { |
| + ExitFunction1(hr = DISP_E_OVERFLOW); |
| + } |
| + *piOut = (INT)ll; |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| +/**************************************************************************** |
| +StrStringToUInt32 - converts a string to an unsigned 32-bit integer. |
| + |
| +****************************************************************************/ |
| +extern "C" HRESULT DAPI StrStringToUInt32( |
| + __in_z LPCWSTR wzIn, |
| + __in DWORD cchIn, |
| + __out UINT* puiOut |
| + ) |
| +{ |
| + HRESULT hr = S_OK; |
| + ULONGLONG ull = 0; |
| + |
| + hr = StrStringToUInt64(wzIn, cchIn, &ull); |
| + ExitOnFailure(hr, "Failed to parse uint64."); |
| + |
| + if (UINT_MAX < ull) |
| + { |
| + ExitFunction1(hr = DISP_E_OVERFLOW); |
| + } |
| + *puiOut = (UINT)ull; |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| +/**************************************************************************** |
| +StrStringToInt64 - converts a string to a signed 64-bit integer. |
| + |
| +****************************************************************************/ |
| +extern "C" HRESULT DAPI StrStringToInt64( |
| + __in_z LPCWSTR wzIn, |
| + __in DWORD cchIn, |
| + __out LONGLONG* pllOut |
| + ) |
| +{ |
| + HRESULT hr = S_OK; |
| + DWORD i = 0; |
| + INT iSign = 1; |
| + INT nDigit = 0; |
| + LARGE_INTEGER liValue = { }; |
| + |
| + // get string length if not provided |
| + if (0 >= cchIn) |
| + { |
| + cchIn = lstrlenW(wzIn); |
| + if (0 >= cchIn) |
| + { |
| + ExitFunction1(hr = E_INVALIDARG); |
| + } |
| + } |
| + |
| + // check sign |
| + if (L'-' == wzIn[0]) |
| + { |
| + if (1 >= cchIn) |
| + { |
| + ExitFunction1(hr = E_INVALIDARG); |
| + } |
| + i = 1; |
| + iSign = -1; |
| + } |
| + |
| + // read digits |
| + while (i < cchIn) |
| + { |
| + nDigit = wzIn[i] - L'0'; |
| + if (0 > nDigit || 9 < nDigit) |
| + { |
| + ExitFunction1(hr = E_INVALIDARG); |
| + } |
| + liValue.QuadPart = liValue.QuadPart * 10 + nDigit * iSign; |
| + |
| + if ((liValue.HighPart ^ iSign) & INT_MIN) |
| + { |
| + ExitFunction1(hr = DISP_E_OVERFLOW); |
| + } |
| + ++i; |
| + } |
| + |
| + *pllOut = liValue.QuadPart; |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| +/**************************************************************************** |
| +StrStringToUInt64 - converts a string to an unsigned 64-bit integer. |
| + |
| +****************************************************************************/ |
| +extern "C" HRESULT DAPI StrStringToUInt64( |
| + __in_z LPCWSTR wzIn, |
| + __in DWORD cchIn, |
| + __out ULONGLONG* pullOut |
| + ) |
| +{ |
| + HRESULT hr = S_OK; |
| + DWORD i = 0; |
| + DWORD nDigit = 0; |
| + ULONGLONG ullValue = 0; |
| + ULONGLONG ull = 0; |
| + |
| + // get string length if not provided |
| + if (0 >= cchIn) |
| + { |
| + cchIn = lstrlenW(wzIn); |
| + if (0 >= cchIn) |
| + { |
| + ExitFunction1(hr = E_INVALIDARG); |
| + } |
| + } |
| + |
| + // read digits |
| + while (i < cchIn) |
| + { |
| + nDigit = wzIn[i] - L'0'; |
| + if (9 < nDigit) |
| + { |
| + ExitFunction1(hr = E_INVALIDARG); |
| + } |
| + ull = (ULONGLONG)(ullValue * 10 + nDigit); |
| + |
| + if (ull < ullValue) |
| + { |
| + ExitFunction1(hr = DISP_E_OVERFLOW); |
| + } |
| + ullValue = ull; |
| + ++i; |
| + } |
| + |
| + *pullOut = ullValue; |
| + |
| +LExit: |
| + return hr; |
| +} |
| + |
| +/**************************************************************************** |
| +StrStringToUpper - alters the given string in-place to be entirely uppercase |
| + |
| +****************************************************************************/ |
| +void DAPI StrStringToUpper( |
| + __inout_z LPWSTR wzIn |
| + ) |
| +{ |
| + ::CharUpperBuffW(wzIn, lstrlenW(wzIn)); |
| +} |
| + |
| +/**************************************************************************** |
| +StrStringToLower - alters the given string in-place to be entirely lowercase |
| + |
| +****************************************************************************/ |
| +void DAPI StrStringToLower( |
| + __inout_z LPWSTR wzIn |
| + ) |
| +{ |
| + ::CharLowerBuffW(wzIn, lstrlenW(wzIn)); |
| +} |
| + |
| + |
| + |
| + |
| +/**************************************************************************** |
| +StrAllocStringMapInvariant - helper function for the ToUpper and ToLower. |
| + |
| +Note: Assumes source and destination buffers will be the same. |
| +****************************************************************************/ |
| +static HRESULT StrAllocStringMapInvariant( |
| + __deref_out_z LPWSTR* pscz, |
| + __in_z LPCWSTR wzSource, |
| + __in int cchSource, |
| + __in DWORD dwMapFlags |
| + ) |
| +{ |
| + HRESULT hr = S_OK; |
| + |
| + hr = StrAllocString(pscz, wzSource, cchSource); |
| + ExitOnFailure(hr, "Failed to allocate a copy of the source string."); |
| + |
| + if (0 == cchSource) |
| + { |
| + // Need the actual string size for LCMapString. This includes the null-terminator |
| + // but LCMapString doesn't care either way. |
| + hr = ::StringCchLengthW(*pscz, INT_MAX, reinterpret_cast<size_t*>(&cchSource)); |
| + ExitOnFailure(hr, "Failed to get the length of the string."); |
| + } |
| + |
| + // Convert the copy of the string to upper or lower case in-place. |
| + if (0 == ::LCMapStringW(LOCALE_INVARIANT, dwMapFlags, *pscz, cchSource, *pscz, cchSource)) |
| + { |
| + ExitWithLastError(hr, "Failed to convert the string case."); |
| + } |
| + |
| +LExit: |
| + return hr; |
| +} |