///////////////////////////////////////////////////////////////////////////////
// *
///////////////////////////////////////////////////////////////////////////////
#ifndef _CESTRING_DEFINED_
#define _CESTRING_DEFINED_
#include <string.h> // This includes the C string functions, e.g.,
#include <stdlib.h>
#include <tchar.h>
#include "CeDebug.h"
#include "CeMisc.h"
#ifdef _WIN32_WCE
extern wchar_t* wce_AsciiToWide( wchar_t* ws, const char* s );
#endif
///////////////////////////////////////////////////////////////////////////////
//
// Reference counted string representation struct
//
///////////////////////////////////////////////////////////////////////////////
struct CeStringRep
{
public:
// Construction/Destruction
int AddRef()
{
ASSERT(! IsBadWritePtr(this, sizeof *this));
ASSERT(0 != m_nLen);
::InterlockedIncrement(&m_nRef);
return m_nRef;
}
int Release()
{
ASSERT(! IsBadWritePtr(this, sizeof *this));
ASSERT(0 != m_nLen);
::InterlockedDecrement(&m_nRef);
return m_nRef;
}
bool IsShared() const { return m_nRef > 1; }
int GetRefs() const { return m_nRef; }
TCHAR* GetString() const { return (TCHAR*) (this+1); }
int GetLength() const { return m_nLen; }
static CeStringRep* AllocBuf(int nStrLen)
{
CeStringRep* pRep = (CeStringRep*) new BYTE[ sizeof(CeStringRep) +
(nStrLen+1)*sizeof(TCHAR) ];
pRep->m_nLen = nStrLen;
pRep->m_nRef = 1;
pRep->GetString()[nStrLen] = _T('\0');
return pRep;
}
static void FreeBuf(CeStringRep* pStr)
{
delete[] (BYTE *) pStr;
}
// retrieve the constants for the null string and or the null string representation
static LPTSTR NullString() { return (LPTSTR) s_lpszCeEmpty; }
static CeStringRep* NullRep() { return s_cerepNullRep; }
private:
static CeStringRep* s_cerepNullRep;
static LPCTSTR s_lpszCeEmpty;
static int s_rgNullData[];
long m_nRef;
long m_nLen;
// TCHAR m_szString[]; -- implied array to TCHAR
};
///////////////////////////////////////////////////////////////////////////////
//
// Classes String and StringValue (from pp. 204, 206-207)
//
///////////////////////////////////////////////////////////////////////////////
class CeString // class to be used by developers
{
public:
// Constructors
CeString()
{ Init(); }
CeString(TCHAR ch)
{ Construct(&ch, 1); }
CeString(LPCTSTR lpsz, int nLength)
{ ASSERT(lpsz != NULL && ! IsBadReadPtr(lpsz, nLength)); Construct(lpsz, nLength); }
#ifdef _WIN32_WCE
CeString(LPCSTR lpsz, int nLength=0)
{
if (nLength == 0)
nLength = strlen(lpsz);
ASSERT(lpsz != NULL && ! IsBadReadPtr(lpsz, nLength));
// allocate a new copy
CeStringRep* pRep = CeStringRep::AllocBuf(nLength);
// assign pointer
m_pStr = pRep->GetString();
// assign characters
for (int ii = 0; ii < nLength; ii++)
m_pStr[ii] = (wchar_t) *lpsz++;
m_pStr[ii] = 0;
}
#endif // _WIN32_WCE
CeString(const CeString& strSrc)
{
m_pStr = strSrc.m_pStr;
if (CeStringRep::NullString() != m_pStr)
GetRep()->AddRef();
}
CeString(LPCTSTR lpsz)
{
if (lpsz != NULL && HIWORD(lpsz) == NULL)
{
Init();
UINT nID = LOWORD((DWORD)lpsz);
// Warning: implicit LoadString() failed.
LoadString(nID, NULL);
}
else
Construct(lpsz);
}
CeString(TCHAR ch, int nChar)
{
// allocate a new copy
CeStringRep* pRep = CeStringRep::AllocBuf(nChar);
// assign pointer
m_pStr = pRep->GetString();
// assign characters
for (int ii = 0; ii < nChar; ii++)
m_pStr[ii] = ch;
}
CeString(HWND hWnd)
{
if (! ::IsWindow(hWnd))
// will now be a null string
Init();
else
{
int nLen = ::GetWindowTextLength(hWnd);
if (nLen)
{
// allocate a new copy and get the window text
CeStringRep* pRep = CeStringRep::AllocBuf(nLen);
m_pStr = pRep->GetString();
::GetWindowText(hWnd, m_pStr, nLen+1);
}
else
Init();
}
}
CeString(short s, int base=10) { Init(); SetShort(s, base); }
CeString(long l, int base=10) { Init(); SetLong(l, base); }
CeString(unsigned long ul, int base=10) { Init(); SetULong(ul, base); }
CeString(double dbl, int p=3) { Init(); SetDouble(dbl, p); }
virtual ~CeString() { Release(); }
public:
// Operators
const CeString& operator= (const CeString& strSrc);
const CeString& operator= (LPCTSTR lpsz);
const CeString& operator= (TCHAR ch) { Assign(&ch, 1); return *this; }
#ifdef _WIN32_WCE
const CeString& operator= (const char *lps);
#endif
const CeString& operator+= (const CeString& strSrc) { Append(strSrc.m_pStr, strSrc.Length()); return *this; }
const CeString& operator+= (LPCTSTR lpsz) { Append(lpsz, lstrlen(lpsz)); return *this; }
const CeString& operator+ (const CeString& T);
const CeString& operator+ (LPCTSTR lpsz);
bool operator == (LPCTSTR lpsz) const { return (Compare(lpsz) == 0);}
bool operator != (LPCTSTR lpsz) const { return (Compare(lpsz) != 0);}
bool operator <= (LPCTSTR lpsz) const { return (Compare(lpsz) <= 0);}
bool operator < (LPCTSTR lpsz) const { return (Compare(lpsz) < 0);}
bool operator >= (LPCTSTR lpsz) const { return (Compare(lpsz) >= 0);}
bool operator > (LPCTSTR lpsz) const { return (Compare(lpsz) > 0);}
operator long() const { return _ttol(m_pStr); }
operator int() const { return _ttoi(m_pStr); }
operator double() const { return _tcstod(m_pStr, NULL); }
operator LPCTSTR() const { return m_pStr; }
TCHAR operator[](int ii) const { CHW_ASSERT(ii >= 0 && ii < Length()); return m_pStr[ii]; }
// may remove this, it allows internal access
TCHAR& operator[](int ii) { CHW_ASSERT(ii >= 0 && ii < Length()); CopyOnWrite(); return m_pStr[ii]; }
// Attributes
int Length() const { return GetRep()->GetLength(); }
int GetLength() const { return GetRep()->GetLength(); }
// for compatability with CString
int GetAllocLength() const { return GetRep()->GetLength(); }
BOOL IsEmpty() const { return (Length() == 0); }
// Operations
int Compare (LPCTSTR lpsz) const { return _tcscmp (m_pStr, lpsz); }
int CompareNoCase (LPCTSTR lpsz) const { return _tcsicmp (m_pStr, lpsz); }
void Truncate(int nLen);
LPCTSTR Find(LPCTSTR lpsz) const { return _tcsstr(m_pStr, lpsz); }
LPCTSTR Find(TCHAR ch) const { return _tcschr(m_pStr, ch); }
int FindIndex(LPCTSTR lpsz) const { LPCTSTR pPos = Find(lpsz); return pPos ? pPos - m_pStr: -1; }
int FindIndex(TCHAR ch) const { LPCTSTR pPos = Find(ch); return pPos ? pPos - m_pStr: -1; }
// LPCTSTR ReverseFind(LPCTSTR lpsz) const { return _tcsrstr(m_sz, lpsz); }
LPCTSTR ReverseFind(TCHAR ch) const { return _tcsrchr(m_pStr, ch); }
int ReverseFindIndex(TCHAR ch) const { LPCTSTR pPos = ReverseFind(ch); return pPos ? pPos - m_pStr: -1; }
LPCTSTR FindOneOf(LPCTSTR lpsz) const { int i = _tcscspn(m_pStr, lpsz); return ((m_pStr[i] == 0) ? NULL : &m_pStr[i]); }
LPCTSTR FindNotOneOf(LPCTSTR lpsz) const { int i = _tcsspn(m_pStr, lpsz); return ((m_pStr[i] == 0) ? NULL : &m_pStr[i]); }
void Format(LPCTSTR szFormat, ...);
int LoadString(UINT nIDS, HINSTANCE hInst=NULL)
{
CopyOnWrite();
#ifdef _WIN32_WCE
if (hInst == NULL) hInst = CeGetAppInstance();
LPCTSTR lpsz = (LPCTSTR) ::LoadString(hInst, nIDS, NULL, 0);
if (NULL == lpsz)
return 0;
else
{
int nLen = *(((WORD *)lpsz) - 1);
return Assign(lpsz, nLen);
}
#else
// error 0
return 0;
#endif
}
void FormatMessage(DWORD dwSystemErrorID);
int GetWindowText(HWND hWnd)
{
// Note: returns empty string on failure
Release();
if (! ::IsWindow(hWnd))
// will now be a null string
return 0;
int nLen = ::GetWindowTextLength(hWnd);
if (! nLen)
// will now be a null string
return 0;
// allocate a new copy and get the window text
CeStringRep* pRep = CeStringRep::AllocBuf(nLen);
m_pStr = pRep->GetString();
return ::GetWindowText(hWnd, m_pStr, nLen+1);
}
void Trim();
void LTrim();
void RTrim();
void Empty() { Release(); }
void MakeUpper() { CopyOnWrite(); _tcsupr(m_pStr); }
void MakeLower() { CopyOnWrite(); _tcslwr(m_pStr); }
void Reverse() { CopyOnWrite(); _tcsrev(m_pStr); }
void Append(LPCTSTR lpsz, int nChars=-1);
void Set(char ch, int i);
void Set(char ch);
void SetShort(short s, int b=10);
void SetLong(long l, int b=10);
void SetULong(unsigned long l, int b=10);
void SetDouble(double dValue, int nPrecision);
// in testing, use at your own risk...
LPTSTR GetBuffer(int nMinLen);
LPTSTR GetBufferSetLength(int nLen);
void ReleaseBuffer();
// convenient for testing
// friend ostream& operator<<(ostream& stream, const String& string);
private:
// Implementation
LPTSTR m_pStr;
// initialize to a null pointer
void Init() { m_pStr = CeStringRep::NullString(); }
// retrieve the string representation structure
CeStringRep* GetRep() const { return ((CeStringRep *) m_pStr) - 1; }
// release data associated with the pointer, but only if not the null string
void Release()
{
if (m_pStr != CeStringRep::NullString())
{
ASSERT(GetRep()->GetRefs() != 0);
if (GetRep()->Release() <= 0)
CeStringRep::FreeBuf( GetRep() );
Init();
}
}
// duplicate the string if others reference it,
// ASSUMES THERE WAS A PREVIOUS VALUE
void CopyOnWrite()
{
if (0 == GetRep()->GetLength())
return;
if (GetRep()->IsShared())
{
// allocate a new copy
CeStringRep* pRep = CeStringRep::AllocBuf(GetRep()->GetLength());
// copy into string
memcpy(pRep->GetString(), m_pStr, (GetRep()->GetLength() + 1) * sizeof(TCHAR));
// release our reference on the old
GetRep()->Release();
// assign the new one
m_pStr = pRep->GetString();
}
ASSERT(GetRep()->GetRefs() >= 1);
}
int Construct(LPCTSTR lpsz, int nLen=-1)
{
// get the length of the string
if (nLen == -1)
nLen = lstrlen(lpsz);
if (nLen == 0)
// null string
m_pStr = CeStringRep::NullString();
else
{
// allocate a new copy
CeStringRep* pRep = CeStringRep::AllocBuf(nLen);
// assign
m_pStr = pRep->GetString();
// copy
memcpy(m_pStr, lpsz, nLen * sizeof(TCHAR));
}
// return the size of the string
return nLen;
}
// allocate and assign a constant string to the string data
// DOES NOT CHECK FOR OLD VALUE...
int Assign(LPCTSTR lpsz, int nLen=-1)
{
// get rid of the old copy
Release();
// construct and return the size of the string
return Construct(lpsz, nLen);
}
};
//ostream& operator<<(ostream& stream, const CeString& string)
//{
// return stream << string.m_pStr;
//}
#endif // _CESTRING_DEFINED_