| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680 |
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992-1998 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
- #include "stdafx.h"
- #include "fixalloc.h"
- #ifdef AFX_CORE1_SEG
- #pragma code_seg(AFX_CORE1_SEG)
- #endif
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- #define new DEBUG_NEW
- HINSTANCE afxCurrentResourceHandle;
- /////////////////////////////////////////////////////////////////////////////
- // 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; }
- //////////////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- #ifdef _AFXDLL
- CString::CString()
- {
- Init();
- }
- #endif
- CString::CString(const CString& stringSrc)
- {
- ASSERT(stringSrc.GetData()->nRefs != 0);
- if (stringSrc.GetData()->nRefs >= 0)
- {
- ASSERT(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
- {
- ASSERT(nLen >= 0);
- ASSERT(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
- {
- ASSERT(nLen > 512);
- delete[] (BYTE*)pData;
- }
- #else
- delete[] (BYTE*)pData;
- #endif
- }
- void CString::Release()
- {
- if (GetData() != _afxDataNil)
- {
- ASSERT(GetData()->nRefs != 0);
- if (InterlockedDecrement(&GetData()->nRefs) <= 0)
- FreeData(GetData());
- Init();
- }
- }
- void PASCAL CString::Release(CStringData* pData)
- {
- if (pData != _afxDataNil)
- {
- ASSERT(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;
- ASSERT(GetData()->nDataLength == 0);
- ASSERT(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));
- }
- ASSERT(GetData()->nRefs <= 1);
- }
- void CString::AllocBeforeWrite(int nLen)
- {
- if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
- {
- Release();
- AllocBuffer(nLen);
- }
- ASSERT(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))
- TRACE1("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();
- ASSERT(stringSrc.GetData() != _afxDataNil);
- m_pchData = stringSrc.m_pchData;
- InterlockedIncrement(&GetData()->nRefs);
- }
- }
- return *this;
- }
- const CString& CString::operator=(LPCTSTR lpsz)
- {
- ASSERT(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
- // Concatenate two sources
- // -- assume that 'this' is a new CString object
- int nNewLen = nSrc1Len + nSrc2Len;
- if (nNewLen != 0)
- {
- AllocBuffer(nNewLen);
- memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
- memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
- }
- }
- CString AFXAPI operator+(const CString& string1, const CString& string2)
- {
- CString s;
- s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
- string2.GetData()->nDataLength, string2.m_pchData);
- return s;
- }
- CString AFXAPI operator+(const CString& string, LPCTSTR lpsz)
- {
- ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
- CString s;
- s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
- CString::SafeStrlen(lpsz), lpsz);
- return s;
- }
- CString AFXAPI operator+(LPCTSTR lpsz, const CString& string)
- {
- ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
- CString s;
- s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
- string.m_pchData);
- return s;
- }
- //////////////////////////////////////////////////////////////////////////////
- // concatenate in place
- void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
- {
- // -- the main routine for += operators
- // concatenating an empty string is a no-op!
- if (nSrcLen == 0)
- return;
- // if the buffer is too small, or we have a width mis-match, just
- // allocate a new buffer (slow but sure)
- if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
- {
- // we have to grow the buffer, use the ConcatCopy routine
- CStringData* pOldData = GetData();
- ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
- ASSERT(pOldData != NULL);
- CString::Release(pOldData);
- }
- else
- {
- // fast concatenation when buffer big enough
- memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
- GetData()->nDataLength += nSrcLen;
- ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
- m_pchData[GetData()->nDataLength] = '\0';
- }
- }
- const CString& CString::operator+=(LPCTSTR lpsz)
- {
- ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
- ConcatInPlace(SafeStrlen(lpsz), lpsz);
- return *this;
- }
- const CString& CString::operator+=(TCHAR ch)
- {
- ConcatInPlace(1, &ch);
- return *this;
- }
- const CString& CString::operator+=(const CString& string)
- {
- ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Advanced direct buffer access
- LPTSTR CString::GetBuffer(int nMinBufLength)
- {
- ASSERT(nMinBufLength >= 0);
- if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
- {
- #ifdef _DEBUG
- // give a warning in case locked string becomes unlocked
- if (GetData() != _afxDataNil && GetData()->nRefs < 0)
- TRACE0("Warning: GetBuffer on locked CString creates unlocked CString!\n");
- #endif
- // we have to grow the buffer
- CStringData* pOldData = GetData();
- int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
- if (nMinBufLength < nOldLen)
- nMinBufLength = nOldLen;
- AllocBuffer(nMinBufLength);
- memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
- GetData()->nDataLength = nOldLen;
- CString::Release(pOldData);
- }
- ASSERT(GetData()->nRefs <= 1);
- // return a pointer to the character storage for this string
- ASSERT(m_pchData != NULL);
- return m_pchData;
- }
- void CString::ReleaseBuffer(int nNewLength)
- {
- CopyBeforeWrite(); // just in case GetBuffer was not called
- if (nNewLength == -1)
- nNewLength = lstrlen(m_pchData); // zero terminated
- ASSERT(nNewLength <= GetData()->nAllocLength);
- GetData()->nDataLength = nNewLength;
- m_pchData[nNewLength] = '\0';
- }
- LPTSTR CString::GetBufferSetLength(int nNewLength)
- {
- ASSERT(nNewLength >= 0);
- GetBuffer(nNewLength);
- GetData()->nDataLength = nNewLength;
- m_pchData[nNewLength] = '\0';
- return m_pchData;
- }
- void CString::FreeExtra()
- {
- ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
- if (GetData()->nDataLength != GetData()->nAllocLength)
- {
- CStringData* pOldData = GetData();
- AllocBuffer(GetData()->nDataLength);
- memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
- ASSERT(m_pchData[GetData()->nDataLength] == '\0');
- CString::Release(pOldData);
- }
- ASSERT(GetData() != NULL);
- }
- LPTSTR CString::LockBuffer()
- {
- LPTSTR lpsz = GetBuffer(0);
- GetData()->nRefs = -1;
- return lpsz;
- }
- void CString::UnlockBuffer()
- {
- ASSERT(GetData()->nRefs == -1);
- if (GetData() != _afxDataNil)
- GetData()->nRefs = 1;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Commonly used routines (rarely used routines in STREX.CPP)
- int CString::Find(TCHAR ch) const
- {
- return Find(ch, 0);
- }
- int CString::Find(TCHAR ch, int nStart) const
- {
- int nLength = GetData()->nDataLength;
- if (nStart >= nLength)
- return -1;
- // find first single character
- LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch);
- // return -1 if not found and index otherwise
- return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
- }
- int CString::FindOneOf(LPCTSTR lpszCharSet) const
- {
- ASSERT(AfxIsValidString(lpszCharSet));
- LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
- return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
- }
- void CString::MakeUpper()
- {
- CopyBeforeWrite();
- _tcsupr(m_pchData);
- }
- void CString::MakeLower()
- {
- CopyBeforeWrite();
- _tcslwr(m_pchData);
- }
- void CString::MakeReverse()
- {
- CopyBeforeWrite();
- _tcsrev(m_pchData);
- }
- void CString::SetAt(int nIndex, TCHAR ch)
- {
- ASSERT(nIndex >= 0);
- ASSERT(nIndex < GetData()->nDataLength);
- CopyBeforeWrite();
- m_pchData[nIndex] = ch;
- }
- #ifndef _UNICODE
- void CString::AnsiToOem()
- {
- CopyBeforeWrite();
- ::AnsiToOem(m_pchData, m_pchData);
- }
- void CString::OemToAnsi()
- {
- CopyBeforeWrite();
- ::OemToAnsi(m_pchData, m_pchData);
- }
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- // CString conversion helpers (these use the current system locale)
- int AFX_CDECL _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
- {
- if (count == 0 && mbstr != NULL)
- return 0;
- int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
- mbstr, count, NULL, NULL);
- ASSERT(mbstr == NULL || result <= (int)count);
- if (result > 0)
- mbstr[result-1] = 0;
- return result;
- }
- int AFX_CDECL _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
- {
- if (count == 0 && wcstr != NULL)
- return 0;
- int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,
- wcstr, count);
- ASSERT(wcstr == NULL || result <= (int)count);
- if (result > 0)
- wcstr[result-1] = 0;
- return result;
- }
- LPWSTR AFXAPI AfxA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars)
- {
- if (lpa == NULL)
- return NULL;
- ASSERT(lpw != NULL);
- // verify that no illegal character present
- // since lpw was allocated based on the size of lpa
- // don't worry about the number of chars
- lpw[0] = '\0';
- VERIFY(MultiByteToWideChar(CP_ACP, 0, lpa, -1, lpw, nChars));
- return lpw;
- }
- LPSTR AFXAPI AfxW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars)
- {
- if (lpw == NULL)
- return NULL;
- ASSERT(lpa != NULL);
- // verify that no illegal character present
- // since lpa was allocated based on the size of lpw
- // don't worry about the number of chars
- lpa[0] = '\0';
- VERIFY(WideCharToMultiByte(CP_ACP, 0, lpw, -1, lpa, nChars, NULL, NULL));
- return lpa;
- }
- ///////////////////////////////////////////////////////////////////////////////
|