475 lines
9.9 KiB
C++
475 lines
9.9 KiB
C++
//
|
|
// IISCStringImpl.cpp
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
|
|
#pragma warning(disable:4786) // Disable warning for names > 256
|
|
|
|
#include "common.h"
|
|
#include <algorithm>
|
|
#include <deque>
|
|
#include <TCHAR.h>
|
|
#include "IISCString.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Constructors
|
|
///////////////////////////////////////////////////////////////////////////
|
|
CString::CString()
|
|
: std::basic_string<TCHAR>()
|
|
{
|
|
}
|
|
|
|
CString::CString(const CString& strInput)
|
|
: std::basic_string<TCHAR>(strInput)
|
|
{
|
|
}
|
|
|
|
CString::CString(const std::basic_string<TCHAR>& strInput)
|
|
: std::basic_string<TCHAR>(strInput)
|
|
{
|
|
}
|
|
|
|
CString::CString(TCHAR ch, int nRepeat /* = 1*/)
|
|
: std::basic_string<TCHAR>(nRepeat, ch)
|
|
{
|
|
}
|
|
|
|
CString::CString(LPCTSTR p)
|
|
: std::basic_string<TCHAR>(p)
|
|
{
|
|
}
|
|
|
|
#ifdef _UNICODE
|
|
CString::CString(LPCSTR strInput)
|
|
{
|
|
int len = strlen(strInput);
|
|
TCHAR * buf = (TCHAR *)_alloca(len * (sizeof(TCHAR) + 1));
|
|
if (0 != MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED,
|
|
strInput, len, buf, len))
|
|
{
|
|
assign(buf);
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT(FALSE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef _UNICODE
|
|
CString::CString(LPCWSTR strInput)
|
|
{
|
|
int len = wstrlen(strInput);
|
|
int buflen = len * (sizeof(TCHAR) + 1);
|
|
TCHAR * buf = (TCHAR *)_alloca(buflen);
|
|
if (0 != WideCharToMultiByte(CP_THREAD_ACP, 0,
|
|
strInput, len, buf, buflen))
|
|
{
|
|
assign(buf);
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT(FALSE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CString::CString(const CComBSTR& bstr)
|
|
{
|
|
assign((LPCTSTR)bstr.m_str);
|
|
}
|
|
|
|
CString::~CString()
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// The string as an array
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
int CString::GetLength() const
|
|
{
|
|
return length();
|
|
};
|
|
|
|
bool CString::IsEmpty() const
|
|
{
|
|
return empty();
|
|
};
|
|
|
|
void CString::Empty()
|
|
{
|
|
erase();
|
|
};
|
|
|
|
TCHAR CString::GetAt(int nIndex) const
|
|
{
|
|
ATLASSERT(nIndex >= 0);
|
|
return at(nIndex);
|
|
};
|
|
|
|
TCHAR CString::operator[](int nIndex) const
|
|
{
|
|
// same as GetAt
|
|
ATLASSERT(nIndex >= 0);
|
|
return at(nIndex);
|
|
}
|
|
|
|
void CString::SetAt(int nIndex, TCHAR ch)
|
|
{
|
|
at(nIndex) = ch;
|
|
};
|
|
|
|
const CString& CString::operator=(const CString& stringSrc)
|
|
{
|
|
assign(stringSrc);
|
|
return *this;
|
|
}
|
|
|
|
const CString& CString::operator=(LPCTSTR p)
|
|
{
|
|
// Here we will have a problem if NULL pointer is passed because
|
|
// later STL will call wcslen(NULL) which uses *p without test.
|
|
// We will emulate the result by erasing current string
|
|
if (p == NULL)
|
|
erase();
|
|
// another problem is when we assign string to self, like str = str.c_str()
|
|
// STL deletes data and then assign it resulting in garbage
|
|
else if (p != this->data())
|
|
assign(p);
|
|
return *this;
|
|
}
|
|
|
|
#ifdef _UNICODE
|
|
const CString& CString::operator=(const unsigned char * lpsz)
|
|
{
|
|
int len = strlen((const char *)lpsz);
|
|
TCHAR * buf = (TCHAR *)_alloca(len * (sizeof(TCHAR) + 1));
|
|
if (0 != MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, (const char *)lpsz, -1, buf, len))
|
|
{
|
|
assign(buf);
|
|
}
|
|
else
|
|
{
|
|
ATLASSERT(FALSE);
|
|
}
|
|
return *this;
|
|
}
|
|
#endif
|
|
|
|
const CString& CString::operator=(TCHAR c)
|
|
{
|
|
assign(1, c);
|
|
return *this;
|
|
}
|
|
|
|
#ifdef _UNICODE
|
|
const CString& CString::operator+=(char ch)
|
|
{
|
|
*this += (TCHAR)ch;
|
|
return *this;
|
|
}
|
|
|
|
const CString& CString::operator=(char ch)
|
|
{
|
|
*this = (TCHAR)ch;
|
|
return *this;
|
|
}
|
|
|
|
CString __stdcall operator+(const CString& string, char ch)
|
|
{
|
|
return string + (TCHAR)ch;
|
|
}
|
|
|
|
CString __stdcall operator+(char ch, const CString& string)
|
|
{
|
|
return (TCHAR)ch + string;
|
|
}
|
|
#endif
|
|
|
|
const CString& CString::operator+=(TCHAR ch)
|
|
{
|
|
append(1, ch);
|
|
return *this;
|
|
}
|
|
|
|
const CString& CString::operator+=(const CString& s)
|
|
{
|
|
append(s);
|
|
return *this;
|
|
}
|
|
|
|
const CString& CString::operator+=(LPCTSTR p)
|
|
{
|
|
append(p);
|
|
return *this;
|
|
}
|
|
|
|
static int __stdcall _LoadString(HINSTANCE hInstance, UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)
|
|
{
|
|
#ifdef _DEBUG
|
|
// LoadString without annoying warning from the Debug kernel if the
|
|
// segment containing the string is not present
|
|
if (::FindResource(hInstance, MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)
|
|
{
|
|
lpszBuf[0] = '\0';
|
|
return 0; // not found
|
|
}
|
|
#endif //_DEBUG
|
|
int nLen = ::LoadString(hInstance, nID, lpszBuf, nMaxBuf);
|
|
if (nLen == 0)
|
|
lpszBuf[0] = '\0';
|
|
return nLen;
|
|
}
|
|
|
|
#ifdef _UNICODE
|
|
#define CHAR_FUDGE 1 // one TCHAR unused is good enough
|
|
#else
|
|
#define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
|
|
#endif
|
|
|
|
#define INITIAL_SIZE 256
|
|
|
|
BOOL CString::LoadString(HINSTANCE hInstance, UINT id)
|
|
{
|
|
// try fixed buffer first (to avoid wasting space in the heap)
|
|
TCHAR szTemp[INITIAL_SIZE];
|
|
int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
|
|
int nLen = _LoadString(hInstance, id, szTemp, nCount);
|
|
if (nCount - nLen > CHAR_FUDGE)
|
|
{
|
|
*this = szTemp;
|
|
return nLen > 0;
|
|
}
|
|
|
|
// try buffer size of 512, then larger size until entire string is retrieved
|
|
int nSize = INITIAL_SIZE;
|
|
LPTSTR p = NULL;
|
|
do
|
|
{
|
|
nSize += INITIAL_SIZE;
|
|
p = get_allocator().allocate(nSize, p);
|
|
nLen = _LoadString(hInstance, id, p, nSize - 1);
|
|
} while (nSize - nLen <= CHAR_FUDGE);
|
|
if (nLen > 0)
|
|
assign(p, nLen);
|
|
|
|
return nLen > 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Comparison
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
int CString::Compare(const TCHAR * psz) const
|
|
{
|
|
if (psz == NULL)
|
|
return this->empty() ? 0 : 1;
|
|
return compare(psz);
|
|
};
|
|
|
|
int CString::CompareNoCase(const TCHAR * psz) const
|
|
{
|
|
if (psz == NULL)
|
|
return this->empty() ? 0 : 1;
|
|
return _tcsicmp(c_str(), psz);
|
|
};
|
|
|
|
int CString::Collate(const TCHAR * psz) const
|
|
{
|
|
if (psz == NULL)
|
|
return this->empty() ? 0 : 1;
|
|
return _tcscoll(c_str(), psz);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Extraction
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
CString CString::Mid(int nFirst) const
|
|
{
|
|
return substr(nFirst);
|
|
};
|
|
|
|
CString CString::Mid(int nFirst, int nCount) const
|
|
{
|
|
return substr(nFirst, nCount);
|
|
};
|
|
|
|
CString CString::Left(int nCount) const
|
|
{
|
|
return substr(0, nCount);
|
|
};
|
|
|
|
CString CString::Right(int nCount) const
|
|
{
|
|
return substr(length() - nCount, nCount);
|
|
};
|
|
|
|
CString CString::SpanIncluding(const TCHAR * pszCharSet) const
|
|
{
|
|
return substr(0, find_first_not_of(pszCharSet));
|
|
};
|
|
|
|
CString CString::SpanExcluding(const TCHAR * pszCharSet) const
|
|
{
|
|
return substr(0, find_first_of(pszCharSet));
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Other Conversions
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
void CString::MakeUpper()
|
|
{
|
|
std::for_each(begin(), end(), _totupper);
|
|
};
|
|
|
|
void CString::MakeLower()
|
|
{
|
|
std::for_each(begin(), end(), _totlower);
|
|
};
|
|
|
|
void CString::MakeReverse()
|
|
{
|
|
std::reverse(begin(), end());
|
|
};
|
|
|
|
void CString::TrimLeft()
|
|
{
|
|
while (_istspace(at(0)))
|
|
erase(0, 1);
|
|
};
|
|
|
|
void CString::TrimRight()
|
|
{
|
|
while (_istspace(at(length() - 1)))
|
|
erase(length() - 1, 1);
|
|
};
|
|
|
|
#define BUFFER_SIZE 1024
|
|
|
|
void __cdecl CString::FormatV(LPCTSTR lpszFormat, va_list argList)
|
|
{
|
|
TCHAR buf[BUFFER_SIZE];
|
|
if (-1 != _vsntprintf(buf, BUFFER_SIZE, lpszFormat, argList))
|
|
{
|
|
buf[BUFFER_SIZE - 1] = L'\0'; // null terminate the string
|
|
assign(buf);
|
|
}
|
|
}
|
|
|
|
// formatting (using wsprintf style formatting)
|
|
void __cdecl CString::Format(LPCTSTR lpszFormat, ...)
|
|
{
|
|
va_list argList;
|
|
va_start(argList, lpszFormat);
|
|
FormatV(lpszFormat, argList);
|
|
va_end(argList);
|
|
}
|
|
|
|
void __cdecl CString::Format(HINSTANCE hInst, UINT nFormatID, ...)
|
|
{
|
|
CString strFormat;
|
|
BOOL bRet = strFormat.LoadString(hInst, nFormatID);
|
|
bRet; // ref
|
|
ATLASSERT(bRet != 0);
|
|
|
|
va_list argList;
|
|
va_start(argList, nFormatID);
|
|
FormatV(strFormat, argList);
|
|
va_end(argList);
|
|
}
|
|
|
|
// formatting (using FormatMessage style formatting)
|
|
BOOL CString::FormatMessage(LPCTSTR lpszFormat, ...)
|
|
{
|
|
// format message into temporary buffer lpszTemp
|
|
va_list argList;
|
|
va_start(argList, lpszFormat);
|
|
LPTSTR lpszTemp;
|
|
BOOL bRet = TRUE;
|
|
|
|
if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
|
|
lpszTemp == NULL)
|
|
bRet = FALSE;
|
|
|
|
// assign lpszTemp into the resulting string and free the temporary
|
|
*this = lpszTemp;
|
|
LocalFree(lpszTemp);
|
|
va_end(argList);
|
|
return bRet;
|
|
}
|
|
|
|
BOOL CString::FormatMessage(HINSTANCE hInst, UINT nFormatID, ...)
|
|
{
|
|
// get format string from string table
|
|
CString strFormat;
|
|
BOOL bRetTmp = strFormat.LoadString(hInst, nFormatID);
|
|
bRetTmp; // ref
|
|
ATLASSERT(bRetTmp != 0);
|
|
|
|
// format message into temporary buffer lpszTemp
|
|
va_list argList;
|
|
va_start(argList, nFormatID);
|
|
LPTSTR lpszTemp;
|
|
BOOL bRet = TRUE;
|
|
|
|
if (::FormatMessage(
|
|
FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
|
strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL
|
|
)
|
|
bRet = FALSE;
|
|
|
|
// assign lpszTemp into the resulting string and free lpszTemp
|
|
*this = lpszTemp;
|
|
LocalFree(lpszTemp);
|
|
va_end(argList);
|
|
return bRet;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Searching
|
|
///////////////////////////////////////////////////////////////////////////
|
|
int CString::Find(TCHAR ch) const
|
|
{
|
|
return find(ch);
|
|
};
|
|
|
|
int CString::Find(const TCHAR * psz) const
|
|
{
|
|
if (psz == NULL)
|
|
return -1;
|
|
return find(psz);
|
|
};
|
|
|
|
int CString::ReverseFind(TCHAR ch) const
|
|
{
|
|
return rfind(ch);
|
|
};
|
|
|
|
int CString::FindOneOf(const TCHAR * psz) const
|
|
{
|
|
if (psz == NULL)
|
|
return -1;
|
|
return find_first_of(psz);
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Operators
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
CString::operator const TCHAR *() const
|
|
{
|
|
return c_str();
|
|
};
|
|
|
|
|
|
|