// // IISCStringImpl.cpp // ////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #pragma warning(disable:4786) // Disable warning for names > 256 #include "common.h" #include #include #include #include "IISCString.h" ////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Constructors /////////////////////////////////////////////////////////////////////////// CString::CString() : std::basic_string() { } CString::CString(const CString& strInput) : std::basic_string(strInput) { } CString::CString(const std::basic_string& strInput) : std::basic_string(strInput) { } CString::CString(TCHAR ch, int nRepeat /* = 1*/) : std::basic_string(nRepeat, ch) { } CString::CString(LPCTSTR p) : std::basic_string(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(); };