Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

382 lines
7.5 KiB

/*++
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;
}