From 3fc8b6f686262e8a595fc10b2bd947526ca77bdc Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 11 Oct 2013 12:15:06 +0000 Subject: CMStringT::Format to return its buffer back git-svn-id: http://svn.miranda-ng.org/main/trunk@6434 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- include/m_string.h | 2037 +++++++++++++++++++-------------------- protocols/MRA/src/Mra_proto.cpp | 4 +- 2 files changed, 1015 insertions(+), 1026 deletions(-) diff --git a/include/m_string.h b/include/m_string.h index fe7cf06edc..ae5e245916 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -1059,1190 +1059,1181 @@ public: { } - static void __stdcall Construct(CMStringT* pString) - { - new(pString) CMStringT; - } - - // Copy constructor - CMStringT(const CMStringT& strSrc) : - CThisSimpleString(strSrc) - { - } + static void __stdcall Construct(CMStringT* pString) + { + new(pString) CMStringT; + } - CMStringT(const XCHAR* pszSrc) : - CThisSimpleString() - { - // nDestLength is in XCHARs - *this = pszSrc; - } + // Copy constructor + CMStringT(const CMStringT& strSrc) : + CThisSimpleString(strSrc) + { + } - CMStringT(const YCHAR* pszSrc) : - CThisSimpleString() - { - *this = pszSrc; - } + CMStringT(const XCHAR* pszSrc) : + CThisSimpleString() + { + // nDestLength is in XCHARs + *this = pszSrc; + } + CMStringT(const YCHAR* pszSrc) : + CThisSimpleString() + { + *this = pszSrc; + } - CMStringT(const unsigned char* pszSrc) : - CThisSimpleString() - { - *this = reinterpret_cast< const char* >(pszSrc); - } - CMStringT(char ch, int nLength = 1) : - CThisSimpleString() - { - if (nLength > 0) - { - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::FloodCharacters(XCHAR(ch), nLength, pszBuffer); - this->ReleaseBufferSetLength(nLength); - } - } + CMStringT(const unsigned char* pszSrc) : + CThisSimpleString() + { + *this = reinterpret_cast< const char* >(pszSrc); + } - CMStringT(wchar_t ch, int nLength = 1) : - CThisSimpleString() - { - if (nLength > 0) - { - //Convert ch to the BaseType - wchar_t pszCh[2] = { ch , 0 }; - int nBaseTypeCharLen = 1; - - if (ch != L'\0') - { - nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); - } - - XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen+1]; - StringTraits::ConvertToBaseType(buffBaseTypeChar, nBaseTypeCharLen+1, pszCh, 1); - //allocate enough characters in String and flood (replicate) with the (converted character)*nLength - PXSTR pszBuffer = this->GetBuffer(nLength*nBaseTypeCharLen); - if (nBaseTypeCharLen == 1) - { //Optimization for a common case - wide char translates to 1 ansi/wide char. - StringTraits::FloodCharacters(buffBaseTypeChar[0], nLength, pszBuffer); - } else - { - XCHAR* p=pszBuffer; - for (int i=0 ; i < nLength ;i++) - { - for (int j=0 ; j < nBaseTypeCharLen ;++j) - { - *p=buffBaseTypeChar[j]; - ++p; - } - } - } - this->ReleaseBufferSetLength(nLength*nBaseTypeCharLen); - delete [] buffBaseTypeChar; - } - } + CMStringT(char ch, int nLength = 1) : + CThisSimpleString() + { + if (nLength > 0) + { + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::FloodCharacters(XCHAR(ch), nLength, pszBuffer); + this->ReleaseBufferSetLength(nLength); + } + } - CMStringT(const XCHAR* pch, int nLength) : - CThisSimpleString(pch, nLength) - { - } + CMStringT(wchar_t ch, int nLength = 1) : + CThisSimpleString() + { + if (nLength > 0) + { + //Convert ch to the BaseType + wchar_t pszCh[2] = { ch , 0 }; + int nBaseTypeCharLen = 1; - CMStringT(const YCHAR* pch, int nLength) : - CThisSimpleString() - { - if (nLength > 0) - { - int nDestLength = StringTraits::GetBaseTypeLength(pch, nLength); - PXSTR pszBuffer = this->GetBuffer(nDestLength); - StringTraits::ConvertToBaseType(pszBuffer, nDestLength, pch, nLength); - this->ReleaseBufferSetLength(nDestLength); - } - } + if (ch != L'\0') + { + nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); + } - // Destructor - ~CMStringT() - { - } + XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen+1]; + StringTraits::ConvertToBaseType(buffBaseTypeChar, nBaseTypeCharLen+1, pszCh, 1); + //allocate enough characters in String and flood (replicate) with the (converted character)*nLength + PXSTR pszBuffer = this->GetBuffer(nLength*nBaseTypeCharLen); + if (nBaseTypeCharLen == 1) + { //Optimization for a common case - wide char translates to 1 ansi/wide char. + StringTraits::FloodCharacters(buffBaseTypeChar[0], nLength, pszBuffer); + } else + { + XCHAR* p=pszBuffer; + for (int i=0 ; i < nLength ;i++) + { + for (int j=0 ; j < nBaseTypeCharLen ;++j) + { + *p=buffBaseTypeChar[j]; + ++p; + } + } + } + this->ReleaseBufferSetLength(nLength*nBaseTypeCharLen); + delete [] buffBaseTypeChar; + } + } - // Assignment operators - CMStringT& operator=(const CMStringT& strSrc) - { - CThisSimpleString::operator=(strSrc); + CMStringT(const XCHAR* pch, int nLength) : + CThisSimpleString(pch, nLength) + { + } - return *this; - } + CMStringT(const YCHAR* pch, int nLength) : + CThisSimpleString() + { + if (nLength > 0) + { + int nDestLength = StringTraits::GetBaseTypeLength(pch, nLength); + PXSTR pszBuffer = this->GetBuffer(nDestLength); + StringTraits::ConvertToBaseType(pszBuffer, nDestLength, pch, nLength); + this->ReleaseBufferSetLength(nDestLength); + } + } - CMStringT& operator=(PCXSTR pszSrc) - { - CThisSimpleString::operator=(pszSrc); + // Destructor + ~CMStringT() + { + } - return *this; - } + // Assignment operators + CMStringT& operator=(const CMStringT& strSrc) + { + CThisSimpleString::operator=(strSrc); - CMStringT& operator=(PCYSTR pszSrc) - { - // nDestLength is in XCHARs - int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength(pszSrc) : 0; - if (nDestLength > 0) - { - PXSTR pszBuffer = this->GetBuffer(nDestLength); - StringTraits::ConvertToBaseType(pszBuffer, nDestLength, pszSrc); - this->ReleaseBufferSetLength(nDestLength); - } - else - { - this->Empty(); - } - - return *this; - } + return *this; + } - CMStringT& operator=(const unsigned char* pszSrc) - { - return operator=(reinterpret_cast< const char* >(pszSrc)); - } + CMStringT& operator=(PCXSTR pszSrc) + { + CThisSimpleString::operator=(pszSrc); - CMStringT& operator=(char ch) - { - char ach[2] = { ch, 0 }; + return *this; + } - return operator=(ach); - } + CMStringT& operator=(PCYSTR pszSrc) + { + // nDestLength is in XCHARs + int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength(pszSrc) : 0; + if (nDestLength > 0) + { + PXSTR pszBuffer = this->GetBuffer(nDestLength); + StringTraits::ConvertToBaseType(pszBuffer, nDestLength, pszSrc); + this->ReleaseBufferSetLength(nDestLength); + } + else + { + this->Empty(); + } - CMStringT& operator=(wchar_t ch) - { - wchar_t ach[2] = { ch, 0 }; + return *this; + } - return operator=(ach); - } + CMStringT& operator=(const unsigned char* pszSrc) + { + return operator=(reinterpret_cast< const char* >(pszSrc)); + } -// CMStringT& operator=(const VARIANT& var); + CMStringT& operator=(char ch) + { + char ach[2] = { ch, 0 }; - CMStringT& operator+=(const CMStringT& str) - { - CThisSimpleString::operator+=(str); - return *this; - } + return operator=(ach); + } - CMStringT& operator+=(const CThisSimpleString& str) - { - CThisSimpleString::operator+=(str); - return *this; - } + CMStringT& operator=(wchar_t ch) + { + wchar_t ach[2] = { ch, 0 }; - CMStringT& operator+=(PCXSTR pszSrc) - { - CThisSimpleString::operator+=(pszSrc); - return *this; - } -// template< int t_nSize > -// CMStringT& operator+=(const CStaticString< XCHAR, t_nSize >& strSrc) -// { -// CThisSimpleString::operator+=(strSrc); -// -// return *this; -// } - CMStringT& operator+=(PCYSTR pszSrc) - { - CMStringT str(pszSrc); + return operator=(ach); + } - return operator+=(str); - } + // CMStringT& operator=(const VARIANT& var); - CMStringT& operator+=(char ch) - { - CThisSimpleString::operator+=(ch); + CMStringT& operator+=(const CMStringT& str) + { + CThisSimpleString::operator+=(str); + return *this; + } - return *this; - } + CMStringT& operator+=(const CThisSimpleString& str) + { + CThisSimpleString::operator+=(str); + return *this; + } - CMStringT& operator+=(unsigned char ch) - { - CThisSimpleString::operator+=(ch); + CMStringT& operator+=(PCXSTR pszSrc) + { + CThisSimpleString::operator+=(pszSrc); + return *this; + } + // template< int t_nSize > + // CMStringT& operator+=(const CStaticString< XCHAR, t_nSize >& strSrc) + // { + // CThisSimpleString::operator+=(strSrc); + // + // return *this; + // } + CMStringT& operator+=(PCYSTR pszSrc) + { + CMStringT str(pszSrc); - return *this; - } + return operator+=(str); + } - CMStringT& operator+=(wchar_t ch) - { - CThisSimpleString::operator+=(ch); + CMStringT& operator+=(char ch) + { + CThisSimpleString::operator+=(ch); - return *this; - } + return *this; + } - // Comparison + CMStringT& operator+=(unsigned char ch) + { + CThisSimpleString::operator+=(ch); - int Compare(PCXSTR psz) const - { - return StringTraits::StringCompare(this->GetString(), psz); - } + return *this; + } - int CompareNoCase(PCXSTR psz) const - { - return StringTraits::StringCompareIgnore(this->GetString(), psz); - } + CMStringT& operator+=(wchar_t ch) + { + CThisSimpleString::operator+=(ch); - int Collate(PCXSTR psz) const - { - return StringTraits::StringCollate(this->GetString(), psz); - } + return *this; + } - int CollateNoCase(PCXSTR psz) const - { - return StringTraits::StringCollateIgnore(this->GetString(), psz); - } + // Comparison - // Advanced manipulation + int Compare(PCXSTR psz) const + { + return StringTraits::StringCompare(this->GetString(), psz); + } - // Delete 'nCount' characters, starting at index 'iIndex' - int Delete(int iIndex, int nCount = 1) - { - if (iIndex < 0) - iIndex = 0; - - if (nCount < 0) - nCount = 0; - - int nLength = this->GetLength(); - if (nCount + iIndex > nLength) - { - nCount = nLength-iIndex; - } - if (nCount > 0) - { - int nNewLength = nLength-nCount; - int nXCHARsToCopy = nLength-(iIndex+nCount)+1; - PXSTR pszBuffer = this->GetBuffer(); - #if _MSC_VER >= 1400 - memmove_s(pszBuffer+iIndex, nXCHARsToCopy*sizeof(XCHAR), pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof(XCHAR)); - #else - memmove(pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof(XCHAR)); - #endif - this->ReleaseBufferSetLength(nNewLength); - } - - return this->GetLength(); - } + int CompareNoCase(PCXSTR psz) const + { + return StringTraits::StringCompareIgnore(this->GetString(), psz); + } - // Insert character 'ch' before index 'iIndex' - int Insert(int iIndex, XCHAR ch) - { - if (iIndex < 0) - iIndex = 0; + int Collate(PCXSTR psz) const + { + return StringTraits::StringCollate(this->GetString(), psz); + } - if (iIndex > this->GetLength()) - iIndex = this->GetLength(); + int CollateNoCase(PCXSTR psz) const + { + return StringTraits::StringCollateIgnore(this->GetString(), psz); + } - int nNewLength = this->GetLength()+1; + // Advanced manipulation - PXSTR pszBuffer = this->GetBuffer(nNewLength); + // Delete 'nCount' characters, starting at index 'iIndex' + int Delete(int iIndex, int nCount = 1) + { + if (iIndex < 0) + iIndex = 0; - // move existing bytes down - #if _MSC_VER >= 1400 - memmove_s(pszBuffer+iIndex+1, (nNewLength-iIndex)*sizeof(XCHAR), pszBuffer+iIndex, (nNewLength-iIndex)*sizeof(XCHAR)); - #else - memmove(pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof(XCHAR)); - #endif - pszBuffer[iIndex] = ch; + if (nCount < 0) + nCount = 0; + int nLength = this->GetLength(); + if (nCount + iIndex > nLength) + { + nCount = nLength-iIndex; + } + if (nCount > 0) + { + int nNewLength = nLength-nCount; + int nXCHARsToCopy = nLength-(iIndex+nCount)+1; + PXSTR pszBuffer = this->GetBuffer(); +#if _MSC_VER >= 1400 + memmove_s(pszBuffer+iIndex, nXCHARsToCopy*sizeof(XCHAR), pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof(XCHAR)); +#else + memmove(pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof(XCHAR)); +#endif this->ReleaseBufferSetLength(nNewLength); - return nNewLength; } - // Insert string 'psz' before index 'iIndex' - int Insert(int iIndex, PCXSTR psz) - { - if (iIndex < 0) - iIndex = 0; - - if (iIndex > this->GetLength()) - { - iIndex = this->GetLength(); - } - - // nInsertLength and nNewLength are in XCHARs - int nInsertLength = StringTraits::SafeStringLen(psz); - int nNewLength = this->GetLength(); - if (nInsertLength > 0) - { - nNewLength += nInsertLength; - - PXSTR pszBuffer = this->GetBuffer(nNewLength); - // move existing bytes down - #if _MSC_VER >= 1400 - memmove_s(pszBuffer+iIndex+nInsertLength, (nNewLength-iIndex-nInsertLength+1)*sizeof(XCHAR), pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof(XCHAR)); - memcpy_s(pszBuffer+iIndex, nInsertLength*sizeof(XCHAR), psz, nInsertLength*sizeof(XCHAR)); - #else - memmove(pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof(XCHAR)); - memcpy(pszBuffer+iIndex, psz, nInsertLength*sizeof(XCHAR)); - #endif - this->ReleaseBufferSetLength(nNewLength); - } - - return nNewLength; - } + return this->GetLength(); + } - // Replace all occurrences of character 'chOld' with character 'chNew' - int Replace(XCHAR chOld, XCHAR chNew) - { - int nCount = 0; - - // short-circuit the nop case - if (chOld != chNew) - { - // otherwise modify each character that matches in the string - bool bCopied = false; - PXSTR pszBuffer = const_cast< PXSTR >(this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). - - int nLength = this->GetLength(); - int iChar = 0; - while(iChar < nLength) - { - // replace instances of the specified character only - if (pszBuffer[iChar] == chOld) - { - if ( !bCopied) - { - bCopied = true; - pszBuffer = this->GetBuffer(nLength); - } - pszBuffer[iChar] = chNew; - nCount++; - } - iChar = int(StringTraits::CharNext(pszBuffer+iChar)-pszBuffer); - } - if (bCopied) - { - this->ReleaseBufferSetLength(nLength); - } - } - - return nCount; - } + // Insert character 'ch' before index 'iIndex' + int Insert(int iIndex, XCHAR ch) + { + if (iIndex < 0) + iIndex = 0; - // Replace all occurrences of string 'pszOld' with string 'pszNew' - int Replace(PCXSTR pszOld, PCXSTR pszNew) - { - // can't have empty or NULL lpszOld - - // nSourceLen is in XCHARs - int nSourceLen = StringTraits::SafeStringLen(pszOld); - if (nSourceLen == 0) - return 0; - // nReplacementLen is in XCHARs - int nReplacementLen = StringTraits::SafeStringLen(pszNew); - - // loop once to figure out the size of the result string - int nCount = 0; - { - PCXSTR pszStart = this->GetString(); - PCXSTR pszEnd = pszStart+this->GetLength(); - while(pszStart < pszEnd) - { - PCXSTR pszTarget; - while((pszTarget = StringTraits::StringFindString(pszStart, pszOld)) != NULL) - { - nCount++; - pszStart = pszTarget+nSourceLen; - } - pszStart += StringTraits::SafeStringLen(pszStart)+1; - } - } - - // if any changes were made, make them - if (nCount > 0) - { - // if the buffer is too small, just - // allocate a new buffer (slow but sure) - int nOldLength = this->GetLength(); - int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount; - - PXSTR pszBuffer = this->GetBuffer(__max(nNewLength, nOldLength)); - - PXSTR pszStart = pszBuffer; - PXSTR pszEnd = pszStart+nOldLength; - - // loop again to actually do the work - while(pszStart < pszEnd) - { - PXSTR pszTarget; - while((pszTarget = StringTraits::StringFindString(pszStart, pszOld)) != NULL) - { - int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen); - memmove_s(pszTarget+nReplacementLen, nBalance*sizeof(XCHAR), - pszTarget+nSourceLen, nBalance*sizeof(XCHAR)); - memcpy_s(pszTarget, nReplacementLen*sizeof(XCHAR), - pszNew, nReplacementLen*sizeof(XCHAR)); - pszStart = pszTarget+nReplacementLen; - pszTarget[nReplacementLen+nBalance] = 0; - nOldLength += (nReplacementLen-nSourceLen); - } - pszStart += StringTraits::SafeStringLen(pszStart)+1; - } - this->ReleaseBufferSetLength(nNewLength); - } - - return nCount; - } + if (iIndex > this->GetLength()) + iIndex = this->GetLength(); - // Remove all occurrences of character 'chRemove' - int Remove(XCHAR chRemove) - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - - PXSTR pszSource = pszBuffer; - PXSTR pszDest = pszBuffer; - PXSTR pszEnd = pszBuffer+nLength; - - while(pszSource < pszEnd) - { - PXSTR pszNewSource = StringTraits::CharNext(pszSource); - if (*pszSource != chRemove) - { - // Copy the source to the destination. Remember to copy all bytes of an MBCS character - // Copy the source to the destination. Remember to copy all bytes of an MBCS character - size_t NewSourceGap = (pszNewSource-pszSource); - PXSTR pszNewDest = pszDest + NewSourceGap; - size_t i = 0; - for (i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) - { - *pszDest = *pszSource; - pszSource++; - pszDest++; - } - } - pszSource = pszNewSource; - } - *pszDest = 0; - int nCount = int(pszSource-pszDest); - this->ReleaseBufferSetLength(nLength-nCount); - - return nCount; - } + int nNewLength = this->GetLength()+1; - CMStringT Tokenize(PCXSTR pszTokens, int& iStart) const - { - if ((pszTokens == NULL) || (*pszTokens == (XCHAR)0)) - { - if (iStart < this->GetLength()) - return CMStringT(this->GetString()+iStart); - } - else - { - PCXSTR pszPlace = this->GetString()+iStart; - PCXSTR pszEnd = this->GetString()+this->GetLength(); - if (pszPlace < pszEnd) - { - int nIncluding = StringTraits::StringSpanIncluding(pszPlace, pszTokens); - - if ((pszPlace+nIncluding) < pszEnd) - { - pszPlace += nIncluding; - int nExcluding = StringTraits::StringSpanExcluding(pszPlace, pszTokens); - - int iFrom = iStart+nIncluding; - int nUntil = nExcluding; - iStart = iFrom+nUntil+1; - - return Mid(iFrom, nUntil); - } - } - } - - // return empty string, done tokenizing - iStart = -1; - - return CMStringT(); - } + PXSTR pszBuffer = this->GetBuffer(nNewLength); - // find routines + // move existing bytes down +#if _MSC_VER >= 1400 + memmove_s(pszBuffer+iIndex+1, (nNewLength-iIndex)*sizeof(XCHAR), pszBuffer+iIndex, (nNewLength-iIndex)*sizeof(XCHAR)); +#else + memmove(pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof(XCHAR)); +#endif + pszBuffer[iIndex] = ch; - // Find the first occurrence of character 'ch', starting at index 'iStart' - int Find(XCHAR ch, int iStart = 0) const - { - // nLength is in XCHARs - int nLength = this->GetLength(); - if (iStart < 0 || iStart >= nLength) - return -1; + this->ReleaseBufferSetLength(nNewLength); + return nNewLength; + } - // find first single character - PCXSTR psz = StringTraits::StringFindChar(this->GetString()+iStart, ch); + // Insert string 'psz' before index 'iIndex' + int Insert(int iIndex, PCXSTR psz) + { + if (iIndex < 0) + iIndex = 0; - // return -1 if not found and index otherwise - return (psz == NULL) ? -1 : int(psz-this->GetString()); - } + if (iIndex > this->GetLength()) + { + iIndex = this->GetLength(); + } - // look for a specific sub-string + // nInsertLength and nNewLength are in XCHARs + int nInsertLength = StringTraits::SafeStringLen(psz); + int nNewLength = this->GetLength(); + if (nInsertLength > 0) + { + nNewLength += nInsertLength; - // Find the first occurrence of string 'pszSub', starting at index 'iStart' - int Find(PCXSTR pszSub, int iStart = 0) const - { - // iStart is in XCHARs - if (pszSub == NULL) - return -1; + PXSTR pszBuffer = this->GetBuffer(nNewLength); + // move existing bytes down +#if _MSC_VER >= 1400 + memmove_s(pszBuffer+iIndex+nInsertLength, (nNewLength-iIndex-nInsertLength+1)*sizeof(XCHAR), pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof(XCHAR)); + memcpy_s(pszBuffer+iIndex, nInsertLength*sizeof(XCHAR), psz, nInsertLength*sizeof(XCHAR)); +#else + memmove(pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof(XCHAR)); + memcpy(pszBuffer+iIndex, psz, nInsertLength*sizeof(XCHAR)); +#endif + this->ReleaseBufferSetLength(nNewLength); + } - // nLength is in XCHARs - int nLength = this->GetLength(); - if (iStart < 0 || iStart > nLength) - return -1; + return nNewLength; + } - // find first matching substring - PCXSTR psz = StringTraits::StringFindString(this->GetString()+iStart, pszSub); + // Replace all occurrences of character 'chOld' with character 'chNew' + int Replace(XCHAR chOld, XCHAR chNew) + { + int nCount = 0; - // return -1 for not found, distance from beginning otherwise - return (psz == NULL) ? -1 : int(psz-this->GetString()); - } + // short-circuit the nop case + if (chOld != chNew) + { + // otherwise modify each character that matches in the string + bool bCopied = false; + PXSTR pszBuffer = const_cast< PXSTR >(this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). + + int nLength = this->GetLength(); + int iChar = 0; + while(iChar < nLength) + { + // replace instances of the specified character only + if (pszBuffer[iChar] == chOld) + { + if ( !bCopied) + { + bCopied = true; + pszBuffer = this->GetBuffer(nLength); + } + pszBuffer[iChar] = chNew; + nCount++; + } + iChar = int(StringTraits::CharNext(pszBuffer+iChar)-pszBuffer); + } + if (bCopied) + { + this->ReleaseBufferSetLength(nLength); + } + } - // Find the first occurrence of any of the characters in string 'pszCharSet' - int FindOneOf(PCXSTR pszCharSet) const - { - PCXSTR psz = StringTraits::StringScanSet(this->GetString(), pszCharSet); - return (psz == NULL) ? -1 : int(psz-this->GetString()); - } + return nCount; + } - // Find the last occurrence of character 'ch' - int ReverseFind(XCHAR ch) const - { - // find last single character - PCXSTR psz = StringTraits::StringFindCharRev(this->GetString(), ch); + // Replace all occurrences of string 'pszOld' with string 'pszNew' + int Replace(PCXSTR pszOld, PCXSTR pszNew) + { + // can't have empty or NULL lpszOld - // return -1 if not found, distance from beginning otherwise - return (psz == NULL) ? -1 : int(psz-this->GetString()); - } + // nSourceLen is in XCHARs + int nSourceLen = StringTraits::SafeStringLen(pszOld); + if (nSourceLen == 0) + return 0; + // nReplacementLen is in XCHARs + int nReplacementLen = StringTraits::SafeStringLen(pszNew); - // manipulation + // loop once to figure out the size of the result string + int nCount = 0; + { + PCXSTR pszStart = this->GetString(); + PCXSTR pszEnd = pszStart+this->GetLength(); + while(pszStart < pszEnd) + { + PCXSTR pszTarget; + while((pszTarget = StringTraits::StringFindString(pszStart, pszOld)) != NULL) + { + nCount++; + pszStart = pszTarget+nSourceLen; + } + pszStart += StringTraits::SafeStringLen(pszStart)+1; + } + } - // Convert the string to uppercase - CMStringT& MakeUpper() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::StringUppercase(pszBuffer, nLength+1); - this->ReleaseBufferSetLength(nLength); + // if any changes were made, make them + if (nCount > 0) + { + // if the buffer is too small, just + // allocate a new buffer (slow but sure) + int nOldLength = this->GetLength(); + int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount; + + PXSTR pszBuffer = this->GetBuffer(__max(nNewLength, nOldLength)); + + PXSTR pszStart = pszBuffer; + PXSTR pszEnd = pszStart+nOldLength; + + // loop again to actually do the work + while(pszStart < pszEnd) + { + PXSTR pszTarget; + while((pszTarget = StringTraits::StringFindString(pszStart, pszOld)) != NULL) + { + int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen); + memmove_s(pszTarget+nReplacementLen, nBalance*sizeof(XCHAR), + pszTarget+nSourceLen, nBalance*sizeof(XCHAR)); + memcpy_s(pszTarget, nReplacementLen*sizeof(XCHAR), + pszNew, nReplacementLen*sizeof(XCHAR)); + pszStart = pszTarget+nReplacementLen; + pszTarget[nReplacementLen+nBalance] = 0; + nOldLength += (nReplacementLen-nSourceLen); + } + pszStart += StringTraits::SafeStringLen(pszStart)+1; + } + this->ReleaseBufferSetLength(nNewLength); + } - return *this; - } + return nCount; + } - // Convert the string to lowercase - CMStringT& MakeLower() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::StringLowercase(pszBuffer, nLength+1); - this->ReleaseBufferSetLength(nLength); + // Remove all occurrences of character 'chRemove' + int Remove(XCHAR chRemove) + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); - return *this; - } + PXSTR pszSource = pszBuffer; + PXSTR pszDest = pszBuffer; + PXSTR pszEnd = pszBuffer+nLength; - // Reverse the string - CMStringT& MakeReverse() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::StringReverse(pszBuffer); - this->ReleaseBufferSetLength(nLength); + while(pszSource < pszEnd) + { + PXSTR pszNewSource = StringTraits::CharNext(pszSource); + if (*pszSource != chRemove) + { + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + size_t NewSourceGap = (pszNewSource-pszSource); + PXSTR pszNewDest = pszDest + NewSourceGap; + size_t i = 0; + for (i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) + { + *pszDest = *pszSource; + pszSource++; + pszDest++; + } + } + pszSource = pszNewSource; + } + *pszDest = 0; + int nCount = int(pszSource-pszDest); + this->ReleaseBufferSetLength(nLength-nCount); - return *this; - } + return nCount; + } - // trimming + CMStringT Tokenize(PCXSTR pszTokens, int& iStart) const + { + if ((pszTokens == NULL) || (*pszTokens == (XCHAR)0)) + { + if (iStart < this->GetLength()) + return CMStringT(this->GetString()+iStart); + } + else + { + PCXSTR pszPlace = this->GetString()+iStart; + PCXSTR pszEnd = this->GetString()+this->GetLength(); + if (pszPlace < pszEnd) + { + int nIncluding = StringTraits::StringSpanIncluding(pszPlace, pszTokens); + + if ((pszPlace+nIncluding) < pszEnd) + { + pszPlace += nIncluding; + int nExcluding = StringTraits::StringSpanExcluding(pszPlace, pszTokens); + + int iFrom = iStart+nIncluding; + int nUntil = nExcluding; + iStart = iFrom+nUntil+1; + + return Mid(iFrom, nUntil); + } + } + } - // Remove all trailing whitespace - CMStringT& TrimRight() - { - // find beginning of trailing spaces by starting - // at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while(*psz != 0) - { - if (StringTraits::IsSpace(*psz)) - { - if (pszLast == NULL) - pszLast = psz; - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext(psz); - } - - if (pszLast != NULL) - { - // truncate at trailing space start - int iLast = int(pszLast-this->GetString()); - - this->Truncate(iLast); - } - - return *this; - } + // return empty string, done tokenizing + iStart = -1; - // Remove all leading whitespace - CMStringT& TrimLeft() - { - // find first non-space character - - PCXSTR psz = this->GetString(); - - while(StringTraits::IsSpace(*psz)) - { - psz = StringTraits::CharNext(psz); - } - - if (psz != this->GetString()) - { - // fix up data and length - int iFirst = int(psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer(this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s(pszBuffer, (this->GetLength()+1)*sizeof(XCHAR), - psz, (nDataLength+1)*sizeof(XCHAR)); - this->ReleaseBufferSetLength(nDataLength); - } - - return *this; - } + return CMStringT(); + } - // Remove all leading and trailing whitespace - CMStringT& Trim() - { - return TrimRight().TrimLeft(); - } + // find routines - // Remove all leading and trailing occurrences of character 'chTarget' - CMStringT& Trim(XCHAR chTarget) - { - return TrimRight(chTarget).TrimLeft(chTarget); - } + // Find the first occurrence of character 'ch', starting at index 'iStart' + int Find(XCHAR ch, int iStart = 0) const + { + // nLength is in XCHARs + int nLength = this->GetLength(); + if (iStart < 0 || iStart >= nLength) + return -1; - // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' - CMStringT& Trim(PCXSTR pszTargets) - { - return TrimRight(pszTargets).TrimLeft(pszTargets); - } + // find first single character + PCXSTR psz = StringTraits::StringFindChar(this->GetString()+iStart, ch); - // trimming anything (either side) + // return -1 if not found and index otherwise + return (psz == NULL) ? -1 : int(psz-this->GetString()); + } - // Remove all trailing occurrences of character 'chTarget' - CMStringT& TrimRight(XCHAR chTarget) - { - // find beginning of trailing matches - // by starting at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while(*psz != 0) - { - if (*psz == chTarget) - { - if (pszLast == NULL) - { - pszLast = psz; - } - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext(psz); - } - - if (pszLast != NULL) - { - // truncate at left-most matching character - int iLast = int(pszLast-this->GetString()); - this->Truncate(iLast); - } - - return *this; - } + // look for a specific sub-string - // Remove all trailing occurrences of any of the characters in string 'pszTargets' - CMStringT& TrimRight(PCXSTR pszTargets) - { - // if we're not trimming anything, we're not doing any work - if ((pszTargets == NULL) || (*pszTargets == 0)) - { - return *this; - } - - // find beginning of trailing matches - // by starting at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = NULL; - - while(*psz != 0) - { - if (StringTraits::StringFindChar(pszTargets, *psz) != NULL) - { - if (pszLast == NULL) - { - pszLast = psz; - } - } - else - { - pszLast = NULL; - } - psz = StringTraits::CharNext(psz); - } - - if (pszLast != NULL) - { - // truncate at left-most matching character - int iLast = int(pszLast-this->GetString()); - this->Truncate(iLast); - } - - return *this; - } + // Find the first occurrence of string 'pszSub', starting at index 'iStart' + int Find(PCXSTR pszSub, int iStart = 0) const + { + // iStart is in XCHARs + if (pszSub == NULL) + return -1; - // Remove all leading occurrences of character 'chTarget' - CMStringT& TrimLeft(XCHAR chTarget) - { - // find first non-matching character - PCXSTR psz = this->GetString(); - - while(chTarget == *psz) - { - psz = StringTraits::CharNext(psz); - } - - if (psz != this->GetString()) - { - // fix up data and length - int iFirst = int(psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer(this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s(pszBuffer, (this->GetLength()+1)*sizeof(XCHAR), - psz, (nDataLength+1)*sizeof(XCHAR)); - this->ReleaseBufferSetLength(nDataLength); - } - - return *this; - } + // nLength is in XCHARs + int nLength = this->GetLength(); + if (iStart < 0 || iStart > nLength) + return -1; - // Remove all leading occurrences of any of the characters in string 'pszTargets' - CMStringT& TrimLeft(PCXSTR pszTargets) - { - // if we're not trimming anything, we're not doing any work - if ((pszTargets == NULL) || (*pszTargets == 0)) - { - return *this; - } - - PCXSTR psz = this->GetString(); - while((*psz != 0) && (StringTraits::StringFindChar(pszTargets, *psz) != NULL)) - { - psz = StringTraits::CharNext(psz); - } - - if (psz != this->GetString()) - { - // fix up data and length - int iFirst = int(psz-this->GetString()); - PXSTR pszBuffer = this->GetBuffer(this->GetLength()); - psz = pszBuffer+iFirst; - int nDataLength = this->GetLength()-iFirst; - memmove_s(pszBuffer, (this->GetLength()+1)*sizeof(XCHAR), - psz, (nDataLength+1)*sizeof(XCHAR)); - this->ReleaseBufferSetLength(nDataLength); - } - - return *this; - } + // find first matching substring + PCXSTR psz = StringTraits::StringFindString(this->GetString()+iStart, pszSub); - // Convert the string to the OEM character set - void AnsiToOem() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::ConvertToOem(pszBuffer, nLength+1); - this->ReleaseBufferSetLength(nLength); - } + // return -1 for not found, distance from beginning otherwise + return (psz == NULL) ? -1 : int(psz-this->GetString()); + } - // Convert the string to the ANSI character set - void OemToAnsi() - { - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::ConvertToAnsi(pszBuffer, nLength+1); - this->ReleaseBufferSetLength(nLength); - } + // Find the first occurrence of any of the characters in string 'pszCharSet' + int FindOneOf(PCXSTR pszCharSet) const + { + PCXSTR psz = StringTraits::StringScanSet(this->GetString(), pszCharSet); + return (psz == NULL) ? -1 : int(psz-this->GetString()); + } - // Very simple sub-string extraction + // Find the last occurrence of character 'ch' + int ReverseFind(XCHAR ch) const + { + // find last single character + PCXSTR psz = StringTraits::StringFindCharRev(this->GetString(), ch); - // Return the substring starting at index 'iFirst' - CMStringT Mid(int iFirst) const - { - return Mid(iFirst, this->GetLength()-iFirst); - } + // return -1 if not found, distance from beginning otherwise + return (psz == NULL) ? -1 : int(psz-this->GetString()); + } - // Return the substring starting at index 'iFirst', with length 'nCount' - CMStringT Mid(int iFirst, int nCount) const - { - // nCount is in XCHARs + // manipulation - // out-of-bounds requests return sensible things - if (iFirst < 0) - iFirst = 0; - if (nCount < 0) - nCount = 0; + // Convert the string to uppercase + CMStringT& MakeUpper() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::StringUppercase(pszBuffer, nLength+1); + this->ReleaseBufferSetLength(nLength); - if ((iFirst + nCount) > this->GetLength()) - nCount = this->GetLength()-iFirst; + return *this; + } - if (iFirst > this->GetLength()) - nCount = 0; + // Convert the string to lowercase + CMStringT& MakeLower() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::StringLowercase(pszBuffer, nLength+1); + this->ReleaseBufferSetLength(nLength); - // optimize case of returning entire string - if ((iFirst == 0) && ((iFirst+nCount) == this->GetLength())) - return *this; + return *this; + } - return CMStringT(this->GetString()+iFirst, nCount); - } + // Reverse the string + CMStringT& MakeReverse() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::StringReverse(pszBuffer); + this->ReleaseBufferSetLength(nLength); - // Return the substring consisting of the rightmost 'nCount' characters - CMStringT Right(int nCount) const - { - // nCount is in XCHARs - if (nCount < 0) - nCount = 0; + return *this; + } - int nLength = this->GetLength(); - if (nCount >= nLength) - { - return *this; - } + // trimming - return CMStringT(this->GetString()+nLength-nCount, nCount); - } + // Remove all trailing whitespace + CMStringT& TrimRight() + { + // find beginning of trailing spaces by starting + // at beginning (DBCS aware) - // Return the substring consisting of the leftmost 'nCount' characters - CMStringT Left(int nCount) const - { - // nCount is in XCHARs - if (nCount < 0) - nCount = 0; + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; - int nLength = this->GetLength(); - if (nCount >= nLength) - return *this; + while(*psz != 0) { + if (StringTraits::IsSpace(*psz)) { + if (pszLast == NULL) + pszLast = psz; + } + else pszLast = NULL; - return CMStringT(this->GetString(), nCount); - } + psz = StringTraits::CharNext(psz); + } - // Return the substring consisting of the leftmost characters in the set 'pszCharSet' - CMStringT SpanIncluding(PCXSTR pszCharSet) const - { - return Left(StringTraits::StringSpanIncluding(this->GetString(), pszCharSet)); - } + if (pszLast != NULL) { + // truncate at trailing space start + int iLast = int(pszLast-this->GetString()); - // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' - CMStringT SpanExcluding(PCXSTR pszCharSet) const - { - return Left(StringTraits::StringSpanExcluding(this->GetString(), pszCharSet)); - } + this->Truncate(iLast); + } - // Format data using format string 'pszFormat' - void Format(PCXSTR pszFormat, ...); + return *this; + } - // Append formatted data using format string 'pszFormat' - void AppendFormat(PCXSTR pszFormat, ...); + // Remove all leading whitespace + CMStringT& TrimLeft() + { + // find first non-space character - void AppendFormatV(PCXSTR pszFormat, va_list args) - { - int nCurrentLength = this->GetLength(); - int nAppendLength = StringTraits::GetFormattedLength(pszFormat, args); - PXSTR pszBuffer = this->GetBuffer(nCurrentLength+nAppendLength); - StringTraits::Format(pszBuffer+nCurrentLength, - nAppendLength+1, pszFormat, args); - this->ReleaseBufferSetLength(nCurrentLength+nAppendLength); - } + PCXSTR psz = this->GetString(); - void FormatV(PCXSTR pszFormat, va_list args) - { - int nLength = StringTraits::GetFormattedLength(pszFormat, args); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::Format(pszBuffer, nLength+1, pszFormat, args); - this->ReleaseBufferSetLength(nLength); - } + while(StringTraits::IsSpace(*psz)) + { + psz = StringTraits::CharNext(psz); + } - // OLE BSTR support + if (psz != this->GetString()) + { + // fix up data and length + int iFirst = int(psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer(this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s(pszBuffer, (this->GetLength()+1)*sizeof(XCHAR), + psz, (nDataLength+1)*sizeof(XCHAR)); + this->ReleaseBufferSetLength(nDataLength); + } - // allocate a BSTR containing a copy of the string - BSTR AllocSysString() const - { - BSTR bstrResult = StringTraits::AllocSysString(this->GetString(), this->GetLength()); - return bstrResult; - } + return *this; + } - BSTR SetSysString(BSTR* pbstr) const - { - StringTraits::ReAllocSysString(this->GetString(), pbstr, this->GetLength()); - return *pbstr; - } + // Remove all leading and trailing whitespace + CMStringT& Trim() + { + return TrimRight().TrimLeft(); + } - // Set the string to the value of environment variable 'pszVar' - BOOL GetEnvironmentVariable(PCXSTR pszVar) - { - ULONG nLength = StringTraits::GetEnvironmentVariable(pszVar, NULL, 0); - BOOL bRetVal = FALSE; - - if (nLength == 0) - { - this->Empty(); - } - else - { - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::GetEnvironmentVariable(pszVar, pszBuffer, nLength); - this->ReleaseBuffer(); - bRetVal = TRUE; - } - - return bRetVal; - } + // Remove all leading and trailing occurrences of character 'chTarget' + CMStringT& Trim(XCHAR chTarget) + { + return TrimRight(chTarget).TrimLeft(chTarget); + } - // Load the string from resource 'nID' - BOOL LoadString(UINT nID) - { - HINSTANCE hInst = StringTraits::FindStringResourceInstance(nID); - if (hInst == NULL) - return FALSE; + // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' + CMStringT& Trim(PCXSTR pszTargets) + { + return TrimRight(pszTargets).TrimLeft(pszTargets); + } - return LoadString(hInst, nID); - } + // trimming anything (either side) - friend CMStringT __stdcall operator+(const CMStringT& str1, const CMStringT& str2) - { - CMStringT strResult; + // Remove all trailing occurrences of character 'chTarget' + CMStringT& TrimRight(XCHAR chTarget) + { + // find beginning of trailing matches + // by starting at beginning (DBCS aware) - Concatenate(strResult, str1, str1.GetLength(), str2, str2.GetLength()); + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; - return strResult; - } + while(*psz != 0) + { + if (*psz == chTarget) + { + if (pszLast == NULL) + { + pszLast = psz; + } + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext(psz); + } - friend CMStringT __stdcall operator+(const CMStringT& str1, PCXSTR psz2) - { - CMStringT strResult; + if (pszLast != NULL) + { + // truncate at left-most matching character + int iLast = int(pszLast-this->GetString()); + this->Truncate(iLast); + } - Concatenate(strResult, str1, str1.GetLength(), psz2, StringLength(psz2)); + return *this; + } - return strResult; - } + // Remove all trailing occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimRight(PCXSTR pszTargets) + { + // if we're not trimming anything, we're not doing any work + if ((pszTargets == NULL) || (*pszTargets == 0)) + { + return *this; + } - friend CMStringT __stdcall operator+(PCXSTR psz1, const CMStringT& str2) - { - CMStringT strResult; + // find beginning of trailing matches + // by starting at beginning (DBCS aware) - Concatenate(strResult, psz1, StringLength(psz1), str2, str2.GetLength()); + PCXSTR psz = this->GetString(); + PCXSTR pszLast = NULL; - return strResult; - } + while(*psz != 0) + { + if (StringTraits::StringFindChar(pszTargets, *psz) != NULL) + { + if (pszLast == NULL) + { + pszLast = psz; + } + } + else + { + pszLast = NULL; + } + psz = StringTraits::CharNext(psz); + } - friend CMStringT __stdcall operator+(const CMStringT& str1, wchar_t ch2) - { - CMStringT strResult; - XCHAR chTemp = XCHAR(ch2); + if (pszLast != NULL) + { + // truncate at left-most matching character + int iLast = int(pszLast-this->GetString()); + this->Truncate(iLast); + } - Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1); + return *this; + } - return strResult; - } + // Remove all leading occurrences of character 'chTarget' + CMStringT& TrimLeft(XCHAR chTarget) + { + // find first non-matching character + PCXSTR psz = this->GetString(); - friend CMStringT __stdcall operator+(const CMStringT& str1, char ch2) - { - CMStringT strResult; - XCHAR chTemp = XCHAR(ch2); + while(chTarget == *psz) + { + psz = StringTraits::CharNext(psz); + } - Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1); + if (psz != this->GetString()) + { + // fix up data and length + int iFirst = int(psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer(this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s(pszBuffer, (this->GetLength()+1)*sizeof(XCHAR), + psz, (nDataLength+1)*sizeof(XCHAR)); + this->ReleaseBufferSetLength(nDataLength); + } - return strResult; - } + return *this; + } - friend CMStringT __stdcall operator+(wchar_t ch1, const CMStringT& str2) - { - CMStringT strResult; - XCHAR chTemp = XCHAR(ch1); + // Remove all leading occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimLeft(PCXSTR pszTargets) + { + // if we're not trimming anything, we're not doing any work + if ((pszTargets == NULL) || (*pszTargets == 0)) + { + return *this; + } - Concatenate(strResult, &chTemp, 1, str2, str2.GetLength()); + PCXSTR psz = this->GetString(); + while((*psz != 0) && (StringTraits::StringFindChar(pszTargets, *psz) != NULL)) + { + psz = StringTraits::CharNext(psz); + } - return strResult; - } + if (psz != this->GetString()) + { + // fix up data and length + int iFirst = int(psz-this->GetString()); + PXSTR pszBuffer = this->GetBuffer(this->GetLength()); + psz = pszBuffer+iFirst; + int nDataLength = this->GetLength()-iFirst; + memmove_s(pszBuffer, (this->GetLength()+1)*sizeof(XCHAR), + psz, (nDataLength+1)*sizeof(XCHAR)); + this->ReleaseBufferSetLength(nDataLength); + } - friend CMStringT __stdcall operator+(char ch1, const CMStringT& str2) - { - CMStringT strResult; - XCHAR chTemp = XCHAR(ch1); + return *this; + } - Concatenate(strResult, &chTemp, 1, str2, str2.GetLength()); + // Convert the string to the OEM character set + void AnsiToOem() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::ConvertToOem(pszBuffer, nLength+1); + this->ReleaseBufferSetLength(nLength); + } - return strResult; - } + // Convert the string to the ANSI character set + void OemToAnsi() + { + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::ConvertToAnsi(pszBuffer, nLength+1); + this->ReleaseBufferSetLength(nLength); + } - friend bool __stdcall operator==(const CMStringT& str1, const CMStringT& str2) - { - return str1.Compare(str2) == 0; - } + // Very simple sub-string extraction - friend bool __stdcall operator==(const CMStringT& str1, PCXSTR psz2) - { - return str1.Compare(psz2) == 0; - } + // Return the substring starting at index 'iFirst' + CMStringT Mid(int iFirst) const + { + return Mid(iFirst, this->GetLength()-iFirst); + } - friend bool __stdcall operator==(PCXSTR psz1, const CMStringT& str2) - { - return str2.Compare(psz1) == 0; - } + // Return the substring starting at index 'iFirst', with length 'nCount' + CMStringT Mid(int iFirst, int nCount) const + { + // nCount is in XCHARs - friend bool __stdcall operator==(const CMStringT& str1, PCYSTR psz2) - { - CMStringT str2(psz2); + // out-of-bounds requests return sensible things + if (iFirst < 0) + iFirst = 0; + if (nCount < 0) + nCount = 0; - return str1 == str2; - } + if ((iFirst + nCount) > this->GetLength()) + nCount = this->GetLength()-iFirst; - friend bool __stdcall operator==(PCYSTR psz1, const CMStringT& str2) - { - CMStringT str1(psz1); + if (iFirst > this->GetLength()) + nCount = 0; - return str1 == str2; - } + // optimize case of returning entire string + if ((iFirst == 0) && ((iFirst+nCount) == this->GetLength())) + return *this; - friend bool __stdcall operator!=(const CMStringT& str1, const CMStringT& str2) - { - return str1.Compare(str2) != 0; - } + return CMStringT(this->GetString()+iFirst, nCount); + } - friend bool __stdcall operator!=(const CMStringT& str1, PCXSTR psz2) - { - return str1.Compare(psz2) != 0; - } + // Return the substring consisting of the rightmost 'nCount' characters + CMStringT Right(int nCount) const + { + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; - friend bool __stdcall operator!=(PCXSTR psz1, const CMStringT& str2) - { - return str2.Compare(psz1) != 0; - } + int nLength = this->GetLength(); + if (nCount >= nLength) + { + return *this; + } - friend bool __stdcall operator!=(const CMStringT& str1, PCYSTR psz2) - { - CMStringT str2(psz2); + return CMStringT(this->GetString()+nLength-nCount, nCount); + } - return str1 != str2; - } + // Return the substring consisting of the leftmost 'nCount' characters + CMStringT Left(int nCount) const + { + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; - friend bool __stdcall operator!=(PCYSTR psz1, const CMStringT& str2) - { - CMStringT str1(psz1); + int nLength = this->GetLength(); + if (nCount >= nLength) + return *this; - return str1 != str2; - } + return CMStringT(this->GetString(), nCount); + } - friend bool __stdcall operator<(const CMStringT& str1, const CMStringT& str2) - { - return str1.Compare(str2) < 0; - } + // Return the substring consisting of the leftmost characters in the set 'pszCharSet' + CMStringT SpanIncluding(PCXSTR pszCharSet) const + { + return Left(StringTraits::StringSpanIncluding(this->GetString(), pszCharSet)); + } - friend bool __stdcall operator<(const CMStringT& str1, PCXSTR psz2) - { - return str1.Compare(psz2) < 0; - } + // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' + CMStringT SpanExcluding(PCXSTR pszCharSet) const + { + return Left(StringTraits::StringSpanExcluding(this->GetString(), pszCharSet)); + } - friend bool __stdcall operator<(PCXSTR psz1, const CMStringT& str2) - { - return str2.Compare(psz1) > 0; - } + // Format data using format string 'pszFormat' + PCXSTR Format(PCXSTR pszFormat, ...) + { + va_list argList; + va_start(argList, pszFormat); + FormatV(pszFormat, argList); + va_end(argList); + return GetString(); + } - friend bool __stdcall operator>(const CMStringT& str1, const CMStringT& str2) - { - return str1.Compare(str2) > 0; - } + // Append formatted data using format string 'pszFormat' + PCXSTR AppendFormat(PCXSTR pszFormat, ...) + { + va_list argList; + va_start(argList, pszFormat); + AppendFormatV(pszFormat, argList); + va_end(argList); + return GetString(); + } - friend bool __stdcall operator>(const CMStringT& str1, PCXSTR psz2) - { - return str1.Compare(psz2) > 0; - } + void AppendFormatV(PCXSTR pszFormat, va_list args) + { + int nCurrentLength = this->GetLength(); + int nAppendLength = StringTraits::GetFormattedLength(pszFormat, args); + PXSTR pszBuffer = this->GetBuffer(nCurrentLength+nAppendLength); + StringTraits::Format(pszBuffer+nCurrentLength, + nAppendLength+1, pszFormat, args); + this->ReleaseBufferSetLength(nCurrentLength+nAppendLength); + } - friend bool __stdcall operator>(PCXSTR psz1, const CMStringT& str2) - { - return str2.Compare(psz1) < 0; - } + void FormatV(PCXSTR pszFormat, va_list args) + { + int nLength = StringTraits::GetFormattedLength(pszFormat, args); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::Format(pszBuffer, nLength+1, pszFormat, args); + this->ReleaseBufferSetLength(nLength); + } - friend bool __stdcall operator<=(const CMStringT& str1, const CMStringT& str2) - { - return str1.Compare(str2) <= 0; - } + // OLE BSTR support - friend bool __stdcall operator<=(const CMStringT& str1, PCXSTR psz2) - { - return str1.Compare(psz2) <= 0; - } + // allocate a BSTR containing a copy of the string + BSTR AllocSysString() const + { + BSTR bstrResult = StringTraits::AllocSysString(this->GetString(), this->GetLength()); + return bstrResult; + } - friend bool __stdcall operator<=(PCXSTR psz1, const CMStringT& str2) - { - return str2.Compare(psz1) >= 0; - } + BSTR SetSysString(BSTR* pbstr) const + { + StringTraits::ReAllocSysString(this->GetString(), pbstr, this->GetLength()); + return *pbstr; + } - friend bool __stdcall operator>=(const CMStringT& str1, const CMStringT& str2) - { - return str1.Compare(str2) >= 0; - } + // Set the string to the value of environment variable 'pszVar' + BOOL GetEnvironmentVariable(PCXSTR pszVar) + { + ULONG nLength = StringTraits::GetEnvironmentVariable(pszVar, NULL, 0); + BOOL bRetVal = FALSE; - friend bool __stdcall operator>=(const CMStringT& str1, PCXSTR psz2) - { - return str1.Compare(psz2) >= 0; - } + if (nLength == 0) + { + this->Empty(); + } + else + { + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::GetEnvironmentVariable(pszVar, pszBuffer, nLength); + this->ReleaseBuffer(); + bRetVal = TRUE; + } - friend bool __stdcall operator>=(PCXSTR psz1, const CMStringT& str2) - { - return str2.Compare(psz1) <= 0; - } + return bRetVal; + } - friend bool __stdcall operator==(XCHAR ch1, const CMStringT& str2) - { - return (str2.GetLength() == 1) && (str2[0] == ch1); - } + // Load the string from resource 'nID' + BOOL LoadString(UINT nID) + { + HINSTANCE hInst = StringTraits::FindStringResourceInstance(nID); + if (hInst == NULL) + return FALSE; - friend bool __stdcall operator==(const CMStringT& str1, XCHAR ch2) - { - return (str1.GetLength() == 1) && (str1[0] == ch2); - } + return LoadString(hInst, nID); + } - friend bool __stdcall operator!=(XCHAR ch1, const CMStringT& str2) - { - return (str2.GetLength() != 1) || (str2[0] != ch1); - } + friend CMStringT __stdcall operator+(const CMStringT& str1, const CMStringT& str2) + { + CMStringT strResult; - friend bool __stdcall operator!=(const CMStringT& str1, XCHAR ch2) - { - return (str1.GetLength() != 1) || (str1[0] != ch2); - } -}; + Concatenate(strResult, str1, str1.GetLength(), str2, str2.GetLength()); -template< typename BaseType, class StringTraits > -inline void CMStringT::Format(PCXSTR pszFormat, ...) -{ - va_list argList; - va_start(argList, pszFormat); - FormatV(pszFormat, argList); - va_end(argList); -} + return strResult; + } -template< typename BaseType, class StringTraits > -inline void CMStringT::AppendFormat(PCXSTR pszFormat, ...) -{ - va_list argList; - va_start(argList, pszFormat); - AppendFormatV(pszFormat, argList); - va_end(argList); -} + friend CMStringT __stdcall operator+(const CMStringT& str1, PCXSTR psz2) + { + CMStringT strResult; + + Concatenate(strResult, str1, str1.GetLength(), psz2, StringLength(psz2)); + + return strResult; + } + + friend CMStringT __stdcall operator+(PCXSTR psz1, const CMStringT& str2) + { + CMStringT strResult; + + Concatenate(strResult, psz1, StringLength(psz1), str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+(const CMStringT& str1, wchar_t ch2) + { + CMStringT strResult; + XCHAR chTemp = XCHAR(ch2); + + Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1); + + return strResult; + } + + friend CMStringT __stdcall operator+(const CMStringT& str1, char ch2) + { + CMStringT strResult; + XCHAR chTemp = XCHAR(ch2); + + Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1); + + return strResult; + } + + friend CMStringT __stdcall operator+(wchar_t ch1, const CMStringT& str2) + { + CMStringT strResult; + XCHAR chTemp = XCHAR(ch1); + + Concatenate(strResult, &chTemp, 1, str2, str2.GetLength()); + + return strResult; + } + + friend CMStringT __stdcall operator+(char ch1, const CMStringT& str2) + { + CMStringT strResult; + XCHAR chTemp = XCHAR(ch1); + + Concatenate(strResult, &chTemp, 1, str2, str2.GetLength()); + + return strResult; + } + + friend bool __stdcall operator==(const CMStringT& str1, const CMStringT& str2) + { + return str1.Compare(str2) == 0; + } + + friend bool __stdcall operator==(const CMStringT& str1, PCXSTR psz2) + { + return str1.Compare(psz2) == 0; + } + + friend bool __stdcall operator==(PCXSTR psz1, const CMStringT& str2) + { + return str2.Compare(psz1) == 0; + } + + friend bool __stdcall operator==(const CMStringT& str1, PCYSTR psz2) + { + CMStringT str2(psz2); + + return str1 == str2; + } + + friend bool __stdcall operator==(PCYSTR psz1, const CMStringT& str2) + { + CMStringT str1(psz1); + + return str1 == str2; + } + + friend bool __stdcall operator!=(const CMStringT& str1, const CMStringT& str2) + { + return str1.Compare(str2) != 0; + } + + friend bool __stdcall operator!=(const CMStringT& str1, PCXSTR psz2) + { + return str1.Compare(psz2) != 0; + } + + friend bool __stdcall operator!=(PCXSTR psz1, const CMStringT& str2) + { + return str2.Compare(psz1) != 0; + } + + friend bool __stdcall operator!=(const CMStringT& str1, PCYSTR psz2) + { + CMStringT str2(psz2); + + return str1 != str2; + } + + friend bool __stdcall operator!=(PCYSTR psz1, const CMStringT& str2) + { + CMStringT str1(psz1); + + return str1 != str2; + } + + friend bool __stdcall operator<(const CMStringT& str1, const CMStringT& str2) + { + return str1.Compare(str2) < 0; + } + + friend bool __stdcall operator<(const CMStringT& str1, PCXSTR psz2) + { + return str1.Compare(psz2) < 0; + } + + friend bool __stdcall operator<(PCXSTR psz1, const CMStringT& str2) + { + return str2.Compare(psz1) > 0; + } + + friend bool __stdcall operator>(const CMStringT& str1, const CMStringT& str2) + { + return str1.Compare(str2) > 0; + } + + friend bool __stdcall operator>(const CMStringT& str1, PCXSTR psz2) + { + return str1.Compare(psz2) > 0; + } + + friend bool __stdcall operator>(PCXSTR psz1, const CMStringT& str2) + { + return str2.Compare(psz1) < 0; + } + + friend bool __stdcall operator<=(const CMStringT& str1, const CMStringT& str2) + { + return str1.Compare(str2) <= 0; + } + + friend bool __stdcall operator<=(const CMStringT& str1, PCXSTR psz2) + { + return str1.Compare(psz2) <= 0; + } + + friend bool __stdcall operator<=(PCXSTR psz1, const CMStringT& str2) + { + return str2.Compare(psz1) >= 0; + } + + friend bool __stdcall operator>=(const CMStringT& str1, const CMStringT& str2) + { + return str1.Compare(str2) >= 0; + } + + friend bool __stdcall operator>=(const CMStringT& str1, PCXSTR psz2) + { + return str1.Compare(psz2) >= 0; + } + + friend bool __stdcall operator>=(PCXSTR psz1, const CMStringT& str2) + { + return str2.Compare(psz1) <= 0; + } + + friend bool __stdcall operator==(XCHAR ch1, const CMStringT& str2) + { + return (str2.GetLength() == 1) && (str2[0] == ch1); + } + + friend bool __stdcall operator==(const CMStringT& str1, XCHAR ch2) + { + return (str1.GetLength() == 1) && (str1[0] == ch2); + } + + friend bool __stdcall operator!=(XCHAR ch1, const CMStringT& str2) + { + return (str2.GetLength() != 1) || (str2[0] != ch1); + } + + friend bool __stdcall operator!=(const CMStringT& str1, XCHAR ch2) + { + return (str1.GetLength() != 1) || (str1[0] != ch2); + } +}; typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; diff --git a/protocols/MRA/src/Mra_proto.cpp b/protocols/MRA/src/Mra_proto.cpp index 23f9a039ae..e085e8cc41 100644 --- a/protocols/MRA/src/Mra_proto.cpp +++ b/protocols/MRA/src/Mra_proto.cpp @@ -475,9 +475,7 @@ bool CMraProto::CmdMessageStatus(ULONG seq, BinBuffer &buf) ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)"User does not accept offline flash animation"); break; default: - CMStringA szMsg; - szMsg.Format("Undefined message delivery error, code: %lu", dwTemp); - ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)szMsg.c_str()); + ProtoBroadcastAck(hContact, dwAckType, ACKRESULT_FAILED, (HANDLE)seq, (LPARAM)CMStringA().Format("Undefined message delivery error, code: %lu", dwTemp)); break; } MraSendQueueFree(hSendQueueHandle, seq); -- cgit v1.2.3