windows-nt/Source/XPSP1/NT/ds/security/passport/atlmfc/cstringt.h
2020-09-26 16:20:57 +08:00

3259 lines
77 KiB
C++

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-2001 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.
/////////////////////////////////////////////////////////////////////////////
// CSTRINGT.H - Framework-independent, templateable string class
#ifndef __CSTRINGT_H__
#define __CSTRINGT_H__
#pragma once
#pragma warning(disable:4786) // avoid 255-character limit warnings
#ifdef _MANAGED
#include <vcclr.h> // For PtrToStringChars
#endif
#include <atlsimpstr.h>
#include <objbase.h>
#include <oleauto.h>
#include <stddef.h>
#ifndef _INC_NEW
#include <new.h>
#endif
#include <stdio.h>
#include <limits.h>
#ifndef _ATL_NO_DEBUG_CRT
#include <crtdbg.h>
#endif
#ifndef _ATL_MIN_CRT
#include <mbstring.h>
#endif
#ifdef _ATL_CSTRING_EXPLICIT_CONSTRUCTORS
#define CSTRING_EXPLICIT explicit
#else
#define CSTRING_EXPLICIT
#endif
#include <atlconv.h>
#include <atlmem.h>
#pragma push_macro("new")
#undef new
/////////////////////////////////////////////////////////////////////////////
// Naming conventions:
// The term "length" can be confusing when dealing with ANSI, Unicode, and
// MBCS character sets, so this file will use the following naming
// conventions to differentiate between the different meanings of
// "length":
//
// 'Byte Length' - Length of a buffer in bytes, regardless of character
// size
// 'Char Length' - Number of distinct characters in string. For wide-
// character strings, this is equivalent to half the 'Byte Length'.
// For ANSI strings, this is equivalent to the 'Byte Length'. For MBCS
// strings, 'Char Length' counts a lead-byte/trail-byte combination
// as one character.
// 'Length' - When neither of the above terms is used, 'Length' refers to
// length in XCHARs, which is equal to 'Byte Length'/sizeof(XCHAR).
/////////////////////////////////////////////////////////////////////////////
namespace ATL
{
/////////////////////////////////////////////////////////////////////////////
// inline helpers
inline int _wcstombsz(char* mbstr, const wchar_t* wcstr, ULONG count) throw()
{
// count is number of bytes
if (count == 0 && mbstr != NULL)
return 0;
int result = ::WideCharToMultiByte(_AtlGetConversionACP(), 0, wcstr, -1,
mbstr, count, NULL, NULL);
ATLASSERT(mbstr == NULL || result <= (int)count);
return result;
}
inline int _mbstowcsz(wchar_t* wcstr, const char* mbstr, ULONG count) throw()
{
// count is number of wchar_t's
if (count == 0 && wcstr != NULL)
return 0;
int result = ::MultiByteToWideChar(_AtlGetConversionACP(), 0, mbstr, -1,
wcstr, count);
ATLASSERT(wcstr == NULL || result <= (int)count);
if ((result > 0) && (wcstr != NULL))
wcstr[result-1] = 0;
return result;
}
#if !defined(_UNICODE) || defined(_CSTRING_ALWAYS_THUNK)
// Win9x doesn't support Unicode versions of these useful string functions.
// If the app was built without _UNICODE defined, we thunk at runtime to
// either the real Unicode implementation (on NT), or a conversion helper
// (on Win9x).
inline void _AtlInstallStringThunk(void** ppThunk, void* pfnWin9x, void* pfnNT) throw()
{
static bool s_bWin9x = (::GetVersion()&0x80000000) != 0;
void* pfn;
if (s_bWin9x)
pfn = pfnWin9x;
else
{
#ifdef _CSTRING_ALWAYS_THUNK
pfn = pfnWin9x;
(void)pfnNT;
#else
pfn = pfnNT;
#endif
}
InterlockedExchangePointer(ppThunk, pfn);
}
typedef int (WINAPI* ATLCOMPARESTRINGW)(LCID, DWORD, LPCWSTR, int, LPCWSTR, int);
typedef BOOL (WINAPI* ATLGETSTRINGTYPEEXW)(LCID, DWORD, LPCWSTR, int, LPWORD);
typedef int (WINAPI* ATLLSTRCMPIW)(LPCWSTR, LPCWSTR);
typedef LPWSTR (WINAPI* ATLCHARLOWERW)(LPWSTR);
typedef LPWSTR (WINAPI* ATLCHARUPPERW)(LPWSTR);
typedef DWORD (WINAPI* ATLGETENVIRONMENTVARIABLEW)(LPCWSTR, LPWSTR, DWORD);
struct _AtlStringThunks
{
ATLCOMPARESTRINGW pfnCompareStringW;
ATLGETSTRINGTYPEEXW pfnGetStringTypeExW;
ATLLSTRCMPIW pfnlstrcmpiW;
ATLCHARLOWERW pfnCharLowerW;
ATLCHARUPPERW pfnCharUpperW;
ATLGETENVIRONMENTVARIABLEW pfnGetEnvironmentVariableW;
};
extern _AtlStringThunks _strthunks;
inline DWORD WINAPI GetEnvironmentVariableWFake(LPCWSTR pszName,
LPWSTR pszBuffer, DWORD nSize)
{
USES_CONVERSION;
ULONG nSizeA;
ULONG nSizeW;
LPSTR pszNameA;
LPSTR pszBufferA;
pszNameA = W2A(pszName);
nSizeA = ::GetEnvironmentVariableA(pszNameA, NULL, 0);
if (nSizeA == 0)
return 0;
pszBufferA = LPSTR(_alloca(nSizeA*2));
::GetEnvironmentVariableA(pszNameA, pszBufferA, nSizeA);
nSizeW = ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszBufferA, -1, NULL, 0);
if (nSize == 0)
return nSizeW;
ATLASSERT(nSize >= nSizeW);
::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszBufferA, -1, pszBuffer, nSizeW);
return nSizeW;
}
inline DWORD WINAPI GetEnvironmentVariableWThunk(LPCWSTR pszName,
LPWSTR pszBuffer, DWORD nSize)
{
_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnGetEnvironmentVariableW),
GetEnvironmentVariableWFake, ::GetEnvironmentVariableW);
return _strthunks.pfnGetEnvironmentVariableW(pszName, pszBuffer, nSize);
}
inline int WINAPI CompareStringWFake(LCID lcid, DWORD dwFlags,
LPCWSTR pszString1, int nLength1, LPCWSTR pszString2, int nLength2)
{
USES_CONVERSION;
return ::CompareStringA(lcid, dwFlags, W2A(pszString1), nLength1, W2A(pszString2), nLength2);
}
inline int WINAPI CompareStringWThunk(LCID lcid, DWORD dwFlags,
LPCWSTR pszString1, int nLength1, LPCWSTR pszString2, int nLength2)
{
_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnCompareStringW), CompareStringWFake, ::CompareStringW);
return _strthunks.pfnCompareStringW(lcid, dwFlags, pszString1, nLength1, pszString2, nLength2);
}
inline BOOL WINAPI GetStringTypeExWFake(LCID lcid, DWORD dwInfoType, LPCWSTR pszSrc,
int nLength, LPWORD pwCharType)
{
int nLengthA;
LPSTR pszA;
nLengthA = ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0, NULL, NULL);
pszA = LPSTR(_alloca(nLengthA*sizeof(char)));
::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nLength, pszA, nLengthA, NULL, NULL);
if (nLength == -1)
nLengthA = -1;
return ::GetStringTypeExA(lcid, dwInfoType, pszA, nLengthA, pwCharType);
}
inline BOOL WINAPI GetStringTypeExWThunk(LCID lcid, DWORD dwInfoType, LPCWSTR pszSrc,
int nLength, LPWORD pwCharType)
{
_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnGetStringTypeExW), GetStringTypeExWFake, ::GetStringTypeExW);
return _strthunks.pfnGetStringTypeExW(lcid, dwInfoType, pszSrc, nLength, pwCharType);
}
inline int WINAPI lstrcmpiWFake(LPCWSTR psz1, LPCWSTR psz2)
{
USES_CONVERSION;
return ::lstrcmpiA(W2A(psz1), W2A(psz2));
}
inline int WINAPI lstrcmpiWThunk(LPCWSTR psz1, LPCWSTR psz2)
{
_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnlstrcmpiW), lstrcmpiWFake, ::lstrcmpiW);
return _strthunks.pfnlstrcmpiW(psz1, psz2);
}
inline LPWSTR WINAPI CharLowerWFake(LPWSTR psz)
{
USES_CONVERSION;
LPSTR pszA;
pszA = W2A(psz);
::CharLowerA(pszA);
wcscpy(psz, A2W(pszA));
return psz;
}
inline LPWSTR WINAPI CharLowerWThunk(LPWSTR psz)
{
_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnCharLowerW), CharLowerWFake, ::CharLowerW);
return _strthunks.pfnCharLowerW(psz);
}
inline LPWSTR WINAPI CharUpperWFake(LPWSTR psz)
{
USES_CONVERSION;
LPSTR pszA;
pszA = W2A(psz);
::CharUpperA(pszA);
wcscpy(psz, A2W(pszA));
return psz;
}
inline LPWSTR WINAPI CharUpperWThunk(LPWSTR psz)
{
_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnCharUpperW), CharUpperWFake, ::CharUpperW);
return _strthunks.pfnCharUpperW(psz);
}
__declspec(selectany) _AtlStringThunks _strthunks =
{
CompareStringWThunk,
GetStringTypeExWThunk,
lstrcmpiWThunk,
CharLowerWThunk,
CharUpperWThunk,
GetEnvironmentVariableWThunk
};
#endif // !_UNICODE
/////////////////////////////////////////////////////////////////////////////
//
#ifndef _ATL_MIN_CRT
template< typename _CharType = char >
class ChTraitsCRT :
public ChTraitsBase< _CharType >
{
public:
static char* CharNext( const char* p ) throw()
{
return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ) ) );
}
static int IsDigit( char ch ) throw()
{
return _ismbcdigit( ch );
}
static int IsSpace( char ch ) throw()
{
return _ismbcspace( ch );
}
static int StringCompare( LPCSTR pszA, LPCSTR pszB ) throw()
{
return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
}
static int StringCompareIgnore( LPCSTR pszA, LPCSTR pszB ) throw()
{
return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
}
static int StringCollate( LPCSTR pszA, LPCSTR pszB ) throw()
{
return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
}
static int StringCollateIgnore( LPCSTR pszA, LPCSTR pszB ) throw()
{
return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
}
static LPSTR StringFindString( LPCSTR pszBlock, LPCSTR pszMatch ) throw()
{
return reinterpret_cast< LPSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ),
reinterpret_cast< const unsigned char* >( pszMatch ) ) );
}
static LPSTR StringFindChar( LPCSTR pszBlock, char chMatch ) throw()
{
return reinterpret_cast< LPSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), chMatch ) );
}
static LPSTR StringFindCharRev( LPCSTR psz, char ch ) throw()
{
return reinterpret_cast< LPSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), ch ) );
}
static LPSTR StringScanSet( LPCSTR pszBlock, LPCSTR pszMatch ) throw()
{
return reinterpret_cast< LPSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ),
reinterpret_cast< const unsigned char* >( pszMatch ) ) );
}
static int StringSpanIncluding( LPCSTR pszBlock, LPCSTR pszSet ) throw()
{
return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet ) );
}
static int StringSpanExcluding( LPCSTR pszBlock, LPCSTR pszSet ) throw()
{
return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet ) );
}
static LPSTR StringUppercase( LPSTR psz ) throw()
{
return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz ) ) );
}
static LPSTR StringLowercase( LPSTR psz ) throw()
{
return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz ) ) );
}
static LPSTR StringReverse( LPSTR psz ) throw()
{
return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz ) ) );
}
static int GetFormattedLength( LPCSTR pszFormat, va_list args ) throw()
{
return _vscprintf( pszFormat, args );
}
static int Format( LPSTR pszBuffer, LPCSTR pszFormat, va_list args ) throw()
{
return vsprintf( pszBuffer, pszFormat, args );
}
static int GetBaseTypeLength( LPCSTR pszSrc ) throw()
{
// Returns required buffer length in XCHARs
return int( strlen( pszSrc ) );
}
static int GetBaseTypeLength( LPCSTR pszSrc, int nLength ) throw()
{
(void)pszSrc;
// Returns required buffer length in XCHARs
return nLength;
}
static int GetBaseTypeLength( LPCWSTR pszSource ) throw()
{
// Returns required buffer length in XCHARs
return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1;
}
static int GetBaseTypeLength( LPCWSTR pszSource, int nLength ) throw()
{
// Returns required buffer length in XCHARs
return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL );
}
static void ConvertToBaseType( LPSTR pszDest, int nDestLength,
LPCSTR pszSrc, int nSrcLength = -1 ) throw()
{
(void)nSrcLength;
// nLen is in XCHARs
memcpy( pszDest, pszSrc, nDestLength*sizeof( char ) );
}
static void ConvertToBaseType( LPSTR pszDest, int nDestLength,
LPCWSTR pszSrc, int nSrcLength = -1 ) throw()
{
// nLen is in XCHARs
::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL );
}
static void ConvertToOem( LPSTR psz ) throw()
{
::AnsiToOem( psz, psz );
}
static void ConvertToAnsi( LPSTR psz ) throw()
{
::OemToAnsi( psz, psz );
}
static void FloodCharacters( char ch, int nLength, char* pch ) throw()
{
// nLength is in XCHARs
memset( pch, ch, nLength );
}
static BSTR AllocSysString( const char* pchData, int nDataLength ) throw()
{
int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength,
NULL, NULL );
BSTR bstr = ::SysAllocStringLen( NULL, nLen );
if( bstr != NULL )
{
::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength,
bstr, nLen );
}
return bstr;
}
static BOOL ReAllocSysString( const char* pchData, BSTR* pbstr, int nDataLength ) throw()
{
int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL );
BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen );
if( bSuccess )
{
::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen );
}
return bSuccess;
}
static DWORD FormatMessage( DWORD dwFlags, LPCVOID pSource,
DWORD dwMessageID, DWORD dwLanguageID, LPSTR pszBuffer,
DWORD nSize, va_list* pArguments ) throw()
{
return ::FormatMessageA( dwFlags, pSource, dwMessageID, dwLanguageID,
pszBuffer, nSize, pArguments );
}
static int SafeStringLen( LPCSTR psz ) throw()
{
// returns length in bytes
return (psz != NULL) ? int( strlen( psz ) ) : 0;
}
static int SafeStringLen( LPCWSTR psz ) throw()
{
// returns length in wchar_ts
return (psz != NULL) ? int( wcslen( psz ) ) : 0;
}
static int GetCharLen( const wchar_t* pch ) throw()
{
(void)pch;
// returns char length
return 1;
}
static int GetCharLen( const char* pch ) throw()
{
// returns char length
return int( _mbclen( reinterpret_cast< const unsigned char* >( pch ) ) );
}
static DWORD GetEnvironmentVariable( LPCSTR pszVar,
LPSTR pszBuffer, DWORD dwSize ) throw()
{
return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize );
}
};
// specialization for wchar_t
template<>
class ChTraitsCRT< wchar_t > :
public ChTraitsBase< wchar_t >
{
#if defined(_UNICODE) && !defined(_CSTRING_ALWAYS_THUNK)
static DWORD _GetEnvironmentVariableW( LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize ) throw()
{
return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize );
}
#else // !_UNICODE
static DWORD WINAPI _GetEnvironmentVariableW( LPCWSTR pszName,
LPWSTR pszBuffer, DWORD nSize ) throw()
{
return _strthunks.pfnGetEnvironmentVariableW( pszName, pszBuffer, nSize );
}
#endif // !_UNICODE
public:
static LPWSTR CharNext( LPCWSTR psz ) throw()
{
return const_cast< LPWSTR >( psz+1 );
}
static int IsDigit( wchar_t ch ) throw()
{
return iswdigit( ch );
}
static int IsSpace( wchar_t ch ) throw()
{
return iswspace( ch );
}
static int StringCompare( LPCWSTR pszA, LPCWSTR pszB ) throw()
{
return wcscmp( pszA, pszB );
}
static int StringCompareIgnore( LPCWSTR pszA, LPCWSTR pszB ) throw()
{
return _wcsicmp( pszA, pszB );
}
static int StringCollate( LPCWSTR pszA, LPCWSTR pszB ) throw()
{
return wcscoll( pszA, pszB );
}
static int StringCollateIgnore( LPCWSTR pszA, LPCWSTR pszB ) throw()
{
return _wcsicoll( pszA, pszB );
}
static LPWSTR StringFindString( LPCWSTR pszBlock, LPCWSTR pszMatch ) throw()
{
return wcsstr( pszBlock, pszMatch );
}
static LPWSTR StringFindChar( LPCWSTR pszBlock, wchar_t chMatch ) throw()
{
return wcschr( pszBlock, chMatch );
}
static LPWSTR StringFindCharRev( LPCWSTR psz, wchar_t ch ) throw()
{
return wcsrchr( psz, ch );
}
static LPWSTR StringScanSet( LPCWSTR pszBlock, LPCWSTR pszMatch ) throw()
{
return wcspbrk( pszBlock, pszMatch );
}
static int StringSpanIncluding( LPCWSTR pszBlock, LPCWSTR pszSet ) throw()
{
return (int)wcsspn( pszBlock, pszSet );
}
static int StringSpanExcluding( LPCWSTR pszBlock, LPCWSTR pszSet ) throw()
{
return (int)wcscspn( pszBlock, pszSet );
}
static LPWSTR StringUppercase( LPWSTR psz ) throw()
{
return _wcsupr( psz );
}
static LPWSTR StringLowercase( LPWSTR psz ) throw()
{
return _wcslwr( psz );
}
static LPWSTR StringReverse( LPWSTR psz ) throw()
{
return _wcsrev( psz );
}
static int GetFormattedLength( LPCWSTR pszFormat, va_list args) throw()
{
return _vscwprintf( pszFormat, args );
}
static int Format( LPWSTR pszBuffer, LPCWSTR pszFormat, va_list args) throw()
{
return vswprintf( pszBuffer, pszFormat, args );
}
static int GetBaseTypeLength( LPCSTR pszSrc ) throw()
{
// Returns required buffer size in wchar_ts
return ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, -1, NULL, 0 )-1;
}
static int GetBaseTypeLength( LPCSTR pszSrc, int nLength ) throw()
{
// Returns required buffer size in wchar_ts
return ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0 );
}
static int GetBaseTypeLength( LPCWSTR pszSrc ) throw()
{
// Returns required buffer size in wchar_ts
return (int)wcslen( pszSrc );
}
static int GetBaseTypeLength( LPCWSTR pszSrc, int nLength ) throw()
{
(void)pszSrc;
// Returns required buffer size in wchar_ts
return nLength;
}
static void ConvertToBaseType( LPWSTR pszDest, int nDestLength,
LPCSTR pszSrc, int nSrcLength = -1) throw()
{
// nLen is in wchar_ts
::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength );
}
static void ConvertToBaseType( LPWSTR pszDest, int nDestLength,
LPCWSTR pszSrc, int nSrcLength = -1) throw()
{
(void)nSrcLength;
// nLen is in wchar_ts
memcpy( pszDest, pszSrc, nDestLength*sizeof( wchar_t ) );
}
static void FloodCharacters( wchar_t ch, int nLength, LPWSTR psz ) throw()
{
// nLength is in XCHARs
for( int i = 0; i < nLength; i++ )
{
psz[i] = ch;
}
}
static BSTR AllocSysString( const wchar_t* pchData, int nDataLength ) throw()
{
return ::SysAllocStringLen( pchData, nDataLength );
}
static BOOL ReAllocSysString( const wchar_t* pchData, BSTR* pbstr, int nDataLength ) throw()
{
return ::SysReAllocStringLen( pbstr, pchData, nDataLength );
}
#ifdef _UNICODE
static DWORD FormatMessage( DWORD dwFlags, LPCVOID pSource,
DWORD dwMessageID, DWORD dwLanguageID, LPWSTR pszBuffer,
DWORD nSize, va_list* pArguments ) throw()
{
return ::FormatMessageW( dwFlags, pSource, dwMessageID, dwLanguageID,
pszBuffer, nSize, pArguments );
}
#endif
static int SafeStringLen( LPCSTR psz ) throw()
{
// returns length in bytes
return (psz != NULL) ? (int)strlen( psz ) : 0;
}
static int SafeStringLen( LPCWSTR psz ) throw()
{
// returns length in wchar_ts
return (psz != NULL) ? (int)wcslen( psz ) : 0;
}
static int GetCharLen( const wchar_t* pch ) throw()
{
(void)pch;
// returns char length
return 1;
}
static int GetCharLen( const char* pch ) throw()
{
// returns char length
return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch ) ) );
}
static DWORD GetEnvironmentVariable( LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize ) throw()
{
return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize );
}
};
#endif // _ATL_MIN_CRT
template< typename _CharType = char >
class ChTraitsOS :
public ChTraitsBase< _CharType >
{
public:
static int tclen(const _CharType* p) throw()
{
ATLASSERT(p != NULL);
_CharType* pnext = CharNext(p);
return ((pnext-p)>1) ? 2 : 1;
}
static _CharType* strchr(const _CharType* p, _CharType ch) throw()
{
ATLASSERT(p != NULL);
//strchr for '\0' should succeed
do
{
if (*p == ch)
{
return const_cast< _CharType* >( p );
}
p = CharNext(p);
} while( *p != 0 );
return NULL;
}
static _CharType* strchr_db(const _CharType* p, char ch1, char ch2) throw()
{
ATLASSERT(p != NULL);
while (*p != 0)
{
if (*p == ch1 && *(p+1) == ch2)
{
return const_cast< _CharType* >( p );
}
p = CharNext(p);
}
return NULL;
}
static _CharType* strrchr(const _CharType* p, _CharType ch) throw()
{
ATLASSERT(p != NULL);
const _CharType* pch = NULL;
while (*p != 0)
{
if (*p == ch)
pch = p;
p = CharNext(p);
}
return const_cast< _CharType* >( pch );
}
static _CharType* _strrev(_CharType* psz) throw()
{
// Optimize NULL, zero-length, and single-char case.
if ((psz == NULL) || (psz[0] == '\0') || (psz[1] == '\0'))
return psz;
_CharType* p = psz;
while (p[1] != 0)
{
_CharType* pNext = CharNext(p);
if(pNext > p + 1)
{
char p1 = *p;
*p = *(p + 1);
*(p + 1) = p1;
}
p = pNext;
}
_CharType* q = psz;
while (q < p)
{
_CharType t = *q;
*q = *p;
*p = t;
q++;
p--;
}
return psz;
}
static _CharType* strstr(const _CharType* pStr, const _CharType* pCharSet) throw()
{
ATLASSERT(p != NULL);
int nLen = lstrlenA(pCharSet);
if (nLen == 0)
return const_cast<_CharType*>(pStr);
const _CharType* pMatch;
const _CharType* pStart = pStr;
while ((pMatch = strchr(pStart, *pCharSet)) != NULL)
{
if (memcmp(pMatch, pCharSet, nLen*sizeof(_CharType)) == 0)
return const_cast<_CharType*>(pMatch);
pStart = CharNextA(pMatch);
}
return NULL;
}
static int strspn(const _CharType* pStr, const _CharType* pCharSet) throw()
{
ATLASSERT(p != NULL);
int nRet = 0;
_CharType* p = pStr;
while (*p != 0)
{
_CharType* pNext = CharNext(p);
if(pNext > p + 1)
{
if(strchr_db(pCharSet, *p, *(p+1)) == NULL)
break;
nRet += 2;
}
else
{
if(strchr(pCharSet, *p) == NULL)
break;
nRet++;
}
p = pNext;
}
return nRet;
}
static int strcspn(const _CharType* pStr, const _CharType* pCharSet) throw()
{
ATLASSERT(p != NULL);
int nRet = 0;
_CharType* p = pStr;
while (*p != 0)
{
_CharType* pNext = CharNext(p);
if(pNext > p + 1)
{
if(strchr_db(pCharSet, *p, *(p+1)) != NULL)
break;
nRet += 2;
}
else
{
if(strchr(pCharSet, *p) != NULL)
break;
nRet++;
}
p = pNext;
}
return nRet;
}
static _CharType* strpbrk(const _CharType* p, const _CharType* lpszCharSet) throw()
{
ATLASSERT(p != NULL);
while (*p != 0)
{
if (strchr(lpszCharSet, *p) != NULL)
{
return const_cast< _CharType* >( p );
}
p = CharNext(p);
}
return NULL;
}
static _CharType* CharNext(const _CharType* p) throw()
{
ATLASSERT(p != NULL);
if (*p == '\0') // ::CharNextA won't increment if we're at a \0 already
return const_cast<_CharType*>(p+1);
else
return ::CharNextA(p);
}
static int IsDigit(_CharType ch) throw()
{
WORD type;
GetStringTypeExA(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
return (type & C1_DIGIT) == C1_DIGIT;
}
static int IsSpace(_CharType ch) throw()
{
WORD type;
GetStringTypeExA(GetThreadLocale(), CT_CTYPE1, &ch, 1, &type);
return (type & C1_SPACE) == C1_SPACE;
}
static int StringCompare(const _CharType* pstrOne,
const _CharType* pstrOther) throw()
{
return lstrcmpA((LPCSTR) pstrOne, (LPCSTR) pstrOther);
}
static int StringCompareIgnore(const _CharType* pstrOne,
const _CharType* pstrOther) throw()
{
return lstrcmpiA((LPCSTR) pstrOne, (LPCSTR) pstrOther);
}
static int StringCollate(const _CharType* pstrOne,
const _CharType* pstrOther) throw()
{
int nRet = CompareStringA(GetThreadLocale(), 0, (LPCSTR)pstrOne, -1,
(LPCSTR)pstrOther, -1);
ATLASSERT(nRet != 0);
return nRet-2; // Convert to strcmp convention. This really is documented.
}
static int StringCollateIgnore(const _CharType* pstrOne,
const _CharType* pstrOther) throw()
{
int nRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, (LPCSTR)pstrOne, -1,
(LPCSTR)pstrOther, -1);
ATLASSERT(nRet != 0);
return nRet-2; // Convert to strcmp convention. This really is documented.
}
static _CharType* StringFindString(const _CharType* pstrBlock,
const _CharType* pstrMatch) throw()
{
return strstr(pstrBlock, pstrMatch);
}
static _CharType* StringFindChar(const _CharType* pstrBlock,
_CharType pstrMatch) throw()
{
return strchr(pstrBlock, pstrMatch);
}
static _CharType* StringFindCharRev(const _CharType* pstr, _CharType ch) throw()
{
return strrchr(pstr, ch);
}
static _CharType* StringScanSet(const _CharType* pstrBlock,
const _CharType* pstrMatch) throw()
{
return strpbrk(pstrBlock, pstrMatch);
}
static int StringSpanIncluding(const _CharType* pstrBlock,
const _CharType* pstrSet) throw()
{
return strspn(pstrBlock, pstrSet);
}
static int StringSpanExcluding(const _CharType* pstrBlock,
const _CharType* pstrSet) throw()
{
return strcspn(pstrBlock, pstrSet);
}
static _CharType* StringUppercase(_CharType* psz) throw()
{
return CharUpperA( psz );
}
static _CharType* StringLowercase(_CharType* psz) throw()
{
return CharLowerA( psz );
}
static _CharType* StringReverse(_CharType* psz) throw()
{
return _strrev( psz );
}
static int GetFormattedLength(const _CharType* pszFormat, va_list args) throw()
{
_CharType szBuffer[1028];
// wvsprintf always truncates the output to 1024 character plus
// the '\0'.
int nLength = wvsprintfA(szBuffer, pszFormat, args);
ATLASSERT(nLength >= 0);
ATLASSERT(nLength <= 1024);
return nLength;
}
static int Format(_CharType* pszBuffer, const _CharType* pszFormat,
va_list args) throw()
{
return wvsprintfA(pszBuffer, pszFormat, args);
}
static int GetBaseTypeLength(const char* pszSrc) throw()
{
// Returns required buffer length in XCHARs
return lstrlenA(pszSrc);
}
static int GetBaseTypeLength(const char* pszSrc, int nLength) throw()
{
(void)pszSrc;
// Returns required buffer length in XCHARs
return nLength;
}
static int GetBaseTypeLength(const wchar_t* pszSrc) throw()
{
// Returns required buffer length in XCHARs
return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, -1, NULL, 0, NULL, NULL)-1;
}
static int GetBaseTypeLength(const wchar_t* pszSrc, int nLength) throw()
{
// Returns required buffer length in XCHARs
return ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0, NULL, NULL);
}
static void ConvertToBaseType(_CharType* pszDest, int nDestLength,
const char* pszSrc, int nSrcLength = -1) throw()
{
(void)nSrcLength;
// nLen is in chars
memcpy(pszDest, pszSrc, nDestLength);
}
static void ConvertToBaseType(_CharType* pszDest, int nDestLength,
const wchar_t* pszSrc, int nSrcLength = -1) throw()
{
// nLen is in XCHARs
::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL);
}
static void ConvertToOem(_CharType* pstrString) throw()
{
::AnsiToOem(pstrString, pstrString);
}
static void ConvertToAnsi(_CharType* pstrString) throw()
{
::OemToAnsi(pstrString, pstrString);
}
static void FloodCharacters(_CharType ch, int nLength, _CharType* pstr) throw()
{
// nLength is in XCHARs
memset(pstr, ch, nLength);
}
static BSTR AllocSysString(const _CharType* pchData, int nDataLength) throw()
{
int nLen = MultiByteToWideChar(_AtlGetConversionACP(), 0, pchData, nDataLength,
NULL, NULL);
BSTR bstr = ::SysAllocStringLen(NULL, nLen);
if (bstr != NULL)
{
MultiByteToWideChar(_AtlGetConversionACP(), 0, pchData, nDataLength,
bstr, nLen);
}
return bstr;
}
static BOOL ReAllocSysString(const _CharType* pchData, BSTR* pbstr,
int nDataLength) throw()
{
int nLen = MultiByteToWideChar(_AtlGetConversionACP(), 0, pchData,
nDataLength, NULL, NULL);
BOOL bSuccess =::SysReAllocStringLen(pbstr, NULL, nLen);
if (bSuccess)
{
MultiByteToWideChar(_AtlGetConversionACP(), 0, pchData, nDataLength,
*pbstr, nLen);
}
return bSuccess;
}
static DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource,
DWORD dwMessageID, DWORD dwLanguageID, char* pstrBuffer,
DWORD nSize, va_list* pArguments) throw()
{
return ::FormatMessageA(dwFlags, lpSource, dwMessageID, dwLanguageID,
pstrBuffer, nSize, pArguments);
}
static int SafeStringLen(const char* psz) throw()
{
// returns length in bytes
return (psz != NULL) ? lstrlenA(psz) : 0;
}
static int SafeStringLen(const wchar_t* psz) throw()
{
// returns length in wchar_ts
return (psz != NULL) ? lstrlenW(psz) : 0;
}
static int GetCharLen(const wchar_t*) throw()
{
// returns char length
return 1;
}
static int GetCharLen(const char* psz) throw()
{
const char* p = ::CharNextA(psz);
return (p - psz);
}
static DWORD GetEnvironmentVariable(const _CharType* pstrVar,
_CharType* pstrBuffer, DWORD dwSize) throw()
{
return ::GetEnvironmentVariableA(pstrVar, pstrBuffer, dwSize);
}
};
// specialization for wchar_t
template<>
class ChTraitsOS< wchar_t > :
public ChTraitsBase< wchar_t >
{
protected:
#if defined(_UNICODE) && !defined(_CSTRING_ALWAYS_THUNK)
static int CompareStringW(LCID lcid, DWORD dwFlags,
LPCWSTR pszString1, int nLength1, LPCWSTR pszString2, int nLength2)
{
return ::CompareStringW(lcid, dwFlags, pszString1, nLength1,
pszString2, nLength2);
}
static BOOL GetStringTypeExW(LCID lcid, DWORD dwInfoType, LPCWSTR pszSrc,
int nLength, LPWORD pwCharType)
{
return ::GetStringTypeExW(lcid, dwInfoType, pszSrc, nLength, pwCharType);
}
static int lstrcmpiW(LPCWSTR psz1, LPCWSTR psz2)
{
return ::lstrcmpiW(psz1, psz2);
}
static LPWSTR CharLowerW(LPWSTR psz)
{
return ::CharLowerW(psz);
}
static LPWSTR CharUpperW(LPWSTR psz)
{
return ::CharUpperW(psz);
}
static DWORD _GetEnvironmentVariableW(LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize)
{
return ::GetEnvironmentVariableW(pszName, pszBuffer, nSize);
}
#else // !_UNICODE
static int WINAPI CompareStringW(LCID lcid, DWORD dwFlags,
LPCWSTR pszString1, int nLength1, LPCWSTR pszString2, int nLength2)
{
return _strthunks.pfnCompareStringW(lcid, dwFlags, pszString1, nLength1, pszString2, nLength2);
}
static BOOL WINAPI GetStringTypeExW(LCID lcid, DWORD dwInfoType, LPCWSTR pszSrc,
int nLength, LPWORD pwCharType)
{
return _strthunks.pfnGetStringTypeExW(lcid, dwInfoType, pszSrc, nLength, pwCharType);
}
static int WINAPI lstrcmpiW(LPCWSTR psz1, LPCWSTR psz2)
{
return _strthunks.pfnlstrcmpiW(psz1, psz2);
}
static LPWSTR WINAPI CharLowerW(LPWSTR psz)
{
ATLASSERT(HIWORD(psz) != 0); // No single chars
return _strthunks.pfnCharLowerW(psz);
}
static LPWSTR WINAPI CharUpperW(LPWSTR psz)
{
ATLASSERT(HIWORD(psz) != 0); // No single chars
return _strthunks.pfnCharUpperW(psz);
}
static DWORD _GetEnvironmentVariableW(LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize)
{
return _strthunks.pfnGetEnvironmentVariableW(pszName, pszBuffer, nSize);
}
#endif // !_UNICODE
public:
static int tclen(const _CharType*) throw()
{
return 1;
}
static _CharType* strchr(const _CharType* p, _CharType ch) throw()
{
//strchr for '\0' should succeed
while (*p != 0)
{
if (*p == ch)
{
return const_cast< _CharType* >( p );
}
p++;
}
return const_cast< _CharType* >((*p == ch) ? p : NULL);
}
static _CharType* strrchr(const _CharType* p, _CharType ch) throw()
{
const _CharType* pch = p+lstrlenW(p);
while ((pch != p) && (*pch != ch))
{
pch--;
}
if (*pch == ch)
{
return const_cast<_CharType*>(pch);
}
else
{
return NULL;
}
}
static _CharType* _strrev(_CharType* psz) throw()
{
// Optimize NULL, zero-length, and single-char case.
if ((psz == NULL) || (psz[0] == L'\0') || (psz[1] == L'\0'))
return psz;
_CharType* p = psz+(lstrlenW( psz )-1);
_CharType* q = psz;
while(q < p)
{
_CharType t = *q;
*q = *p;
*p = t;
q++;
p--;
}
return psz;
}
static _CharType* strstr(const _CharType* pStr, const _CharType* pCharSet) throw()
{
int nLen = lstrlenW(pCharSet);
if (nLen == 0)
return const_cast<_CharType*>(pStr);
const _CharType* pMatch;
const _CharType* pStart = pStr;
while ((pMatch = strchr(pStart, *pCharSet)) != NULL)
{
if (memcmp(pMatch, pCharSet, nLen*sizeof(_CharType)) == 0)
return const_cast<_CharType*>(pMatch);
pStart++;
}
return NULL;
}
static int strspn(const _CharType* psz, const _CharType* pszCharSet) throw()
{
int nRet = 0;
const _CharType* p = psz;
while (*p != 0)
{
if(strchr(pszCharSet, *p) == NULL)
break;
nRet++;
p++;
}
return nRet;
}
static int strcspn(const _CharType* psz, const _CharType* pszCharSet) throw()
{
int nRet = 0;
const _CharType* p = psz;
while (*p != 0)
{
if(strchr(pszCharSet, *p) != NULL)
break;
nRet++;
p++;
}
return nRet;
}
static _CharType* strpbrk(const _CharType* psz, const _CharType* pszCharSet) throw()
{
const wchar_t* p = psz;
while (*p != 0)
{
if (strchr(pszCharSet, *p) != NULL)
return const_cast< wchar_t* >( p );
p++;
}
return NULL;
}
static wchar_t* CharNext(const wchar_t* p) throw()
{
return const_cast< wchar_t* >( p+1 );
}
static int IsDigit(_CharType ch) throw()
{
WORD type;
GetStringTypeExW(0, CT_CTYPE1, &ch, 1, &type);
return (type & C1_DIGIT) == C1_DIGIT;
}
static int IsSpace(_CharType ch) throw()
{
WORD type;
GetStringTypeExW(0, CT_CTYPE1, &ch, 1, &type);
return (type & C1_SPACE) == C1_SPACE;
}
static int StringCompare(const _CharType* pstrOne,
const _CharType* pstrOther) throw()
{
return wcscmp(pstrOne, pstrOther);
}
static int StringCompareIgnore(const _CharType* pstrOne,
const _CharType* pstrOther) throw()
{
return lstrcmpiW(pstrOne, pstrOther);
}
static int StringCollate(const _CharType* pstrOne,
const _CharType* pstrOther) throw()
{
int nRet;
nRet = CompareStringW(GetThreadLocale(), 0, pstrOne, -1, pstrOther, -1);
ATLASSERT(nRet != 0);
return nRet-2; // Convert to strcmp convention. This really is documented.
}
static int StringCollateIgnore(const _CharType* pstrOne,
const _CharType* pstrOther) throw()
{
int nRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
pstrOne, -1, pstrOther, -1);
ATLASSERT(nRet != 0);
return nRet-2; // Convert to strcmp convention. This really is documented.
}
static _CharType* StringFindString(const _CharType* pstrBlock,
const _CharType* pstrMatch) throw()
{
return strstr(pstrBlock, pstrMatch);
}
static _CharType* StringFindChar(const _CharType* pstrBlock,
_CharType pstrMatch) throw()
{
return strchr(pstrBlock, pstrMatch);
}
static _CharType* StringFindCharRev(const _CharType* pstr, _CharType ch) throw()
{
return strrchr(pstr, ch);
}
static _CharType* StringScanSet(const _CharType* pszBlock,
const _CharType* pszMatch) throw()
{
return strpbrk(pszBlock, pszMatch);
}
static int StringSpanIncluding(const _CharType* pszBlock,
const _CharType* pszSet) throw()
{
return strspn(pszBlock, pszSet);
}
static int StringSpanExcluding(const _CharType* pszBlock,
const _CharType* pszSet) throw()
{
return strcspn(pszBlock, pszSet);
}
static _CharType* StringUppercase(_CharType* psz) throw()
{
CharUpperW(psz);
return psz;
}
static _CharType* StringLowercase(_CharType* psz) throw()
{
CharLowerW(psz);
return psz;
}
static _CharType* StringReverse(_CharType* psz) throw()
{
return _strrev(psz);
}
#ifdef _UNICODE
static int GetFormattedLength(const _CharType* pszFormat, va_list args) throw()
{
_CharType szBuffer[1028];
// wvsprintf always truncates the output to 1024 character plus
// the '\0'.
int nLength = wvsprintfW(szBuffer, pszFormat, args);
ATLASSERT(nLength >= 0);
ATLASSERT(nLength <= 1024);
return nLength;
}
static int Format(_CharType* pszBuffer, const _CharType* pszFormat,
va_list args) throw()
{
return wvsprintfW(pszBuffer, pszFormat, args);
}
#endif
static int GetBaseTypeLength(const char* pszSrc) throw()
{
// Returns required buffer size in wchar_ts
return ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, -1, NULL, 0)-1;
}
static int GetBaseTypeLength(const char* pszSrc, int nLength) throw()
{
// Returns required buffer size in wchar_ts
return ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0);
}
static int GetBaseTypeLength(const wchar_t* pszSrc) throw()
{
// Returns required buffer size in wchar_ts
return lstrlenW(pszSrc);
}
static int GetBaseTypeLength(const wchar_t* pszSrc, int nLength) throw()
{
(void)pszSrc;
// Returns required buffer size in wchar_ts
return nLength;
}
static void ConvertToBaseType(_CharType* pszDest, int nDestLength,
const char* pszSrc, int nSrcLength = -1) throw()
{
// nLen is in wchar_ts
::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength);
}
static void ConvertToBaseType(_CharType* pszDest, int nDestLength,
const wchar_t* pszSrc, int nSrcLength = -1) throw()
{
(void)nSrcLength;
// nLen is in wchar_ts
memcpy(pszDest, pszSrc, nDestLength*sizeof(wchar_t));
}
// this conversion on Unicode strings makes no sense
/*
static void ConvertToOem(_CharType*)
{
ATLASSERT(FALSE);
}
*/
// this conversion on Unicode strings makes no sense
/*
static void ConvertToAnsi(_CharType*)
{
ATLASSERT(FALSE);
}
*/
static void FloodCharacters(_CharType ch, int nLength, _CharType* pstr) throw()
{
// nLength is in XCHARs
for (int i = 0; i < nLength; i++)
pstr[i] = ch;
}
static BSTR AllocSysString(const _CharType* pchData, int nDataLength) throw()
{
BSTR bstr = ::SysAllocStringLen(pchData, nDataLength);
return bstr;
}
static BOOL ReAllocSysString(const _CharType* pchData, BSTR* pbstr,
int nDataLength) throw()
{
return ::SysReAllocStringLen(pbstr, pchData, nDataLength);
}
#ifdef _UNICODE
static DWORD FormatMessage(DWORD dwFlags, LPCVOID lpSource,
DWORD dwMessageID, DWORD dwLanguageID, wchar_t* pstrBuffer,
DWORD nSize, va_list* pArguments) throw()
{
return ::FormatMessageW(dwFlags, lpSource, dwMessageID, dwLanguageID,
pstrBuffer, nSize, pArguments);
}
#endif
static int SafeStringLen(const char* psz) throw()
{
// returns length in bytes
return (psz != NULL) ? lstrlenA(psz) : 0;
}
static int SafeStringLen(const wchar_t* psz) throw()
{
// returns length in wchar_ts
return (psz != NULL) ? lstrlenW(psz) : 0;
}
static int GetCharLen(const wchar_t*) throw()
{
// returns char length
return 1;
}
static int GetCharLen(const char* psz) throw()
{
LPCSTR p = ::CharNextA( psz );
return int( p-psz );
}
static DWORD GetEnvironmentVariable(const _CharType* pstrVar,
_CharType* pstrBuffer, DWORD dwSize) throw()
{
return ::GetEnvironmentVariableW(pstrVar, pstrBuffer, dwSize);
}
};
template< typename BaseType, class StringTraits >
class CStringT :
public CSimpleStringT< BaseType >
{
public:
typedef CSimpleStringT< BaseType > CThisSimpleString;
typedef StringTraits StrTraits;
public:
CStringT() throw() :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
}
explicit CStringT( IAtlStringMgr* pStringMgr ) throw() :
CThisSimpleString( pStringMgr )
{
}
CStringT( const VARIANT& varSrc ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
CComVariant varResult;
HRESULT hr = ::VariantChangeType( &varResult, const_cast< VARIANT* >( &varSrc ), 0, VT_BSTR );
if( FAILED( hr ) )
{
AtlThrow( hr );
}
*this = V_BSTR( &varResult );
}
CStringT( const VARIANT& varSrc, IAtlStringMgr* pStringMgr ) :
CThisSimpleString( pStringMgr )
{
CComVariant varResult;
HRESULT hr = ::VariantChangeType( &varResult, const_cast< VARIANT* >( &varSrc ), 0, VT_BSTR );
if( FAILED( hr ) )
{
AtlThrow( hr );
}
*this = V_BSTR( &varResult );
}
static void Construct( CStringT* pString )
{
new( pString ) CStringT;
}
// Copy constructor
CStringT( const CStringT& strSrc ) :
CThisSimpleString( strSrc )
{
}
// Construct from CSimpleStringT
CStringT( const CThisSimpleString& strSrc ) :
CThisSimpleString( strSrc )
{
}
CStringT( const XCHAR* pszSrc ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
if( !CheckImplicitLoad( pszSrc ) )
{
// nDestLength is in XCHARs
*this = pszSrc;
}
}
CStringT( LPCSTR pszSrc, IAtlStringMgr* pStringMgr ) :
CThisSimpleString( pStringMgr )
{
if( !CheckImplicitLoad( pszSrc ) )
{
// nDestLength is in XCHARs
*this = pszSrc;
}
}
CSTRING_EXPLICIT CStringT( const YCHAR* pszSrc ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
if( !CheckImplicitLoad( pszSrc ) )
{
*this = pszSrc;
}
}
CStringT( LPCWSTR pszSrc, IAtlStringMgr* pStringMgr ) :
CThisSimpleString( pStringMgr )
{
if( !CheckImplicitLoad( pszSrc ) )
{
*this = pszSrc;
}
}
#ifdef _MANAGED
CStringT( System::String* pString ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
const wchar_t __pin* psz = PtrToStringChars( pString );
*this = psz;
}
#endif
CSTRING_EXPLICIT CStringT( const unsigned char* pszSrc ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
*this = reinterpret_cast< const char* >( pszSrc );
}
CStringT( const unsigned char* pszSrc, IAtlStringMgr* pStringMgr ) :
CThisSimpleString( pStringMgr )
{
*this = reinterpret_cast< const char* >( pszSrc );
}
CSTRING_EXPLICIT CStringT( wchar_t ch, int nLength = 1 ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
ATLASSERT( nLength >= 0 );
if( nLength > 0 )
{
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::FloodCharacters( XCHAR( ch ), nLength, pszBuffer );
ReleaseBuffer( nLength );
}
}
CStringT( const XCHAR* pch, int nLength ) :
CThisSimpleString( pch, nLength, StringTraits::GetDefaultManager() )
{
}
CStringT( const XCHAR* pch, int nLength, IAtlStringMgr* pStringMgr ) :
CThisSimpleString( pch, nLength, pStringMgr )
{
}
CStringT( const YCHAR* pch, int nLength ) :
CThisSimpleString( StringTraits::GetDefaultManager() )
{
ATLASSERT( nLength >= 0 );
if( nLength > 0 )
{
ATLASSERT( AtlIsValidAddress( pch, nLength*sizeof( YCHAR ), FALSE ) );
int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength );
PXSTR pszBuffer = GetBuffer( nDestLength );
StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength );
ReleaseBuffer( nDestLength );
}
}
CStringT( const YCHAR* pch, int nLength, IAtlStringMgr* pStringMgr ) :
CThisSimpleString( pStringMgr )
{
ATLASSERT( nLength >= 0 );
if( nLength > 0 )
{
ATLASSERT( AtlIsValidAddress( pch, nLength*sizeof( YCHAR ), FALSE ) );
int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength );
PXSTR pszBuffer = GetBuffer( nDestLength );
StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength );
ReleaseBuffer( nDestLength );
}
}
// Destructor
~CStringT() throw()
{
}
// Assignment operators
CStringT& operator=( const CStringT& strSrc )
{
CThisSimpleString::operator=( strSrc );
return( *this );
}
CStringT& operator=( const CThisSimpleString& strSrc )
{
CThisSimpleString::operator=( strSrc );
return( *this );
}
CStringT& operator=( PCXSTR pszSrc )
{
CThisSimpleString::operator=( pszSrc );
return( *this );
}
CStringT& operator=( PCYSTR pszSrc )
{
// nDestLength is in XCHARs
int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0;
if( nDestLength > 0 )
{
PXSTR pszBuffer = GetBuffer( nDestLength );
StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc );
ReleaseBuffer( nDestLength );
}
else
{
Empty();
}
return( *this );
}
CStringT& operator=( const unsigned char* pszSrc )
{
return( operator=( reinterpret_cast< const char* >( pszSrc ) ) );
}
CStringT& operator=( char ch )
{
char ach[2] = { ch, 0 };
return( operator=( ach ) );
}
CStringT& operator=( wchar_t ch )
{
wchar_t ach[2] = { ch, 0 };
return( operator=( ach ) );
}
CStringT& operator=( const VARIANT& var )
{
CComVariant varResult;
HRESULT hr = ::VariantChangeType( &varResult, const_cast< VARIANT* >( &var ), 0, VT_BSTR );
if( FAILED( hr ) )
{
AtlThrow( hr );
}
*this = V_BSTR( &varResult );
return( *this );
}
CStringT& operator+=( const CThisSimpleString& str )
{
CThisSimpleString::operator+=( str );
return( *this );
}
CStringT& operator+=( PCXSTR pszSrc )
{
CThisSimpleString::operator+=( pszSrc );
return( *this );
}
template< int t_nSize >
CStringT& operator+=( const CStaticString< XCHAR, t_nSize >& strSrc )
{
CThisSimpleString::operator+=( strSrc );
return( *this );
}
CStringT& operator+=( PCYSTR psz )
{
CStringT str( psz, GetManager() );
return( operator+=( str ) );
}
CStringT& operator+=( char ch )
{
CThisSimpleString::operator+=( ch );
return( *this );
}
CStringT& operator+=( unsigned char ch )
{
CThisSimpleString::operator+=( ch );
return( *this );
}
CStringT& operator+=( wchar_t ch )
{
CThisSimpleString::operator+=( ch );
return( *this );
}
CStringT& operator+=( const VARIANT& var )
{
CComVariant varResult;
HRESULT hr = ::VariantChangeType( &varResult, const_cast< VARIANT* >( &var ), 0, VT_BSTR );
if( FAILED( hr ) )
{
AtlThrow( hr );
}
*this += V_BSTR( &varResult );
return( *this );
}
// Comparison
int Compare( PCXSTR psz ) const throw()
{
ATLASSERT( AtlIsValidString( psz ) );
return( StringTraits::StringCompare( GetString(), psz ) );
}
int CompareNoCase( PCXSTR psz ) const throw()
{
ATLASSERT( AtlIsValidString( psz ) );
return( StringTraits::StringCompareIgnore( GetString(), psz ) );
}
int Collate( PCXSTR psz ) const throw()
{
ATLASSERT( AtlIsValidString( psz ) );
return( StringTraits::StringCollate( GetString(), psz ) );
}
int CollateNoCase( PCXSTR psz ) const throw()
{
ATLASSERT( AtlIsValidString( psz ) );
return( StringTraits::StringCollateIgnore( GetString(), psz ) );
}
// Advanced manipulation
// Delete 'nCount' characters, starting at index 'iIndex'
int Delete( int iIndex, int nCount = 1 )
{
ATLASSERT( iIndex >= 0 );
ATLASSERT( nCount >= 0 );
int nLength = GetLength();
if( (nCount+iIndex) > nLength )
{
nCount = nLength-iIndex;
}
if( nCount > 0 )
{
int nNewLength = nLength-nCount;
int nXCHARsToCopy = nLength-(iIndex+nCount)+1;
PXSTR pszBuffer = GetBuffer();
memmove( pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR ) );
ReleaseBuffer( nNewLength );
}
return( GetLength() );
}
// Insert character 'ch' before index 'iIndex'
int Insert( int iIndex, XCHAR ch )
{
ATLASSERT( iIndex >= 0 );
if( iIndex > GetLength() )
{
iIndex = GetLength();
}
int nNewLength = GetLength()+1;
PXSTR pszBuffer = GetBuffer( nNewLength );
// move existing bytes down
memmove( pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR ) );
pszBuffer[iIndex] = ch;
ReleaseBuffer( nNewLength );
return( nNewLength );
}
// Insert string 'psz' before index 'iIndex'
int Insert( int iIndex, PCXSTR psz )
{
ATLASSERT( iIndex >= 0 );
if( iIndex > GetLength() )
{
iIndex = GetLength();
}
// nInsertLength and nNewLength are in XCHARs
int nInsertLength = StringTraits::SafeStringLen( psz );
int nNewLength = GetLength();
if( nInsertLength > 0 )
{
nNewLength += nInsertLength;
PXSTR pszBuffer = GetBuffer( nNewLength );
// move existing bytes down
memmove( pszBuffer+iIndex+nInsertLength,
pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ) );
memcpy( pszBuffer+iIndex, psz, nInsertLength*sizeof( XCHAR ) );
ReleaseBuffer( nNewLength );
}
return( nNewLength );
}
// Replace all occurrences of character 'chOld' with character 'chNew'
int Replace( XCHAR chOld, 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 >( GetString() ); // We don't actually write to pszBuffer until we've called GetBuffer().
int nLength = GetLength();
int iChar = 0;
while( iChar < nLength )
{
// replace instances of the specified character only
if( pszBuffer[iChar] == chOld )
{
if( !bCopied )
{
bCopied = true;
pszBuffer = GetBuffer( nLength );
}
pszBuffer[iChar] = chNew;
nCount++;
}
iChar = int( StringTraits::CharNext( pszBuffer+iChar )-pszBuffer );
}
if( bCopied )
{
ReleaseBuffer( nLength );
}
}
return( nCount );
}
// Replace all occurrences of string 'pszOld' with string 'pszNew'
int Replace( PCXSTR pszOld, PCXSTR pszNew )
{
// can't have empty or NULL lpszOld
// nSourceLen is in XCHARs
int nSourceLen = StringTraits::SafeStringLen( pszOld );
if( nSourceLen == 0 )
return( 0 );
// nReplacementLen is in XCHARs
int nReplacementLen = StringTraits::SafeStringLen( pszNew );
// loop once to figure out the size of the result string
int nCount = 0;
{
PCXSTR pszStart = GetString();
PCXSTR pszEnd = pszStart+GetLength();
while( pszStart < pszEnd )
{
PCXSTR pszTarget;
while( (pszTarget = StringTraits::StringFindString( pszStart, pszOld ) ) != NULL)
{
nCount++;
pszStart = pszTarget+nSourceLen;
}
pszStart += StringTraits::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 = GetLength();
int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount;
PXSTR pszBuffer = 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 = StringTraits::StringFindString( pszStart, pszOld ) ) != NULL )
{
int nBalance = nOldLength-int(pszTarget-pszBuffer+nSourceLen);
memmove( pszTarget+nReplacementLen, pszTarget+nSourceLen, nBalance*sizeof( XCHAR ) );
memcpy( pszTarget, pszNew, nReplacementLen*sizeof( XCHAR ) );
pszStart = pszTarget+nReplacementLen;
pszTarget[nReplacementLen+nBalance] = 0;
nOldLength += (nReplacementLen-nSourceLen);
}
pszStart += StringTraits::SafeStringLen( pszStart )+1;
}
ATLASSERT( pszBuffer[nNewLength] == 0 );
ReleaseBuffer( nNewLength );
}
return( nCount );
}
// Remove all occurrences of character 'chRemove'
int Remove( XCHAR chRemove )
{
int nLength = GetLength();
PXSTR pszBuffer = GetBuffer( nLength );
PXSTR pszSource = pszBuffer;
PXSTR pszDest = pszBuffer;
PXSTR pszEnd = pszBuffer+nLength;
while( pszSource < pszEnd )
{
if( *pszSource != chRemove )
{
*pszDest = *pszSource;
pszDest = StringTraits::CharNext( pszDest );
}
pszSource = StringTraits::CharNext( pszSource );
}
*pszDest = 0;
int nCount = int( pszSource-pszDest );
ReleaseBuffer( nLength-nCount );
return( nCount );
}
CStringT Tokenize( PCXSTR pszTokens, int& iStart ) const
{
ATLASSERT( iStart >= 0 );
if( pszTokens == NULL )
{
return( *this );
}
PCXSTR pszPlace = GetString()+iStart;
PCXSTR pszEnd = GetString()+GetLength();
if( pszPlace < pszEnd )
{
int nIncluding = StringTraits::StringSpanIncluding( pszPlace,
pszTokens );
if( (pszPlace+nIncluding) < pszEnd )
{
pszPlace += nIncluding;
int nExcluding = StringTraits::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( CStringT( GetManager() ) );
}
// find routines
// Find the first occurrence of character 'ch', starting at index 'iStart'
int Find( XCHAR ch, int iStart = 0 ) const throw()
{
// iStart is in XCHARs
ATLASSERT( iStart >= 0 );
// nLength is in XCHARs
int nLength = GetLength();
if( iStart >= nLength)
{
return( -1 );
}
// find first single character
PCXSTR psz = StringTraits::StringFindChar( GetString()+iStart, ch );
// return -1 if not found and index otherwise
return( (psz == NULL) ? -1 : int( psz-GetString() ) );
}
// look for a specific sub-string
// Find the first occurrence of string 'pszSub', starting at index 'iStart'
int Find( PCXSTR pszSub, int iStart = 0 ) const throw()
{
// iStart is in XCHARs
ATLASSERT( iStart >= 0 );
ATLASSERT( AtlIsValidString( pszSub ) );
// nLength is in XCHARs
int nLength = GetLength();
if( iStart > nLength )
{
return( -1 );
}
// find first matching substring
PCXSTR psz = StringTraits::StringFindString( GetString()+iStart, pszSub );
// return -1 for not found, distance from beginning otherwise
return( (psz == NULL) ? -1 : int( psz-GetString() ) );
}
// Find the first occurrence of any of the characters in string 'pszCharSet'
int FindOneOf( PCXSTR pszCharSet ) const throw()
{
ATLASSERT( AtlIsValidString( pszCharSet ) );
PCXSTR psz = StringTraits::StringScanSet( GetString(), pszCharSet );
return( (psz == NULL) ? -1 : int( psz-GetString() ) );
}
// Find the last occurrence of character 'ch'
int ReverseFind( XCHAR ch ) const throw()
{
// find last single character
PCXSTR psz = StringTraits::StringFindCharRev( GetString(), ch );
// return -1 if not found, distance from beginning otherwise
return( (psz == NULL) ? -1 : int( psz-GetString() ) );
}
// manipulation
// Convert the string to uppercase
CStringT& MakeUpper()
{
int nLength = GetLength();
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::StringUppercase( pszBuffer );
ReleaseBuffer( nLength );
return( *this );
}
// Convert the string to lowercase
CStringT& MakeLower()
{
int nLength = GetLength();
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::StringLowercase( pszBuffer );
ReleaseBuffer( nLength );
return( *this );
}
// Reverse the string
CStringT& MakeReverse()
{
int nLength = GetLength();
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::StringReverse( pszBuffer );
ReleaseBuffer( nLength );
return( *this );
}
// trimming
// Remove all trailing whitespace
CStringT& TrimRight()
{
// find beginning of trailing spaces by starting
// at beginning (DBCS aware)
PCXSTR psz = GetString();
PCXSTR pszLast = NULL;
while( *psz != 0 )
{
if( StringTraits::IsSpace( *psz ) )
{
if( pszLast == NULL )
pszLast = psz;
}
else
{
pszLast = NULL;
}
psz = StringTraits::CharNext( psz );
}
if( pszLast != NULL )
{
// truncate at trailing space start
int iLast = int( pszLast-GetString() );
Truncate( iLast );
}
return( *this );
}
// Remove all leading whitespace
CStringT& TrimLeft()
{
// find first non-space character
PCXSTR psz = GetString();
while( StringTraits::IsSpace( *psz ) )
{
psz = StringTraits::CharNext( psz );
}
if( psz != GetString() )
{
// fix up data and length
int iFirst = int( psz-GetString() );
PXSTR pszBuffer = GetBuffer( GetLength() );
psz = pszBuffer+iFirst;
int nDataLength = GetLength()-iFirst;
memmove( pszBuffer, psz, (nDataLength+1)*sizeof( XCHAR ) );
ReleaseBuffer( nDataLength );
}
return( *this );
}
// Remove all leading and trailing whitespace
CStringT& Trim()
{
return( TrimRight().TrimLeft() );
}
// Remove all leading and trailing occurrences of character 'chTarget'
CStringT& Trim( XCHAR chTarget )
{
return( TrimRight( chTarget ).TrimLeft( chTarget ) );
}
// Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets'
CStringT& Trim( PCXSTR pszTargets )
{
return( TrimRight( pszTargets ).TrimLeft( pszTargets ) );
}
// trimming anything (either side)
// Remove all trailing occurrences of character 'chTarget'
CStringT& TrimRight( XCHAR chTarget )
{
// find beginning of trailing matches
// by starting at beginning (DBCS aware)
PCXSTR psz = GetString();
PCXSTR pszLast = NULL;
while( *psz != 0 )
{
if( *psz == chTarget )
{
if( pszLast == NULL )
{
pszLast = psz;
}
}
else
{
pszLast = NULL;
}
psz = StringTraits::CharNext( psz );
}
if( pszLast != NULL )
{
// truncate at left-most matching character
int iLast = int( pszLast-GetString() );
Truncate( iLast );
}
return( *this );
}
// Remove all trailing occurrences of any of the characters in string 'pszTargets'
CStringT& TrimRight( 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 = GetString();
PCXSTR pszLast = NULL;
while( *psz != 0 )
{
if( StringTraits::StringFindChar( pszTargets, *psz ) != NULL )
{
if( pszLast == NULL )
{
pszLast = psz;
}
}
else
{
pszLast = NULL;
}
psz = StringTraits::CharNext( psz );
}
if( pszLast != NULL )
{
// truncate at left-most matching character
int iLast = int( pszLast-GetString() );
Truncate( iLast );
}
return( *this );
}
// Remove all leading occurrences of character 'chTarget'
CStringT& TrimLeft( XCHAR chTarget )
{
// find first non-matching character
PCXSTR psz = GetString();
while( chTarget == *psz )
{
psz = StringTraits::CharNext( psz );
}
if( psz != GetString() )
{
// fix up data and length
int iFirst = int( psz-GetString() );
PXSTR pszBuffer = GetBuffer( GetLength() );
psz = pszBuffer+iFirst;
int nDataLength = GetLength()-iFirst;
memmove( pszBuffer, psz, (nDataLength+1)*sizeof( XCHAR ) );
ReleaseBuffer( nDataLength );
}
return( *this );
}
// Remove all leading occurrences of any of the characters in string 'pszTargets'
CStringT& TrimLeft( PCXSTR pszTargets )
{
// if we're not trimming anything, we're not doing any work
if( (pszTargets == NULL) || (*pszTargets == 0) )
{
return( *this );
}
PCXSTR psz = GetString();
while( (*psz != 0) && (StringTraits::StringFindChar( pszTargets, *psz ) != NULL) )
{
psz = StringTraits::CharNext( psz );
}
if( psz != GetString() )
{
// fix up data and length
int iFirst = int( psz-GetString() );
PXSTR pszBuffer = GetBuffer( GetLength() );
psz = pszBuffer+iFirst;
int nDataLength = GetLength()-iFirst;
memmove( pszBuffer, psz, (nDataLength+1)*sizeof( XCHAR ) );
ReleaseBuffer( nDataLength );
}
return( *this );
}
__if_exists( StringTraits::ConvertToOem )
{
// Convert the string to the OEM character set
void AnsiToOem()
{
int nLength = GetLength();
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::ConvertToOem( pszBuffer );
ReleaseBuffer( nLength );
}
}
__if_exists( StringTraits::ConvertToAnsi )
{
// Convert the string to the ANSI character set
void OemToAnsi()
{
int nLength = GetLength();
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::ConvertToAnsi( pszBuffer );
ReleaseBuffer( nLength );
}
}
// Very simple sub-string extraction
// Return the substring starting at index 'iFirst'
CStringT Mid( int iFirst ) const
{
return( Mid( iFirst, GetLength()-iFirst ) );
}
// Return the substring starting at index 'iFirst', with length 'nCount'
CStringT Mid( int iFirst, int nCount ) const
{
// nCount is in XCHARs
// out-of-bounds requests return sensible things
ATLASSERT( iFirst >= 0 );
ATLASSERT( nCount >= 0 );
if( (iFirst+nCount) > GetLength() )
{
nCount = GetLength()-iFirst;
}
if( iFirst > GetLength() )
{
nCount = 0;
}
ATLASSERT( (nCount == 0) || ((iFirst+nCount) <= GetLength()) );
// optimize case of returning entire string
if( (iFirst == 0) && ((iFirst+nCount) == GetLength()) )
{
return( *this );
}
CStringT strDest( GetManager() ); //GetString()+nFirst, nCount );
PXSTR pszBuffer = strDest.GetBufferSetLength( nCount );
memcpy( pszBuffer, GetString()+iFirst, nCount*sizeof( XCHAR ) );
strDest.ReleaseBuffer( nCount );
return( strDest );
}
// Return the substring consisting of the rightmost 'nCount' characters
CStringT Right( int nCount ) const
{
// nCount is in XCHARs
ATLASSERT( nCount >= 0 );
if( nCount >= GetLength() )
{
return( *this );
}
CStringT strDest( GetManager() );
PXSTR pszBuffer = strDest.GetBufferSetLength( nCount );
memcpy( pszBuffer, GetString()+GetLength()-nCount, nCount*sizeof( XCHAR ) );
strDest.ReleaseBuffer( nCount );
return( strDest );
}
// Return the substring consisting of the leftmost 'nCount' characters
CStringT Left( int nCount ) const
{
// nCount is in XCHARs
ATLASSERT( nCount >= 0 );
if( nCount >= GetLength() )
{
return( *this );
}
CStringT strDest( GetManager() );
PXSTR pszBuffer = strDest.GetBufferSetLength( nCount );
memcpy( pszBuffer, GetString(), nCount*sizeof( XCHAR ) );
strDest.ReleaseBuffer( nCount );
return( strDest );
}
// Return the substring consisting of the leftmost characters in the set 'pszCharSet'
CStringT SpanIncluding( PCXSTR pszCharSet ) const
{
ATLASSERT( AtlIsValidString( pszCharSet ) );
return( Left( StringTraits::StringSpanIncluding( GetString(), pszCharSet ) ) );
}
// Return the substring consisting of the leftmost characters not in the set 'pszCharSet'
CStringT SpanExcluding( PCXSTR pszCharSet ) const
{
ATLASSERT( AtlIsValidString( pszCharSet ) );
return( Left( StringTraits::StringSpanExcluding( GetString(), pszCharSet ) ) );
}
// Format data using format string 'pszFormat'
void __cdecl Format( PCXSTR pszFormat, ... )
{
ATLASSERT( AtlIsValidString( pszFormat ) );
va_list argList;
va_start( argList, pszFormat );
FormatV( pszFormat, argList );
va_end( argList );
}
// Format data using format string loaded from resource 'nFormatID'
void __cdecl Format( UINT nFormatID, ... )
{
CStringT strFormat( GetManager() );
ATLVERIFY( 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'
void __cdecl AppendFormat( UINT nFormatID, ... )
{
CStringT strTemp( GetManager() );
va_list argList;
va_start( argList, nFormatID );
CStringT strFormat( GetManager() );
ATLVERIFY( strFormat.LoadString( nFormatID ) );
strTemp.FormatV( strFormat, argList );
operator+=( strTemp );
va_end( argList );
}
// Append formatted data using format string 'pszFormat'
void __cdecl AppendFormat( PCXSTR pszFormat, ... )
{
ATLASSERT( AtlIsValidString( pszFormat ) );
CStringT strTemp( GetManager() );
va_list argList;
va_start( argList, pszFormat );
strTemp.FormatV( pszFormat, argList );
operator+=( strTemp );
va_end( argList );
}
void FormatV( PCXSTR pszFormat, va_list args )
{
ATLASSERT( AtlIsValidString( pszFormat ) );
int nLength = StringTraits::GetFormattedLength( pszFormat, args );
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::Format( pszBuffer, pszFormat, args );
ReleaseBuffer( nLength );
}
__if_exists(StringTraits::FormatMessage)
{
// Format a message using format string 'pszFormat'
void __cdecl FormatMessage( PCXSTR pszFormat, ... )
{
va_list argList;
va_start( argList, pszFormat );
FormatMessageV( pszFormat, &argList );
va_end( argList );
}
// Format a message using format string loaded from resource 'nFormatID'
void __cdecl FormatMessage( UINT nFormatID, ... )
{
// get format string from string table
CStringT strFormat( GetManager() );
ATLVERIFY( strFormat.LoadString( nFormatID ) );
va_list argList;
va_start( argList, nFormatID );
FormatMessageV( strFormat, &argList );
va_end( argList );
}
}
// OLE BSTR support
// Allocate a BSTR containing a copy of the string
BSTR AllocSysString() const
{
BSTR bstrResult = StringTraits::AllocSysString( GetString(),
GetLength() );
if( bstrResult == NULL )
{
ThrowMemoryException();
}
return( bstrResult );
}
BSTR SetSysString( BSTR* pbstr ) const
{
ATLASSERT( AtlIsValidAddress( pbstr, sizeof( BSTR ) ) );
if( !StringTraits::ReAllocSysString( GetString(), pbstr,
GetLength() ) )
{
ThrowMemoryException();
}
ATLASSERT( *pbstr != NULL );
return( *pbstr );
}
// Set the string to the value of environment variable 'pszVar'
BOOL GetEnvironmentVariable( PCXSTR pszVar )
{
ULONG nLength = StringTraits::GetEnvironmentVariable( pszVar, NULL, 0 );
BOOL bRetVal = FALSE;
if( nLength == 0 )
{
Empty();
}
else
{
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::GetEnvironmentVariable( pszVar, pszBuffer, nLength );
ReleaseBuffer();
bRetVal = TRUE;
}
return( bRetVal );
}
// Load the string from resource 'nID'
BOOL LoadString( UINT nID )
{
HINSTANCE hInst = StringTraits::FindStringResourceInstance( nID );
if( hInst == NULL )
{
return( FALSE );
}
return( LoadString( hInst, nID ) );
}
// Load the string from resource 'nID' in module 'hInstance'
BOOL LoadString( HINSTANCE hInstance, UINT nID )
{
const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage( hInstance, nID );
if( pImage == NULL )
{
return( FALSE );
}
int nLength = StringTraits::GetBaseTypeLength( pImage->achString, pImage->nLength );
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::ConvertToBaseType( pszBuffer, nLength, pImage->achString, pImage->nLength );
ReleaseBuffer( nLength );
return( TRUE );
}
// Load the string from resource 'nID' in module 'hInstance', using language 'wLanguageID'
BOOL LoadString( HINSTANCE hInstance, UINT nID, WORD wLanguageID )
{
const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage( hInstance, nID, wLanguageID );
if( pImage == NULL )
{
return( FALSE );
}
int nLength = StringTraits::GetBaseTypeLength( pImage->achString, pImage->nLength );
PXSTR pszBuffer = GetBuffer( nLength );
StringTraits::ConvertToBaseType( pszBuffer, nLength, pImage->achString, pImage->nLength );
ReleaseBuffer( nLength );
return( TRUE );
}
friend CStringT operator+( const CStringT& str1, const CStringT& str2 )
{
CStringT strResult( str1.GetManager() );
Concatenate( strResult, str1, str1.GetLength(), str2, str2.GetLength() );
return( strResult );
}
friend CStringT operator+( const CStringT& str1, PCXSTR psz2 )
{
CStringT strResult( str1.GetManager() );
Concatenate( strResult, str1, str1.GetLength(), psz2, StringLength( psz2 ) );
return( strResult );
}
friend CStringT operator+( PCXSTR psz1, const CStringT& str2 )
{
CStringT strResult( str2.GetManager() );
Concatenate( strResult, psz1, StringLength( psz1 ), str2, str2.GetLength() );
return( strResult );
}
friend CStringT operator+( const CStringT& str1, wchar_t ch2 )
{
CStringT strResult( str1.GetManager() );
XCHAR chTemp = XCHAR( ch2 );
Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 );
return( strResult );
}
friend CStringT operator+( const CStringT& str1, char ch2 )
{
CStringT strResult( str1.GetManager() );
XCHAR chTemp = XCHAR( ch2 );
Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 );
return( strResult );
}
friend CStringT operator+( wchar_t ch1, const CStringT& str2 )
{
CStringT strResult( str2.GetManager() );
XCHAR chTemp = XCHAR( ch1 );
Concatenate( strResult, &chTemp, 1, str2, str2.GetLength() );
return( strResult );
}
friend CStringT operator+( char ch1, const CStringT& str2 )
{
CStringT strResult( str2.GetManager() );
XCHAR chTemp = XCHAR( ch1 );
Concatenate( strResult, &chTemp, 1, str2, str2.GetLength() );
return( strResult );
}
friend bool operator==( const CStringT& str1, const CStringT& str2 ) throw()
{
return( str1.Compare( str2 ) == 0 );
}
friend bool operator==(
const CStringT& str1, PCXSTR psz2 ) throw()
{
return( str1.Compare( psz2 ) == 0 );
}
friend bool operator==(
PCXSTR psz1, const CStringT& str2 ) throw()
{
return( str2.Compare( psz1 ) == 0 );
}
friend bool operator==(
const CStringT& str1, PCYSTR psz2 ) throw( ... )
{
CStringT str2( psz2, str1.GetManager() );
return( str1 == str2 );
}
friend bool operator==(
PCYSTR psz1, const CStringT& str2 ) throw( ... )
{
CStringT str1( psz1, str2.GetManager() );
return( str1 == str2 );
}
friend bool operator!=(
const CStringT& str1, const CStringT& str2 ) throw()
{
return( str1.Compare( str2 ) != 0 );
}
friend bool operator!=(
const CStringT& str1, PCXSTR psz2 ) throw()
{
return( str1.Compare( psz2 ) != 0 );
}
friend bool operator!=(
PCXSTR psz1, const CStringT& str2 ) throw()
{
return( str2.Compare( psz1 ) != 0 );
}
friend bool operator!=(
const CStringT& str1, PCYSTR psz2 ) throw( ... )
{
CStringT str2( psz2, str1.GetManager() );
return( str1 != str2 );
}
friend bool operator!=(
PCYSTR psz1, const CStringT& str2 ) throw( ... )
{
CStringT str1( psz1, str2.GetManager() );
return( str1 != str2 );
}
friend bool operator<( const CStringT& str1, const CStringT& str2 ) throw()
{
return( str1.Compare( str2 ) < 0 );
}
friend bool operator<( const CStringT& str1, PCXSTR psz2 ) throw()
{
return( str1.Compare( psz2 ) < 0 );
}
friend bool operator<( PCXSTR psz1, const CStringT& str2 ) throw()
{
return( str2.Compare( psz1 ) >= 0 );
}
friend bool operator>( const CStringT& str1, const CStringT& str2 ) throw()
{
return( str1.Compare( str2 ) > 0 );
}
friend bool operator>( const CStringT& str1, PCXSTR psz2 ) throw()
{
return( str1.Compare( psz2 ) > 0 );
}
friend bool operator>( PCXSTR psz1, const CStringT& str2 ) throw()
{
return( str2.Compare( psz1 ) <= 0 );
}
friend bool operator<=( const CStringT& str1, const CStringT& str2 ) throw()
{
return( str1.Compare( str2 ) <= 0 );
}
friend bool operator<=( const CStringT& str1, PCXSTR psz2 ) throw()
{
return( str1.Compare( psz2 ) <= 0 );
}
friend bool operator<=( PCXSTR psz1, const CStringT& str2 ) throw()
{
return( str2.Compare( psz1 ) > 0 );
}
friend bool operator>=( const CStringT& str1, const CStringT& str2 ) throw()
{
return( str1.Compare( str2 ) >= 0 );
}
friend bool operator>=( const CStringT& str1, PCXSTR psz2 ) throw()
{
return( str1.Compare( psz2 ) >= 0 );
}
friend bool operator>=( PCXSTR psz1, const CStringT& str2 ) throw()
{
return( str2.Compare( psz1 ) < 0 );
}
friend bool operator==( XCHAR ch1, const CStringT& str2 ) throw()
{
return( (str2.GetLength() == 1) && (str2[0] == ch1) );
}
friend bool operator==( const CStringT& str1, XCHAR ch2 ) throw()
{
return( (str1.GetLength() == 1) && (str1[0] == ch2) );
}
friend bool operator!=( XCHAR ch1, const CStringT& str2 ) throw()
{
return( (str2.GetLength() != 1) || (str2[0] != ch1) );
}
friend bool operator!=( const CStringT& str1, XCHAR ch2 ) throw()
{
return( (str1.GetLength() != 1) || (str1[0] != ch2) );
}
private:
bool CheckImplicitLoad( const void* pv )
{
bool bRet = false;
if( (pv != NULL) && IS_INTRESOURCE( pv ) )
{
UINT nID = LOWORD( reinterpret_cast< DWORD_PTR >( pv ) );
if( !LoadString( nID ) )
{
ATLTRACE( atlTraceString, 2, _T( "Warning: implicit LoadString(%u) failed\n" ), nID );
}
bRet = true;
}
return( bRet );
}
__if_exists( StringTraits::FormatMessage )
{
void FormatMessageV( PCXSTR pszFormat, va_list* pArgList )
{
// format message into temporary buffer pszTemp
CHeapPtr< XCHAR, CLocalAllocator > pszTemp;
DWORD dwResult = StringTraits::FormatMessage( FORMAT_MESSAGE_FROM_STRING|
FORMAT_MESSAGE_ALLOCATE_BUFFER, pszFormat, 0, 0, reinterpret_cast< PXSTR >( &pszTemp ),
0, pArgList );
if( dwResult == 0 )
{
ThrowMemoryException();
}
*this = pszTemp;
}
}
};
class IFixedStringLog
{
public:
virtual void OnAllocateSpill( int nActualChars, int nFixedChars, const CStringData* pData ) throw() = 0;
virtual void OnReallocateSpill( int nActualChars, int nFixedChars, const CStringData* pData ) throw() = 0;
};
class CFixedStringMgr :
public IAtlStringMgr
{
public:
CFixedStringMgr( CStringData* pData, int nChars, IAtlStringMgr* pMgr = NULL ) throw() :
m_pData( pData ),
m_pMgr( pMgr )
{
m_pData->nRefs = -1;
m_pData->nDataLength = 0;
m_pData->nAllocLength = nChars;
m_pData->pStringMgr = this;
*static_cast< wchar_t* >( m_pData->data() ) = 0;
}
~CFixedStringMgr() throw()
{
}
// IAtlStringMgr
public:
virtual CStringData* Allocate( int nChars, int nCharSize ) throw()
{
ATLASSERT( m_pData->nRefs == -1 );
ATLASSERT( m_pData->nDataLength == 0 );
if( nChars > m_pData->nAllocLength )
{
if( s_pLog != NULL )
{
s_pLog->OnAllocateSpill( nChars, m_pData->nAllocLength, m_pData );
}
CStringData* pData = m_pMgr->Allocate( nChars, nCharSize );
if( pData != NULL )
{
pData->pStringMgr = this;
pData->nRefs = -1; // Locked
}
return pData;
}
m_pData->nRefs = -1; // Locked
m_pData->nDataLength = 0;
m_pData->pStringMgr = this;
return m_pData;
}
virtual void Free( CStringData* pData ) throw()
{
ATLASSERT( pData->nRefs <= 0 );
if( pData != m_pData )
{
// Must have been allocated from the backup manager
pData->pStringMgr = m_pMgr;
m_pMgr->Free( pData );
}
// Always make sure the fixed buffer is ready to be used as the nil string.
m_pData->nRefs = -1;
m_pData->nDataLength = 0;
*static_cast< wchar_t* >( m_pData->data() ) = 0;
}
virtual CStringData* Reallocate( CStringData* pData, int nChars, int nCharSize ) throw()
{
CStringData* pNewData;
ATLASSERT( pData->nRefs < 0 );
if( pData != m_pData )
{
pData->pStringMgr = m_pMgr;
pNewData = m_pMgr->Reallocate( pData, nChars, nCharSize );
if( pNewData == NULL )
{
pData->pStringMgr = this;
}
else
{
pNewData->pStringMgr = this;
}
}
else
{
if( nChars > pData->nAllocLength )
{
if( s_pLog != NULL )
{
s_pLog->OnReallocateSpill( nChars, pData->nAllocLength, pData );
}
pNewData = m_pMgr->Allocate( nChars, nCharSize );
if( pNewData == NULL )
{
return NULL;
}
// Copy the string data
memcpy( pNewData->data(), pData->data(), (pData->nAllocLength+1)*nCharSize );
pNewData->nRefs = pData->nRefs; // Locked
pNewData->pStringMgr = this;
pNewData->nDataLength = pData->nDataLength;
}
else
{
// Don't do anything if the buffer is already big enough.
pNewData = pData;
}
}
return pNewData;
}
virtual CStringData* GetNilString() throw()
{
ATLASSERT( m_pData->nRefs == -1 );
ATLASSERT( m_pData->nDataLength == 0 );
return m_pData;
}
virtual IAtlStringMgr* Clone() throw()
{
return m_pMgr;
}
public:
static IFixedStringLog* s_pLog;
IAtlStringMgr* GetBackupManager() const throw()
{
return m_pMgr;
}
protected:
IAtlStringMgr* m_pMgr;
CStringData* m_pData;
};
__declspec( selectany ) IFixedStringLog* CFixedStringMgr::s_pLog = NULL;
#pragma warning( push )
#pragma warning( disable: 4355 ) // 'this' used in base member initializer list
template< class StringType, int t_nChars >
class CFixedStringT :
private CFixedStringMgr, // This class must be first, since it needs to be initialized before StringType
public StringType
{
public:
CFixedStringT() throw() :
CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
StringType( static_cast< CFixedStringMgr* >( this ) )
{
}
explicit CFixedStringT( IAtlStringMgr* pStringMgr ) throw() :
CFixedStringMgr( &m_data, t_nChars, pStringMgr ),
StringType( static_cast< CFixedStringMgr* >( this ) )
{
}
CFixedStringT( const CFixedStringT< StringType, t_nChars >& str ) :
CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
StringType( str.GetString(), str.GetLength(), static_cast< CFixedStringMgr* >( this ) )
{
}
CFixedStringT( const StringType& str ) :
CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
StringType( str.GetString(), str.GetLength(), static_cast< CFixedStringMgr* >( this ) )
{
}
CFixedStringT( const StringType::XCHAR* psz ) :
CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
StringType( psz, static_cast< CFixedStringMgr* >( this ) )
{
}
CFixedStringT( const StringType::XCHAR* psz, int nLength ) :
CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
StringType( psz, nLength, static_cast< CFixedStringMgr* >( this ) )
{
}
explicit CFixedStringT( const StringType::YCHAR* psz ) :
CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
StringType( psz, static_cast< CFixedStringMgr* >( this ) )
{
}
explicit CFixedStringT( const unsigned char* psz ) :
CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
StringType( psz, static_cast< CFixedStringMgr* >( this ) )
{
}
~CFixedStringT() throw()
{
Empty();
}
CFixedStringT< StringType, t_nChars >& operator=( const CFixedStringT< StringType, t_nChars >& str )
{
StringType::operator=( str );
return *this;
}
CFixedStringT< StringType, t_nChars >& operator=( const char* psz )
{
StringType::operator=( psz );
return *this;
}
CFixedStringT< StringType, t_nChars >& operator=( const wchar_t* psz )
{
StringType::operator=( psz );
return *this;
}
CFixedStringT< StringType, t_nChars >& operator=( const unsigned char* psz )
{
StringType::operator=( psz );
return *this;
}
CFixedStringT< StringType, t_nChars >& operator=( const StringType& str )
{
StringType::operator=( str );
return *this;
}
// Implementation
protected:
CStringData m_data;
StringType::XCHAR m_achData[t_nChars+1];
};
#pragma warning( pop )
class CFixedStringLog :
public IFixedStringLog
{
public:
CFixedStringLog() throw()
{
CFixedStringMgr::s_pLog = this;
}
~CFixedStringLog() throw()
{
CFixedStringMgr::s_pLog = NULL;
}
public:
void OnAllocateSpill( int nActualChars, int nFixedChars, const CStringData* pData ) throw()
{
(void)nActualChars;
(void)nFixedChars;
(void)pData;
ATLTRACE( atlTraceString, 0, _T( "CFixedStringMgr::Allocate() spilling to heap. %d chars (fixed size = %d chars)\n" ), nActualChars, nFixedChars );
}
void OnReallocateSpill( int nActualChars, int nFixedChars, const CStringData* pData ) throw()
{
(void)nActualChars;
(void)nFixedChars;
(void)pData;
ATLTRACE( atlTraceString, 0, _T( "CFixedStringMgr::Reallocate() spilling to heap. %d chars (fixed size = %d chars)\n" ), nActualChars, nFixedChars );
}
};
}; // namespace ATL
#pragma pop_macro("new")
#endif // __CSTRINGT_H__ (whole file)