|
|
/*++
Copyright (c) 1985 - 1999, Microsoft Corporation
Module Name:
cstring.cpp
Abstract:
This file implements the CString class.
Author:
Revision History:
Notes:
--*/
#include "private.h"
#include <tchar.h>
#include "cstring.h"
/////////////////////////////////////////////////////////////////////////////
// static class data
// afxChNil is left for backward compatibility
TCHAR afxChNil = TEXT('\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)
int _afxInitData[] = { -1, 0, 0, 0 }; CStringData* _afxDataNil = (CStringData*)&_afxInitData;
LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));
/////////////////////////////////////////////////////////////////////////////
// CString
CString::CString( ) { Init(); }
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; } }
CString::CString( LPCSTR lpsz ) { Init(); *this = lpsz; }
CString::CString( LPCSTR lpsz, int nLength ) { Init(); if (nLength != 0) { AllocBuffer(nLength); memcpy(m_pchData, lpsz, nLength*sizeof(TCHAR)); } }
CString::~CString( ) { // free any attached data
if (GetData() != _afxDataNil) { if (InterlockedDecrement(&GetData()->nRefs) <= 0) FreeData(GetData()); } }
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)); } }
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;
pData = (CStringData*) new BYTE[ sizeof(CStringData) + (nLen+1)*sizeof(TCHAR) ];
if (pData) { pData->nAllocLength = nLen;
pData->nRefs = 1; pData->data()[nLen] = TEXT('\0'); pData->nDataLength = nLen; m_pchData = pData->data(); } } }
void CString::FreeData( CStringData* pData ) { delete [] (BYTE*)pData; }
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::AllocBeforeWrite( int nLen ) { if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength) { Release(); AllocBuffer(nLen); } ASSERT(GetData()->nRefs <= 1); }
int CString::Compare( LPCTSTR lpsz ) const { return _tcscmp(m_pchData, lpsz); // MBSC/Unicode aware
}
int CString::CompareNoCase( LPCTSTR lpsz ) const { return _tcsicmp(m_pchData, lpsz); // MBCS/Unicode aware
}
CString CString::Mid( int nFirst ) const { return Mid(nFirst, GetData()->nDataLength - nFirst); }
CString CString::Mid( int nFirst, int nCount ) const { // out-of-bounds requests return sensible things
if (nFirst < 0) nFirst = 0; if (nCount < 0) nCount = 0;
if (nFirst + nCount > GetData()->nDataLength) nCount = GetData()->nDataLength - nFirst; if (nFirst > GetData()->nDataLength) nCount = 0;
ASSERT(nFirst >= 0); ASSERT(nFirst + nCount <= GetData()->nDataLength);
// optimize case of returning entire string
if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength) return *this;
CString dest; AllocCopy(dest, nCount, nFirst, 0); return dest; }
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); }
/////////////////////////////////////////////////////////////////////////////
// Assignment opeators
// 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] = TEXT('\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 reference around
Release(); ASSERT(stringSrc.GetData() != _afxDataNil); m_pchData = stringSrc.m_pchData; InterlockedIncrement(&GetData()->nRefs); } } return *this; }
const CString& CString::operator=( char ch ) { AssignCopy(1, &ch); return *this; }
const CString& CString::operator=( LPCTSTR lpsz ) { ASSERT(lpsz != NULL); AssignCopy(SafeStrlen(lpsz), lpsz); return *this; }
CString::operator LPCTSTR( ) const { return m_pchData; }
int PASCAL CString::SafeStrlen( LPCTSTR lpsz ) { return (lpsz == NULL) ? 0 : lstrlen(lpsz); }
// Compare helpers
bool operator==( const CString& s1, const CString& s2 ) { return s1.Compare(s2) == 0; }
bool operator==( const CString& s1, LPCTSTR s2 ) { return s1.Compare(s2) == 0; }
bool operator==( LPCTSTR s1, CString& s2 ) { return s2.Compare(s1) == 0; }
|