// 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; 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; }