1213 lines
31 KiB
C++
1213 lines
31 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: N C S T R I N G . C P P
|
||
|
//
|
||
|
// Contents: Common string routines.
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
// Author: shaunco 24 Mar 1997
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include <pch.h>
|
||
|
#pragma hdrstop
|
||
|
#include "ncdebug.h"
|
||
|
#include "ncstring.h"
|
||
|
#include "ncmsz.h"
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CbOfSzSafe, CbOfSzaSafe,
|
||
|
// CbOfSzAndTermSafe, CbOfSzaAndTermSafe
|
||
|
//
|
||
|
// Purpose: Count the bytes required to hold a string. The string
|
||
|
// may be NULL in which case zero is returned.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// psz [in] String to return count of bytes for.
|
||
|
//
|
||
|
// Returns: Count of bytes required to store string.
|
||
|
//
|
||
|
// Author: shaunco 24 Mar 1997
|
||
|
//
|
||
|
// Notes: 'AndTerm' variants includes space for the null-terminator.
|
||
|
//
|
||
|
ULONG
|
||
|
CbOfSzSafe (
|
||
|
IN PCWSTR psz)
|
||
|
{
|
||
|
return (psz) ? CbOfSz(psz) : 0;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
CbOfSzaSafe (
|
||
|
IN PCSTR psza)
|
||
|
{
|
||
|
return (psza) ? CbOfSza(psza) : 0;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
CbOfTSzSafe (
|
||
|
IN PCTSTR psza)
|
||
|
{
|
||
|
return (psza) ? CbOfTSz(psza) : 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
CbOfSzAndTermSafe (
|
||
|
IN PCWSTR psz)
|
||
|
{
|
||
|
return (psz) ? CbOfSzAndTerm(psz) : 0;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
CbOfSzaAndTermSafe (
|
||
|
IN PCSTR psza)
|
||
|
{
|
||
|
return (psza) ? CbOfSzaAndTerm(psza) : 0;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
CbOfTSzAndTermSafe (
|
||
|
IN PCTSTR psza)
|
||
|
{
|
||
|
return (psza) ? CbOfTSzAndTerm(psza) : 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG
|
||
|
CchOfSzSafe (
|
||
|
IN PCTSTR psz)
|
||
|
{
|
||
|
return (psz) ? _tcslen(psz) : 0;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DwFormatString
|
||
|
//
|
||
|
// Purpose: Uses FormatMessage to format a string from variable arguments.
|
||
|
// The string is formatted into a fixed-size buffer the caller
|
||
|
// provides.
|
||
|
// See the description of FormatMessage in the Win32 API.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pszFmt [in] pointer to format string
|
||
|
// pszBuf [out] pointer to formatted output
|
||
|
// cchBuf [in] count of characters in pszBuf
|
||
|
// ... [in] replaceable string parameters
|
||
|
//
|
||
|
// Returns: the return value of FormatMessage
|
||
|
//
|
||
|
// Author: shaunco 15 Apr 1997
|
||
|
//
|
||
|
// Notes: The variable arguments must be strings otherwise
|
||
|
// FormatMessage will barf.
|
||
|
//
|
||
|
DWORD
|
||
|
WINAPIV
|
||
|
DwFormatString (
|
||
|
IN PCWSTR pszFmt,
|
||
|
OUT PWSTR pszBuf,
|
||
|
IN DWORD cchBuf,
|
||
|
IN ...)
|
||
|
{
|
||
|
Assert (pszFmt);
|
||
|
|
||
|
va_list val;
|
||
|
va_start(val, cchBuf);
|
||
|
DWORD dwRet = FormatMessageW (FORMAT_MESSAGE_FROM_STRING,
|
||
|
pszFmt, 0, 0, pszBuf, cchBuf, &val);
|
||
|
va_end(val);
|
||
|
return dwRet;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DwFormatStringWithLocalAlloc
|
||
|
//
|
||
|
// Purpose: Uses FormatMessage to format a string from variable arguments.
|
||
|
// The string is allocated by FormatMessage using LocalAlloc.
|
||
|
// See the description of FormatMessage in the Win32 API.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pszFmt [in] pointer to format string
|
||
|
// ppszBuf [out] the returned formatted string
|
||
|
// ... [in] replaceable string parameters
|
||
|
//
|
||
|
// Returns: the return value of FormatMessage
|
||
|
//
|
||
|
// Author: shaunco 3 May 1997
|
||
|
//
|
||
|
// Notes: The variable arguments must be strings otherwise
|
||
|
// FormatMessage will barf.
|
||
|
//
|
||
|
DWORD
|
||
|
WINAPIV
|
||
|
DwFormatStringWithLocalAlloc (
|
||
|
IN PCWSTR pszFmt,
|
||
|
OUT PWSTR* ppszBuf,
|
||
|
IN ...)
|
||
|
{
|
||
|
Assert (pszFmt);
|
||
|
|
||
|
va_list val;
|
||
|
va_start(val, ppszBuf);
|
||
|
DWORD dwRet = FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||
|
FORMAT_MESSAGE_FROM_STRING,
|
||
|
pszFmt, 0, 0,
|
||
|
(PWSTR)ppszBuf,
|
||
|
0, &val);
|
||
|
va_end(val);
|
||
|
return dwRet;
|
||
|
}
|
||
|
|
||
|
|
||
|
PWSTR
|
||
|
WszAllocateAndCopyWsz (
|
||
|
IN PCWSTR pszSrc)
|
||
|
{
|
||
|
if (!pszSrc)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ULONG cb = (wcslen (pszSrc) + 1) * sizeof(WCHAR);
|
||
|
PWSTR psz = (PWSTR)MemAlloc (cb);
|
||
|
if (psz)
|
||
|
{
|
||
|
CopyMemory (psz, pszSrc, cb);
|
||
|
}
|
||
|
|
||
|
return psz;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: WszLoadStringPcch
|
||
|
//
|
||
|
// Purpose: Load a resource string. (This function will never return NULL.)
|
||
|
//
|
||
|
// Arguments:
|
||
|
// hinst [in] Instance handle of module with the string resource.
|
||
|
// unId [in] Resource ID of the string to load.
|
||
|
// pcch [out] Pointer to returned character length.
|
||
|
//
|
||
|
// Returns: Pointer to the constant string.
|
||
|
//
|
||
|
// Author: shaunco 24 Mar 1997
|
||
|
//
|
||
|
// Notes: The loaded string is pointer directly into the read-only
|
||
|
// resource section. Any attempt to write through this pointer
|
||
|
// will generate an access violation.
|
||
|
//
|
||
|
// The implementations is referenced from "Win32 Binary Resource
|
||
|
// Formats" (MSDN) 4.8 String Table Resources
|
||
|
//
|
||
|
// User must have RCOPTIONS = -N turned on in your sources file.
|
||
|
//
|
||
|
PCWSTR
|
||
|
WszLoadStringPcch (
|
||
|
IN HINSTANCE hinst,
|
||
|
IN UINT unId,
|
||
|
OUT int* pcch)
|
||
|
{
|
||
|
Assert(hinst);
|
||
|
Assert(unId);
|
||
|
Assert(pcch);
|
||
|
|
||
|
static const WCHAR c_szSpace[] = L" ";
|
||
|
|
||
|
PCWSTR psz = c_szSpace;
|
||
|
int cch = 1;
|
||
|
|
||
|
// String Tables are broken up into 16 string segments. Find the segment
|
||
|
// containing the string we are interested in.
|
||
|
// See KB ID: Q20011 for a half-explanation of the second argument below.
|
||
|
HRSRC hrsrcInfo = FindResource (hinst,
|
||
|
(PTSTR)ULongToPtr( ((LONG)(((USHORT)unId >> 4) + 1)) ),
|
||
|
RT_STRING);
|
||
|
if (hrsrcInfo)
|
||
|
{
|
||
|
// Page the resource segment into memory.
|
||
|
HGLOBAL hglbSeg = LoadResource (hinst, hrsrcInfo);
|
||
|
if (hglbSeg)
|
||
|
{
|
||
|
// Lock the resource.
|
||
|
psz = (PCWSTR)LockResource(hglbSeg);
|
||
|
if (psz)
|
||
|
{
|
||
|
// Move past the other strings in this segment.
|
||
|
// (16 strings in a segment -> & 0x0F)
|
||
|
unId &= 0x0F;
|
||
|
|
||
|
cch = 0;
|
||
|
do
|
||
|
{
|
||
|
psz += cch; // Step to start of next string
|
||
|
cch = *((WCHAR*)psz++); // PASCAL like string count
|
||
|
}
|
||
|
while (unId--);
|
||
|
|
||
|
// If we have a non-zero count, it includes the
|
||
|
// null-terminiator. Subtract this off for the return value.
|
||
|
//
|
||
|
if (cch)
|
||
|
{
|
||
|
cch--;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AssertSz(0, "String resource not found");
|
||
|
psz = c_szSpace;
|
||
|
cch = 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
psz = c_szSpace;
|
||
|
cch = 1;
|
||
|
TraceLastWin32Error("SzLoadStringPcch: LockResource failed.");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
TraceLastWin32Error("SzLoadStringPcch: LoadResource failed.");
|
||
|
}
|
||
|
else
|
||
|
TraceLastWin32Error("SzLoadStringPcch: FindResource failed.");
|
||
|
|
||
|
*pcch = cch;
|
||
|
Assert(*pcch);
|
||
|
Assert(psz);
|
||
|
return psz;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SzaDupSza
|
||
|
//
|
||
|
// Purpose: Duplicates a string
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pszaSrc [in] string to be duplicated
|
||
|
//
|
||
|
// Returns: Pointer to the new copy of the string
|
||
|
//
|
||
|
// Author: CWill 25 Mar 1997
|
||
|
//
|
||
|
// Notes: The string return must be freed (MemFree).
|
||
|
//
|
||
|
PSTR
|
||
|
SzaDupSza (
|
||
|
PCSTR pszaSrc)
|
||
|
{
|
||
|
AssertSz(pszaSrc, "Invalid source string");
|
||
|
|
||
|
PSTR pszaDst;
|
||
|
pszaDst = (PSTR) MemAlloc (CbOfSzaAndTerm(pszaSrc));
|
||
|
|
||
|
if (pszaDst)
|
||
|
{
|
||
|
strcpy(pszaDst, pszaSrc);
|
||
|
}
|
||
|
|
||
|
return pszaDst;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TszDupTsz
|
||
|
//
|
||
|
// Purpose: Duplicates a string
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pszSrc [in] string to be duplicated
|
||
|
//
|
||
|
// Returns: Pointer to the new copy of the string
|
||
|
//
|
||
|
// Notes: The string return must be freed.
|
||
|
//
|
||
|
PTSTR
|
||
|
TszDupTsz (
|
||
|
IN PCTSTR pszSrc)
|
||
|
{
|
||
|
AssertSz(pszSrc, "Invalid source string");
|
||
|
|
||
|
PTSTR pszDst;
|
||
|
pszDst = (PTSTR) MemAlloc (CbOfTSzAndTermSafe(pszSrc));
|
||
|
if (pszDst)
|
||
|
{
|
||
|
_tcscpy(pszDst, pszSrc);
|
||
|
}
|
||
|
|
||
|
return pszDst;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: WszDupWsz
|
||
|
//
|
||
|
// Purpose: Duplicates a wide string
|
||
|
//
|
||
|
// Arguments:
|
||
|
// szOld [in] String to duplicate
|
||
|
//
|
||
|
// Returns: Newly allocated copy
|
||
|
//
|
||
|
// Author: danielwe 4 Aug 2000
|
||
|
//
|
||
|
// Notes: Caller must free result with delete []
|
||
|
//
|
||
|
LPWSTR WszDupWsz(LPCWSTR szOld)
|
||
|
{
|
||
|
LPWSTR szNew;
|
||
|
|
||
|
szNew = new WCHAR[lstrlen(szOld) + 1];
|
||
|
if (szNew)
|
||
|
{
|
||
|
lstrcpy(szNew, szOld);
|
||
|
}
|
||
|
|
||
|
return szNew;
|
||
|
}
|
||
|
|
||
|
LPWSTR WszFromSz(LPCSTR szAnsi)
|
||
|
{
|
||
|
Assert(szAnsi);
|
||
|
|
||
|
LPWSTR pszResult;
|
||
|
LPWSTR pszWide;
|
||
|
INT cchWide;
|
||
|
INT result;
|
||
|
|
||
|
pszResult = NULL;
|
||
|
|
||
|
if (!szAnsi)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
result = ::MultiByteToWideChar(CP_ACP,
|
||
|
0,
|
||
|
szAnsi,
|
||
|
-1,
|
||
|
NULL,
|
||
|
0);
|
||
|
if (!result)
|
||
|
{
|
||
|
TraceLastWin32Error("WszFromSz: MultiByteToWideChar #1");
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
cchWide = result;
|
||
|
|
||
|
pszWide = new WCHAR [ cchWide ];
|
||
|
if (!pszWide)
|
||
|
{
|
||
|
TraceError("WszFromSz: new", E_OUTOFMEMORY);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
result = ::MultiByteToWideChar(CP_ACP,
|
||
|
0,
|
||
|
szAnsi,
|
||
|
-1,
|
||
|
pszWide,
|
||
|
cchWide);
|
||
|
if (!result)
|
||
|
{
|
||
|
TraceLastWin32Error("WszFromSz: MultiByteToWideChar #2");
|
||
|
|
||
|
delete [] pszWide;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
pszResult = pszWide;
|
||
|
|
||
|
Cleanup:
|
||
|
return pszResult;
|
||
|
}
|
||
|
|
||
|
LPWSTR WszFromUtf8(LPCSTR szUtf8)
|
||
|
{
|
||
|
Assert(szUtf8);
|
||
|
|
||
|
LPWSTR pszResult;
|
||
|
LPWSTR pszWide;
|
||
|
INT cchWide;
|
||
|
INT result;
|
||
|
|
||
|
pszResult = NULL;
|
||
|
|
||
|
if (!szUtf8)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
result = ::MultiByteToWideChar(CP_UTF8,
|
||
|
0,
|
||
|
szUtf8,
|
||
|
-1,
|
||
|
NULL,
|
||
|
0);
|
||
|
if (!result)
|
||
|
{
|
||
|
TraceLastWin32Error("WszFromUtf8: MultiByteToWideChar #1");
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
cchWide = result;
|
||
|
|
||
|
pszWide = new WCHAR [ cchWide ];
|
||
|
if (!pszWide)
|
||
|
{
|
||
|
TraceError("WszFromUtf8: new", E_OUTOFMEMORY);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
result = ::MultiByteToWideChar(CP_UTF8,
|
||
|
0,
|
||
|
szUtf8,
|
||
|
-1,
|
||
|
pszWide,
|
||
|
cchWide);
|
||
|
if (!result)
|
||
|
{
|
||
|
TraceLastWin32Error("WszFromUtf8: MultiByteToWideChar #2");
|
||
|
|
||
|
delete [] pszWide;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
pszResult = pszWide;
|
||
|
|
||
|
Cleanup:
|
||
|
return pszResult;
|
||
|
}
|
||
|
|
||
|
LPSTR SzFromWsz(LPCWSTR szWide)
|
||
|
{
|
||
|
Assert(szWide);
|
||
|
|
||
|
LPSTR pszResult;
|
||
|
LPSTR pszAnsi;
|
||
|
INT cbAnsi;
|
||
|
INT result;
|
||
|
|
||
|
pszResult = NULL;
|
||
|
|
||
|
if (!szWide)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
result = ::WideCharToMultiByte(CP_ACP,
|
||
|
0,
|
||
|
szWide,
|
||
|
-1,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (!result)
|
||
|
{
|
||
|
TraceLastWin32Error("SzFromWsz: WideCharToMultiByte #1");
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
cbAnsi = result;
|
||
|
|
||
|
pszAnsi = (CHAR *)MemAlloc(cbAnsi);
|
||
|
if (!pszAnsi)
|
||
|
{
|
||
|
TraceError("SzFromWsz: MemAlloc", E_OUTOFMEMORY);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
result = ::WideCharToMultiByte(CP_ACP,
|
||
|
0,
|
||
|
szWide,
|
||
|
-1,
|
||
|
pszAnsi,
|
||
|
cbAnsi,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (!result)
|
||
|
{
|
||
|
TraceLastWin32Error("SzFromWsz: WideCharToMultiByte #2");
|
||
|
|
||
|
MemFree(pszAnsi);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
pszResult = pszAnsi;
|
||
|
|
||
|
Cleanup:
|
||
|
return pszResult;
|
||
|
}
|
||
|
|
||
|
LPSTR Utf8FromWsz(LPCWSTR szWide)
|
||
|
{
|
||
|
Assert(szWide);
|
||
|
|
||
|
LPSTR pszResult;
|
||
|
LPSTR pszUtf8;
|
||
|
INT cbUtf8;
|
||
|
INT result;
|
||
|
|
||
|
pszResult = NULL;
|
||
|
|
||
|
if (!szWide)
|
||
|
{
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
result = ::WideCharToMultiByte(CP_UTF8,
|
||
|
0,
|
||
|
szWide,
|
||
|
-1,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (!result)
|
||
|
{
|
||
|
TraceLastWin32Error("Utf8FromWsz: WideCharToMultiByte #1");
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
cbUtf8 = result;
|
||
|
|
||
|
pszUtf8 = (CHAR *)MemAlloc(cbUtf8);
|
||
|
if (!pszUtf8)
|
||
|
{
|
||
|
TraceError("SzFromWsz: MemAlloc", E_OUTOFMEMORY);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
result = ::WideCharToMultiByte(CP_UTF8,
|
||
|
0,
|
||
|
szWide,
|
||
|
-1,
|
||
|
pszUtf8,
|
||
|
cbUtf8,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
if (!result)
|
||
|
{
|
||
|
TraceLastWin32Error("Utf8FromWsz: WideCharToMultiByte #2");
|
||
|
|
||
|
MemFree(pszUtf8);
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
pszResult = pszUtf8;
|
||
|
|
||
|
Cleanup:
|
||
|
return pszResult;
|
||
|
}
|
||
|
|
||
|
LPWSTR WszFromTsz(LPCTSTR pszInputString)
|
||
|
{
|
||
|
#ifdef _UNICODE
|
||
|
return WszAllocateAndCopyWsz(pszInputString);
|
||
|
#else // not unicode
|
||
|
return WszFromSz(pszInputString);
|
||
|
#endif // _UNICODE
|
||
|
}
|
||
|
|
||
|
LPTSTR TszFromWsz(LPCWSTR pszInputString)
|
||
|
{
|
||
|
#ifdef _UNICODE
|
||
|
return WszAllocateAndCopyWsz(pszInputString);
|
||
|
#else // not unicode
|
||
|
return SzFromWsz(pszInputString);
|
||
|
#endif // _UNICODE
|
||
|
}
|
||
|
|
||
|
LPTSTR TszFromSz(LPCSTR szAnsi)
|
||
|
{
|
||
|
#ifdef _UNICODE
|
||
|
return WszFromSz(szAnsi);
|
||
|
#else
|
||
|
return SzaDupSza(szAnsi);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
LPSTR SzFromTsz(LPCTSTR pszInputString)
|
||
|
{
|
||
|
#ifdef _UNICODE
|
||
|
return SzFromWsz(pszInputString);
|
||
|
#else
|
||
|
return SzaDupSza(pszInputString);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegAddStringToDelimitedSz
|
||
|
//
|
||
|
// Purpose: Add a string into a REG_MULTI_SZ registry value.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pszAddString [in] The string to add to the delimited psz.
|
||
|
// pszIn [in] The delimited psz list.
|
||
|
// chDelimiter [in] The character to be used to delimit the
|
||
|
// values. Most multi-valued REG_SZ strings are
|
||
|
// delimited with either ',' or ' '. This will
|
||
|
// be used to delimit the value that we add,
|
||
|
// as well.
|
||
|
// dwFlags [in] Can contain one or more of the following
|
||
|
// values:
|
||
|
//
|
||
|
// STRING_FLAG_ALLOW_DUPLICATES
|
||
|
// Don't remove duplicate values when adding
|
||
|
// the string to the list. Default is to
|
||
|
// remove all other instance of this string.
|
||
|
// STRING_FLAG_ENSURE_AT_FRONT
|
||
|
// Insert the string as the first element of
|
||
|
// the list.
|
||
|
// STRING_FLAG_ENSURE_AT_END
|
||
|
// Insert the string as the last
|
||
|
// element of the list. This can not be used
|
||
|
// with STRING_FLAG_ENSURE_AT_FRONT.
|
||
|
// STRING_FLAG_ENSURE_AT_INDEX
|
||
|
// Ensure that the string is at dwStringIndex
|
||
|
// in the psz. If the index specified
|
||
|
// is greater than the number of strings
|
||
|
// in the psz, the string will be
|
||
|
// placed at the end.
|
||
|
// dwStringIndex [in] If STRING_FLAG_ENSURE_AT_INDEX is specified,
|
||
|
// this is the index for the string position.
|
||
|
// Otherwise, this value is ignored.
|
||
|
// pmszOut [out] The new delimited psz.
|
||
|
//
|
||
|
//
|
||
|
// Returns: S_OK or an HRESULT_FROM_WIN32 error code.
|
||
|
//
|
||
|
// Author: jeffspr 27 Mar 1997
|
||
|
//
|
||
|
// Modified: BillBe 9 Nov 1998
|
||
|
// (Extracted from HrRegAddStringToSz and modified)
|
||
|
//
|
||
|
//
|
||
|
// Note:
|
||
|
// Might want to allow for the removal of leading/trailing spaces
|
||
|
//
|
||
|
HRESULT
|
||
|
HrAddStringToDelimitedSz (
|
||
|
IN PCTSTR pszAddString,
|
||
|
IN PCTSTR pszIn,
|
||
|
IN TCHAR chDelimiter,
|
||
|
IN DWORD dwFlags,
|
||
|
IN DWORD dwStringIndex,
|
||
|
OUT PTSTR* ppszOut)
|
||
|
{
|
||
|
Assert(pszAddString);
|
||
|
Assert(ppszOut);
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// Don't continue if the pointers are NULL
|
||
|
if (!pszAddString || !ppszOut)
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
}
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Initialize out param
|
||
|
*ppszOut = NULL;
|
||
|
}
|
||
|
|
||
|
BOOL fEnsureAtFront = dwFlags & STRING_FLAG_ENSURE_AT_FRONT;
|
||
|
BOOL fEnsureAtEnd = dwFlags & STRING_FLAG_ENSURE_AT_END;
|
||
|
BOOL fEnsureAtIndex = dwFlags & STRING_FLAG_ENSURE_AT_INDEX;
|
||
|
|
||
|
// Can't specify more than one of these flags
|
||
|
if ((fEnsureAtFront && fEnsureAtEnd) ||
|
||
|
(fEnsureAtFront && fEnsureAtIndex) ||
|
||
|
(fEnsureAtEnd && fEnsureAtIndex))
|
||
|
{
|
||
|
AssertSz(FALSE, "Invalid flags in HrAddStringToSz");
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
// Have to specify at least one of these
|
||
|
if (!fEnsureAtFront && !fEnsureAtEnd && !fEnsureAtIndex)
|
||
|
{
|
||
|
AssertSz(FALSE, "Must specify a STRING_FLAG_ENSURE flag");
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
// Alloc the new blob, including enough space for the trailing comma
|
||
|
//
|
||
|
*ppszOut = (PTSTR) MemAlloc (CbOfTSzAndTermSafe(pszIn) +
|
||
|
CbOfTSzSafe(pszAddString) + sizeof(TCHAR));
|
||
|
|
||
|
if (!*ppszOut)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
DWORD dwCurrentIndex = 0; // Current index in the new buffer
|
||
|
|
||
|
// Prime the new string
|
||
|
//
|
||
|
(*ppszOut)[0] = L'\0';
|
||
|
|
||
|
// If we have the "ensure at front" flag, do so with the passed in
|
||
|
// value. We also do this if we have the ensure at index flag
|
||
|
// set with index of 0 or if the ensure at index is set but
|
||
|
// the input string is null or empty
|
||
|
//
|
||
|
if (fEnsureAtFront || (fEnsureAtIndex && (0 == dwStringIndex)) ||
|
||
|
(fEnsureAtIndex && (!pszIn || !*pszIn)))
|
||
|
{
|
||
|
_tcscpy (*ppszOut, pszAddString);
|
||
|
++dwCurrentIndex;
|
||
|
}
|
||
|
|
||
|
// If there was a previous value, walk through it and copy as needed.
|
||
|
// If not, then we're done.
|
||
|
if (pszIn && *pszIn)
|
||
|
{
|
||
|
PCTSTR pszCurrent = pszIn;
|
||
|
|
||
|
// Loop through the old buffer, and copy all of the strings that
|
||
|
// are not identical to our insertion string.
|
||
|
//
|
||
|
|
||
|
// Find the first string's end (at the delimiter).
|
||
|
PCTSTR pszEnd = _tcschr (pszCurrent, chDelimiter);
|
||
|
|
||
|
while (*pszCurrent)
|
||
|
{
|
||
|
// If the delimiter didn't exist, set the end to the end of the
|
||
|
// entire string
|
||
|
//
|
||
|
if (!pszEnd)
|
||
|
{
|
||
|
pszEnd = pszCurrent + _tcslen (pszCurrent);
|
||
|
}
|
||
|
|
||
|
LONG lLength = _tcslen (*ppszOut);
|
||
|
if (fEnsureAtIndex && (dwCurrentIndex == dwStringIndex))
|
||
|
{
|
||
|
// We know we are not at the first item since
|
||
|
// this would mean dwStringIndex is 0 and we would
|
||
|
// have copied the string before this point
|
||
|
//
|
||
|
(*ppszOut)[lLength++] = chDelimiter;
|
||
|
(*ppszOut)[lLength++] = L'\0';
|
||
|
|
||
|
// Append the string.
|
||
|
_tcscat (*ppszOut, pszAddString);
|
||
|
++dwCurrentIndex;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DWORD_PTR cch = pszEnd - pszCurrent;
|
||
|
// If we are allowing duplicates or the current string
|
||
|
// doesn't match the string we want to add, then we will
|
||
|
// copy it.
|
||
|
//
|
||
|
if ((dwFlags & STRING_FLAG_ALLOW_DUPLICATES) ||
|
||
|
(_tcsnicmp (pszCurrent, pszAddString, cch) != 0))
|
||
|
{
|
||
|
// If we're not the first item, then add the delimiter.
|
||
|
//
|
||
|
if (lLength > 0)
|
||
|
{
|
||
|
(*ppszOut)[lLength++] = chDelimiter;
|
||
|
(*ppszOut)[lLength++] = L'\0';
|
||
|
}
|
||
|
|
||
|
// Append the string.
|
||
|
_tcsncat (*ppszOut, pszCurrent, cch);
|
||
|
++dwCurrentIndex;
|
||
|
}
|
||
|
|
||
|
// Advance the pointer to one past the end of the current
|
||
|
// string unless, the end is not the delimiter but NULL.
|
||
|
// In that case, set the current point to equal the end
|
||
|
// pointer
|
||
|
//
|
||
|
pszCurrent = pszEnd + (*pszEnd ? 1 : 0);
|
||
|
|
||
|
// If the current pointer is not at the end of the input
|
||
|
// string, then find the next delimiter
|
||
|
//
|
||
|
if (*pszCurrent)
|
||
|
{
|
||
|
pszEnd = _tcschr (pszCurrent, chDelimiter);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we don't have the "insert at front" flag, then we should insert
|
||
|
// at the end (this is the same as having the
|
||
|
// STRING_FLAG_ENSURE_AT_END flag set)
|
||
|
//
|
||
|
if (fEnsureAtEnd ||
|
||
|
(fEnsureAtIndex && (dwCurrentIndex <= dwStringIndex)))
|
||
|
{
|
||
|
LONG lLength = _tcslen (*ppszOut);
|
||
|
|
||
|
// If we're not the first item, add the delimiter.
|
||
|
//
|
||
|
if (_tcslen (*ppszOut) > 0)
|
||
|
{
|
||
|
(*ppszOut)[lLength++] = chDelimiter;
|
||
|
(*ppszOut)[lLength++] = L'\0';
|
||
|
}
|
||
|
|
||
|
// Append the string.
|
||
|
//
|
||
|
_tcscat (*ppszOut, pszAddString);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceError ("HrAddStringToDelimitedSz", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrRegRemoveStringFromDelimitedSz
|
||
|
//
|
||
|
// Purpose: Removes a string from a delimited string value
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pszRemove [in] The string to be removed from the multi-sz
|
||
|
// pszIn [in] The delimited list to scan for pszRemove
|
||
|
// cDelimiter [in] The character to be used to delimit the
|
||
|
// values. Most multi-valued REG_SZ strings are
|
||
|
// delimited with either ',' or ' '.
|
||
|
// dwFlags [in] Can contain one or more of the following
|
||
|
// values:
|
||
|
//
|
||
|
// STRING_FLAG_REMOVE_SINGLE
|
||
|
// Don't remove more than one value, if
|
||
|
// multiple are present.
|
||
|
// STRING_FLAG_REMOVE_ALL
|
||
|
// If multiple matching values are present,
|
||
|
// remove them all.
|
||
|
// ppszOut [out] The string with pszRemove removed. Note
|
||
|
// that the output parameter is always set even
|
||
|
// if pszRemove did not exist in the list.
|
||
|
//
|
||
|
// Returns: S_OK or an HRESULT_FROM_WIN32 error code.
|
||
|
//
|
||
|
// Author: jeffspr 27 Mar 1997
|
||
|
//
|
||
|
// Modified: BillBe 10 Nov 1998
|
||
|
// (Extracted from HrRegAddStringToSz and modified)
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
// Note:
|
||
|
// Might want to allow for the removal of leading/trailing spaces
|
||
|
//
|
||
|
HRESULT
|
||
|
HrRemoveStringFromDelimitedSz(
|
||
|
IN PCTSTR pszRemove,
|
||
|
IN PCTSTR pszIn,
|
||
|
IN TCHAR chDelimiter,
|
||
|
IN DWORD dwFlags,
|
||
|
OUT PTSTR* ppszOut)
|
||
|
{
|
||
|
|
||
|
Assert(pszIn && *pszIn);
|
||
|
Assert(ppszOut);
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// If the out param is not specified, get out
|
||
|
if (!ppszOut)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
// Alloc the new blob
|
||
|
//
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
*ppszOut = (PTSTR) MemAlloc (CbOfTSzAndTermSafe (pszIn));
|
||
|
|
||
|
if (*ppszOut)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
// Prime the new string
|
||
|
//
|
||
|
(*ppszOut)[0] = L'\0';
|
||
|
|
||
|
// If there was a previous value, walk through it and copy as needed.
|
||
|
// If not, then we're done
|
||
|
//
|
||
|
if (pszIn)
|
||
|
{
|
||
|
// Loop through the old buffer, and copy all of the strings that
|
||
|
// are not identical to our insertion string.
|
||
|
//
|
||
|
PCTSTR pszCurrent = pszIn;
|
||
|
|
||
|
// Loop through the old buffer, and copy all of the strings that
|
||
|
// are not identical to our insertion string.
|
||
|
//
|
||
|
|
||
|
// Find the first string's end (at the delimiter).
|
||
|
PCTSTR pszEnd = _tcschr (pszCurrent, chDelimiter);
|
||
|
|
||
|
// Keep track of how many instances have been removed.
|
||
|
DWORD dwNumRemoved = 0;
|
||
|
|
||
|
while (*pszCurrent)
|
||
|
{
|
||
|
// If the delimiter didn't exist, set the end to the end of
|
||
|
// the entire string.
|
||
|
//
|
||
|
if (!pszEnd)
|
||
|
{
|
||
|
pszEnd = pszCurrent + _tcslen (pszCurrent);
|
||
|
}
|
||
|
|
||
|
DWORD_PTR cch = pszEnd - pszCurrent;
|
||
|
INT iCompare;
|
||
|
// If we have a match, and we want to remove it (meaning that
|
||
|
// if we have the remove-single set, that we haven't removed
|
||
|
// one already).
|
||
|
|
||
|
iCompare = _tcsnicmp (pszCurrent, pszRemove, cch);
|
||
|
|
||
|
if ((iCompare) ||
|
||
|
((dwFlags & STRING_FLAG_REMOVE_SINGLE) &&
|
||
|
(dwNumRemoved > 0)))
|
||
|
{
|
||
|
LONG lLength = _tcslen (*ppszOut);
|
||
|
|
||
|
// If we're not the first item, then add the delimiter.
|
||
|
//
|
||
|
if (lLength > 0)
|
||
|
{
|
||
|
(*ppszOut)[lLength++] = chDelimiter;
|
||
|
(*ppszOut)[lLength++] = L'\0';
|
||
|
}
|
||
|
|
||
|
// Append the string.
|
||
|
_tcsncat (*ppszOut, pszCurrent, cch);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwNumRemoved++;
|
||
|
}
|
||
|
|
||
|
// Advance the pointer to one past the end of the current
|
||
|
// string unless, the end is not the delimiter but NULL.
|
||
|
// In that case, set the current point to equal the end
|
||
|
// pointer
|
||
|
//
|
||
|
pszCurrent = pszEnd + (*pszEnd ? 1 : 0);
|
||
|
|
||
|
// If the current pointer is not at the end of the input
|
||
|
// string, then find the next delimiter
|
||
|
//
|
||
|
if (*pszCurrent)
|
||
|
{
|
||
|
pszEnd = _tcschr (pszCurrent, chDelimiter);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceError("HrRemoveStringFromDelimitedSz", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrReallocAndCopyString
|
||
|
//
|
||
|
// Purpose: Copies a given string into a string pointer that might
|
||
|
// already contain an alloc()ed string. If the destination
|
||
|
// pointer contains a string (e.g. is non-null), that string
|
||
|
// is freed before the copy occurs.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pszSrc The string to copy. This may be NULL.
|
||
|
// ppszDest The address of the pointer which will contain the copied
|
||
|
// string. If *ppszDest is non-NULL when the function is
|
||
|
// called, its value will be freed before the string is
|
||
|
// copied. On return, it will contain a copy of pszSrc,
|
||
|
// or be set to NULL (if pszSrc is NULL).
|
||
|
//
|
||
|
// Returns: TRUE if the *ppszDest was set
|
||
|
// E_OUTOFMEMORY if the new string could not be allocated
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT
|
||
|
HrReallocAndCopyString(/* IN */ LPCWSTR pszSrc, /* INOUT */ LPWSTR * ppszDest)
|
||
|
{
|
||
|
Assert(ppszDest);
|
||
|
|
||
|
HRESULT hr;
|
||
|
LPWSTR pszTemp;
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
pszTemp = NULL;
|
||
|
|
||
|
if (pszSrc)
|
||
|
{
|
||
|
// copy the string into pszTemp
|
||
|
pszTemp = WszAllocateAndCopyWsz(pszSrc);
|
||
|
if (!pszTemp)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*ppszDest)
|
||
|
{
|
||
|
delete [] *ppszDest;
|
||
|
}
|
||
|
*ppszDest = pszTemp;
|
||
|
|
||
|
Cleanup:
|
||
|
TraceError("HrReallocAndCopyString", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCopyString
|
||
|
//
|
||
|
// Purpose: Copies a string using new
|
||
|
//
|
||
|
// Arguments:
|
||
|
// szSrc [in] String to be copied
|
||
|
// pszDest [out] Copy
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: mbend 12 Nov 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrCopyString(const char * szSrc, char ** pszDest)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if(szSrc)
|
||
|
{
|
||
|
*pszDest = new char[lstrlenA(szSrc) + 1];
|
||
|
if(!*pszDest)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
lstrcpyA(*pszDest, szSrc);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidError, FAL, hr, (hr == E_POINTER), "HrCopyString");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCopyString
|
||
|
//
|
||
|
// Purpose: Copies a string using new
|
||
|
//
|
||
|
// Arguments:
|
||
|
// szSrc [in] String to be copied
|
||
|
// pszDest [out] Copy
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// Author: mbend 12 Nov 2000
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
HRESULT HrCopyString(const wchar_t * szSrc, wchar_t ** pszDest)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if(szSrc)
|
||
|
{
|
||
|
*pszDest = new wchar_t[lstrlen(szSrc) + 1];
|
||
|
if(!*pszDest)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
if(SUCCEEDED(hr))
|
||
|
{
|
||
|
lstrcpy(*pszDest, szSrc);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_POINTER;
|
||
|
}
|
||
|
|
||
|
TraceHr(ttidError, FAL, hr, (hr == E_POINTER), "HrCopyString");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Stol.. er. "borrowed" from \\index2\ntsrc\enduser\windows.com\wuv3\wuv3\string.cpp
|
||
|
//
|
||
|
char *stristr(const char *string1, const char *string2)
|
||
|
{
|
||
|
char *pSave = (char *)string1;
|
||
|
char *ps1 = (char *)string1;
|
||
|
char *ps2 = (char *)string2;
|
||
|
|
||
|
if ( !*ps1 || !ps2 || !ps1 )
|
||
|
return NULL;
|
||
|
|
||
|
if ( !*ps2 )
|
||
|
return ps1;
|
||
|
|
||
|
while( *ps1 )
|
||
|
{
|
||
|
while( *ps2 && (toupper(*ps2) == toupper(*ps1)) )
|
||
|
{
|
||
|
ps2++;
|
||
|
ps1++;
|
||
|
}
|
||
|
if ( !*ps2 )
|
||
|
return pSave;
|
||
|
if ( ps2 == string2 )
|
||
|
{
|
||
|
ps1++;
|
||
|
pSave = ps1;
|
||
|
}
|
||
|
else
|
||
|
ps2 = (char *)string2;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|