|
|
///////////////////////////////////////////////////////////////////////////////
/* 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)
|