405 lines
14 KiB
C++
405 lines
14 KiB
C++
#ifndef __VSTRING_HPP
|
|
#define __VSTRING_HPP
|
|
|
|
#include "vStandard.h"
|
|
|
|
// <VDOC<CLASS=VString><DESC=Encapsulates a dynamically allocated C style string><FAMILY=String Processing><AUTHOR=Todd Osborne (todd.osborne@poboxes.com)>VDOC>
|
|
class VString
|
|
{
|
|
public:
|
|
// Default constructor
|
|
VString()
|
|
{ m_lpszString = NULL; }
|
|
|
|
// Construct with existing C string
|
|
VString(LPCTSTR lpszString, int nCount = -1)
|
|
{ m_lpszString = NULL; AllocCopy(lpszString, TRUE, nCount); }
|
|
|
|
// Construct with existing VString reference
|
|
VString(VString& strOriginal, int nCount = -1)
|
|
{ m_lpszString = NULL; AllocCopy(strOriginal.GetBuffer(), TRUE, nCount); }
|
|
|
|
// Construct with existing VString pointer
|
|
VString(VString* pstrOriginal, int nCount = -1)
|
|
{ m_lpszString = NULL; AllocCopy(*pstrOriginal, TRUE, nCount); }
|
|
|
|
// Construct by loading string from resouce. If hResource is NULL, VGetResourceHandle() will be used
|
|
VString(UINT nStringID, HINSTANCE hResource = NULL)
|
|
{ m_lpszString = NULL; LoadString(nStringID, hResource); }
|
|
|
|
// Construct by initializing with text from a window
|
|
VString(HWND hWnd)
|
|
{ m_lpszString = NULL; GetWindowText(hWnd); }
|
|
|
|
// Destructor
|
|
virtual ~VString()
|
|
{ Empty(); }
|
|
|
|
// Overloaded Operators
|
|
|
|
// Return C style strings
|
|
TCHAR &operator[](int nIndex)
|
|
{ assert(m_lpszString); assert(nIndex < lstrlen(m_lpszString)); return m_lpszString[nIndex]; }
|
|
|
|
operator LPTSTR()
|
|
{ return m_lpszString; }
|
|
|
|
operator LPCTSTR()
|
|
{ return m_lpszString; }
|
|
|
|
// Assignment
|
|
BOOL operator = (LPCTSTR lpszString)
|
|
{ return AllocCopy(lpszString, TRUE); }
|
|
BOOL operator = (VString& string)
|
|
{ return AllocCopy((LPCTSTR)string, TRUE); }
|
|
BOOL operator = (VString* pString)
|
|
{ return AllocCopy((LPCTSTR)*pString, TRUE); }
|
|
|
|
// Concatenation
|
|
BOOL operator += (TCHAR nChar)
|
|
{ return AddChar(nChar); }
|
|
BOOL operator += (LPCTSTR lpszString)
|
|
{ return AllocCopy(lpszString, FALSE); }
|
|
BOOL operator += (VString& string)
|
|
{ return AllocCopy((LPCTSTR)string, FALSE); }
|
|
BOOL operator += (VString* pString)
|
|
{ return AllocCopy((LPCTSTR)*pString, FALSE); }
|
|
|
|
// Comparison without case
|
|
BOOL operator == (LPCTSTR lpszString)
|
|
{ return CompareNoCase(lpszString) == 0; }
|
|
BOOL operator == (VString& string)
|
|
{ return CompareNoCase((LPCTSTR)string) == 0; }
|
|
BOOL operator == (VString* pString)
|
|
{ return CompareNoCase((LPCTSTR)*pString) == 0; }
|
|
|
|
BOOL operator != (LPCTSTR lpszString)
|
|
{ return CompareNoCase(lpszString) != 0; }
|
|
BOOL operator != (VString& string)
|
|
{ return CompareNoCase((LPCTSTR)string) != 0; }
|
|
BOOL operator != (VString* pString)
|
|
{ return CompareNoCase((LPCTSTR)*pString) != 0; }
|
|
|
|
BOOL operator < (LPCTSTR lpszString)
|
|
{ return CompareNoCase(lpszString) == -1; }
|
|
BOOL operator < (VString& string)
|
|
{ return CompareNoCase((LPCTSTR)string) == -1; }
|
|
BOOL operator < (VString* pString)
|
|
{ return CompareNoCase((LPCTSTR)*pString) == -1; }
|
|
|
|
BOOL operator <= (LPCTSTR lpszString)
|
|
{ return CompareNoCase(lpszString) != 1; }
|
|
BOOL operator <= (VString& string)
|
|
{ return CompareNoCase((LPCTSTR)string) != -1; }
|
|
BOOL operator <= (VString* pString)
|
|
{ return CompareNoCase((LPCTSTR)*pString) != -1; }
|
|
|
|
BOOL operator > (LPCTSTR lpszString)
|
|
{ return CompareNoCase(lpszString) == 1; }
|
|
BOOL operator > (VString& string)
|
|
{ return CompareNoCase((LPCTSTR)string) == 1; }
|
|
BOOL operator > (VString* pString)
|
|
{ return CompareNoCase((LPCTSTR)*pString) == 1; }
|
|
|
|
BOOL operator >= (LPCTSTR lpszString)
|
|
{ return CompareNoCase(lpszString) != -1; }
|
|
BOOL operator >= (VString& string)
|
|
{ return CompareNoCase((LPCTSTR)string) != -1; }
|
|
BOOL operator >= (VString* pString)
|
|
{ return CompareNoCase((LPCTSTR)*pString) != -1; }
|
|
|
|
// Add a single character to the end of the string
|
|
// Protected by critical section in AllocCopy()
|
|
BOOL AddChar(TCHAR nChar)
|
|
{ TCHAR sz[] = {nChar, _T('\0')}; return AllocCopy(sz, FALSE); }
|
|
|
|
// Case sensitive comparison
|
|
// Returns zero if the strings are identical, -1 if this VString object is less than lpszString, or 1 if this VString object is greater than lpszString
|
|
int Compare(LPCTSTR lpszString)
|
|
{ assert(m_lpszString && lpszString); return lstrcmp(m_lpszString, lpszString); }
|
|
|
|
// Compare without case
|
|
// Returns zero if the strings are identical (ignoring case), -1 if this VString object is less than lpszString (ignoring case), or 1 if this VString object is greater than lpszString (ignoring case)
|
|
int CompareNoCase(LPCTSTR lpszString)
|
|
{ assert(m_lpszString && lpszString); return lstrcmpi(m_lpszString, lpszString); }
|
|
|
|
// Clear contents of string
|
|
void Empty()
|
|
{
|
|
if (NULL != m_lpszString) {
|
|
delete [] m_lpszString;
|
|
m_lpszString = NULL;
|
|
}
|
|
}
|
|
|
|
// Find first occurence of substring or character in string. Returns index into string if found, -1 otherwise
|
|
int Find(LPCTSTR lpszSubString)
|
|
{ assert(m_lpszString && lpszSubString); LPTSTR lpszFound = _tcsstr(m_lpszString, lpszSubString); return (lpszFound) ? (int)(lpszFound - m_lpszString) : -1; }
|
|
|
|
int Find(TCHAR nChar)
|
|
{ assert(m_lpszString); LPTSTR lpszFound = _tcschr(m_lpszString, nChar); return (lpszFound) ? (int)(lpszFound - m_lpszString) : -1; }
|
|
|
|
// Get the internal buffer
|
|
LPTSTR GetBuffer()
|
|
{ return m_lpszString; }
|
|
|
|
// Get the length of the string
|
|
int GetLength()
|
|
{ return (m_lpszString) ? lstrlen(m_lpszString) : 0; }
|
|
|
|
// Set the path of the module in hInstance into VString. If bPathOnly is specified,
|
|
// only the path, including the last backlash will be saved, otherwise the entire path will be.
|
|
// If hInstance is NULL, VGetInstanceHandle() will be used
|
|
BOOL GetModulePath(HINSTANCE hInstance = NULL, BOOL bPathOnly = TRUE)
|
|
{
|
|
TCHAR sz[MAX_PATH] = {_T('\0')};
|
|
|
|
if ( GetModuleFileName((hInstance) ? hInstance : VGetInstanceHandle(), sz, sizeof(sz)/sizeof(TCHAR)) )
|
|
{
|
|
// Terminate after last backslash?
|
|
TCHAR *pszEnd = (bPathOnly) ? _tcsrchr(sz, _T('\\')) : NULL;
|
|
|
|
if ( pszEnd )
|
|
*(pszEnd + 1) = _T('\0');
|
|
|
|
return AllocCopy(sz, TRUE);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy text from a window to the VString
|
|
BOOL GetWindowText(HWND hWnd)
|
|
{
|
|
assert(hWnd && IsWindow(hWnd));
|
|
|
|
BOOL bResult = TRUE;
|
|
|
|
if ( hWnd && IsWindow(hWnd) )
|
|
{
|
|
int nLen = (int)::SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0);
|
|
|
|
if ( nLen )
|
|
{
|
|
TCHAR sz[1024];
|
|
LPTSTR lpszWindowText = sz;
|
|
|
|
// Dynamic memory alloc only if stack is not sufficient
|
|
if ( nLen > sizeof(sz - 1)/sizeof(TCHAR) )
|
|
lpszWindowText = new TCHAR[nLen + 1];
|
|
|
|
if ( lpszWindowText )
|
|
{
|
|
// Get text and copy to VString
|
|
::GetWindowText(hWnd, lpszWindowText, nLen + 1);
|
|
bResult = AllocCopy(lpszWindowText, TRUE);
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
// Free if not stack alloc
|
|
if ( lpszWindowText != sz )
|
|
delete [] lpszWindowText;
|
|
}
|
|
else
|
|
// Empty window text is still valid. VString is reset
|
|
Empty();
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
// Is the string empty?
|
|
BOOL IsEmpty()
|
|
{ return (GetLength()) ? FALSE : TRUE; }
|
|
|
|
// Substring extraction
|
|
VString Left(int nCount)
|
|
{ VString str; str.AllocCopy(m_lpszString, TRUE, nCount); return str; }
|
|
|
|
// Load a string from resources. Returns TRUE on success, FALSE on failure
|
|
// If hResource is NULL, VGetResourceHandle() will be used
|
|
BOOL LoadString(UINT nStringID, HINSTANCE hResource = NULL)
|
|
{
|
|
TCHAR szTemp[1024];
|
|
BOOL bResult = FALSE;
|
|
|
|
if ( !hResource )
|
|
hResource = VGetResourceHandle();
|
|
|
|
assert(hResource);
|
|
|
|
// Attempt to load string into stack buffer first
|
|
int nLen = ::LoadString(hResource, nStringID, szTemp, sizeof(szTemp)/sizeof(TCHAR));
|
|
|
|
if ( nLen )
|
|
{
|
|
if ( nLen == sizeof(szTemp)/sizeof(TCHAR) - 1 )
|
|
{
|
|
// Calculate the largest size possible for string block (whole block, not just nStringID)
|
|
HRSRC hRes = FindResource(hResource, MAKEINTRESOURCE((nStringID >> 4) + 1), RT_STRING);
|
|
DWORD dwSize = (hRes) ? SizeofResource(hResource, hRes) : 0;
|
|
assert(dwSize);
|
|
|
|
// Allocate temporary block equal to the size of the entire string block
|
|
// This is quite wasteful, but WinAPI does not provide a way to extract an
|
|
// exact string length from the resources, and LoadString() will copy only
|
|
// up to the buffer size, truncating longer strings
|
|
LPTSTR lpszNewString = new TCHAR[dwSize + 1];
|
|
|
|
if ( lpszNewString )
|
|
{
|
|
// Load string into temp var and AllocCopy() to set permanently
|
|
bResult = (::LoadString(hResource, nStringID, lpszNewString, dwSize)) ? AllocCopy(lpszNewString, TRUE) : FALSE;
|
|
|
|
// Free local string
|
|
delete [] lpszNewString;
|
|
}
|
|
}
|
|
else
|
|
bResult = AllocCopy(szTemp, TRUE);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
// Make the string a GetOpenFileName() or GetSaveFileName() filter. That is, replace
|
|
// all occurances of \n in the string with \0 (zero terminators)
|
|
LPCTSTR MakeFilter()
|
|
{
|
|
int nLen = GetLength();
|
|
|
|
for ( int i = 0; i < nLen; i++ )
|
|
{
|
|
if ( *(m_lpszString + i) == _T('\n') )
|
|
*(m_lpszString + i) = _T('\0');
|
|
}
|
|
|
|
return m_lpszString;
|
|
}
|
|
|
|
// Make all characters lower case
|
|
LPCTSTR MakeLower()
|
|
{ assert(m_lpszString); return _tcslwr(m_lpszString); }
|
|
|
|
// Make all characters upper case
|
|
LPCTSTR MakeUpper()
|
|
{ assert(m_lpszString); return _tcsupr(m_lpszString); }
|
|
|
|
// Substring extraction
|
|
VString Mid(int nFirst, int nCount)
|
|
{
|
|
assert(m_lpszString);
|
|
assert(nCount >= 0);
|
|
|
|
VString str;
|
|
|
|
if ( nFirst < GetLength() )
|
|
str.AllocCopy(m_lpszString + nFirst, TRUE, nCount);
|
|
|
|
return str;
|
|
}
|
|
|
|
VString Mid(int nFirst)
|
|
{ return Mid(nFirst, GetLength() - nFirst); }
|
|
|
|
VString Right(int nCount)
|
|
{
|
|
assert(m_lpszString);
|
|
|
|
VString str;
|
|
|
|
if ( nCount <= GetLength() )
|
|
str.AllocCopy(m_lpszString + (GetLength() - nCount), TRUE, nCount);
|
|
|
|
return str;
|
|
}
|
|
|
|
// Remote all spaces from left and right side of string
|
|
void Trim()
|
|
{ TrimLeft(); TrimRight(); }
|
|
|
|
// Remove all space characters from left side of string
|
|
void TrimLeft()
|
|
{
|
|
if ( m_lpszString )
|
|
{
|
|
int nIndex = 0;
|
|
|
|
while ( m_lpszString[nIndex] && m_lpszString[nIndex] == _T(' '))
|
|
nIndex++;
|
|
|
|
if ( nIndex )
|
|
AllocCopy(m_lpszString + nIndex, TRUE);
|
|
}
|
|
}
|
|
|
|
// Remove all space characters from right side of string
|
|
void TrimRight()
|
|
{
|
|
if ( m_lpszString )
|
|
{
|
|
int nLength = GetLength();
|
|
int nIndex = nLength - 1;
|
|
|
|
while ( m_lpszString[nIndex] && m_lpszString[nIndex] == _T(' '))
|
|
nIndex--;
|
|
|
|
if ( nIndex < nLength - 1 )
|
|
AllocCopy(m_lpszString, TRUE, nIndex + 1);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
// Allocate and copy. If nCount is -1, entire string will be copied, otherwise only nCount characters
|
|
BOOL AllocCopy(LPCTSTR lpszString, BOOL bReplace, int nCount = -1)
|
|
{
|
|
// Fix count of characters to copy if needed
|
|
if ( nCount == -1 )
|
|
nCount = lstrlen(lpszString);
|
|
|
|
// Determine length of lpszString
|
|
int nLen = (lpszString) ? lstrlen(lpszString) : 0;
|
|
|
|
if ( nLen )
|
|
{
|
|
// nCount should not be less that or equal to 0
|
|
assert(nCount > 0);
|
|
|
|
// Use the min of nLen and nCount as the new length
|
|
if ( nCount < nLen )
|
|
nLen = nCount;
|
|
|
|
// Allocate memory to new buffer
|
|
LPTSTR lpszNewString = new TCHAR[nLen + 1 + ((bReplace || !GetLength()) ? 0 : GetLength())];
|
|
|
|
if ( lpszNewString )
|
|
{
|
|
if ( bReplace || !m_lpszString )
|
|
lstrcpyn(lpszNewString, lpszString, nLen + 1);
|
|
else
|
|
{
|
|
// Append
|
|
lstrcpy(lpszNewString, m_lpszString);
|
|
lstrcpyn(lpszNewString + GetLength(), lpszString, nLen + 1);
|
|
}
|
|
// Free old memory and save new pointer
|
|
Empty();
|
|
m_lpszString = lpszNewString;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
else
|
|
Empty();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
private:
|
|
// Embedded Member(s)
|
|
LPTSTR m_lpszString;
|
|
};
|
|
|
|
#endif // __VSTRING_HPP
|