2024-12-21 10:04:04 +08:00
|
|
|
// QuickString.cpp: implementation of the COXQuickString class.
|
|
|
|
|
//
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Version: 9.3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "OXQuickString.h"
|
|
|
|
|
|
|
|
|
|
#include "UTBStrOp.h"
|
|
|
|
|
#include "UTB64Bit.h"
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Construction/Destruction
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
COXQuickString::COXQuickString()
|
|
|
|
|
{
|
|
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COXQuickString::COXQuickString(LPCTSTR szText)
|
|
|
|
|
{
|
|
|
|
|
Init();
|
|
|
|
|
SetString(szText);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COXQuickString::COXQuickString(const COXQuickString& str)
|
|
|
|
|
{
|
|
|
|
|
Init();
|
|
|
|
|
SetString(str.GetString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COXQuickString::~COXQuickString()
|
|
|
|
|
{
|
|
|
|
|
Empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Operations
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void COXQuickString::Empty()
|
|
|
|
|
{
|
|
|
|
|
delete [] m_szText;
|
|
|
|
|
|
|
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void COXQuickString::Init()
|
|
|
|
|
{
|
|
|
|
|
m_szText = NULL;
|
|
|
|
|
m_nBufferSize = 0;
|
|
|
|
|
m_nLength = 0;
|
|
|
|
|
m_nGrowBy = 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LPTSTR COXQuickString::AllocBuffer(UINT nBufferSize)
|
|
|
|
|
{
|
|
|
|
|
return new TCHAR[nBufferSize];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::IsEmpty() const
|
|
|
|
|
{
|
|
|
|
|
return (!m_szText || !(*m_szText));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::SetString(LPCTSTR szText)
|
|
|
|
|
{
|
|
|
|
|
// We do a fresh memory allocation when setting the string.
|
|
|
|
|
Empty();
|
|
|
|
|
|
|
|
|
|
if (!szText)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
m_nLength = PtrToUint(_tcslen(szText));
|
|
|
|
|
m_nBufferSize = m_nLength + 1;
|
|
|
|
|
|
|
|
|
|
m_szText = AllocBuffer(m_nBufferSize);
|
|
|
|
|
if (!m_szText)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
UTBStr::tcscpy(m_szText, m_nBufferSize, szText);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::SetString(LPCTSTR szText, int nCount)
|
|
|
|
|
{
|
|
|
|
|
// We do a fresh memory allocation when setting the string.
|
|
|
|
|
Empty();
|
|
|
|
|
|
|
|
|
|
if (!szText || nCount <= 0)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
m_nLength = min(PtrToUint(_tcslen(szText)), (UINT)nCount);
|
|
|
|
|
m_nBufferSize = m_nLength + 1;
|
|
|
|
|
|
|
|
|
|
m_szText = AllocBuffer(m_nBufferSize);
|
|
|
|
|
if (!m_szText)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
UTBStr::tcsncpy(m_szText, m_nBufferSize, szText, m_nLength+1);
|
|
|
|
|
m_szText[m_nLength] = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::Append(TCHAR ch)
|
|
|
|
|
{
|
|
|
|
|
UINT nLength = m_nLength + 1;
|
|
|
|
|
|
|
|
|
|
// We reuse memory (if possible) when adding to the string.
|
|
|
|
|
if (nLength+1 > m_nBufferSize)
|
|
|
|
|
{
|
|
|
|
|
LPTSTR tmp = AllocBuffer(nLength+m_nGrowBy);
|
|
|
|
|
if (!tmp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
tmp[0] = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
m_nBufferSize = m_nLength + m_nGrowBy;
|
|
|
|
|
|
|
|
|
|
if (m_szText)
|
|
|
|
|
{
|
|
|
|
|
UTBStr::tcscpy(tmp, nLength+m_nGrowBy, m_szText);
|
|
|
|
|
delete [] m_szText;
|
|
|
|
|
}
|
|
|
|
|
m_szText = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_szText[m_nLength++] = ch;
|
|
|
|
|
m_szText[m_nLength] = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::AddString(LPCTSTR szText)
|
|
|
|
|
{
|
|
|
|
|
if (!szText)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
UINT nLength = m_nLength + _tcslen(szText);
|
|
|
|
|
|
|
|
|
|
// We reuse memory (if possible) when adding to the string.
|
|
|
|
|
if (nLength+1 > m_nBufferSize)
|
|
|
|
|
{
|
|
|
|
|
LPTSTR tmp = AllocBuffer(nLength+1);
|
|
|
|
|
if (!tmp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
tmp[0] = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
//m_nBufferSize = m_nLength + 1; // v9.3 Update 01 - Fix by Maurizio Giunti 2008-01-10
|
|
|
|
|
m_nBufferSize = nLength + 1;
|
|
|
|
|
|
|
|
|
|
if (m_szText)
|
|
|
|
|
{
|
|
|
|
|
UTBStr::tcscpy(tmp, nLength+1, m_szText);
|
|
|
|
|
delete [] m_szText;
|
|
|
|
|
}
|
|
|
|
|
m_szText = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UTBStr::tcscat(m_szText, nLength+1, szText);
|
|
|
|
|
|
|
|
|
|
m_nLength = nLength;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::AddString(LPCTSTR szText, int nCount)
|
|
|
|
|
{
|
|
|
|
|
if (!szText)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
UINT nLength = m_nLength + min(_tcslen(szText), (UINT)nCount);
|
|
|
|
|
|
|
|
|
|
// We reuse memory (if possible) when adding to the string.
|
|
|
|
|
if (nLength+1 > m_nBufferSize)
|
|
|
|
|
{
|
|
|
|
|
LPTSTR tmp = AllocBuffer(nLength+1);
|
|
|
|
|
if (!tmp)
|
|
|
|
|
return FALSE;
|
|
|
|
|
tmp[0] = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
m_nBufferSize = nLength + 1;
|
|
|
|
|
|
|
|
|
|
if (m_szText)
|
|
|
|
|
{
|
|
|
|
|
UTBStr::tcscpy(tmp, nLength+1, m_szText);
|
|
|
|
|
delete [] m_szText;
|
|
|
|
|
}
|
|
|
|
|
m_szText = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UTBStr::tcsncat(m_szText, nLength+1, szText, nCount);
|
|
|
|
|
m_szText[nLength] = TEXT('\0');
|
|
|
|
|
m_nLength = nLength;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LPCTSTR COXQuickString::GetString() const
|
|
|
|
|
{
|
|
|
|
|
static const char chNull = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
if (IsEmpty())
|
|
|
|
|
return (LPCTSTR)&chNull;
|
|
|
|
|
else
|
|
|
|
|
return (LPCTSTR)m_szText;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UINT COXQuickString::GetLength() const
|
|
|
|
|
{
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
UINT nLength = m_szText? PtrToUint(_tcslen(m_szText)) : 0;
|
|
|
|
|
ASSERT(nLength == m_nLength);
|
|
|
|
|
#endif
|
|
|
|
|
return m_nLength;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::SetLength(UINT nLength)
|
|
|
|
|
{
|
|
|
|
|
// Do easy cases and return immediately if no problems
|
|
|
|
|
if (nLength == m_nBufferSize)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (!nLength)
|
|
|
|
|
{
|
|
|
|
|
Empty();
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nLength < m_nBufferSize)
|
|
|
|
|
{
|
|
|
|
|
m_szText[nLength] = TEXT('\0');
|
|
|
|
|
m_nLength = min(m_nLength, nLength);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Memory (re)allocation needed
|
|
|
|
|
|
|
|
|
|
LPTSTR pBuf = AllocBuffer(nLength);
|
|
|
|
|
if (!pBuf)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
m_nBufferSize = nLength;
|
|
|
|
|
if (m_szText)
|
|
|
|
|
{
|
|
|
|
|
UTBStr::tcscpy(pBuf, nLength, m_szText);
|
|
|
|
|
delete [] m_szText;
|
|
|
|
|
}
|
|
|
|
|
m_szText = pBuf;
|
|
|
|
|
m_szText[m_nLength] = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void COXQuickString::SetGrowBy(UINT nGrowBy)
|
|
|
|
|
{
|
|
|
|
|
m_nGrowBy = nGrowBy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UINT COXQuickString::GetGrowBy() const
|
|
|
|
|
{
|
|
|
|
|
return m_nGrowBy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::Compare(LPCTSTR szText, BOOL bCaseSensitive /*=TRUE*/)
|
|
|
|
|
{
|
|
|
|
|
if (!szText || IsEmpty())
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
BOOL bSame = FALSE;
|
|
|
|
|
if (!bCaseSensitive)
|
|
|
|
|
bSame = (_tcsicmp(m_szText, szText) == 0);
|
|
|
|
|
else
|
|
|
|
|
bSame = (_tcscmp(m_szText, szText) == 0);
|
|
|
|
|
|
|
|
|
|
return bSame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::operator==(LPCTSTR szText)
|
|
|
|
|
{
|
|
|
|
|
return Compare(szText, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::operator==(COXQuickString& str)
|
|
|
|
|
{
|
|
|
|
|
return Compare(str.GetString(), TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::operator!=(LPCTSTR szText)
|
|
|
|
|
{
|
|
|
|
|
return !Compare(szText, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::operator!=(COXQuickString& str)
|
|
|
|
|
{
|
|
|
|
|
return !Compare(str.GetString(), TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COXQuickString::operator LPCTSTR() const
|
|
|
|
|
{
|
|
|
|
|
return GetString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void COXQuickString::operator=(LPCTSTR szText)
|
|
|
|
|
{
|
|
|
|
|
SetString(szText);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void COXQuickString::operator=(COXQuickString& str)
|
|
|
|
|
{
|
|
|
|
|
if (this == &str)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
SetString(str.GetString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void COXQuickString::operator+=(LPCTSTR szText)
|
|
|
|
|
{
|
|
|
|
|
AddString(szText);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void COXQuickString::operator+=(COXQuickString& str)
|
|
|
|
|
{
|
|
|
|
|
AddString(str.GetString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::Strip()
|
|
|
|
|
{
|
|
|
|
|
const TCHAR chNBSP = TEXT(' '); // This is character 160, NOT character 32
|
|
|
|
|
|
|
|
|
|
if (IsEmpty())
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
int nLength = 0;
|
|
|
|
|
LPTSTR ptr = m_szText;
|
|
|
|
|
if (!ptr || !ptr[0])
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
// Remove leading whitespace (keep NBSP characters)
|
|
|
|
|
while (_istspace(*ptr) && *ptr != chNBSP)
|
|
|
|
|
{
|
|
|
|
|
ptr++;
|
|
|
|
|
nLength++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find how many "good" characters we have (good = are not consequetive spaces)
|
|
|
|
|
LPTSTR pStart = ptr;
|
|
|
|
|
int nGoodChars = 0;
|
|
|
|
|
while (*ptr)
|
|
|
|
|
{
|
|
|
|
|
nLength++;
|
|
|
|
|
if (!_istspace(*ptr) || *ptr == chNBSP)
|
|
|
|
|
nGoodChars++;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!_istspace(*(ptr+1)) || *ptr == chNBSP)
|
|
|
|
|
nGoodChars++;
|
|
|
|
|
}
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy over these "good" chars over to a new buffer
|
|
|
|
|
LPTSTR szNewString = AllocBuffer(nGoodChars+1);
|
|
|
|
|
if (!szNewString)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
ptr = pStart;
|
|
|
|
|
int nCount = 0;
|
|
|
|
|
while (*ptr && nCount < nGoodChars)
|
|
|
|
|
{
|
|
|
|
|
if (!_istspace(*ptr) || *ptr == chNBSP)
|
|
|
|
|
szNewString[nCount++] = *ptr;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ( (!_istspace(*(ptr+1)) || *ptr == chNBSP) && *(ptr+1))
|
|
|
|
|
szNewString[nCount++] = TEXT(' ');
|
|
|
|
|
}
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete [] m_szText;
|
|
|
|
|
|
|
|
|
|
// Return the new string
|
|
|
|
|
szNewString[nCount] = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
m_szText = szNewString;
|
|
|
|
|
m_nLength = nCount;
|
|
|
|
|
m_nBufferSize = nGoodChars+1;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::TrimRight()
|
|
|
|
|
{
|
|
|
|
|
if (IsEmpty())
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
LPTSTR ptr = m_szText+m_nLength-1;
|
|
|
|
|
|
|
|
|
|
while (_istspace(*ptr) && ptr >= m_szText)
|
|
|
|
|
ptr--;
|
|
|
|
|
|
|
|
|
|
m_nLength = PtrToUint(ptr - m_szText + 1);
|
|
|
|
|
m_szText[m_nLength] = TEXT('\0');
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::TrimLeft()
|
|
|
|
|
{
|
|
|
|
|
if (IsEmpty())
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
LPTSTR ptr = m_szText;
|
|
|
|
|
while (ptr - m_szText < (int)m_nLength && _istspace(*ptr))
|
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
|
|
if (ptr != m_szText)
|
|
|
|
|
{
|
|
|
|
|
int nLength = m_nLength-(ptr-m_szText);
|
|
|
|
|
LPTSTR szNewString = AllocBuffer(nLength+1);
|
|
|
|
|
if (!szNewString)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
UTBStr::tcscpy(szNewString, nLength+1, ptr);
|
|
|
|
|
szNewString[nLength] = TEXT('\0');
|
|
|
|
|
m_nLength = nLength;
|
|
|
|
|
m_nBufferSize = nLength+1;
|
|
|
|
|
|
|
|
|
|
delete [] m_szText;
|
|
|
|
|
m_szText = szNewString;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL COXQuickString::Trim()
|
|
|
|
|
{
|
|
|
|
|
return (TrimRight() && TrimLeft());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UINT COXQuickString::NumTokens(TCHAR chDelimiter)
|
|
|
|
|
{
|
|
|
|
|
if (IsEmpty())
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
int nNumTokens = 1;
|
|
|
|
|
for (LPCTSTR ptr = m_szText; *ptr; ptr++)
|
|
|
|
|
{
|
|
|
|
|
if (*ptr == chDelimiter)
|
|
|
|
|
nNumTokens++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nNumTokens;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const COXQuickString COXQuickString::GetToken(int nIndex, TCHAR chDelimiter) const
|
|
|
|
|
{
|
|
|
|
|
COXQuickString strReturn;
|
|
|
|
|
|
|
|
|
|
if (IsEmpty())
|
|
|
|
|
return strReturn;
|
|
|
|
|
|
|
|
|
|
LPCTSTR pstrStart = m_szText;
|
|
|
|
|
LPCTSTR pstrBuffer = pstrStart;
|
|
|
|
|
|
|
|
|
|
int nCurrent = 0;
|
|
|
|
|
int nStart = 0;
|
|
|
|
|
int nEnd = 0;
|
|
|
|
|
int nOldStart = 0;
|
|
|
|
|
|
|
|
|
|
// Search for token
|
|
|
|
|
while (nCurrent <= nIndex && *pstrBuffer != TEXT('\0'))
|
|
|
|
|
{
|
|
|
|
|
if (*pstrBuffer == chDelimiter)
|
|
|
|
|
{
|
|
|
|
|
nOldStart = nStart;
|
|
|
|
|
nStart = nEnd+1;
|
|
|
|
|
nCurrent++;
|
|
|
|
|
}
|
|
|
|
|
nEnd++;
|
|
|
|
|
pstrBuffer++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// May have reached the end of the string
|
|
|
|
|
if (*pstrBuffer == TEXT('\0'))
|
|
|
|
|
{
|
|
|
|
|
nOldStart = nStart;
|
|
|
|
|
nEnd++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nCurrent < nIndex)
|
|
|
|
|
{
|
|
|
|
|
//TRACE1("Warning: GetStringField - Couldn't find field %d.\n", nIndex);
|
|
|
|
|
return strReturn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strReturn.SetString(m_szText+nOldStart, nEnd-nOldStart-1);
|
|
|
|
|
|
|
|
|
|
return strReturn;
|
|
|
|
|
}
|