/* Miranda NG: the free IM client for Microsoft* Windows* Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #pragma once #ifndef M_STRING_H__ #define M_STRING_H__ #include #include #ifdef _MSC_VER #include #else #include #endif // _WINDOWS #include #include #ifdef __MINGW32__ #include __inline size_t strnlen(const char *string, size_t maxlen) { const char *end = (const char *)memchr ((const void *)string, '\0', maxlen); return end ? (size_t) (end - string) : maxlen; } __inline size_t wcsnlen(const wchar_t *string, size_t maxlen) { const wchar_t *end = wmemchr (string, L'\0', maxlen); return end ? (size_t) (end - string) : maxlen; } /* FIXME: This may be wrong assumption about Langpack_GetDefaultCodePage */ #define Langpack_GetDefaultCodePage() CP_THREAD_ACP /* FIXME: This is unsafe */ #define memcpy_s(dest,size,src,count) memcpy(dest,src,count) /* FIXME: This is quite silly implementation of _mbsstr */ #define _mbsstr(str,search) strstr((const char *)str,(const char *)search) #define __max(x,y) (((x)<(y))?(y):(x)) #endif /* __MINGW32__ */ ///////////////////////////////////////////////////////////////////////////////////////// struct CMStringData; MIR_CORE_DLL(CMStringData*) mirstr_allocate(int nChars, int nCharSize); MIR_CORE_DLL(void) mirstr_free(CMStringData *pData); MIR_CORE_DLL(CMStringData*) mirstr_realloc(CMStringData* pData, int nChars, int nCharSize); MIR_CORE_DLL(CMStringData*) mirstr_getNil(); MIR_CORE_DLL(void) mirstr_lock(CMStringData* pThis); MIR_CORE_DLL(void) mirstr_release(CMStringData* pThis); MIR_CORE_DLL(void) mirstr_unlock(CMStringData* pThis); ///////////////////////////////////////////////////////////////////////////////////////// enum CMStringDataFormat { FORMAT }; struct CMStringData { int nDataLength; // Length of currently used data in XCHARs (not including terminating null) int nAllocLength; // Length of allocated data in XCHARs (not including terminating null) long nRefs; // Reference count: negative == locked __forceinline void* data() { return (this + 1); } __forceinline void AddRef() { InterlockedIncrement(&nRefs); } __forceinline bool IsLocked() const { return nRefs < 0; } __forceinline bool IsShared() const { return nRefs > 1; } __forceinline void Lock() { mirstr_lock(this); } __forceinline void Release() { mirstr_release(this); } __forceinline void Unlock() { mirstr_unlock(this); } }; template< typename BaseType = char > class ChTraitsBase { public: typedef char XCHAR; typedef LPSTR PXSTR; typedef LPCSTR PCXSTR; typedef wchar_t YCHAR; typedef LPWSTR PYSTR; typedef LPCWSTR PCYSTR; }; template<> class ChTraitsBase< wchar_t > { public: typedef wchar_t XCHAR; typedef LPWSTR PXSTR; typedef LPCWSTR PCXSTR; typedef char YCHAR; typedef LPSTR PYSTR; typedef LPCSTR PCYSTR; }; template< typename BaseType > class CMSimpleStringT { public: typedef typename ChTraitsBase< BaseType >::XCHAR XCHAR; typedef typename ChTraitsBase< BaseType >::PXSTR PXSTR; typedef typename ChTraitsBase< BaseType >::PCXSTR PCXSTR; typedef typename ChTraitsBase< BaseType >::YCHAR YCHAR; typedef typename ChTraitsBase< BaseType >::PYSTR PYSTR; typedef typename ChTraitsBase< BaseType >::PCYSTR PCYSTR; public: explicit CMSimpleStringT(); CMSimpleStringT(const CMSimpleStringT& strSrc); CMSimpleStringT(PCXSTR pszSrc); CMSimpleStringT(const XCHAR* pchSrc, int nLength); ~CMSimpleStringT(); CMSimpleStringT& operator=(const CMSimpleStringT& strSrc); __forceinline CMSimpleStringT& operator=(PCXSTR pszSrc) { SetString(pszSrc); return *this; } __forceinline CMSimpleStringT& operator+=(const CMSimpleStringT& strSrc) { Append(strSrc); return *this; } __forceinline CMSimpleStringT& operator+=(PCXSTR pszSrc) { Append(pszSrc); return *this; } __forceinline CMSimpleStringT& operator+=(char ch) { AppendChar(XCHAR(ch)); return *this; } __forceinline CMSimpleStringT& operator+=(unsigned char ch) { AppendChar(XCHAR(ch)); return *this; } __forceinline CMSimpleStringT& operator+=(wchar_t ch) { AppendChar(XCHAR(ch)); return *this; } __forceinline XCHAR operator[](int iChar) const { return m_pszData[iChar]; } __forceinline operator PCXSTR() const { return m_pszData; } __forceinline PCXSTR c_str() const { return m_pszData; } __forceinline int GetAllocLength() const { return GetData()->nAllocLength; } __forceinline XCHAR GetAt(int iChar) const { return m_pszData[iChar]; } __forceinline PXSTR GetBuffer(int nMinBufferLength) { return PrepareWrite(nMinBufferLength); } __forceinline int GetLength() const { return GetData()->nDataLength; } __forceinline PCXSTR GetString() const { return m_pszData; } __forceinline PCXSTR GetTail() const { return m_pszData + GetData()->nDataLength; } __forceinline bool IsEmpty() const { return GetLength() == 0; } __forceinline void Preallocate(int nLength) { PrepareWrite(nLength); } __forceinline void ReleaseBufferSetLength(int nNewLength) { SetLength(nNewLength); } void Append(PCXSTR pszSrc); void Append(PCXSTR pszSrc, int nLength); void AppendChar(XCHAR ch); void Append(const CMSimpleStringT& strSrc); void Empty(); void FreeExtra(); PXSTR GetBuffer(); PXSTR GetBufferSetLength(int nLength); PXSTR LockBuffer(); void UnlockBuffer(); void ReleaseBuffer(int nNewLength = -1); void Truncate(int nNewLength); void SetAt(int iChar, XCHAR ch); void SetString(PCXSTR pszSrc); void SetString(PCXSTR pszSrc, int nLength); public: template friend CMSimpleStringT operator+(const CMSimpleStringT &str1, const CMSimpleStringT &str2); template friend CMSimpleStringT operator+(const CMSimpleStringT &str1, PCXSTR psz2); template friend CMSimpleStringT operator+(PCXSTR psz1, const CMSimpleStringT &str2); static void MIR_SYSCALL CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars); static void MIR_SYSCALL CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars); static void MIR_SYSCALL CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars); static void MIR_SYSCALL CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars); static int MIR_SYSCALL StringLength(const char* psz); static int MIR_SYSCALL StringLength(const wchar_t* psz); static int MIR_SYSCALL StringLengthN(const char* psz, size_t sizeInXChar); static int MIR_SYSCALL StringLengthN(const wchar_t* psz, size_t sizeInXChar); static void MIR_SYSCALL Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2); // Implementation private: __forceinline CMStringData* GetData() const { return (reinterpret_cast(m_pszData)-1); } void Attach(CMStringData* pData); void Fork(int nLength); PXSTR PrepareWrite(int nLength); void PrepareWrite2(int nLength); void Reallocate(int nLength); void SetLength(int nLength); static CMStringData* MIR_SYSCALL CloneData(CMStringData* pData); private: PXSTR m_pszData; }; template< typename _CharType = char > class ChTraitsCRT : public ChTraitsBase < _CharType > { public: static char* MIR_SYSCALL CharNext(const char *p) { #ifdef _MSC_VER return reinterpret_cast(_mbsinc(reinterpret_cast(p))); #else return reinterpret_cast(p+1); #endif } static int MIR_SYSCALL IsDigit(char ch) { #ifdef _MSC_VER return _ismbcdigit(ch); #else return isdigit(ch); #endif } static int MIR_SYSCALL IsSpace(char ch) { #ifdef _MSC_VER return _ismbcspace(ch); #else return isspace(ch); #endif } static int MIR_SYSCALL StringCompare(const char *pszA, const char *pszB) { #ifdef _MSC_VER return _mbscmp(reinterpret_cast(pszA), reinterpret_cast(pszB)); #else return strcmp(pszA, pszB); #endif } static int MIR_SYSCALL StringCompareIgnore(const char *pszA, const char *pszB) { #ifdef _MSC_VER return _mbsicmp(reinterpret_cast(pszA), reinterpret_cast(pszB)); #else return strcasecmp(pszA, pszB); #endif } static int MIR_SYSCALL StringCollate(const char *pszA, const char *pszB) { #ifdef _MSC_VER return _mbscoll(reinterpret_cast(pszA), reinterpret_cast(pszB)); #else return strcoll(pszA, pszB); #endif } static int MIR_SYSCALL StringCollateIgnore(const char *pszA, const char *pszB) { #ifdef _MSC_VER return _mbsicoll(reinterpret_cast(pszA), reinterpret_cast(pszB)); #else return strcoll(pszA, pszB); #endif } static const char* MIR_SYSCALL StringFindString(const char *pszBlock, const char *pszMatch) { #ifdef _MSC_VER return reinterpret_cast(_mbsstr(reinterpret_cast(pszBlock), reinterpret_cast(pszMatch))); #else return strstr(pszBlock, pszMatch); #endif } static char* MIR_SYSCALL StringFindString(char *pszBlock, const char *pszMatch) { return const_cast(StringFindString(const_cast(pszBlock), pszMatch)); } static const char* MIR_SYSCALL StringFindChar(const char *pszBlock, char chMatch) { #ifdef _MSC_VER return reinterpret_cast(_mbschr(reinterpret_cast(pszBlock), (unsigned char)chMatch)); #else return strchr(pszBlock, chMatch); #endif } static const char* MIR_SYSCALL StringFindCharRev(const char *psz, char ch) { #ifdef _MSC_VER return reinterpret_cast(_mbsrchr(reinterpret_cast(psz), (unsigned char)ch)); #else return strrchr(psz, ch); #endif } static const char* MIR_SYSCALL StringScanSet(const char *pszBlock, const char *pszMatch) { #ifdef _MSC_VER return reinterpret_cast(_mbspbrk(reinterpret_cast(pszBlock), reinterpret_cast(pszMatch))); #else return strpbrk(pszBlock, pszMatch); #endif } static int MIR_SYSCALL StringSpanIncluding(const char *pszBlock, const char *pszSet) { #ifdef _MSC_VER return (int)_mbsspn(reinterpret_cast(pszBlock), reinterpret_cast(pszSet)); #else return (int)strspn(pszBlock, pszSet); #endif } static int MIR_SYSCALL StringSpanExcluding(const char *pszBlock, const char *pszSet) { #ifdef _MSC_VER return (int)_mbscspn(reinterpret_cast(pszBlock), reinterpret_cast(pszSet)); #else return (int)strcspn(pszBlock, pszSet); #endif } static char* MIR_SYSCALL StringUppercase(char *psz) { #ifdef _MSC_VER CharUpperBuffA(psz, (uint32_t)strlen(psz)); #else strupr(psz); #endif return psz; } static char* MIR_SYSCALL StringLowercase(char *psz) { #ifdef _MSC_VER CharLowerBuffA(psz, (uint32_t)strlen(psz)); #else strlwr(psz); #endif return psz; } static char* MIR_SYSCALL StringUppercase(char *psz, size_t size) { #ifdef _MSC_VER CharUpperBuffA(psz, (uint32_t)size); #else #endif return psz; } static char* MIR_SYSCALL StringLowercase(char *psz, size_t size) { #ifdef _MSC_VER CharLowerBuffA(psz, (uint32_t)size); #endif return psz; } static char* MIR_SYSCALL StringReverse(char *psz) { #ifdef _MSC_VER return reinterpret_cast(_mbsrev(reinterpret_cast(psz))); #else return strrev(psz); #endif } static int MIR_SYSCALL GetFormattedLength(_Printf_format_string_ const char *pszFormat, va_list args) { #ifdef _MSC_VER return _vscprintf(pszFormat, args); #else return 0; // !!!!!!!!!! #endif } static int MIR_SYSCALL Format(char *pszBuffer, size_t nlength, _Printf_format_string_ const char *pszFormat, va_list args) { #ifdef _MSC_VER return vsprintf_s(pszBuffer, nlength, pszFormat, args); #else return 0; // !!!!!!!!!! #endif } static int MIR_SYSCALL GetBaseTypeLength(const char *pszSrc) { // Returns required buffer length in XCHARs return int(strlen(pszSrc)); } static int MIR_SYSCALL GetBaseTypeLength(const char *pszSrc, int nLength) { (void)pszSrc; // Returns required buffer length in XCHARs return nLength; } static int MIR_SYSCALL GetBaseTypeLength(const wchar_t *pszSource) { // Returns required buffer length in XCHARs #ifdef _MSC_VER return ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSource, -1, NULL, 0, NULL, NULL) - 1; #else return 0; #endif } static int MIR_SYSCALL GetBaseTypeLength(const wchar_t *pszSource, int nLength) { // Returns required buffer length in XCHARs #ifdef _MSC_VER return ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSource, nLength, NULL, 0, NULL, NULL); #else return 0; #endif } static void MIR_SYSCALL ConvertToBaseType(char*pszDest, int nDestLength, const char *pszSrc, int nSrcLength = -1) { if (nSrcLength == -1) { nSrcLength = 1 + GetBaseTypeLength(pszSrc); } // nLen is in XCHARs memcpy_s(pszDest, nDestLength*sizeof(char), pszSrc, nSrcLength*sizeof(char)); } static void MIR_SYSCALL ConvertToBaseType(char*pszDest, int nDestLength, const wchar_t *pszSrc, int nSrcLength = -1) { // nLen is in XCHARs #ifdef _MSC_VER ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL); #endif } static void ConvertToOem(_CharType* pstrString) { #ifdef _MSC_VER bool fSuccess = ::CharToOemA(pstrString, pstrString); #endif // _MSC_VER } static void ConvertToAnsi(_CharType* pstrString) { #ifdef _MSC_VER bool fSuccess = ::OemToCharA(pstrString, pstrString); #endif } static void ConvertToOem(_CharType* pstrString, size_t size) { #ifdef _MSC_VER uint32_t dwSize = static_cast(size); ::CharToOemBuffA(pstrString, pstrString, dwSize); #endif } static void ConvertToAnsi(_CharType* pstrString, size_t size) { #ifdef _MSC_VER uint32_t dwSize = static_cast(size); ::OemToCharBuffA(pstrString, pstrString, dwSize); #endif } static void MIR_SYSCALL FloodCharacters(char ch, int nLength, char* pch) { // nLength is in XCHARs memset(pch, ch, nLength); } static int MIR_SYSCALL SafeStringLen(const char *psz) { // returns length in bytes return (psz != NULL) ? int(strlen(psz)) : 0; } static int MIR_SYSCALL SafeStringLen(const wchar_t *psz) { // returns length in wchar_ts return (psz != NULL) ? int(wcslen(psz)) : 0; } static int MIR_SYSCALL GetCharLen(const wchar_t *pch) { // returns char length return 1; } static int MIR_SYSCALL GetCharLen(const char *pch) { // returns char length #ifdef _MSC_VER return int(_mbclen(reinterpret_cast(pch))); #else return mblen(pch, strlen(pch)); #endif } static uint32_t MIR_SYSCALL GetEnvironmentVariable(const char *pszVar, char*pszBuffer, uint32_t dwSize) { #ifdef _MSC_VER return ::GetEnvironmentVariableA(pszVar, pszBuffer, dwSize); #else return 0; // !!!!!!!!!! #endif } static char* MirCopy(const char *pstrString, size_t size) { return mir_strndup(pstrString, size); } }; // specialization for wchar_t template<> class ChTraitsCRT< wchar_t > : public ChTraitsBase< wchar_t > { static uint32_t MIR_SYSCALL _GetEnvironmentVariableW(const wchar_t *pszName, wchar_t *pszBuffer, uint32_t nSize) { #ifdef _MSC_VER return ::GetEnvironmentVariableW(pszName, pszBuffer, nSize); #else return 0; // !!!!!!!!!! #endif } public: static wchar_t* MIR_SYSCALL CharNext(const wchar_t *psz) { return const_cast(psz+1); } static int MIR_SYSCALL IsDigit(wchar_t ch) { #ifdef _MSC_VER return iswdigit(static_cast(ch)); #else return 0; #endif } static int MIR_SYSCALL IsSpace(wchar_t ch) { #ifdef _MSC_VER return iswspace(static_cast(ch)); #else return 0; #endif } static int MIR_SYSCALL StringCompare(const wchar_t *pszA, const wchar_t *pszB) { return wcscmp(pszA, pszB); } static int MIR_SYSCALL StringCompareIgnore(const wchar_t *pszA, const wchar_t *pszB) { #ifdef _MSC_VER return _wcsicmp(pszA, pszB); #else return 0; #endif } static int MIR_SYSCALL StringCollate(const wchar_t *pszA, const wchar_t *pszB) { return wcscoll(pszA, pszB); } static int MIR_SYSCALL StringCollateIgnore(const wchar_t *pszA, const wchar_t *pszB) { #ifdef _MSC_VER return _wcsicoll(pszA, pszB); #else return 0; #endif } static const wchar_t* MIR_SYSCALL StringFindString(const wchar_t *pszBlock, const wchar_t *pszMatch) { return wcsstr(pszBlock, pszMatch); } static wchar_t* MIR_SYSCALL StringFindString(wchar_t *pszBlock, const wchar_t *pszMatch) { return const_cast(wcsstr(pszBlock, pszMatch)); } static const wchar_t* MIR_SYSCALL StringFindChar(const wchar_t *pszBlock, wchar_t chMatch) { return wcschr(pszBlock, chMatch); } static const wchar_t* MIR_SYSCALL StringFindCharRev(const wchar_t *psz, wchar_t ch) { return wcsrchr(psz, ch); } static const wchar_t* MIR_SYSCALL StringScanSet(const wchar_t *pszBlock, const wchar_t *pszMatch) { return wcspbrk(pszBlock, pszMatch); } static int MIR_SYSCALL StringSpanIncluding(const wchar_t *pszBlock, const wchar_t *pszSet) { return (int)wcsspn(pszBlock, pszSet); } static int MIR_SYSCALL StringSpanExcluding(const wchar_t *pszBlock, const wchar_t *pszSet) { return (int)wcscspn(pszBlock, pszSet); } static wchar_t* MIR_SYSCALL StringUppercase(wchar_t *psz) { #ifdef _MSC_VER CharUpperBuffW(psz, (uint32_t)wcslen(psz)); #endif return psz; } static wchar_t* MIR_SYSCALL StringLowercase(wchar_t *psz) { #ifdef _MSC_VER CharLowerBuffW(psz, (uint32_t)wcslen(psz)); #endif return psz; } static wchar_t* MIR_SYSCALL StringUppercase(wchar_t *psz, size_t len) { #ifdef _MSC_VER CharUpperBuffW(psz, (uint32_t)len); #endif return psz; } static wchar_t* MIR_SYSCALL StringLowercase(wchar_t *psz, size_t len) { #ifdef _MSC_VER CharLowerBuffW(psz, (uint32_t)len); #endif return psz; } static wchar_t* MIR_SYSCALL StringReverse(wchar_t *psz) { #ifdef _MSC_VER return _wcsrev(psz); #else return psz; #endif } static int MIR_SYSCALL GetFormattedLength(_Printf_format_string_ const wchar_t *pszFormat, va_list args) { #ifdef _MSC_VER return _vscwprintf(pszFormat, args); #else return 0; #endif } static int MIR_SYSCALL Format(wchar_t *pszBuffer, _Printf_format_string_ const wchar_t *pszFormat, va_list args) { #pragma warning(push) #pragma warning(disable : 4996) #ifdef _MSC_VER return vswprintf(pszBuffer, pszFormat, args); #else return 0; #endif #pragma warning(pop) } static int MIR_SYSCALL Format(wchar_t *pszBuffer, size_t nLength, _Printf_format_string_ const wchar_t *pszFormat, va_list args) { #pragma warning(push) #pragma warning(disable : 4996) #ifdef _MSC_VER return _vsnwprintf(pszBuffer, nLength, pszFormat, args); #else return 0; #endif #pragma warning(pop) } static int MIR_SYSCALL GetBaseTypeLength(const char *pszSrc) { // Returns required buffer size in wchar_ts #ifdef _MSC_VER return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, nullptr, 0)-1; #else return 0; #endif } static int MIR_SYSCALL GetBaseTypeLength(const char *pszSrc, int nLength) { // Returns required buffer size in wchar_ts #ifdef _MSC_VER return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, nLength, nullptr, 0); #else return 0; #endif } static int MIR_SYSCALL GetBaseTypeLength(const wchar_t *pszSrc) { // Returns required buffer size in wchar_ts return (int)wcslen(pszSrc); } static int MIR_SYSCALL GetBaseTypeLength(const wchar_t *pszSrc, int nLength) { (void)pszSrc; // Returns required buffer size in wchar_ts return nLength; } static void MIR_SYSCALL ConvertToBaseType(wchar_t *pszDest, int nDestLength, const char *pszSrc, int nSrcLength = -1) { // nLen is in wchar_ts #ifdef _MSC_VER ::MultiByteToWideChar(CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength); #endif } static void MIR_SYSCALL ConvertToBaseType(wchar_t *pszDest, int nDestLength, const wchar_t *pszSrc, int nSrcLength = -1) { if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } // nLen is in wchar_ts #if _MSC_VER >= 1400 wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength); #else wmemcpy(pszDest, pszSrc, nDestLength); #endif } static void MIR_SYSCALL FloodCharacters(wchar_t ch, int nLength, wchar_t *psz) { // nLength is in XCHARs for (int i = 0; i < nLength; i++) { psz[i] = ch; } } static int MIR_SYSCALL SafeStringLen(const char *psz) { // returns length in bytes return (psz != nullptr) ? (int)strlen(psz) : 0; } static int MIR_SYSCALL SafeStringLen(const wchar_t *psz) { // returns length in wchar_ts return (psz != nullptr) ? (int)wcslen(psz) : 0; } static int MIR_SYSCALL GetCharLen(const wchar_t* pch) { (void)pch; // returns char length return 1; } static int MIR_SYSCALL GetCharLen(const char* pch) { // returns char length #ifdef _MSC_VER return (int)(_mbclen(reinterpret_cast< const unsigned char* >(pch))); #else return mblen(pch, strlen(pch)); #endif } static uint32_t MIR_SYSCALL GetEnvironmentVariable(const wchar_t *pszVar, wchar_t *pszBuffer, uint32_t dwSize) { return _GetEnvironmentVariableW(pszVar, pszBuffer, dwSize); } static void MIR_SYSCALL ConvertToOem(wchar_t* /*psz*/) { } static void MIR_SYSCALL ConvertToAnsi(wchar_t* /*psz*/) { } static void MIR_SYSCALL ConvertToOem(wchar_t* /*psz*/, size_t) { } static void MIR_SYSCALL ConvertToAnsi(wchar_t* /*psz*/, size_t) { } static wchar_t* MirCopy(const wchar_t *pstrString, size_t size) { return mir_wstrndup(pstrString, size); } }; template< typename BaseType, class StringTraits > class MIR_CORE_EXPORT CMStringT : public CMSimpleStringT< BaseType > { public: typedef CMSimpleStringT< BaseType> CThisSimpleString; typedef typename CThisSimpleString::XCHAR XCHAR; typedef typename CThisSimpleString::PXSTR PXSTR; typedef typename CThisSimpleString::PCXSTR PCXSTR; typedef typename CThisSimpleString::YCHAR YCHAR; typedef typename CThisSimpleString::PYSTR PYSTR; typedef typename CThisSimpleString::PCYSTR PCYSTR; public: CMStringT(); // Copy constructor CMStringT(const CMStringT& strSrc); CMStringT(const XCHAR* pszSrc); CMStringT(CMStringDataFormat, _Printf_format_string_ const XCHAR* pszFormat, ...); CMStringT(const YCHAR* pszSrc); CMStringT(const unsigned char* pszSrc); CMStringT(char ch, int nLength = 1); CMStringT(wchar_t ch, int nLength = 1); CMStringT(const XCHAR* pch, int nLength); CMStringT(const YCHAR* pch, int nLength); // Destructor ~CMStringT(); // Assignment operators CMStringT& operator=(const CMStringT& strSrc); CMStringT& operator=(PCXSTR pszSrc); CMStringT& operator=(PCYSTR pszSrc); CMStringT& operator=(const unsigned char* pszSrc); CMStringT& operator=(char ch); CMStringT& operator=(wchar_t ch); CMStringT& operator+=(const CMStringT& str); CMStringT& operator+=(const CThisSimpleString& str); CMStringT& operator+=(PCXSTR pszSrc); CMStringT& operator+=(PCYSTR pszSrc); CMStringT& operator+=(char ch); CMStringT& operator+=(unsigned char ch); CMStringT& operator+=(wchar_t ch); // Comparison int Compare(PCXSTR psz) const; int CompareNoCase(PCXSTR psz) const; int Collate(PCXSTR psz) const; int CollateNoCase(PCXSTR psz) const; // Advanced manipulation // Delete 'nCount' characters, starting at index 'iIndex' int Delete(int iIndex, int nCount = 1); // Insert character 'ch' before index 'iIndex' int Insert(int iIndex, XCHAR ch); // Insert string 'psz' before index 'iIndex' int Insert(int iIndex, PCXSTR psz); // Replace all occurrences of character 'chOld' with character 'chNew' int Replace(XCHAR chOld, XCHAR chNew); // Replace all occurrences of string 'pszOld' with string 'pszNew' int Replace(PCXSTR pszOld, PCXSTR pszNew); // Remove all occurrences of character 'chRemove' int Remove(XCHAR chRemove); CMStringT Tokenize(PCXSTR pszTokens, int& iStart) const; // find routines // Find the first occurrence of character 'ch', starting at index 'iStart' int Find(XCHAR ch, int iStart = 0) const; // look for a specific sub-string // Find the first occurrence of string 'pszSub', starting at index 'iStart' int Find(PCXSTR pszSub, int iStart = 0) const; // Find the first occurrence of any of the characters in string 'pszCharSet' int FindOneOf(PCXSTR pszCharSet) const; // Find the last occurrence of character 'ch' int ReverseFind(XCHAR ch) const; // manipulation // Convert the string to uppercase CMStringT& MakeUpper(); // Convert the string to lowercase CMStringT& MakeLower(); // Reverse the string CMStringT& MakeReverse(); // trimming // Remove all trailing whitespace CMStringT& TrimRight(); // Remove all leading whitespace CMStringT& TrimLeft(); // Remove all leading and trailing whitespace CMStringT& Trim(); // Remove all leading and trailing occurrences of character 'chTarget' CMStringT& Trim(XCHAR chTarget); // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' CMStringT& Trim(PCXSTR pszTargets); // trimming anything (either side) // Remove all trailing occurrences of character 'chTarget' CMStringT& TrimRight(XCHAR chTarget); // Remove all trailing occurrences of any of the characters in string 'pszTargets' CMStringT& TrimRight(PCXSTR pszTargets); // Remove all leading occurrences of character 'chTarget' CMStringT& TrimLeft(XCHAR chTarget); // Remove all leading occurrences of any of the characters in string 'pszTargets' CMStringT& TrimLeft(PCXSTR pszTargets); // Convert the string to the OEM character set void AnsiToOem(); // Convert the string to the ANSI character set void OemToAnsi(); // Very simple sub-string extraction // Return the substring starting at index 'iFirst' CMStringT Mid(int iFirst) const; // Return the substring starting at index 'iFirst', with length 'nCount' CMStringT Mid(int iFirst, int nCount) const; // Return the substring consisting of the rightmost 'nCount' characters CMStringT Right(int nCount) const; // Return the substring consisting of the leftmost 'nCount' characters CMStringT Left(int nCount) const; // Return the substring consisting of the leftmost characters in the set 'pszCharSet' CMStringT SpanIncluding(PCXSTR pszCharSet) const; // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' CMStringT SpanExcluding(PCXSTR pszCharSet) const; // Format data using format string 'pszFormat' PCXSTR Format(PCXSTR _Printf_format_string_ pszFormat, ...); PCXSTR FormatV(PCXSTR _Printf_format_string_ pszFormat, va_list args); // Append formatted data using format string 'pszFormat' PCXSTR AppendFormat(PCXSTR _Printf_format_string_ pszFormat, ...); void AppendFormatV(PCXSTR _Printf_format_string_ pszFormat, va_list args); // return a copy of string to be freed by mir_free() PXSTR Detach() const; // Set the string to the value of environment variable 'pszVar' BOOL GetEnvironmentVariable(PCXSTR pszVar); friend bool __forceinline operator==(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) == 0; } friend bool __forceinline operator==(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) == 0; } friend bool __forceinline operator==(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) == 0; } friend bool __forceinline operator==(const CMStringT& str1, PCYSTR psz2) { return str1 == CMStringT(psz2); } friend bool __forceinline operator==(PCYSTR psz1, const CMStringT& str2) { return CMStringT(psz1) == str2; } friend bool __forceinline operator!=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) != 0; } friend bool __forceinline operator!=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) != 0; } friend bool __forceinline operator!=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) != 0; } friend bool __forceinline operator!=(const CMStringT& str1, PCYSTR psz2) { return str1 != CMStringT(psz2); } friend bool __forceinline operator!=(PCYSTR psz1, const CMStringT& str2) { return CMStringT(psz1) != str2; } friend bool __forceinline operator<(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) < 0; } friend bool __forceinline operator<(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) < 0; } friend bool __forceinline operator<(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) > 0; } friend bool __forceinline operator>(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) > 0; } friend bool __forceinline operator>(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) > 0; } friend bool __forceinline operator>(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) < 0; } friend bool __forceinline operator<=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) <= 0; } friend bool __forceinline operator<=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) <= 0; } friend bool __forceinline operator<=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) >= 0; } friend bool __forceinline operator>=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) >= 0; } friend bool __forceinline operator>=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) >= 0; } friend bool __forceinline operator>=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) <= 0; } friend bool __forceinline operator==(XCHAR ch1, const CMStringT& str2) { return (str2.GetLength() == 1) && (str2[0] == ch1); } friend bool __forceinline operator==(const CMStringT& str1, XCHAR ch2) { return (str1.GetLength() == 1) && (str1[0] == ch2); } friend bool __forceinline operator!=(XCHAR ch1, const CMStringT& str2) { return (str2.GetLength() != 1) || (str2[0] != ch1); } friend bool __forceinline operator!=(const CMStringT& str1, XCHAR ch2) { return (str1.GetLength() != 1) || (str1[0] != ch2); } }; template< typename BaseType, class StringTraits > MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, const CMStringT& str2); template< typename BaseType, class StringTraits > MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, typename CMStringT::PCXSTR psz2); template< typename BaseType, class StringTraits > MIR_CORE_EXPORT CMStringT CALLBACK operator+(typename CMStringT::PCXSTR psz1, const CMStringT& str2); template< typename BaseType, class StringTraits > MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, wchar_t ch2); template< typename BaseType, class StringTraits > MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, char ch2); template< typename BaseType, class StringTraits > MIR_CORE_EXPORT CMStringT CALLBACK operator + (wchar_t ch1, const CMStringT& str2); template< typename BaseType, class StringTraits > MIR_CORE_EXPORT CMStringT CALLBACK operator+(char ch1, const CMStringT& str2); typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; #endif // M_STRING_H__