从ATL整理的CString代码 可以用于其他项目
#pragma once
#include <assert.h>
#include <mbstring.h>
#include <atlexcept.h>
#define IN_OPT
#define IN_OUT
#ifndef MYATLENSURE_RETURN_VAL
#define MYATLENSURE_RETURN_VAL(expr, val) \
do { \
int __atl_condVal=!!(expr); \
assert(__atl_condVal); \
if(!(__atl_condVal)) return val; \
} __pragma(warning(suppress:4127)) while (0)
#endif // MYATLENSURE_RETURN_VAL
//向上对齐;下面使用时都是按8字节向上对齐的,两个位运算,第一个是可能带有进位的加法(+nAlign - 1)另一个是抹掉低log2(nAlign)位
//0->0 1->8 2->8 ... 8->8 9->16...
template< typename N >
inline N MyAlignUp(IN N n, IN ULONG nAlign) throw()
{
return(N( (n + (nAlign - 1)) & ~(N(nAlign) - 1) ));
}
//带有运算范围溢出检测的加法
template<typename T>
inline HRESULT MyAtlAdd(_Out_ T* ptResult, IN T tLeft, IN T tRight)
{
if(::ATL::AtlLimits<T>::_Max - tLeft < tRight)
{
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
}
*ptResult = tLeft + tRight;
return S_OK;
}
//带有运算范围溢出检测的乘法
template<typename T>
inline HRESULT MyAtlMultiply(_Out_ T* ptResult, IN T tLeft, IN T tRight)
{
/* avoid divide 0 */
if(tLeft == 0)
{
*ptResult = 0;
return S_OK;
}
if(::ATL::AtlLimits<T>::_Max / tLeft < tRight)
{
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
}
*ptResult = tLeft * tRight;
return S_OK;
}
inline HRESULT MyAtlMultiply(_Out_ unsigned long *piResult, IN unsigned long iLeft, IN unsigned long iRight)
{
unsigned __int64 i64Result = static_cast<unsigned __int64>(iLeft) * static_cast<unsigned __int64>(iRight);
if(i64Result > ULONG_MAX)
{
return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
}
*piResult = static_cast<unsigned long>(i64Result);
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// Verify that a null-terminated string points to valid memory
inline BOOL MyAtlIsValidString(
_In_reads_z_(nMaxLength) LPCWSTR psz,
_In_ size_t nMaxLength = INT_MAX)
{
(nMaxLength);
return (psz != NULL);
}
// Verify that a null-terminated string points to valid memory
inline BOOL MyAtlIsValidString(
_In_reads_z_(nMaxLength) LPCSTR psz,
_In_ size_t nMaxLength = UINT_MAX)
{
(nMaxLength);
return (psz != NULL);
}
/***********************************************************************************
*
* 为了避免编译器的bug,自己实现一个CString,从ATL扒代码,简化了一些
*
*************************************************************************************/
struct MyCStringData;//CString 数据指向CStringData* +1处,CStringData用于实现字符串引用数管理
__interface IMyStrMgr
{
public:
MyCStringData * Allocate(IN int nAllocLength, IN int nCharSize) throw(); // Allocate a new MyCStringData
void Free(IN_OUT MyCStringData * pData) throw();// Free an existing MyCStringData
MyCStringData * Reallocate(IN_OUT MyCStringData * pData, IN int nAllocLength, IN int nCharSize) throw(); // Change the size of an existing MyCStringData
MyCStringData * GetNilString() throw(); // Get the MyCStringData for a Nil string
IMyStrMgr * Clone() throw();
};
struct MyCStringData
{
IMyStrMgr* pStringMgr; // String manager for this MyCStringData
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)
/**/volatile long nRefs; // Reference count: negative == locked(原著中没有volatile)
// XCHAR data[nAllocLength+1]// A MyCStringData is always followed in memory by the actual array of character data
void* data() throw()
{
return (this + 1);
}
void AddRef() throw()
{
assert(nRefs > 0);
InterlockedIncrement(&nRefs);
}
bool IsLocked() const throw()
{
return nRefs < 0;
}
bool IsShared() const throw()
{
return(nRefs > 1);
}
void Lock() throw()
{
assert(nRefs <= 1);
nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary
if(nRefs == 0)
{
nRefs = -1;
}
}
void Release() throw()
{
assert(nRefs != 0);
if(InterlockedDecrement(&nRefs) <= 0)
{
pStringMgr->Free(this);
}
}
void Unlock() throw()
{
assert(IsLocked());
if(IsLocked())
{
nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary
if(nRefs == 0)
{
nRefs = 1;
}
}
}
};
//空的CString都指向一个公共的CStringData(在mgr中的static变量)
class MyNilStringData : public MyCStringData
{
public:
MyNilStringData() throw()
{
pStringMgr = NULL;
nRefs = 2; // Never gets freed by IAtlStringMgr(微软用这种办法避免进行指针的判断,是优化的方法,但也是此篇代码解决问题的由来)
nDataLength = 0;
nAllocLength = 0;
achNil[0] = 0;
achNil[1] = 0;
}
void SetManager(IN IMyStrMgr* pMgr) throw()
{
assert(pStringMgr == NULL);
pStringMgr = pMgr;
}
public:
wchar_t achNil[2];
};
class MyWin32Heap//分配回收采用Heap
{
public:
HANDLE m_hHeap;
bool m_bOwnHeap;
public:
MyWin32Heap(IN HANDLE hHeap) throw() :
m_hHeap(hHeap),
m_bOwnHeap(false)
{
assert(hHeap != NULL);
}
void Attach(IN HANDLE hHeap, IN bool bTakeOwnership) throw()
{
assert(hHeap != NULL);
assert(m_hHeap == NULL);
m_hHeap = hHeap;
m_bOwnHeap = bTakeOwnership;
}
HANDLE Detach() throw()
{
HANDLE hHeap;
hHeap = m_hHeap;
m_hHeap = NULL;
m_bOwnHeap = false;
return(hHeap);
}
void* Allocate(IN size_t nBytes) throw()
{
return(::HeapAlloc(m_hHeap, 0, nBytes));
}
virtual void Free(IN_OPT void* p) throw()
{
if(p != NULL)
{
BOOL bSuccess;
bSuccess = ::HeapFree(m_hHeap, 0, p);
assert(bSuccess);
}
}
void* Reallocate(IN_OPT void* p, IN size_t nBytes) throw()
{
if(p == NULL)
{
return(Allocate(nBytes));
}
if(nBytes == 0)
{
Free(p);
return NULL;
}
return(::HeapReAlloc(m_hHeap, 0, p, nBytes));
}
virtual size_t GetSize(IN_OUT void* p) throw()
{
return(::HeapSize(m_hHeap, 0, p));
}
};
class MyStrMgr : public IMyStrMgr
{
public:
MyStrMgr(IN_OPT MyWin32Heap* pMemMgr = NULL) throw() :
m_pMemMgr(pMemMgr)
{
m_nil.SetManager(this);
}
virtual ~MyStrMgr() throw() = default;
void SetMemoryManager(IN MyWin32Heap* pMemMgr) throw()
{
assert(m_pMemMgr == NULL);
m_pMemMgr = pMemMgr;
}
static IMyStrMgr* GetInstance()//获取管理器,内部2个静态对象
{
//#pragma warning(push)
//#pragma warning(disable: 4640) // will always be initialized on entry thread by CImageStaticInitializer
static MyWin32Heap strHeap(::GetProcessHeap());
static MyStrMgr strMgr(&strHeap);
//#pragma warning(pop)
return &strMgr;
}
// IMyStrMgr
public:
virtual MyCStringData* Allocate(IN int nChars, IN int nCharSize) throw()
{
//nChars 字符数;nCharSize 字符占的字节数
if(!(nChars >= 0))
return NULL;
size_t nTotalSize;//包含StringData的总分配字节
MyCStringData* pData;
size_t nDataBytes;//应分配给字符串的字节数
if(FAILED(MyAtlAdd(&nChars, nChars, 1)))
{
return NULL;
}
int nAlignedChars = MyAlignUp(nChars, 8); // Prevent excessive reallocation. The heap will usually round up anyway.
if(!(nChars <= nAlignedChars))
{
return NULL;//MYATLENSURE_RETURN_VAL(nChars <= nAlignedChars, NULL);
}
if(FAILED(MyAtlMultiply(&nDataBytes, static_cast<size_t>(nAlignedChars), static_cast<size_t>(nCharSize))) ||
FAILED(MyAtlAdd(&nTotalSize, static_cast<size_t>(sizeof(MyCStringData)), nDataBytes)))
{
return NULL;
}
pData = static_cast<MyCStringData*>(m_pMemMgr->Allocate(nTotalSize));
if(pData == NULL)
{
return(NULL);
}
//分配后设置StringData的内容
pData->pStringMgr = this;
pData->nRefs = 1;
pData->nAllocLength = nAlignedChars - 1;//由于上面+1,这里-1 ,应该是防止可能的越界问题
pData->nDataLength = 0;
return(pData);
}
virtual void Free(IN MyCStringData* pData) throw()
{
assert(pData != NULL);
assert(pData->pStringMgr == this);
m_pMemMgr->Free(pData);
}
virtual MyCStringData* Reallocate(IN_OUT MyCStringData* pData, IN int nChars, IN int nCharSize) throw()
{
MYATLENSURE_RETURN_VAL(nChars >= 0, NULL);
assert(pData->pStringMgr == this);
MyCStringData* pNewData;
ULONG nTotalSize;
ULONG nDataBytes;
if(FAILED(MyAtlAdd(&nChars, nChars, 1)))
{
return NULL;
}
int nAlignedChars = MyAlignUp(nChars, 8); // Prevent excessive reallocation. The heap will usually round up anyway.
MYATLENSURE_RETURN_VAL(nChars <= nAlignedChars, NULL);
if(FAILED(MyAtlMultiply(&nDataBytes, static_cast<ULONG>(nAlignedChars), static_cast<ULONG>(nCharSize))) ||
FAILED(MyAtlAdd(&nTotalSize, static_cast<ULONG>(sizeof(MyCStringData)), nDataBytes)))
{
return NULL;
}
pNewData = static_cast<MyCStringData*>(m_pMemMgr->Reallocate(pData, nTotalSize));
if(pNewData == NULL)
{
return NULL;
}
pNewData->nAllocLength = nAlignedChars - 1;
return pNewData;
}
virtual MyCStringData* GetNilString() throw()
{
//GetNilString 返回一个空字符串,用于CString 的默认初始化,通过返回共享的StringData并增加1个引用数,优化性能
m_nil.AddRef();
return &m_nil;
}
virtual IMyStrMgr* Clone() throw()
{
return this;//记住这个Clone函数干甚么了
}
protected:
MyWin32Heap* m_pMemMgr;
MyNilStringData m_nil;
};
//MyStaticString 应该是对静态字符串常量的封装,目前没有用过,需要几个宏来配合(原著中有)
template< typename BaseType, const int t_nSize >
class MyStaticString
{
public:
MyStaticString(_In_z_ const BaseType* psz) : m_psz(psz)
{
}
operator const BaseType*() const
{
return m_psz;
}
static int __cdecl GetLength()
{
return (t_nSize / sizeof(BaseType)) - 1;
}
private:
const BaseType* m_psz;
private:
MyStaticString(IN const MyStaticString& str) throw();
MyStaticString& operator=(IN const MyStaticString& str) throw();
};
//MyChTraitsBase 是对字符类型的封装,提供XCHAR 和YCHAR X-Y 是宽窄字符的相对关系,当支持宽窄转换时 就是从X-Y的转换
template< typename BaseType = char >
class MyChTraitsBase
{
public:
typedef char XCHAR;
typedef LPSTR PXSTR;
typedef LPCSTR PCXSTR;
typedef wchar_t YCHAR;
typedef LPWSTR PYSTR;
typedef LPCWSTR PCYSTR;
};
template<>
class MyChTraitsBase< 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 MyCSimpleStringT
{
public:
typedef typename MyChTraitsBase< BaseType >::XCHAR XCHAR;
typedef typename MyChTraitsBase< BaseType >::PXSTR PXSTR;
typedef typename MyChTraitsBase< BaseType >::PCXSTR PCXSTR;
typedef typename MyChTraitsBase< BaseType >::YCHAR YCHAR;
typedef typename MyChTraitsBase< BaseType >::PYSTR PYSTR;
typedef typename MyChTraitsBase< BaseType >::PCYSTR PCYSTR;
public:
explicit MyCSimpleStringT(IN_OUT IMyStrMgr* pStringMgr)
{
//默认构造 data指向NilString
ATLENSURE(pStringMgr != NULL);
MyCStringData* pData = pStringMgr->GetNilString();
Attach(pData);
}
MyCSimpleStringT(IN const MyCSimpleStringT& strSrc)
{
//拷贝构造 克隆srcData CloneData 内有点逻辑
MyCStringData* pSrcData = strSrc.GetData();
MyCStringData* pNewData = CloneData(pSrcData);
Attach(pNewData);
}
MyCSimpleStringT(_In_z_ PCXSTR pszSrc, IN_OUT IMyStrMgr* pStringMgr)
{
ATLENSURE(pStringMgr != NULL);
int nLength = StringLength(pszSrc);
MyCStringData* pData = pStringMgr->Allocate(nLength, sizeof(XCHAR));
if(pData == NULL)
{
ThrowMemoryException();
}
Attach(pData);
SetLength(nLength);
CopyChars(m_pszData, nLength, pszSrc, nLength);
}
MyCSimpleStringT(_In_reads_(nLength) const XCHAR* pchSrc, IN int nLength, IN_OUT IMyStrMgr* pStringMgr)
{
ATLENSURE(pStringMgr != NULL);
if(pchSrc == NULL && nLength != 0)
AtlThrow(E_INVALIDARG);
MyCStringData* pData = pStringMgr->Allocate(nLength, sizeof(XCHAR));
if(pData == NULL)
{
ThrowMemoryException();
}
Attach(pData);
SetLength(nLength);
CopyChars(m_pszData, nLength, pchSrc, nLength);
}
~MyCSimpleStringT() throw()
{
MyCStringData* pData = GetData();
pData->Release();
}
operator MyCSimpleStringT < BaseType > &()
{
return *(MyCSimpleStringT < BaseType > *)this;
}
MyCSimpleStringT& operator=(IN const MyCSimpleStringT& strSrc)
{
MyCStringData* pSrcData = strSrc.GetData();
MyCStringData* pOldData = GetData();
if(pSrcData != pOldData)
{
if(pOldData->IsLocked() || pSrcData->pStringMgr != pOldData->pStringMgr)
{
SetString(strSrc.GetString(), strSrc.GetLength());
}
else
{
MyCStringData* pNewData = CloneData(pSrcData);
pOldData->Release();
Attach(pNewData);
}
}
return(*this);
}
MyCSimpleStringT& operator=(_In_opt_z_ PCXSTR pszSrc)
{
SetString(pszSrc);
return(*this);
}
MyCSimpleStringT& operator+=(IN const MyCSimpleStringT& strSrc)
{
Append(strSrc);
return(*this);
}
MyCSimpleStringT& operator+=(_In_z_ PCXSTR pszSrc)
{
Append(pszSrc);
return(*this);
}
template< int t_nSize >
MyCSimpleStringT& operator+=(IN const MyStaticString< XCHAR, t_nSize >& strSrc)
{
Append(static_cast<const XCHAR *>(strSrc), strSrc.GetLength());
return(*this);
}
MyCSimpleStringT& operator+=(IN char ch)
{
AppendChar(XCHAR(ch));
return(*this);
}
MyCSimpleStringT& operator+=(IN unsigned char ch)
{
AppendChar(XCHAR(ch));
return(*this);
}
MyCSimpleStringT& operator+=(IN wchar_t ch)
{
AppendChar(XCHAR(ch));
return(*this);
}
XCHAR operator[](IN int iChar) const
{
assert((iChar >= 0) && (iChar <= GetLength())); // Indexing the '\0' is OK
if((iChar < 0) || (iChar > GetLength()))
AtlThrow(E_INVALIDARG);
return(m_pszData[iChar]);
}
operator PCXSTR() const throw()
{
return(m_pszData);
}
void Append(_In_z_ PCXSTR pszSrc)
{
Append(pszSrc, StringLength(pszSrc));
}
void Append(_In_reads_(nLength) PCXSTR pszSrc, IN int nLength)
{
// See comment in SetString() about why we do this
UINT_PTR nOffset = pszSrc - GetString();
UINT nOldLength = GetLength();
if(nOldLength < 0)
{
// protects from underflow
nOldLength = 0;
}
//Make sure the nLength is greater than zero
ATLENSURE_THROW(nLength >= 0, E_INVALIDARG);
//Make sure we don't read pass end of the terminating NULL
nLength = StringLengthN(pszSrc, nLength);
//Make sure after the string doesn't exceed INT_MAX after appending
ATLENSURE_THROW(INT_MAX - nLength >= static_cast<int>(nOldLength), E_INVALIDARG);
int nNewLength = nOldLength + nLength;
PXSTR pszBuffer = GetBuffer(nNewLength);
if(nOffset <= nOldLength)
{
pszSrc = pszBuffer + nOffset;
// No need to call CopyCharsOverlapped, since the destination is
// beyond the end of the original buffer
}
CopyChars(pszBuffer + nOldLength, nLength, pszSrc, nLength);
ReleaseBufferSetLength(nNewLength);
}
void AppendChar(IN XCHAR ch)
{
UINT nOldLength = GetLength();
int nNewLength = nOldLength + 1;
PXSTR pszBuffer = GetBuffer(nNewLength);
pszBuffer[nOldLength] = ch;
ReleaseBufferSetLength(nNewLength);
}
void Append(IN const MyCSimpleStringT& strSrc)
{
Append(strSrc.GetString(), strSrc.GetLength());
}
void Empty() throw()
{
MyCStringData* pOldData = GetData();
IMyStrMgr* pStringMgr = pOldData->pStringMgr;
if(pOldData->nDataLength == 0)
{
return;
}
if(pOldData->IsLocked())
{
// Don't reallocate a locked buffer that's shrinking
SetLength(0);
}
else
{
pOldData->Release();
MyCStringData* pNewData = pStringMgr->GetNilString();
Attach(pNewData);
}
}
void FreeExtra()
{
MyCStringData* pOldData = GetData();
int nLength = pOldData->nDataLength;
IMyStrMgr* pStringMgr = pOldData->pStringMgr;
if(pOldData->nAllocLength == nLength)
{
return;
}
if(!pOldData->IsLocked()) // Don't reallocate a locked buffer that's shrinking
{
MyCStringData* pNewData = pStringMgr->Allocate(nLength, sizeof(XCHAR));
if(pNewData == NULL)
{
SetLength(nLength);
return;
}
CopyChars(PXSTR(pNewData->data()), nLength,
PCXSTR(pOldData->data()), nLength);
pOldData->Release();
Attach(pNewData);
SetLength(nLength);
}
}
int GetAllocLength() const throw()
{
return(GetData()->nAllocLength);
}
XCHAR GetAt(IN int iChar) const
{
assert((iChar >= 0) && (iChar <= GetLength())); // Indexing the '\0' is OK
if((iChar < 0) || (iChar > GetLength()))
AtlThrow(E_INVALIDARG);
return(m_pszData[iChar]);
}
PXSTR GetBuffer()
{
MyCStringData* pData = GetData();
if(pData->IsShared())
{
Fork(pData->nDataLength);
}
return(m_pszData);
}
_Ret_notnull_ _Post_writable_size_(nMinBufferLength + 1) PXSTR GetBuffer(IN int nMinBufferLength)
{
return(PrepareWrite(nMinBufferLength));
}
_Ret_notnull_ _Post_writable_size_(nLength + 1) PXSTR GetBufferSetLength(IN int nLength)
{
PXSTR pszBuffer = GetBuffer(nLength);
SetLength(nLength);
return(pszBuffer);
}
int GetLength() const throw()
{
return(GetData()->nDataLength);
}
IMyStrMgr* GetManager() const throw()
{
IMyStrMgr* pStringMgr = GetData()->pStringMgr;
return pStringMgr ? pStringMgr->Clone() : NULL;
}
PCXSTR GetString() const throw()
{
return(m_pszData);
}
bool IsEmpty() const throw()
{
return(GetLength() == 0);
}
PXSTR LockBuffer()
{
MyCStringData* pData = GetData();
if(pData->IsShared())
{
Fork(pData->nDataLength);
pData = GetData(); // Do it again, because the fork might have changed it
}
pData->Lock();
return(m_pszData);
}
void UnlockBuffer() throw()
{
MyCStringData* pData = GetData();
pData->Unlock();
}
void Preallocate(IN int nLength)
{
PrepareWrite(nLength);
}
void ReleaseBuffer(IN int nNewLength = -1)
{
if(nNewLength == -1)
{
int nAlloc = GetData()->nAllocLength;
nNewLength = StringLengthN(m_pszData, nAlloc);
}
SetLength(nNewLength);
}
void ReleaseBufferSetLength(IN int nNewLength)
{
assert(nNewLength >= 0);
SetLength(nNewLength);
}
void Truncate(IN int nNewLength)
{
assert(nNewLength <= GetLength());
GetBuffer(nNewLength);
ReleaseBufferSetLength(nNewLength);
}
void SetAt(IN int iChar, IN XCHAR ch)
{
assert((iChar >= 0) && (iChar < GetLength()));
if((iChar < 0) || (iChar >= GetLength()))
AtlThrow(E_INVALIDARG);
int nLength = GetLength();
PXSTR pszBuffer = GetBuffer();
pszBuffer[iChar] = ch;
ReleaseBufferSetLength(nLength);
}
void SetManager(IN_OUT IMyStrMgr* pStringMgr)
{
assert(IsEmpty());
MyCStringData* pData = GetData();
pData->Release();
pData = pStringMgr->GetNilString();
Attach(pData);
}
void SetString(_In_opt_z_ PCXSTR pszSrc)
{
SetString(pszSrc, StringLength(pszSrc));
}
void SetString(_In_reads_opt_(nLength) PCXSTR pszSrc, IN int nLength)
{
if(nLength == 0)
{
Empty();
}
else
{
// It is possible that pszSrc points to a location inside of our
// buffer. GetBuffer() might change m_pszData if (1) the buffer
// is shared or (2) the buffer is too small to hold the new
// string. We detect this aliasing, and modify pszSrc to point
// into the newly allocated buffer instead.
if(pszSrc == NULL)
AtlThrow(E_INVALIDARG);
UINT nOldLength = GetLength();
UINT_PTR nOffset = pszSrc - GetString();
// If 0 <= nOffset <= nOldLength, then pszSrc points into our
// buffer
PXSTR pszBuffer = GetBuffer(nLength);
if(nOffset <= nOldLength)
{
CopyCharsOverlapped(pszBuffer, GetAllocLength(),
pszBuffer + nOffset, nLength);
}
else
{
CopyChars(pszBuffer, GetAllocLength(), pszSrc, nLength);
}
ReleaseBufferSetLength(nLength);
}
}
public:
friend MyCSimpleStringT operator+(IN const MyCSimpleStringT& str1, IN const MyCSimpleStringT& str2)
{
MyCSimpleStringT s(str1.GetManager());
Concatenate(s, str1, str1.GetLength(), str2, str2.GetLength());
return(s);
}
friend MyCSimpleStringT operator+(IN const MyCSimpleStringT& str1, _In_z_ PCXSTR psz2)
{
MyCSimpleStringT s(str1.GetManager());
Concatenate(s, str1, str1.GetLength(), psz2, StringLength(psz2));
return(s);
}
friend MyCSimpleStringT operator+(_In_z_ PCXSTR psz1, IN const MyCSimpleStringT& str2)
{
MyCSimpleStringT s(str2.GetManager());
Concatenate(s, psz1, StringLength(psz1), str2, str2.GetLength());
return(s);
}
__declspec(deprecated("MyCSimpleStringT::CopyChars must be passed a buffer size"))
static void __cdecl CopyChars(_Out_writes_(nChars) XCHAR* pchDest,
_In_reads_opt_(nChars) const XCHAR* pchSrc,
IN int nChars) throw()
{
if(pchSrc != NULL)
{
#pragma warning (push)
#pragma warning(disable : 4996)
memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR));
#pragma warning (pop)
}
}
static void __cdecl CopyChars(
_Out_writes_to_(nDestLen, nChars) XCHAR* pchDest,
IN size_t nDestLen,
_In_reads_opt_(nChars) const XCHAR* pchSrc,
IN int nChars) throw()
{
memcpy_s(pchDest, nDestLen * sizeof(XCHAR),
pchSrc, nChars * sizeof(XCHAR));
}
__declspec(deprecated("MyCSimpleStringT::CopyCharsOverlapped must be passed a buffer size"))
static void __cdecl CopyCharsOverlapped(
_Out_writes_(nChars) XCHAR* pchDest,
_In_reads_(nChars) const XCHAR* pchSrc,
IN int nChars) throw()
{
#pragma warning (push)
#pragma warning(disable : 4996)
memmove(pchDest, pchSrc, nChars * sizeof(XCHAR));
#pragma warning (pop)
}
static void __cdecl CopyCharsOverlapped(
_Out_writes_to_(nDestLen, nDestLen) XCHAR* pchDest,
IN size_t nDestLen,
_In_reads_(nChars) const XCHAR* pchSrc,
IN int nChars) throw()
{
memmove_s(pchDest, nDestLen * sizeof(XCHAR),
pchSrc, nChars * sizeof(XCHAR));
}
static int __cdecl StringLength(_In_opt_z_ const char* psz) throw()
{
if(psz == NULL)
{
return(0);
}
return(int(strlen(psz)));
}
static int __cdecl StringLength(_In_opt_z_ const wchar_t* psz) throw()
{
if(psz == NULL)
{
return(0);
}
return(int(wcslen(psz)));
}
static int __cdecl StringLengthN(
_In_reads_opt_z_(sizeInXChar) const char* psz,
IN size_t sizeInXChar) throw()
{
if(psz == NULL)
{
return(0);
}
return(int(strnlen(psz, sizeInXChar)));
}
static int __cdecl StringLengthN(
_In_reads_opt_z_(sizeInXChar) const wchar_t* psz,
IN size_t sizeInXChar) throw()
{
if(psz == NULL)
{
return(0);
}
return(int(wcsnlen(psz, sizeInXChar)));
}
protected:
static void __cdecl Concatenate(
IN_OUT MyCSimpleStringT& strResult,
_In_reads_(nLength1) PCXSTR psz1,
IN int nLength1,
_In_reads_(nLength2) PCXSTR psz2,
IN int nLength2)
{
int nNewLength = nLength1 + nLength2;
PXSTR pszBuffer = strResult.GetBuffer(nNewLength);
CopyChars(pszBuffer, nLength1, psz1, nLength1);
CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2);
strResult.ReleaseBufferSetLength(nNewLength);
}
__declspec(noinline) __declspec(noreturn) static void __cdecl ThrowMemoryException()
{
throw ATL::CAtlException(E_OUTOFMEMORY);
}
// Implementation
private:
void Attach(IN_OUT MyCStringData* pData) throw()
{
m_pszData = static_cast<PXSTR>(pData->data());
}
ATL_NOINLINE void Fork(IN int nLength)
{
MyCStringData* pOldData = GetData();
int nOldLength = pOldData->nDataLength;
MyCStringData* pNewData = pOldData->pStringMgr->Clone()->Allocate(nLength, sizeof(XCHAR));
if(pNewData == NULL)
{
ThrowMemoryException();
}
int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength) + 1; // Copy '\0'
CopyChars(PXSTR(pNewData->data()), nCharsToCopy,
PCXSTR(pOldData->data()), nCharsToCopy);
pNewData->nDataLength = nOldLength;
pOldData->Release();
Attach(pNewData);
}
MyCStringData* GetData() const throw()
{
return(reinterpret_cast<MyCStringData*>(m_pszData) - 1);
}
PXSTR PrepareWrite(IN int nLength)
{
if(nLength < 0)
AtlThrow(E_INVALIDARG);
MyCStringData* pOldData = GetData();
int nShared = 1 - pOldData->nRefs; // nShared < 0 means true, >= 0 means false
int nTooShort = pOldData->nAllocLength - nLength; // nTooShort < 0 means true, >= 0 means false
if((nShared | nTooShort) < 0) // If either sign bit is set (i.e. either is less than zero), we need to copy data
{
PrepareWrite2(nLength);
}
return(m_pszData);
}
ATL_NOINLINE void PrepareWrite2(IN int nLength)
{
MyCStringData* pOldData = GetData();
if(pOldData->nDataLength > nLength)
{
nLength = pOldData->nDataLength;
}
if(pOldData->IsShared())
{
Fork(nLength);
}
else if(pOldData->nAllocLength < nLength)
{
// Grow exponentially, until we hit 1G, then by 1M thereafter.
int nNewLength = pOldData->nAllocLength;
if(nNewLength > 1024 * 1024 * 1024)
{
nNewLength += 1024 * 1024;
}
else
{
// Exponential growth factor is 1.5.
nNewLength = nNewLength + nNewLength / 2;
}
if(nNewLength < nLength)
{
nNewLength = nLength;
}
Reallocate(nNewLength);
}
}
ATL_NOINLINE void Reallocate(IN int nLength)
{
MyCStringData* pOldData = GetData();
assert(pOldData->nAllocLength < nLength);
IMyStrMgr* pStringMgr = pOldData->pStringMgr;
if(pOldData->nAllocLength >= nLength || nLength <= 0)
{
ThrowMemoryException();
return;
}
MyCStringData* pNewData = pStringMgr->Reallocate(pOldData, nLength, sizeof(XCHAR));
if(pNewData == NULL)
{
ThrowMemoryException();
}
Attach(pNewData);
}
void SetLength(IN int nLength)
{
assert(nLength >= 0);
assert(nLength <= GetData()->nAllocLength);
if(nLength < 0 || nLength > GetData()->nAllocLength)
AtlThrow(E_INVALIDARG);
GetData()->nDataLength = nLength;
m_pszData[nLength] = 0;
}
static MyCStringData* __cdecl CloneData(IN_OUT MyCStringData* pData)
{
MyCStringData* pNewData = NULL;
IMyStrMgr* pNewStringMgr = pData->pStringMgr->Clone();
if(!pData->IsLocked() && (pNewStringMgr == pData->pStringMgr))
{
pNewData = pData;
pNewData->AddRef();
}
else
{
pNewData = pNewStringMgr->Allocate(pData->nDataLength, sizeof(XCHAR));
if(pNewData == NULL)
{
ThrowMemoryException();
}
pNewData->nDataLength = pData->nDataLength;
CopyChars(PXSTR(pNewData->data()), pData->nDataLength + 1,
PCXSTR(pData->data()), pData->nDataLength + 1); // Copy '\0'
}
return(pNewData);
}
private:
PXSTR m_pszData;
};
/******************************************************************************************
*函数:GetCurrentModule
*功能:获取模块自身的基地址,如果在DLL内使用,就是那个dll的模块基地址,如果在exe内调用,
*则是这个exe的基地址
*返回值:模块基地址,HMODULE,其实是个DWORD的地址值
*******************************************************************************************/
__inline HMODULE MyGetCurrentModule(VOID)
{
/*没有使用宏判断windows的版本*/
MEMORY_BASIC_INFORMATION membinfo;
static int ibase = 0;//这里要是静态变量,否则失败
VirtualQuery(&ibase, &membinfo, sizeof(membinfo));
return (HMODULE)membinfo.AllocationBase; //可转换为IMAGE_DOS_HEADER(内存中的),本来就是
}
inline int MyAtlStrLen(_In_opt_z_ const wchar_t *str)
{
if(str == NULL)
return 0;
return static_cast<int>(::wcslen(str));
}
inline int MyAtlStrLen(_In_opt_z_ const char *str)
{
if(str == NULL)
return 0;
return static_cast<int>(::strlen(str));
}
template <typename _CharType >
class MyStringTraits
{
public:
static HINSTANCE FindStringResourceInstance(IN UINT nID) throw()
{
static HMODULE hBase = MyGetCurrentModule();
return hBase;
}
static IMyStrMgr* GetDefaultManager() throw()
{
return MyStrMgr::GetInstance();
}
static LPWSTR __cdecl CharNext(_In_ LPCWSTR psz) throw()
{
return const_cast<LPWSTR>(psz + 1);
}
static int __cdecl IsDigit(_In_ wchar_t ch) throw()
{
return iswdigit(static_cast<unsigned short>(ch));
}
static int __cdecl IsSpace(_In_ wchar_t ch) throw()
{
return iswspace(static_cast<unsigned short>(ch));
}
static int __cdecl StringCompare(
_In_z_ LPCWSTR pszA,
_In_z_ LPCWSTR pszB) throw()
{
return wcscmp(pszA, pszB);
}
static int __cdecl StringCompareIgnore(
_In_z_ LPCWSTR pszA,
_In_z_ LPCWSTR pszB) throw()
{
return _wcsicmp(pszA, pszB);
}
static int __cdecl StringCollate(
_In_z_ LPCWSTR pszA,
_In_z_ LPCWSTR pszB) throw()
{
return wcscoll(pszA, pszB);
}
static int __cdecl StringCollateIgnore(
_In_z_ LPCWSTR pszA,
_In_z_ LPCWSTR pszB) throw()
{
return _wcsicoll(pszA, pszB);
}
static LPCWSTR __cdecl StringFindString(
_In_z_ LPCWSTR pszBlock,
_In_z_ LPCWSTR pszMatch) throw()
{
return wcsstr(pszBlock, pszMatch);
}
static LPWSTR __cdecl StringFindString(
_In_z_ LPWSTR pszBlock,
_In_z_ LPCWSTR pszMatch) throw()
{
return(const_cast<LPWSTR>(StringFindString(const_cast<LPCWSTR>(pszBlock), pszMatch)));
}
static LPCWSTR __cdecl StringFindChar(
_In_z_ LPCWSTR pszBlock,
_In_ wchar_t chMatch) throw()
{
return wcschr(pszBlock, chMatch);
}
static LPCWSTR __cdecl StringFindCharRev(
_In_z_ LPCWSTR psz,
_In_ wchar_t ch) throw()
{
return wcsrchr(psz, ch);
}
static LPCWSTR __cdecl StringScanSet(
_In_z_ LPCWSTR pszBlock,
_In_z_ LPCWSTR pszMatch) throw()
{
return wcspbrk(pszBlock, pszMatch);
}
static int __cdecl StringSpanIncluding(
_In_z_ LPCWSTR pszBlock,
_In_z_ LPCWSTR pszSet) throw()
{
return (int)wcsspn(pszBlock, pszSet);
}
static int __cdecl StringSpanExcluding(
_In_z_ LPCWSTR pszBlock,
_In_z_ LPCWSTR pszSet) throw()
{
return (int)wcscspn(pszBlock, pszSet);
}
static LPWSTR __cdecl StringUppercase(
_Inout_updates_(size) LPWSTR psz,
_In_ size_t size) throw()
{
errno_t err = _wcsupr_s(psz, size);
return (err == 0) ? psz : NULL;
}
static LPWSTR __cdecl StringLowercase(
_Inout_updates_(size) LPWSTR psz,
_In_ size_t size) throw()
{
errno_t err = _wcslwr_s(psz, size);
return (err == 0) ? psz : NULL;
}
static LPWSTR __cdecl StringReverse(_Inout_z_ LPWSTR psz) throw()
{
return _wcsrev(psz);
}
static int __cdecl GetFormattedLength(
_In_z_ _Printf_format_string_ LPCWSTR pszFormat, va_list args) throw()
{
#if _MSC_VER < 1900
return _vscwprintf(pszFormat, args);
#else
// Explicitly request the legacy wide format specifiers mode from the CRT,
// for compatibility with previous versions. While the CRT supports two
// modes, the ATL and MFC functions that accept format strings only support
// legacy mode format strings.
int const result = __stdio_common_vswprintf(
_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS |
_CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR |
_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS,
NULL, 0, pszFormat, NULL, args);
return result < 0 ? -1 : result;
#endif
}
static int __cdecl Format(
_Out_writes_(nLength) LPWSTR pszBuffer,
_In_ size_t nLength,
_In_ _Printf_format_string_ LPCWSTR pszFormat, va_list args) throw()
{
#if _MSC_VER < 1900
return vswprintf_s(pszBuffer, nLength, pszFormat, args);
#else
// Explicitly request the legacy wide format specifiers mode from the CRT,
// for compatibility with previous versions. While the CRT supports two
// modes, the ATL and MFC functions that accept format strings only support
// legacy mode format strings.
int const result = __stdio_common_vswprintf_s(
_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS |
_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS,
pszBuffer, nLength, pszFormat, NULL, args);
return result < 0 ? -1 : result;
#endif
}
static int __cdecl GetBaseTypeLength(_In_z_ LPCSTR pszSrc) throw()
{
// Returns required buffer size in wchar_ts
return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, NULL, 0) - 1;
}
static int __cdecl GetBaseTypeLength(
_In_reads_(nLength) LPCSTR pszSrc,
_In_ int nLength) throw()
{
// Returns required buffer size in wchar_ts
return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, nLength, NULL, 0);
}
static int __cdecl GetBaseTypeLength(_In_z_ LPCWSTR pszSrc) throw()
{
// Returns required buffer size in wchar_ts
return MyAtlStrLen(pszSrc);
}
static int __cdecl GetBaseTypeLength(
_In_reads_(nLength) LPCWSTR pszSrc,
_In_ int nLength) throw()
{
(void)pszSrc;
// Returns required buffer size in wchar_ts
return nLength;
}
static void __cdecl ConvertToBaseType(
_Out_writes_(nDestLength) LPWSTR pszDest,
_In_ int nDestLength,
_In_ LPCSTR pszSrc,
_In_ int nSrcLength = -1) throw()
{
// nLen is in wchar_ts
::MultiByteToWideChar(CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength);
}
static void __cdecl ConvertToBaseType(
_Out_writes_(nDestLength) LPWSTR pszDest,
_In_ int nDestLength,
_In_ LPCWSTR pszSrc,
_In_ int nSrcLength = -1)
{
if(nSrcLength == -1)
{
nSrcLength = 1 + GetBaseTypeLength(pszSrc);
}
// nLen is in wchar_ts
wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength);
}
static void __cdecl FloodCharacters(
_In_ wchar_t ch,
_In_ int nLength,
_Out_writes_all_(nLength) WCHAR *psz) throw()
{
// nLength is in XCHARs
for(int i = 0; i < nLength; i++)
{
psz[i] = ch;
}
}
_Ret_maybenull_z_ static BSTR __cdecl AllocSysString(
_In_reads_(nDataLength) const wchar_t* pchData,
_In_ int nDataLength) throw()
{
return ::SysAllocStringLen(pchData, nDataLength);
}
static BOOL __cdecl ReAllocSysString(
_In_reads_(nDataLength) const wchar_t* pchData,
_Inout_ _Deref_post_opt_valid_ _Post_z_ BSTR* pbstr,
_In_ int nDataLength) throw()
{
return ::SysReAllocStringLen(pbstr, pchData, nDataLength);
}
static int __cdecl SafeStringLen(_In_opt_z_ LPCSTR psz) throw()
{
// returns length in bytes
return (psz != NULL) ? (int)strlen(psz) : 0;
}
static int __cdecl SafeStringLen(_In_opt_z_ LPCWSTR psz) throw()
{
// returns length in wchar_ts
return (psz != NULL) ? (int)wcslen(psz) : 0;
}
static int __cdecl GetCharLen(_In_opt_z_ const wchar_t* pch) throw()
{
(void)pch;
// returns char length
return 1;
}
static int __cdecl GetCharLen(_In_z_ const char* pch) throw()
{
// returns char length
return (int)(_mbclen(reinterpret_cast<const unsigned char*>(pch)));
}
#ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
static void __cdecl ConvertToOem(_In_opt_z_ LPWSTR /*psz*/)
{
ATLENSURE(FALSE); // Unsupported Feature
}
static void __cdecl ConvertToAnsi(_In_opt_z_ LPWSTR /*psz*/)
{
ATLENSURE(FALSE); // Unsupported Feature
}
static void __cdecl ConvertToOem(
_In_reads_(nLen) LPWSTR /*psz*/,
_In_ size_t nLen)
{
UNREFERENCED_PARAMETER(nLen);
ATLENSURE(FALSE); // Unsupported Feature
}
static void __cdecl ConvertToAnsi(
_In_reads_(nLen) LPWSTR /*psz*/,
_In_ size_t nLen)
{
UNREFERENCED_PARAMETER(nLen);
ATLENSURE(FALSE); // Unsupported Feature
}
#endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
static char* __cdecl CharNext(IN const char* p) throw()
{
return reinterpret_cast<char*>(_mbsinc(reinterpret_cast<const unsigned char*>(p)));
}
static int __cdecl IsDigit(IN char ch) throw()
{
return _ismbcdigit(ch);
}
static int __cdecl IsSpace(IN char ch) throw()
{
return _ismbcspace(ch);
}
static int __cdecl StringCompare(_In_z_ LPCSTR pszA, _In_z_ LPCSTR pszB) throw()
{
return _mbscmp(reinterpret_cast<const unsigned char*>(pszA), reinterpret_cast<const unsigned char*>(pszB));
}
static int __cdecl StringCompareIgnore(_In_z_ LPCSTR pszA, _In_z_ LPCSTR pszB) throw()
{
return _mbsicmp(reinterpret_cast<const unsigned char*>(pszA), reinterpret_cast<const unsigned char*>(pszB));
}
static int __cdecl StringCollate(
_In_z_ LPCSTR pszA,
_In_z_ LPCSTR pszB) throw()
{
return _mbscoll(reinterpret_cast<const unsigned char*>(pszA), reinterpret_cast<const unsigned char*>(pszB));
}
static int __cdecl StringCollateIgnore(
_In_z_ LPCSTR pszA,
_In_z_ LPCSTR pszB) throw()
{
return _mbsicoll(reinterpret_cast<const unsigned char*>(pszA), reinterpret_cast<const unsigned char*>(pszB));
}
static LPCSTR __cdecl StringFindString(
_In_z_ LPCSTR pszBlock,
_In_z_ LPCSTR pszMatch) throw()
{
return reinterpret_cast<LPCSTR>(_mbsstr(reinterpret_cast<const unsigned char*>(pszBlock),
reinterpret_cast<const unsigned char*>(pszMatch)));
}
static LPSTR __cdecl StringFindString(
_In_z_ LPSTR pszBlock,
_In_z_ LPCSTR pszMatch) throw()
{
return(const_cast<LPSTR>(StringFindString(const_cast<LPCSTR>(pszBlock), pszMatch)));
}
static LPCSTR __cdecl StringFindChar(_In_z_ LPCSTR pszBlock, IN char chMatch) throw()
{
return reinterpret_cast<LPCSTR>(_mbschr(reinterpret_cast<const unsigned char*>(pszBlock), (unsigned char)chMatch));
}
static LPCSTR __cdecl StringFindCharRev(_In_z_ LPCSTR psz, IN char ch) throw()
{
return reinterpret_cast<LPCSTR>(_mbsrchr(reinterpret_cast<const unsigned char*>(psz), (unsigned char)ch));
}
static LPCSTR __cdecl StringScanSet(_In_z_ LPCSTR pszBlock, _In_z_ LPCSTR pszMatch) throw()
{
return reinterpret_cast<LPCSTR>(_mbspbrk(reinterpret_cast<const unsigned char*>(pszBlock),
reinterpret_cast<const unsigned char*>(pszMatch)));
}
static int __cdecl StringSpanIncluding(
_In_z_ LPCSTR pszBlock,
_In_z_ LPCSTR pszSet) throw()
{
return (int)_mbsspn(reinterpret_cast<const unsigned char*>(pszBlock), reinterpret_cast<const unsigned char*>(pszSet));
}
static int __cdecl StringSpanExcluding(LPCSTR pszBlock, LPCSTR pszSet) throw()
{
return (int)_mbscspn(reinterpret_cast<const unsigned char*>(pszBlock), reinterpret_cast<const unsigned char*>(pszSet));
}
static LPSTR __cdecl StringUppercase(_Inout_updates_z_(size) LPSTR psz, IN size_t size)
{
Checked::mbsupr_s(reinterpret_cast<unsigned char*>(psz), size);
return psz;
}
static LPSTR __cdecl StringLowercase(_Inout_updates_z_(size) LPSTR psz, IN size_t size)
{
Checked::mbslwr_s(reinterpret_cast<unsigned char*>(psz), size);
return psz;
}
static LPSTR __cdecl StringReverse(_Inout_z_ LPSTR psz) throw()
{
return reinterpret_cast<LPSTR>(_mbsrev(reinterpret_cast<unsigned char*>(psz)));
}
static int __cdecl GetFormattedLength(LPCSTR pszFormat, va_list args) throw()
{
return _vscprintf(pszFormat, args);
}
static int __cdecl Format(
_Out_writes_to_(nlength, return) LPSTR pszBuffer,
IN size_t nlength,
_In_z_ _Printf_format_string_ LPCSTR pszFormat, va_list args) throw()
{
return vsprintf_s(pszBuffer, nlength, pszFormat, args);
}
static void __cdecl ConvertToBaseType(OUT LPSTR pszDest, IN int nDestLength, _In_z_ LPCSTR pszSrc, IN int nSrcLength = -1)
{
if(nSrcLength == -1)
{
nSrcLength = 1 + GetBaseTypeLength(pszSrc);
}
// nLen is in XCHARs
Checked::memcpy_s(pszDest, nDestLength * sizeof(char), pszSrc, nSrcLength * sizeof(char));
}
static void __cdecl ConvertToBaseType(OUT LPSTR pszDest, IN int nDestLength, IN LPCWSTR pszSrc, IN int nSrcLength = -1) throw()
{
// nLen is in XCHARs
::WideCharToMultiByte(CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL);
}
static void __cdecl FloodCharacters(IN char ch, IN int nLength, _Out_writes_all_(nLength) char* pch) throw()
{
// nLength is in XCHARs
memset(pch, ch, nLength);
}
static BSTR __cdecl AllocSysString(_In_reads_(nDataLength) const char* pchData, IN int nDataLength) throw()
{
int nLen = ::MultiByteToWideChar(CP_ACP, 0, pchData, nDataLength,
NULL, NULL);
BSTR bstr = ::SysAllocStringLen(NULL, nLen);
if(bstr != NULL)
{
::MultiByteToWideChar(CP_ACP, 0, pchData, nDataLength, bstr, nLen);
}
return bstr;
}
_Success_(return != FALSE)
static BOOL __cdecl ReAllocSysString(
_In_reads_(nDataLength) const char* pchData,
IN_OUT _Deref_post_opt_valid_ _Post_z_ BSTR* pbstr,
IN int nDataLength) throw()
{
int nLen = ::MultiByteToWideChar(CP_ACP, 0, pchData, nDataLength, NULL, NULL);
BOOL bSuccess = ::SysReAllocStringLen(pbstr, NULL, nLen);
if(bSuccess && nLen > 0)
{
bSuccess = (0 != ::MultiByteToWideChar(CP_ACP, 0, pchData, nDataLength, *pbstr, nLen));
}
return bSuccess;
}
};
#ifdef _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
#define MYSTRING_EXPLICIT explicit
#else
#define MYSTRING_EXPLICIT
#endif
template< typename BaseType >
class MyCStringT :
public MyCSimpleStringT< BaseType>
{
public:
typedef MyCSimpleStringT< BaseType> CThisSimpleString;
typedef MyStringTraits<BaseType> StrTraits;
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:
MyCStringT() throw() :
CThisSimpleString(StrTraits::GetDefaultManager())
{
}
static void __cdecl Construct(IN MyCStringT* pString)
{
new(pString) MyCStringT;
}
// Copy constructor
MyCStringT(IN const MyCStringT& strSrc) :
CThisSimpleString(strSrc)
{
}
// Construct from MyCSimpleStringT
operator MyCSimpleStringT < BaseType > &()
{
return *(MyCSimpleStringT < BaseType> *)this;
}
template <bool bMFCDLL>
MyCStringT(IN const MyCSimpleStringT<BaseType>& strSrc) :
CThisSimpleString(strSrc)
{
}
MyCStringT(_In_opt_z_ const XCHAR* pszSrc) :
CThisSimpleString(StrTraits::GetDefaultManager())
{
if(!CheckImplicitLoad(pszSrc))
{
*this = pszSrc;
}
}
MyCStringT(
_In_opt_z_ const XCHAR* pszSrc,
IN IMyStrMgr* pStringMgr) :
CThisSimpleString(pStringMgr)
{
if(!CheckImplicitLoad(pszSrc))
{
*this = pszSrc;
}
}
MyCStringT(const VARIANT& varSrc);
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MYSTRING_EXPLICIT MyCStringT(_In_opt_z_ const YCHAR* pszSrc) :
CThisSimpleString(StrTraits::GetDefaultManager())
{
if(!CheckImplicitLoad(pszSrc))
{
*this = pszSrc;
}
}
MyCStringT(
_In_opt_z_ const YCHAR* pszSrc,
IN IMyStrMgr* pStringMgr) :
CThisSimpleString(pStringMgr)
{
if(!CheckImplicitLoad(pszSrc))
{
*this = pszSrc;
}
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
explicit MyCStringT(
_In_ IMyStrMgr* pStringMgr) throw() :
CThisSimpleString(pStringMgr)
{
}
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MYSTRING_EXPLICIT MyCStringT(_In_z_ const unsigned char* pszSrc) :
CThisSimpleString(StrTraits::GetDefaultManager())
{
*this = reinterpret_cast<const char*>(pszSrc);
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT(
_In_opt_z_ const unsigned char* pszSrc,
IN IMyStrMgr* pStringMgr) :
CThisSimpleString(pStringMgr)
{
*this = reinterpret_cast<const char*>(pszSrc);
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
#ifdef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
#define _CSTRING_CHAR_T XCHAR
#else // def _CSTRING_NARROW_WIDE_CONVERSION
#define _CSTRING_CHAR_T char
#endif // def _CSTRING_NARROW_WIDE_CONVERSION
MYSTRING_EXPLICIT MyCStringT(
IN _CSTRING_CHAR_T ch,
IN int nLength = 1) :
CThisSimpleString(StrTraits::GetDefaultManager())
{
assert(nLength >= 0);
if(nLength > 0)
{
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::FloodCharacters(XCHAR(ch), nLength, pszBuffer);
this->ReleaseBufferSetLength(nLength);
}
}
#undef _CSTRING_CHAR_T
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MYSTRING_EXPLICIT MyCStringT(
IN wchar_t ch,
IN int nLength = 1) :
CThisSimpleString(StrTraits::GetDefaultManager())
{
assert(nLength >= 0);
if(nLength > 0)
{
//Convert ch to the BaseType
wchar_t pszCh[2] = { ch , 0 };
int nBaseTypeCharLen = 1;
if(ch != L'\0')
{
nBaseTypeCharLen = StrTraits::GetBaseTypeLength(pszCh);
}
CTempBuffer<XCHAR, 10> buffBaseTypeChar;
buffBaseTypeChar.Allocate(nBaseTypeCharLen + 1);
StrTraits::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.
StrTraits::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);
}
}
#else
private:
MYSTRING_EXPLICIT MyCStringT(
IN YCHAR ch,
IN int nLength = 1);
public:
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT(const XCHAR* pch, int nLength) :
CThisSimpleString(pch, nLength, StrTraits::GetDefaultManager())
{
}
MyCStringT(
_In_reads_(nLength) const XCHAR* pch,
IN int nLength,
IN IMyStrMgr* pStringMgr) :
CThisSimpleString(pch, nLength, pStringMgr)
{
}
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT(
_In_reads_(nLength) const YCHAR* pch,
IN int nLength) :
CThisSimpleString(StrTraits::GetDefaultManager())
{
assert(nLength >= 0);
if(nLength > 0)
{
assert(AtlIsValidAddress(pch, nLength * sizeof(YCHAR), FALSE));
if(pch == NULL)
AtlThrow(E_INVALIDARG);
int nDestLength = StrTraits::GetBaseTypeLength(pch, nLength);
PXSTR pszBuffer = this->GetBuffer(nDestLength);
StrTraits::ConvertToBaseType(pszBuffer, nDestLength, pch, nLength);
this->ReleaseBufferSetLength(nDestLength);
}
}
MyCStringT(
_In_reads_(nLength) const YCHAR* pch,
IN int nLength,
IN IMyStrMgr* pStringMgr) :
CThisSimpleString(pStringMgr)
{
assert(nLength >= 0);
if(nLength > 0)
{
assert(AtlIsValidAddress(pch, nLength * sizeof(YCHAR), FALSE));
if(pch == NULL)
AtlThrow(E_INVALIDARG);
int nDestLength = StrTraits::GetBaseTypeLength(pch, nLength);
PXSTR pszBuffer = this->GetBuffer(nDestLength);
StrTraits::ConvertToBaseType(pszBuffer, nDestLength, pch, nLength);
this->ReleaseBufferSetLength(nDestLength);
}
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
// Destructor
~MyCStringT() throw()
{
}
// Assignment operators
MyCStringT& operator=(IN const MyCStringT& strSrc)
{
CThisSimpleString::operator=(strSrc);
return(*this);
}
MyCStringT& operator=(IN const MyCSimpleStringT<BaseType>& strSrc)
{
CThisSimpleString::operator=(strSrc);
return(*this);
}
MyCStringT& operator=(_In_opt_z_ PCXSTR pszSrc)
{
CThisSimpleString::operator=(pszSrc);
return(*this);
}
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT& operator=(_In_opt_z_ PCYSTR pszSrc)
{
// nDestLength is in XCHARs
int nDestLength = (pszSrc != NULL) ? StrTraits::GetBaseTypeLength(pszSrc) : 0;
if(nDestLength > 0)
{
PXSTR pszBuffer = this->GetBuffer(nDestLength);
StrTraits::ConvertToBaseType(pszBuffer, nDestLength, pszSrc);
this->ReleaseBufferSetLength(nDestLength);
}
else
{
this->Empty();
}
return(*this);
}
MyCStringT& operator=(_In_opt_z_ const unsigned char* pszSrc)
{
return(operator=(reinterpret_cast<const char*>(pszSrc)));
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT& operator=(IN XCHAR ch)
{
XCHAR ach[2] = { ch, 0 };
return(operator=(ach));
}
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT& operator=(IN YCHAR ch)
{
YCHAR ach[2] = { ch, 0 };
return(operator=(ach));
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT& operator=(IN const VARIANT& var);
MyCStringT& operator+=(IN const CThisSimpleString& str)
{
CThisSimpleString::operator+=(str);
return(*this);
}
MyCStringT& operator+=(_In_z_ PCXSTR pszSrc)
{
CThisSimpleString::operator+=(pszSrc);
return(*this);
}
template< int t_nSize >
MyCStringT& operator+=(IN const MyStaticString< XCHAR, t_nSize >& strSrc)
{
CThisSimpleString::operator+=(strSrc);
return(*this);
}
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT& operator+=(_In_opt_z_ PCYSTR pszSrc)
{
MyCStringT str(pszSrc, GetManager());
return(operator+=(str));
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT& operator+=(IN XCHAR ch)
{
CThisSimpleString::operator+=(ch);
return(*this);
}
#ifdef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
private:
MyCStringT& operator+=(IN YCHAR ch);
public:
#else
MyCStringT& operator+=(IN unsigned char ch)
{
CThisSimpleString::operator+=(ch);
return(*this);
}
MyCStringT& operator+=(IN YCHAR ch)
{
CThisSimpleString::operator+=(ch);
return(*this);
}
#endif // def _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
MyCStringT& operator+=(IN const VARIANT& var);
// Override from base class
IMyStrMgr* GetManager() const throw()
{
IMyStrMgr* pStringMgr = CThisSimpleString::GetManager();
if(pStringMgr)
{
return pStringMgr;
}
pStringMgr = StrTraits::GetDefaultManager();
return pStringMgr->Clone();
}
// Comparison
int Compare(_In_z_ PCXSTR psz) const
{
ATLENSURE(MyAtlIsValidString(psz));
_Analysis_assume_(psz); // MyAtlIsValidString guarantees that psz != NULL
return(StrTraits::StringCompare(this->GetString(), psz));
}
int CompareNoCase(_In_z_ PCXSTR psz) const
{
ATLENSURE(MyAtlIsValidString(psz));
_Analysis_assume_(psz); // MyAtlIsValidString guarantees that psz != NULL
return(StrTraits::StringCompareIgnore(this->GetString(), psz));
}
int Collate(_In_z_ PCXSTR psz) const throw()
{
assert(MyAtlIsValidString(psz));
return(StrTraits::StringCollate(this->GetString(), psz));
}
int CollateNoCase(_In_z_ PCXSTR psz) const throw()
{
assert(MyAtlIsValidString(psz));
return(StrTraits::StringCollateIgnore(this->GetString(), psz));
}
// Advanced manipulation
// Delete 'nCount' characters, starting at index 'iIndex'
int Delete(
IN int iIndex,
IN int nCount = 1)
{
if(iIndex < 0)
iIndex = 0;
if(nCount < 0)
nCount = 0;
int nLength = this->GetLength();
if((::ATL::AtlAddThrow(nCount, iIndex)) > nLength)
{
nCount = nLength - iIndex;
}
if(nCount > 0)
{
int nNewLength = nLength - nCount;
int nXCHARsToCopy = nLength - (iIndex + nCount) + 1;
PXSTR pszBuffer = this->GetBuffer();
Checked::memmove_s(pszBuffer + iIndex, nXCHARsToCopy * sizeof(XCHAR),
pszBuffer + iIndex + nCount, nXCHARsToCopy * sizeof(XCHAR));
this->ReleaseBufferSetLength(nNewLength);
}
return(this->GetLength());
}
// Insert character 'ch' before index 'iIndex'
int Insert(
IN int iIndex,
IN XCHAR ch)
{
if(iIndex < 0)
iIndex = 0;
if(iIndex > this->GetLength())
{
iIndex = this->GetLength();
}
int nNewLength = this->GetLength() + 1;
PXSTR pszBuffer = this->GetBuffer(nNewLength);
// move existing bytes down
Checked::memmove_s(pszBuffer + iIndex + 1, (nNewLength - iIndex) * sizeof(XCHAR),
pszBuffer + iIndex, (nNewLength - iIndex) * sizeof(XCHAR));
pszBuffer[iIndex] = ch;
this->ReleaseBufferSetLength(nNewLength);
return(nNewLength);
}
// Insert string 'psz' before index 'iIndex'
int Insert(
IN int iIndex,
_In_z_ PCXSTR psz)
{
if(iIndex < 0)
iIndex = 0;
if(iIndex > this->GetLength())
{
iIndex = this->GetLength();
}
// nInsertLength and nNewLength are in XCHARs
int nInsertLength = StrTraits::SafeStringLen(psz);
int nNewLength = this->GetLength();
if(nInsertLength > 0)
{
nNewLength += nInsertLength;
PXSTR pszBuffer = this->GetBuffer(nNewLength);
// move existing bytes down
Checked::memmove_s(pszBuffer + iIndex + nInsertLength, (nNewLength - iIndex - nInsertLength + 1) * sizeof(XCHAR),
pszBuffer + iIndex, (nNewLength - iIndex - nInsertLength + 1) * sizeof(XCHAR));
Checked::memcpy_s(pszBuffer + iIndex, nInsertLength * sizeof(XCHAR),
psz, nInsertLength * sizeof(XCHAR));
this->ReleaseBufferSetLength(nNewLength);
}
return(nNewLength);
}
// Replace all occurrences of character 'chOld' with character 'chNew'
int Replace(
IN XCHAR chOld,
IN 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(StrTraits::CharNext(pszBuffer + iChar) - pszBuffer);
}
if(bCopied)
{
this->ReleaseBufferSetLength(nLength);
}
}
return(nCount);
}
// Replace all occurrences of string 'pszOld' with string 'pszNew'
int Replace(
_In_z_ PCXSTR pszOld,
_In_z_ PCXSTR pszNew)
{
// can't have empty or NULL lpszOld
// nSourceLen is in XCHARs
int nSourceLen = StrTraits::SafeStringLen(pszOld);
if(nSourceLen == 0)
return(0);
// nReplacementLen is in XCHARs
int nReplacementLen = StrTraits::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 = StrTraits::StringFindString(pszStart, pszOld)) != NULL)
{
nCount++;
pszStart = pszTarget + nSourceLen;
}
pszStart += StrTraits::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 = StrTraits::StringFindString(pszStart, pszOld)) != NULL)
{
int nBalance = nOldLength - int(pszTarget - pszBuffer + nSourceLen);
Checked::memmove_s(pszTarget + nReplacementLen, nBalance * sizeof(XCHAR),
pszTarget + nSourceLen, nBalance * sizeof(XCHAR));
Checked::memcpy_s(pszTarget, nReplacementLen * sizeof(XCHAR),
pszNew, nReplacementLen * sizeof(XCHAR));
pszStart = pszTarget + nReplacementLen;
pszTarget[nReplacementLen + nBalance] = 0;
nOldLength += (nReplacementLen - nSourceLen);
}
pszStart += StrTraits::SafeStringLen(pszStart) + 1;
}
assert(pszBuffer[nNewLength] == 0);
this->ReleaseBufferSetLength(nNewLength);
}
return(nCount);
}
// Remove all occurrences of character 'chRemove'
int Remove(IN 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 = StrTraits::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);
}
MyCStringT Tokenize(
_In_z_ PCXSTR pszTokens,
IN_OUT int& iStart) const
{
assert(iStart >= 0);
if(iStart < 0)
AtlThrow(E_INVALIDARG);
if((pszTokens == NULL) || (*pszTokens == (XCHAR)0))
{
if(iStart < this->GetLength())
{
return(MyCStringT(this->GetString() + iStart, GetManager()));
}
}
else
{
PCXSTR pszPlace = this->GetString() + iStart;
PCXSTR pszEnd = this->GetString() + this->GetLength();
if(pszPlace < pszEnd)
{
int nIncluding = StrTraits::StringSpanIncluding(pszPlace,
pszTokens);
if((pszPlace + nIncluding) < pszEnd)
{
pszPlace += nIncluding;
int nExcluding = StrTraits::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(MyCStringT(GetManager()));
}
// find routines
// Find the first occurrence of character 'ch', starting at index 'iStart'
int Find(
IN XCHAR ch,
IN int iStart = 0) const throw()
{
// iStart is in XCHARs
assert(iStart >= 0);
// nLength is in XCHARs
int nLength = this->GetLength();
if(iStart < 0 || iStart >= nLength)
{
return(-1);
}
// find first single character
PCXSTR psz = StrTraits::StringFindChar(this->GetString() + iStart, ch);
// return -1 if not found and index otherwise
return((psz == NULL) ? -1 : int(psz - this->GetString()));
}
// look for a specific sub-string
// Find the first occurrence of string 'pszSub', starting at index 'iStart'
int Find(
_In_z_ PCXSTR pszSub,
IN int iStart = 0) const throw()
{
// iStart is in XCHARs
assert(iStart >= 0);
assert(MyAtlIsValidString(pszSub));
if(pszSub == NULL)
{
return(-1);
}
// nLength is in XCHARs
int nLength = this->GetLength();
if(iStart < 0 || iStart > nLength)
{
return(-1);
}
// find first matching substring
PCXSTR psz = StrTraits::StringFindString(this->GetString() + iStart, pszSub);
// return -1 for not found, distance from beginning otherwise
return((psz == NULL) ? -1 : int(psz - this->GetString()));
}
// Find the first occurrence of any of the characters in string 'pszCharSet'
int FindOneOf(_In_z_ PCXSTR pszCharSet) const throw()
{
assert(MyAtlIsValidString(pszCharSet));
PCXSTR psz = StrTraits::StringScanSet(this->GetString(), pszCharSet);
return((psz == NULL) ? -1 : int(psz - this->GetString()));
}
// Find the last occurrence of character 'ch'
int ReverseFind(IN XCHAR ch) const throw()
{
// find last single character
PCXSTR psz = StrTraits::StringFindCharRev(this->GetString(), ch);
// return -1 if not found, distance from beginning otherwise
return((psz == NULL) ? -1 : int(psz - this->GetString()));
}
// manipulation
// Convert the string to uppercase
MyCStringT& MakeUpper()
{
int nLength = this->GetLength();
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::StringUppercase(pszBuffer, nLength + 1);
this->ReleaseBufferSetLength(nLength);
return(*this);
}
// Convert the string to lowercase
MyCStringT& MakeLower()
{
int nLength = this->GetLength();
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::StringLowercase(pszBuffer, nLength + 1);
this->ReleaseBufferSetLength(nLength);
return(*this);
}
// Reverse the string
MyCStringT& MakeReverse()
{
int nLength = this->GetLength();
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::StringReverse(pszBuffer);
this->ReleaseBufferSetLength(nLength);
return(*this);
}
// trimming
// Remove all trailing whitespace
MyCStringT& TrimRight()
{
// find beginning of trailing spaces by starting
// at beginning (DBCS aware)
PCXSTR psz = this->GetString();
PCXSTR pszLast = NULL;
while(*psz != 0)
{
if(StrTraits::IsSpace(*psz))
{
if(pszLast == NULL)
pszLast = psz;
}
else
{
pszLast = NULL;
}
psz = StrTraits::CharNext(psz);
}
if(pszLast != NULL)
{
// truncate at trailing space start
int iLast = int(pszLast - this->GetString());
this->Truncate(iLast);
}
return(*this);
}
// Remove all leading whitespace
MyCStringT& TrimLeft()
{
// find first non-space character
PCXSTR psz = this->GetString();
while(StrTraits::IsSpace(*psz))
{
psz = StrTraits::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);
}
// Remove all leading and trailing whitespace
MyCStringT& Trim()
{
return(TrimRight().TrimLeft());
}
// Remove all leading and trailing occurrences of character 'chTarget'
MyCStringT& Trim(IN XCHAR chTarget)
{
return(TrimRight(chTarget).TrimLeft(chTarget));
}
// Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets'
MyCStringT& Trim(_In_z_ PCXSTR pszTargets)
{
return(TrimRight(pszTargets).TrimLeft(pszTargets));
}
// trimming anything (either side)
// Remove all trailing occurrences of character 'chTarget'
MyCStringT& TrimRight(IN 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 = StrTraits::CharNext(psz);
}
if(pszLast != NULL)
{
// truncate at left-most matching character
int iLast = int(pszLast - this->GetString());
this->Truncate(iLast);
}
return(*this);
}
// Remove all trailing occurrences of any of the characters in string 'pszTargets'
MyCStringT& TrimRight(_In_z_ 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(StrTraits::StringFindChar(pszTargets, *psz) != NULL)
{
if(pszLast == NULL)
{
pszLast = psz;
}
}
else
{
pszLast = NULL;
}
psz = StrTraits::CharNext(psz);
}
if(pszLast != NULL)
{
// truncate at left-most matching character
int iLast = int(pszLast - this->GetString());
this->Truncate(iLast);
}
return(*this);
}
// Remove all leading occurrences of character 'chTarget'
MyCStringT& TrimLeft(IN XCHAR chTarget)
{
// find first non-matching character
PCXSTR psz = this->GetString();
while(chTarget == *psz)
{
psz = StrTraits::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;
Checked::memmove_s(pszBuffer, (this->GetLength() + 1) * sizeof(XCHAR),
psz, (nDataLength + 1) * sizeof(XCHAR));
this->ReleaseBufferSetLength(nDataLength);
}
return(*this);
}
// Remove all leading occurrences of any of the characters in string 'pszTargets'
MyCStringT& TrimLeft(_In_z_ 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) && (StrTraits::StringFindChar(pszTargets, *psz) != NULL))
{
psz = StrTraits::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;
Checked::memmove_s(pszBuffer, (this->GetLength() + 1) * sizeof(XCHAR),
psz, (nDataLength + 1) * sizeof(XCHAR));
this->ReleaseBufferSetLength(nDataLength);
}
return(*this);
}
#ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
// Convert the string to the OEM character set
void AnsiToOem()
{
int nLength = this->GetLength();
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::ConvertToOem(pszBuffer, nLength + 1);
this->ReleaseBufferSetLength(nLength);
}
// Convert the string to the ANSI character set
void OemToAnsi()
{
int nLength = this->GetLength();
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::ConvertToAnsi(pszBuffer, nLength + 1);
this->ReleaseBufferSetLength(nLength);
}
#endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
// Very simple sub-string extraction
// Return the substring starting at index 'iFirst'
MyCStringT Mid(IN int iFirst) const
{
return(Mid(iFirst, this->GetLength() - iFirst));
}
// Return the substring starting at index 'iFirst', with length 'nCount'
MyCStringT Mid(
IN int iFirst,
IN int nCount) const
{
// nCount is in XCHARs
// out-of-bounds requests return sensible things
if(iFirst < 0)
iFirst = 0;
if(nCount < 0)
nCount = 0;
if((::ATL::AtlAddThrow(iFirst, nCount)) > this->GetLength())
{
nCount = this->GetLength() - iFirst;
}
if(iFirst > this->GetLength())
{
nCount = 0;
}
assert((nCount == 0) || ((iFirst + nCount) <= this->GetLength()));
// optimize case of returning entire string
if((iFirst == 0) && ((iFirst + nCount) == this->GetLength()))
{
return(*this);
}
return(MyCStringT(this->GetString() + iFirst, nCount, GetManager()));
}
// Return the substring consisting of the rightmost 'nCount' characters
MyCStringT Right(IN int nCount) const
{
// nCount is in XCHARs
if(nCount < 0)
nCount = 0;
int nLength = this->GetLength();
if(nCount >= nLength)
{
return(*this);
}
return(MyCStringT(this->GetString() + nLength - nCount, nCount, GetManager()));
}
// Return the substring consisting of the leftmost 'nCount' characters
MyCStringT Left(IN int nCount) const
{
// nCount is in XCHARs
if(nCount < 0)
nCount = 0;
int nLength = this->GetLength();
if(nCount >= nLength)
{
return(*this);
}
return(MyCStringT(this->GetString(), nCount, GetManager()));
}
// Return the substring consisting of the leftmost characters in the set 'pszCharSet'
MyCStringT SpanIncluding(_In_z_ PCXSTR pszCharSet) const
{
assert(MyAtlIsValidString(pszCharSet));
if(pszCharSet == NULL)
AtlThrow(E_INVALIDARG);
return(Left(StrTraits::StringSpanIncluding(this->GetString(), pszCharSet)));
}
// Return the substring consisting of the leftmost characters not in the set 'pszCharSet'
MyCStringT SpanExcluding(_In_z_ PCXSTR pszCharSet) const
{
assert(MyAtlIsValidString(pszCharSet));
if(pszCharSet == NULL)
AtlThrow(E_INVALIDARG);
return(Left(StrTraits::StringSpanExcluding(this->GetString(), pszCharSet)));
}
// Format data using format string 'pszFormat'
void __cdecl Format(_In_z_ _Printf_format_string_ PCXSTR pszFormat, ...);
// Format data using format string loaded from resource 'nFormatID'
void __cdecl Format(IN _FormatMessage_format_string_ UINT nFormatID, ...);
// Append formatted data using format string loaded from resource 'nFormatID'
void __cdecl AppendFormat(IN _FormatMessage_format_string_ UINT nFormatID, ...);
// Append formatted data using format string 'pszFormat'
void __cdecl AppendFormat(_In_z_ _Printf_format_string_ PCXSTR pszFormat, ...);
void AppendFormatV(
_In_z_ _Printf_format_string_ PCXSTR pszFormat,
IN va_list args)
{
assert(MyAtlIsValidString(pszFormat));
if(pszFormat == NULL)
AtlThrow(E_INVALIDARG);
int nCurrentLength = this->GetLength();
int nAppendLength = StrTraits::GetFormattedLength(pszFormat, args);
if(nAppendLength < 0)
AtlThrow(E_FAIL);
PXSTR pszBuffer = this->GetBuffer(nCurrentLength + nAppendLength);
StrTraits::Format(pszBuffer + nCurrentLength,
nAppendLength + 1, pszFormat, args);
this->ReleaseBufferSetLength(nCurrentLength + nAppendLength);
}
void FormatV(
_In_z_ _Printf_format_string_ PCXSTR pszFormat,
IN va_list args)
{
assert(MyAtlIsValidString(pszFormat));
if(pszFormat == NULL)
AtlThrow(E_INVALIDARG);
int nLength = StrTraits::GetFormattedLength(pszFormat, args);
if(nLength < 0)
AtlThrow(E_FAIL);
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::Format(pszBuffer, nLength + 1, pszFormat, args);
this->ReleaseBufferSetLength(nLength);
}
// OLE BSTR support
// Allocate a BSTR containing a copy of the string
_Ret_z_ BSTR AllocSysString() const
{
BSTR bstrResult = StrTraits::AllocSysString(this->GetString(), this->GetLength());
if(bstrResult == NULL)
{
CThisSimpleString::ThrowMemoryException();
}
return(bstrResult);
}
_Ret_maybenull_z_ BSTR SetSysString(IN_OUT _Deref_post_opt_valid_ _Post_z_ BSTR* pbstr) const
{
assert(AtlIsValidAddress(pbstr, sizeof(BSTR)));
if(!StrTraits::ReAllocSysString(this->GetString(), pbstr,
this->GetLength()))
{
CThisSimpleString::ThrowMemoryException();
}
assert(*pbstr != NULL);
return(*pbstr);
}
#ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
// Set the string to the value of environment variable 'pszVar'
// Load the string from resource 'nID'
_Check_return_ BOOL LoadString(IN UINT nID)
{
HINSTANCE hInst = StrTraits::FindStringResourceInstance(nID);
if(hInst == NULL)
{
return(FALSE);
}
return(LoadString(hInst, nID));
}
#pragma warning(push)
#pragma warning(disable:4200)
struct MYSTRINGRESOURCEIMAGE
{
WORD nLength;
WCHAR achString[];
};
#pragma warning(pop)
static inline const MYSTRINGRESOURCEIMAGE* _AtlGetStringResourceImage(
IN HINSTANCE hInstance,
IN HRSRC hResource,
IN UINT id) throw()
{
const MYSTRINGRESOURCEIMAGE* pImage;
const MYSTRINGRESOURCEIMAGE* pImageEnd;
ULONG nResourceSize;
HGLOBAL hGlobal;
UINT iIndex;
hGlobal = ::LoadResource(hInstance, hResource);
if(hGlobal == NULL)
{
return(NULL);
}
pImage = (const MYSTRINGRESOURCEIMAGE*)::LockResource(hGlobal);
if(pImage == NULL)
{
return(NULL);
}
nResourceSize = ::SizeofResource(hInstance, hResource);
pImageEnd = (const MYSTRINGRESOURCEIMAGE*)(LPBYTE(pImage) + nResourceSize);
iIndex = id & 0x000f;
while((iIndex > 0) && (pImage < pImageEnd))
{
pImage = (const MYSTRINGRESOURCEIMAGE*)(LPBYTE(pImage) + (sizeof(MYSTRINGRESOURCEIMAGE) + (pImage->nLength * sizeof(WCHAR))));
iIndex--;
}
if(pImage >= pImageEnd)
{
return(NULL);
}
if(pImage->nLength == 0)
{
return(NULL);
}
return(pImage);
}
static inline const MYSTRINGRESOURCEIMAGE* AtlGetStringResourceImage(
IN HINSTANCE hInstance,
IN UINT id) throw()
{
HRSRC hResource;
/*
The and operation (& static_cast<WORD>(~0)) protects the expression from being greater
than WORD - this would cause a runtime error when the application is compiled with /RTCc flag.
*/
hResource = ::FindResourceW(hInstance, MAKEINTRESOURCEW((((id >> 4) + 1) & static_cast<WORD>(~0))), (LPWSTR)RT_STRING);
if(hResource == NULL)
{
return(NULL);
}
return _AtlGetStringResourceImage(hInstance, hResource, id);
}
// Load the string from resource 'nID' in module 'hInstance'
_Check_return_ BOOL LoadString(
IN HINSTANCE hInstance,
IN UINT nID)
{
const MYSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage(hInstance, nID);
if(pImage == NULL)
{
return(FALSE);
}
int nLength = StrTraits::GetBaseTypeLength(pImage->achString, pImage->nLength);
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::ConvertToBaseType(pszBuffer, nLength, (LPCWSTR)pImage->achString, pImage->nLength);
this->ReleaseBufferSetLength(nLength);
return(TRUE);
}
// Load the string from resource 'nID' in module 'hInstance', using language 'wLanguageID'
_Check_return_ BOOL LoadString(
IN HINSTANCE hInstance,
IN UINT nID,
IN WORD wLanguageID)
{
const MYSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage(hInstance, nID, wLanguageID);
if(pImage == NULL)
{
return(FALSE);
}
int nLength = StrTraits::GetBaseTypeLength(pImage->achString, pImage->nLength);
PXSTR pszBuffer = this->GetBuffer(nLength);
StrTraits::ConvertToBaseType(pszBuffer, nLength, pImage->achString, pImage->nLength);
this->ReleaseBufferSetLength(nLength);
return(TRUE);
}
#endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
friend MyCStringT operator+(
IN const MyCStringT& str1,
IN const MyCStringT& str2)
{
MyCStringT strResult(str1.GetManager());
CThisSimpleString::Concatenate(strResult, str1, str1.GetLength(), str2, str2.GetLength());
return(strResult);
}
friend MyCStringT operator+(
IN const MyCStringT& str1,
_In_z_ PCXSTR psz2)
{
MyCStringT strResult(str1.GetManager());
CThisSimpleString::Concatenate(strResult, str1, str1.GetLength(), psz2, CThisSimpleString::StringLength(psz2));
return(strResult);
}
friend MyCStringT operator+(
_In_z_ PCXSTR psz1,
IN const MyCStringT& str2)
{
MyCStringT strResult(str2.GetManager());
CThisSimpleString::Concatenate(strResult, psz1, CThisSimpleString::StringLength(psz1), str2, str2.GetLength());
return(strResult);
}
#ifdef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
#define _CSTRING_CHAR_T XCHAR
#else // def _CSTRING_NARROW_WIDE_CONVERSION
#define _CSTRING_CHAR_T char
#endif // def _CSTRING_NARROW_WIDE_CONVERSION
friend MyCStringT operator+(
IN const MyCStringT& str1,
IN _CSTRING_CHAR_T ch2)
{
MyCStringT strResult(str1.GetManager());
XCHAR chTemp = XCHAR(ch2);
CThisSimpleString::Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1);
return(strResult);
}
friend MyCStringT operator+(
IN _CSTRING_CHAR_T ch1,
IN const MyCStringT& str2)
{
MyCStringT strResult(str2.GetManager());
XCHAR chTemp = XCHAR(ch1);
CThisSimpleString::Concatenate(strResult, &chTemp, 1, str2, str2.GetLength());
return(strResult);
}
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
friend MyCStringT operator+(
IN const MyCStringT& str1,
IN wchar_t ch2)
{
MyCStringT strResult(str1.GetManager());
XCHAR chTemp = XCHAR(ch2);
CThisSimpleString::Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1);
return(strResult);
}
friend MyCStringT operator+(
IN wchar_t ch1,
IN const MyCStringT& str2)
{
MyCStringT strResult(str2.GetManager());
XCHAR chTemp = XCHAR(ch1);
CThisSimpleString::Concatenate(strResult, &chTemp, 1, str2, str2.GetLength());
return(strResult);
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
friend bool operator==(
IN const MyCStringT& str1,
IN const MyCStringT& str2) throw()
{
return(str1.Compare(str2) == 0);
}
friend bool operator==(
IN const MyCStringT& str1,
_In_z_ PCXSTR psz2) throw()
{
return(str1.Compare(psz2) == 0);
}
friend bool operator==(
_In_z_ PCXSTR psz1,
IN const MyCStringT& str2) throw()
{
return(str2.Compare(psz1) == 0);
}
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
friend bool operator==(
IN const MyCStringT& str1,
_In_z_ PCYSTR psz2) throw(...)
{
MyCStringT str2(psz2, str1.GetManager());
return(str1 == str2);
}
friend bool operator==(
_In_z_ PCYSTR psz1,
IN const MyCStringT& str2) throw(...)
{
MyCStringT str1(psz1, str2.GetManager());
return(str1 == str2);
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
friend bool operator!=(
IN const MyCStringT& str1,
IN const MyCStringT& str2) throw()
{
return(str1.Compare(str2) != 0);
}
friend bool operator!=(
IN const MyCStringT& str1,
_In_z_ PCXSTR psz2) throw()
{
return(str1.Compare(psz2) != 0);
}
friend bool operator!=(
_In_z_ PCXSTR psz1,
IN const MyCStringT& str2) throw()
{
return(str2.Compare(psz1) != 0);
}
#ifndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
friend bool operator!=(
IN const MyCStringT& str1,
_In_z_ PCYSTR psz2) throw(...)
{
MyCStringT str2(psz2, str1.GetManager());
return(str1 != str2);
}
friend bool operator!=(
_In_z_ PCYSTR psz1,
IN const MyCStringT& str2) throw(...)
{
MyCStringT str1(psz1, str2.GetManager());
return(str1 != str2);
}
#endif // ndef _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
friend bool operator<(
IN const MyCStringT& str1,
IN const MyCStringT& str2) throw()
{
return(str1.Compare(str2) < 0);
}
friend bool operator<(
IN const MyCStringT& str1,
_In_z_ PCXSTR psz2) throw()
{
return(str1.Compare(psz2) < 0);
}
friend bool operator<(
_In_z_ PCXSTR psz1,
IN const MyCStringT& str2) throw()
{
return(str2.Compare(psz1) > 0);
}
friend bool operator>(
IN const MyCStringT& str1,
IN const MyCStringT& str2) throw()
{
return(str1.Compare(str2) > 0);
}
friend bool operator>(
IN const MyCStringT& str1,
_In_z_ PCXSTR psz2) throw()
{
return(str1.Compare(psz2) > 0);
}
friend bool operator>(
_In_z_ PCXSTR psz1,
IN const MyCStringT& str2) throw()
{
return(str2.Compare(psz1) < 0);
}
friend bool operator<=(
IN const MyCStringT& str1,
IN const MyCStringT& str2) throw()
{
return(str1.Compare(str2) <= 0);
}
friend bool operator<=(
IN const MyCStringT& str1,
_In_z_ PCXSTR psz2) throw()
{
return(str1.Compare(psz2) <= 0);
}
friend bool operator<=(
_In_z_ PCXSTR psz1,
IN const MyCStringT& str2) throw()
{
return(str2.Compare(psz1) >= 0);
}
friend bool operator>=(
IN const MyCStringT& str1,
IN const MyCStringT& str2) throw()
{
return(str1.Compare(str2) >= 0);
}
friend bool operator>=(
IN const MyCStringT& str1,
_In_z_ PCXSTR psz2) throw()
{
return(str1.Compare(psz2) >= 0);
}
friend bool operator>=(
_In_z_ PCXSTR psz1,
IN const MyCStringT& str2) throw()
{
return(str2.Compare(psz1) <= 0);
}
friend bool operator==(
IN XCHAR ch1,
IN const MyCStringT& str2) throw()
{
return((str2.GetLength() == 1) && (str2[0] == ch1));
}
friend bool operator==(
IN const MyCStringT& str1,
IN XCHAR ch2) throw()
{
return((str1.GetLength() == 1) && (str1[0] == ch2));
}
friend bool operator!=(
IN XCHAR ch1,
IN const MyCStringT& str2) throw()
{
return((str2.GetLength() != 1) || (str2[0] != ch1));
}
friend bool operator!=(
IN const MyCStringT& str1,
IN XCHAR ch2) throw()
{
return((str1.GetLength() != 1) || (str1[0] != ch2));
}
private:
bool CheckImplicitLoad(IN_OPT const void* pv)
{
bool bRet = false;
if((pv != NULL) && IS_INTRESOURCE(pv))
{
UINT nID = LOWORD(reinterpret_cast<DWORD_PTR>(pv));
(nID);
#ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
if(!LoadString(nID))
{
//ATLTRACE(atlTraceString, 2, _T("Warning: implicit LoadString(%u) failed\n"), nID);
}
bRet = true;
#else
//ATLTRACE(atlTraceString, 2, _T("Warning: LoadString(%u) not supported under the current WINAPI_FAMILY.\n"), nID);
#endif
}
return(bRet);
}
};
template< typename BaseType >
MyCStringT<BaseType>::MyCStringT(const VARIANT& varSrc) :
CThisSimpleString(StrTraits::GetDefaultManager())
{
CComVariant varResult;
HRESULT hr = ::VariantChangeType(&varResult, const_cast<VARIANT*>(&varSrc), 0, VT_BSTR);
if(FAILED(hr))
{
AtlThrow(hr);
}
*this = V_BSTR(&varResult);
}
#ifndef _CSTRING_BUFFER_SIZE
#define _CSTRING_BUFFER_SIZE(_CStringObj) ((_CStringObj).GetAllocLength() + 1)
#endif
#pragma warning(push)
#pragma warning(disable : 4793)
// Format data using format string 'pszFormat'
template< typename BaseType >
inline void __cdecl MyCStringT<BaseType >::Format(PCXSTR pszFormat, ...)
{
assert(MyAtlIsValidString(pszFormat));
va_list argList;
va_start(argList, pszFormat);
FormatV(pszFormat, argList);
va_end(argList);
}
// Format data using format string loaded from resource 'nFormatID'
template< typename BaseType >
inline void __cdecl MyCStringT<BaseType>::Format(UINT nFormatID, ...)
{
MyCStringT strFormat(GetManager());
ATLENSURE(strFormat.LoadString(nFormatID));
va_list argList;
va_start(argList, nFormatID);
FormatV(strFormat, argList);
va_end(argList);
}
// Append formatted data using format string loaded from resource 'nFormatID'
template< typename BaseType >
inline void __cdecl MyCStringT<BaseType>::AppendFormat(UINT nFormatID, ...)
{
va_list argList;
va_start(argList, nFormatID);
MyCStringT strFormat(GetManager());
ATLENSURE(strFormat.LoadString(nFormatID));
AppendFormatV(strFormat, argList);
va_end(argList);
}
// Append formatted data using format string 'pszFormat'
template< typename BaseType >
inline void __cdecl MyCStringT<BaseType>::AppendFormat(PCXSTR pszFormat, ...)
{
assert(MyAtlIsValidString(pszFormat));
va_list argList;
va_start(argList, pszFormat);
AppendFormatV(pszFormat, argList);
va_end(argList);
}
/**************************************************************************
*
* 文件名也得叫做atlstr.h这样通过设置附加包含路径,就可以替换原有的atlstr.h
* 替换后CString CStringA CStringW等定义都发生变化
**************************************************************************/
#define MY_CSTRING
#define _CSTRING_NS
#define MY_STR_DEFINE 0
#if MY_STR_DEFINE
#define CStringW MyCStringT<WCHAR>
#define CStringA MyCStringT<CHAR>
#ifdef _UNICODE
#define CString CStringW;
#else
#define CString CStringA;
#endif
#define CAtlString CString
#else
typedef MyCStringT<WCHAR> CStringW;
typedef MyCStringT<CHAR> CStringA;
#ifdef _UNICODE
typedef CStringW CString;
#else
typedef CStringA CString;
#endif
typedef CString CAtlString;
#endif