Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

949 lines
17 KiB

///////////////////////////////////////////////////////////////////////////////
/* File: strclass.cpp
Description: Typical class to handle strings.
Revision History:
Date Description Programmer
-------- --------------------------------------------------- ----------
07/01/97 Initial creation. BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
#include "pch.h"
#pragma hdrstop
#include "strclass.h"
#ifdef StrCpy
# undef StrCpy
#endif
#ifdef StrCpyN
# undef StrCpyN
#endif
#ifdef StrLen
# undef StrLen
#endif
#ifdef UNICODE
# define StrCpy StrCpyW
# define StrCpyN StrCpyNW
# define StrLen StrLenW
#else
# define StrCpy StrCpyA
# define StrCpyN StrCpyNA
# define StrLen StrLenA
#endif // UNICODE
const INT MAX_RESOURCE_STR_LEN = 4097;
//
// Disable "'operator ->' is not a UDT or reference to a UDT" warning.
// This is caused when we create an autoptr to a non-UDT. It's meaningless
// since there's no reason to call operator-> on a non-UDT autoptr.
//
#pragma warning (disable : 4284)
CString::CString(
VOID
) : m_pValue(new StringValue())
{
}
CString::CString(
INT cch
) : m_pValue(new StringValue(cch))
{
}
CString::CString(
LPCSTR pszA
) : m_pValue(new StringValue(pszA))
{
}
CString::CString(
LPCWSTR pszW
) : m_pValue(new StringValue(pszW))
{
}
CString::CString(
const CString& rhs
) : m_pValue(rhs.m_pValue)
{
InterlockedIncrement(&(m_pValue->m_cRef));
}
CString::CString(
HINSTANCE hInst,
INT idMsg,
...
) : m_pValue(NULL)
{
LPTSTR pszMsg = NULL;
va_list args;
va_start(args, idMsg);
Format(hInst, idMsg, &args);
va_end(args);
}
CString::~CString(
VOID
)
{
if (NULL != m_pValue)
{
if (0 == InterlockedDecrement(&(m_pValue->m_cRef)))
delete m_pValue;
}
}
//
// Length of string, excluding nul terminator.
//
INT
CString::Length(
VOID
) const
{
return m_pValue->Length();
}
VOID
CString::Empty(
VOID
)
{
if (0 == InterlockedDecrement(&(m_pValue->m_cRef)))
{
delete m_pValue;
m_pValue = NULL;
}
m_pValue = new StringValue();
}
BOOL
CString::IsEmpty(
VOID
) const
{
return (NULL != m_pValue && 0 == m_pValue->Length());
}
CString&
CString::operator = (
const CString& rhs
)
{
if (m_pValue != rhs.m_pValue) // Chk for assignment to *this.
{
if (0 == InterlockedDecrement(&(m_pValue->m_cRef)))
delete m_pValue;
m_pValue = rhs.m_pValue;
InterlockedIncrement(&(m_pValue->m_cRef));
}
return *this;
}
CString&
CString::operator = (
LPCWSTR rhsW
)
{
if (0 == InterlockedDecrement(&(m_pValue->m_cRef)))
{
delete m_pValue;
m_pValue = NULL;
}
m_pValue = new StringValue(rhsW);
return *this;
}
CString&
CString::operator = (
LPCSTR rhsA
)
{
if (0 == InterlockedDecrement(&(m_pValue->m_cRef)))
{
delete m_pValue;
m_pValue = NULL;
}
m_pValue = new StringValue(rhsA);
return *this;
}
CString
CString::operator + (
const CString& rhs
) const
{
CString strNew;
LPTSTR pszTemp = NULL;
try
{
pszTemp = StringValue::Concat(m_pValue, rhs.m_pValue);
strNew = pszTemp;
}
catch(...)
{
delete[] pszTemp;
throw;
}
delete[] pszTemp;
return strNew;
}
CString&
CString::operator += (
const CString& rhs
)
{
LPTSTR pszTemp = NULL;
try
{
pszTemp = StringValue::Concat(m_pValue, rhs.m_pValue);
*this = pszTemp;
}
catch(...)
{
delete[] pszTemp;
throw;
}
delete[] pszTemp;
return *this;
}
BOOL
CString::operator == (
const CString& rhs
) const
{
return (0 == lstrcmp(m_pValue->m_psz, rhs.m_pValue->m_psz));
}
INT
CString::Compare(
LPCWSTR rhsW
) const
{
StringValue Value(rhsW);
return lstrcmp(m_pValue->m_psz, Value.m_psz);
}
INT
CString::Compare(
LPCSTR rhsA
) const
{
StringValue Value(rhsA);
return lstrcmp(m_pValue->m_psz, Value.m_psz);
}
INT
CString::CompareNoCase(
LPCWSTR rhsW
) const
{
StringValue Value(rhsW);
return lstrcmpi(m_pValue->m_psz, Value.m_psz);
}
INT
CString::CompareNoCase(
LPCSTR rhsA
) const
{
StringValue Value(rhsA);
return lstrcmpi(m_pValue->m_psz, Value.m_psz);
}
BOOL
CString::operator < (
const CString& rhs
) const
{
return (0 > lstrcmp(m_pValue->m_psz, rhs.m_pValue->m_psz));
}
TCHAR
CString::operator[](
INT index
) const
{
if (!ValidIndex(index))
throw CMemoryException(CMemoryException::index);
return m_pValue->m_psz[index];
}
TCHAR&
CString::operator[](
INT index
)
{
if (!ValidIndex(index))
throw CMemoryException(CMemoryException::index);
CopyOnWrite();
return m_pValue->m_psz[index];
}
INT
CString::First(
TCHAR ch
) const
{
LPCTSTR psz = m_pValue->m_psz;
LPCTSTR pszLast = psz;
INT i = 0;
while(psz && *psz)
{
if (ch == *psz)
return i;
psz = CharNext(psz);
i += (INT)(psz - pszLast);
pszLast = psz;
}
return -1;
}
INT
CString::Last(
TCHAR ch
) const
{
INT iLast = -1;
INT i = 0;
LPCTSTR psz = m_pValue->m_psz;
LPCTSTR pszPrev = psz;
while(psz && *psz)
{
if (ch == *psz)
iLast = i;
psz = CharNext(psz);
i += (INT)(psz - pszPrev);
pszPrev = psz;
}
return iLast;
}
CString
CString::SubString(
INT iFirst,
INT cch
)
{
if (!ValidIndex(iFirst))
throw CMemoryException(CMemoryException::index);
INT cchToEnd = Length() - iFirst;
if (-1 == cch || cch > cchToEnd)
return CString(m_pValue->m_psz + iFirst);
LPTSTR pszTemp = new TCHAR[cch + 1];
if (NULL == pszTemp)
throw CAllocException();
CString::StrCpyN(pszTemp, m_pValue->m_psz + iFirst, cch + 1);
CString strTemp(pszTemp);
delete[] pszTemp;
return strTemp;
}
VOID
CString::ToUpper(
INT iFirst,
INT cch
)
{
if (!ValidIndex(iFirst))
throw CMemoryException(CMemoryException::index);
CopyOnWrite();
INT cchToEnd = Length() - iFirst;
if (-1 == cch || cch > cchToEnd)
cch = cchToEnd;
CharUpperBuff(m_pValue->m_psz + iFirst, cch);
}
VOID
CString::ToLower(
INT iFirst,
INT cch
)
{
if (!ValidIndex(iFirst))
throw CMemoryException(CMemoryException::index);
CopyOnWrite();
INT cchToEnd = Length() - iFirst;
if (-1 == cch || cch > cchToEnd)
cch = cchToEnd;
CharLowerBuff(m_pValue->m_psz + iFirst, cch);
}
VOID
CString::Size(
INT cch
)
{
StringValue *m_psv = new StringValue(cch + 1);
CString::StrCpyN(m_psv->m_psz, m_pValue->m_psz, cch);
if (m_pValue->m_cRef > 1)
{
InterlockedDecrement(&(m_pValue->m_cRef));
}
else
{
delete m_pValue;
}
m_pValue = m_psv;
}
VOID
CString::CopyOnWrite(
VOID
)
{
//
// Only need to copy if ref cnt > 1.
//
if (m_pValue->m_cRef > 1)
{
LPTSTR pszTemp = m_pValue->m_psz;
InterlockedDecrement(&(m_pValue->m_cRef));
m_pValue = NULL;
m_pValue = new StringValue(pszTemp);
}
}
BOOL
CString::Format(
LPCTSTR pszFmt,
...
)
{
BOOL bResult;
va_list args;
va_start(args, pszFmt);
bResult = Format(pszFmt, &args);
va_end(args);
return bResult;
}
BOOL
CString::Format(
LPCTSTR pszFmt,
va_list *pargs
)
{
BOOL bResult = FALSE;
TCHAR szBuffer[MAX_RESOURCE_STR_LEN];
INT cchLoaded;
cchLoaded = ::FormatMessage(FORMAT_MESSAGE_FROM_STRING,
pszFmt,
0,
0,
szBuffer,
ARRAYSIZE(szBuffer),
pargs);
if (0 < cchLoaded)
{
if (NULL != m_pValue && 0 == InterlockedDecrement(&(m_pValue->m_cRef)))
delete m_pValue;
m_pValue = NULL;
m_pValue = new StringValue(szBuffer);
bResult = TRUE;
}
else
{
DWORD dwLastError = GetLastError();
if (ERROR_SUCCESS != dwLastError)
{
DBGERROR((TEXT("CString::Format failed with error 0x%08X"), dwLastError));
throw CResourceException(CResourceException::string, NULL, 0);
}
}
return bResult;
}
BOOL
CString::Format(
HINSTANCE hInst,
UINT idFmt,
...
)
{
BOOL bResult;
va_list args;
va_start(args, idFmt);
bResult = Format(hInst, idFmt, &args);
va_end(args);
return bResult;
}
BOOL
CString::Format(
HINSTANCE hInst,
UINT idFmt,
va_list *pargs
)
{
BOOL bResult = FALSE;
TCHAR szFmtStr[MAX_RESOURCE_STR_LEN]; // Buffer for format string (if needed).
INT cchLoaded;
//
// Try to load the format string as a string resource.
//
cchLoaded = ::LoadString(hInst, idFmt, szFmtStr, ARRAYSIZE(szFmtStr));
if (0 < cchLoaded)
{
//
// The format string was in a string resource.
// Now format it with the arg list.
//
bResult = Format(szFmtStr, pargs);
}
else
{
TCHAR szBuffer[MAX_RESOURCE_STR_LEN];
//
// The format string may be in a message resource.
// Note that if it is, the resulting formatted string will
// be automatically attached to m_psz by ::FormatMessage.
//
cchLoaded = ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_FROM_HMODULE,
hInst,
(DWORD)idFmt,
LANGIDFROMLCID(GetThreadLocale()),
(LPTSTR)szBuffer,
ARRAYSIZE(szBuffer),
pargs);
if (0 < cchLoaded)
{
if (NULL != m_pValue && 0 == InterlockedDecrement(&(m_pValue->m_cRef)))
delete m_pValue;
m_pValue = NULL;
m_pValue = new StringValue(szBuffer);
bResult = TRUE;
}
else
{
DWORD dwLastError = GetLastError();
if (ERROR_SUCCESS != dwLastError)
{
DBGERROR((TEXT("CString::Format failed with error 0x%08X"), dwLastError));
throw CResourceException(CResourceException::string, hInst, idFmt);
}
}
}
return bResult;
}
LPTSTR
CString::GetBuffer(
INT cchMax
)
{
if (-1 == cchMax)
cchMax = m_pValue->m_cchAlloc;
CopyOnWrite();
if (cchMax > m_pValue->m_cchAlloc)
{
//
// Extend the buffer, copying original contents to dest.
//
StringValue *pv = new StringValue(cchMax);
StrCpyN(pv->m_psz, m_pValue->m_psz, cchMax);
if (0 == InterlockedDecrement(&(m_pValue->m_cRef)))
delete m_pValue;
m_pValue = pv;
LPTSTR pszEnd = m_pValue->m_psz + m_pValue->m_cchAlloc - 1;
if (pszEnd >= m_pValue->m_psz && TEXT('\0') != *(pszEnd))
{
//
// Ensure it's nul terminated.
//
*(pszEnd) = TEXT('\0');
}
}
return m_pValue->m_psz;
}
VOID
CString::ReleaseBuffer(
void
)
{
//
// Update the string length member after client has had free access
// to internal buffer.
//
m_pValue->m_cch = StrLen(m_pValue->m_psz);
}
void
CString::Rtrim(
void
)
{
LPTSTR s = GetBuffer();
int len = Length();
while(0 < --len && IsWhiteSpace(s[len]))
s[len] = TEXT('\0');
ReleaseBuffer();
}
void
CString::Ltrim(
void
)
{
LPTSTR s0;
LPTSTR s = s0 = GetBuffer();
while(*s && IsWhiteSpace(*s))
s++;
while(*s)
*s0++ = *s++;
*s0 = TEXT('\0');
ReleaseBuffer();
}
VOID
CString::ExpandEnvironmentStrings(
VOID
)
{
DWORD cchBuffer = 0; // Size of expansion buffer.
DWORD cchPath = 0; // Count of actual chars in expanded buffer.
CString strExpanded; // Expansion buffer.
//
// If necessary, keep increasing expansion buffer size until entire
// expanded string fits.
//
do
{
cchBuffer += MAX_PATH;
cchPath = ::ExpandEnvironmentStrings(*this,
strExpanded.GetBuffer(cchBuffer),
cchBuffer);
}
while(0 != cchPath && cchPath > cchBuffer);
ReleaseBuffer();
*this = strExpanded;
}
bool
CString::GetDisplayRect(
HDC hdc,
LPRECT prc
) const
{
return (0 != DrawText(hdc, Cstr(), Length(), prc, DT_CALCRECT));
}
VOID
CString::DebugOut(
BOOL bNewline
) const
{
OutputDebugString(m_pValue->m_psz);
if (bNewline)
OutputDebugString(TEXT("\n\r"));
}
CString::StringValue::StringValue(
VOID
) : m_psz(new TCHAR[1]),
m_cchAlloc(1),
m_cch(0),
m_cRef(1)
{
*m_psz = TEXT('\0');
}
CString::StringValue::StringValue(
LPCSTR pszA
) : m_psz(NULL),
m_cchAlloc(0),
m_cch(0),
m_cRef(1)
{
#ifdef UNICODE
m_psz = AnsiToWide(pszA, &m_cchAlloc);
m_cch = StrLenW(m_psz);
#else
m_cch = CString::StrLenA(pszA);
m_psz = Dup(pszA, m_cch + 1);
m_cchAlloc = m_cch + 1;
#endif
}
CString::StringValue::StringValue(
LPCWSTR pszW
) : m_psz(NULL),
m_cchAlloc(0),
m_cch(0),
m_cRef(1)
{
#ifdef UNICODE
m_cch = CString::StrLenW(pszW);
m_psz = Dup(pszW, m_cch + 1);
m_cchAlloc = m_cch + 1;
#else
m_psz = WideToAnsi(pszW, &m_cchAlloc);
m_cch = StrLenA(m_psz);
#endif
}
CString::StringValue::StringValue(
INT cch
) : m_psz(NULL),
m_cchAlloc(0),
m_cch(0),
m_cRef(0)
{
m_psz = Dup(TEXT(""), cch);
m_cRef = 1;
m_cchAlloc = cch;
}
CString::StringValue::~StringValue(
VOID
)
{
delete[] m_psz;
}
LPWSTR
CString::StringValue::AnsiToWide(
LPCSTR pszA,
INT *pcch
)
{
INT cchW = 0;
LPWSTR pszW = NULL;
cchW = MultiByteToWideChar(CP_ACP,
0,
pszA,
-1,
NULL,
0);
pszW = new WCHAR[cchW];
if (NULL == pszW)
throw CAllocException();
MultiByteToWideChar(CP_ACP,
0,
pszA,
-1,
pszW,
cchW);
if (NULL != pcch)
*pcch = cchW;
return pszW;
}
LPSTR
CString::StringValue::WideToAnsi(
LPCWSTR pszW,
INT *pcch
)
{
INT cchA = 0;
LPSTR pszA = NULL;
cchA = WideCharToMultiByte(CP_ACP,
0,
pszW,
-1,
NULL,
0,
NULL,
NULL);
pszA = new CHAR[cchA];
if (NULL == pszA)
throw CAllocException();
WideCharToMultiByte(CP_ACP,
0,
pszW,
-1,
pszA,
cchA,
NULL,
NULL);
if (NULL != pcch)
*pcch = cchA;
return pszA;
}
INT
CString::StringValue::Length(
VOID
) const
{
if (0 == m_cch && NULL != m_psz)
{
m_cch = StrLen(m_psz);
}
return m_cch;
}
LPWSTR
CString::StringValue::Dup(
LPCWSTR pszW,
INT cch
)
{
if (0 == cch)
cch = CString::StrLenW(pszW) + 1;
LPWSTR pszNew = new WCHAR[cch];
if (NULL == pszNew)
throw CAllocException();
CString::StrCpyW(pszNew, pszW);
return pszNew;
}
LPSTR
CString::StringValue::Dup(
LPCSTR pszA,
INT cch
)
{
if (0 == cch)
cch = CString::StrLenA(pszA) + 1;
LPSTR pszNew = new CHAR[cch];
if (NULL == pszNew)
throw CAllocException();
CString::StrCpyA(pszNew, pszA);
return pszNew;
}
LPTSTR
CString::StringValue::Concat(
CString::StringValue *psv1,
CString::StringValue *psv2
)
{
LPTSTR pszTemp = NULL;
INT len1 = psv1->Length();
INT len2 = psv2->Length();
pszTemp = new TCHAR[len1 + len2 + 1];
if (NULL == pszTemp)
throw CAllocException();
CString::StrCpy(pszTemp, psv1->m_psz);
CString::StrCpy(pszTemp + len1, psv2->m_psz);
return pszTemp;
}
#pragma warning (default : 4284)