📄 atl_cstring.cpp
字号:
// MFC CString extracted from Visual C++ 6.0 sp3 for use with ATL.
// Can be used stand-alone with no dependencies on MFC libraries.
// Created via DevStudio macro written by K. Shane Triem, 6/25/1999.
// -----------------------------------------------------------------
#include "stdafx.h"
#include "ATL_CString.h"
#include "limits.h"
#ifndef __AFX_H__
#define __AFX_H__
#endif
#include "..\src\FixAlloc.h"
#include <TCHAR.H>
#include <stdio.h>
#define TRY try
#define CATCH catch
#define CATCH_ALL(e) catch (...)
#define THROW_LAST() throw
#define END_CATCH_ALL
//-----------------------------------------------------------------------------
// --- from STRCORE.CPP
/////////////////////////////////////////////////////////////////////////////
// static class data, special inlines
// afxChNil is left for backward compatibility
AFX_DATADEF TCHAR afxChNil = '\0';
// For an empty string, m_pchData will point here
// (note: avoids special case of checking for NULL m_pchData)
// empty string data (and locked)
AFX_STATIC_DATA int _afxInitData[] = { -1, 0, 0, 0 };
AFX_STATIC_DATA CStringData* _afxDataNil = (CStringData*)&_afxInitData;
AFX_COMDAT LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));
// special function to make afxEmptyString work even during initialization
const CString& AFXAPI AfxGetEmptyString()
{ return *(CString*)&_afxPchNil; }
// --- from VALIDADD.CPP
// AfxIsValidString() returns TRUE if the passed pointer
// references a string of at least the given length in characters.
// A length of -1 (the default parameter) means that the string
// buffer's minimum length isn't known, and the function will
// return TRUE no matter how long the string is. The memory
// used by the string can be read-only.
BOOL AFXAPI AfxIsValidString(LPCWSTR lpsz, int nLength /* = -1 */)
{
if (lpsz == NULL)
return FALSE;
return /*afxData.bWin95 || */ ::IsBadStringPtrW(lpsz, nLength) == 0;
}
// As above, but for ANSI strings.
BOOL AFXAPI AfxIsValidString(LPCSTR lpsz, int nLength /* = -1 */)
{
if (lpsz == NULL)
return FALSE;
return ::IsBadStringPtrA(lpsz, nLength) == 0;
}
// AfxIsValidAddress() returns TRUE if the passed parameter points
// to at least nBytes of accessible memory. If bReadWrite is TRUE,
// the memory must be writeable; if bReadWrite is FALSE, the memory
// may be const.
BOOL AFXAPI AfxIsValidAddress(const void* lp, UINT nBytes,
BOOL bReadWrite /* = TRUE */)
{
// simple version using Win-32 APIs for pointer validation.
return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
(!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
}
// --- from OLEDISP1.CPP
///////////////////////////////////////////////////////////////////////////////
// OLE BSTR support
BSTR CString::AllocSysString() const
{
#if defined(_UNICODE) || defined(OLE2ANSI)
BSTR bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
if (bstr == NULL)
{
ATLASSERT(0);
//AfxThrowMemoryException();
return NULL;
}
#else
int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
GetData()->nDataLength, NULL, NULL);
BSTR bstr = ::SysAllocStringLen(NULL, nLen);
if (bstr == NULL)
{
ATLASSERT(0);
//AfxThrowMemoryException();
return NULL;
}
MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength,
bstr, nLen);
#endif
return bstr;
}
BSTR CString::SetSysString(BSTR* pbstr) const
{
ATLASSERT(AfxIsValidAddress(pbstr, sizeof(BSTR)));
#if defined(_UNICODE) || defined(OLE2ANSI)
if (!::SysReAllocStringLen(pbstr, m_pchData, GetData()->nDataLength))
{
ATLASSERT(0);
//AfxThrowMemoryException();
return *pbstr;
}
#else
int nLen = MultiByteToWideChar(CP_ACP, 0, m_pchData,
GetData()->nDataLength, NULL, NULL);
if (!::SysReAllocStringLen(pbstr, NULL, nLen))
{
ATLASSERT(0);
//AfxThrowMemoryException();
return *pbstr;
}
MultiByteToWideChar(CP_ACP, 0, m_pchData, GetData()->nDataLength,
*pbstr, nLen);
#endif
ATLASSERT(*pbstr != NULL);
return *pbstr;
}
// --- from STRCORE.CPP
#ifdef _AFXDLL
CString::CString()
{
Init();
}
#endif
CString::CString(const CString& stringSrc)
{
ATLASSERT(stringSrc.GetData()->nRefs != 0);
if (stringSrc.GetData()->nRefs >= 0)
{
ATLASSERT(stringSrc.GetData() != _afxDataNil);
m_pchData = stringSrc.m_pchData;
InterlockedIncrement(&GetData()->nRefs);
}
else
{
Init();
*this = stringSrc.m_pchData;
}
}
#ifndef _DEBUG
#pragma warning(disable: 4074)
#pragma init_seg(compiler)
#define ROUND(x,y) (((x)+(y-1))&~(y-1))
#define ROUND4(x) ROUND(x, 4)
AFX_STATIC CFixedAlloc _afxAlloc64(ROUND4(65*sizeof(TCHAR)+sizeof(CStringData)));
AFX_STATIC CFixedAlloc _afxAlloc128(ROUND4(129*sizeof(TCHAR)+sizeof(CStringData)));
AFX_STATIC CFixedAlloc _afxAlloc256(ROUND4(257*sizeof(TCHAR)+sizeof(CStringData)));
AFX_STATIC CFixedAlloc _afxAlloc512(ROUND4(513*sizeof(TCHAR)+sizeof(CStringData)));
#endif //!_DEBUG
void CString::AllocBuffer(int nLen)
// always allocate one extra character for '\0' termination
// assumes [optimistically] that data length will equal allocation length
{
ATLASSERT(nLen >= 0);
ATLASSERT(nLen <= INT_MAX-1); // max size (enough room for 1 extra)
if (nLen == 0)
Init();
else
{
CStringData* pData;
#ifndef _DEBUG
if (nLen <= 64)
{
pData = (CStringData*)_afxAlloc64.Alloc();
pData->nAllocLength = 64;
}
else if (nLen <= 128)
{
pData = (CStringData*)_afxAlloc128.Alloc();
pData->nAllocLength = 128;
}
else if (nLen <= 256)
{
pData = (CStringData*)_afxAlloc256.Alloc();
pData->nAllocLength = 256;
}
else if (nLen <= 512)
{
pData = (CStringData*)_afxAlloc512.Alloc();
pData->nAllocLength = 512;
}
else
#endif
{
pData = (CStringData*)
new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
pData->nAllocLength = nLen;
}
pData->nRefs = 1;
pData->data()[nLen] = '\0';
pData->nDataLength = nLen;
m_pchData = pData->data();
}
}
void FASTCALL CString::FreeData(CStringData* pData)
{
#ifndef _DEBUG
int nLen = pData->nAllocLength;
if (nLen == 64)
_afxAlloc64.Free(pData);
else if (nLen == 128)
_afxAlloc128.Free(pData);
else if (nLen == 256)
_afxAlloc256.Free(pData);
else if (nLen == 512)
_afxAlloc512.Free(pData);
else
{
ATLASSERT(nLen > 512);
delete[] (BYTE*)pData;
}
#else
delete[] (BYTE*)pData;
#endif
}
void CString::Release()
{
if (GetData() != _afxDataNil)
{
ATLASSERT(GetData()->nRefs != 0);
if (InterlockedDecrement(&GetData()->nRefs) <= 0)
FreeData(GetData());
Init();
}
}
void PASCAL CString::Release(CStringData* pData)
{
if (pData != _afxDataNil)
{
ATLASSERT(pData->nRefs != 0);
if (InterlockedDecrement(&pData->nRefs) <= 0)
FreeData(pData);
}
}
void CString::Empty()
{
if (GetData()->nDataLength == 0)
return;
if (GetData()->nRefs >= 0)
Release();
else
*this = &afxChNil;
ATLASSERT(GetData()->nDataLength == 0);
ATLASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
}
void CString::CopyBeforeWrite()
{
if (GetData()->nRefs > 1)
{
CStringData* pData = GetData();
Release();
AllocBuffer(pData->nDataLength);
memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
}
ATLASSERT(GetData()->nRefs <= 1);
}
void CString::AllocBeforeWrite(int nLen)
{
if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
{
Release();
AllocBuffer(nLen);
}
ATLASSERT(GetData()->nRefs <= 1);
}
CString::~CString()
// free any attached data
{
if (GetData() != _afxDataNil)
{
if (InterlockedDecrement(&GetData()->nRefs) <= 0)
FreeData(GetData());
}
}
//////////////////////////////////////////////////////////////////////////////
// Helpers for the rest of the implementation
void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
int nExtraLen) const
{
// will clone the data attached to this string
// allocating 'nExtraLen' characters
// Places results in uninitialized string 'dest'
// Will copy the part or all of original data to start of new string
int nNewLen = nCopyLen + nExtraLen;
if (nNewLen == 0)
{
dest.Init();
}
else
{
dest.AllocBuffer(nNewLen);
memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
}
}
//////////////////////////////////////////////////////////////////////////////
// More sophisticated construction
CString::CString(LPCTSTR lpsz)
{
Init();
if (lpsz != NULL && HIWORD(lpsz) == NULL)
{
UINT nID = LOWORD((DWORD)lpsz);
if (!LoadString(nID))
ATLTRACE("Warning: implicit LoadString(%u) failed\n", nID);
}
else
{
int nLen = SafeStrlen(lpsz);
if (nLen != 0)
{
AllocBuffer(nLen);
memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
}
}
}
/////////////////////////////////////////////////////////////////////////////
// Special conversion constructors
#ifdef _UNICODE
CString::CString(LPCSTR lpsz)
{
Init();
int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
if (nSrcLen != 0)
{
AllocBuffer(nSrcLen);
_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
ReleaseBuffer();
}
}
#else //_UNICODE
CString::CString(LPCWSTR lpsz)
{
Init();
int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
if (nSrcLen != 0)
{
AllocBuffer(nSrcLen*2);
_wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
ReleaseBuffer();
}
}
#endif //!_UNICODE
//////////////////////////////////////////////////////////////////////////////
// Diagnostic support
//#ifdef _DEBUG
//CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CString& string)
//{
// dc << string.m_pchData;
// return dc;
//}
//#endif //_DEBUG
//////////////////////////////////////////////////////////////////////////////
// Assignment operators
// All assign a new value to the string
// (a) first see if the buffer is big enough
// (b) if enough room, copy on top of old buffer, set size and type
// (c) otherwise free old string data, and create a new one
//
// All routines return the new string (but as a 'const CString&' so that
// assigning it again will cause a copy, eg: s1 = s2 = "hi there".
//
void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
{
AllocBeforeWrite(nSrcLen);
memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
GetData()->nDataLength = nSrcLen;
m_pchData[nSrcLen] = '\0';
}
const CString& CString::operator=(const CString& stringSrc)
{
if (m_pchData != stringSrc.m_pchData)
{
if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) ||
stringSrc.GetData()->nRefs < 0)
{
// actual copy necessary since one of the strings is locked
AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
}
else
{
// can just copy references around
Release();
ATLASSERT(stringSrc.GetData() != _afxDataNil);
m_pchData = stringSrc.m_pchData;
InterlockedIncrement(&GetData()->nRefs);
}
}
return *this;
}
const CString& CString::operator=(LPCTSTR lpsz)
{
ATLASSERT(lpsz == NULL || AfxIsValidString(lpsz));
AssignCopy(SafeStrlen(lpsz), lpsz);
return *this;
}
/////////////////////////////////////////////////////////////////////////////
// Special conversion assignment
#ifdef _UNICODE
const CString& CString::operator=(LPCSTR lpsz)
{
int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
AllocBeforeWrite(nSrcLen);
_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
ReleaseBuffer();
return *this;
}
#else //!_UNICODE
const CString& CString::operator=(LPCWSTR lpsz)
{
int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
AllocBeforeWrite(nSrcLen*2);
_wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
ReleaseBuffer();
return *this;
}
#endif //!_UNICODE
//////////////////////////////////////////////////////////////////////////////
// concatenation
// NOTE: "operator+" is done as friend functions for simplicity
// There are three variants:
// CString + CString
// and for ? = TCHAR, LPCTSTR
// CString + ?
// ? + CString
void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
int nSrc2Len, LPCTSTR lpszSrc2Data)
{
// -- master concatenation routine
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -