// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 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__

// ORIG: #pragma once

#ifndef _ATL_NO_PRAGMA_WARNINGS
#ifndef UNIX
#pragma warning (push)
#pragma warning(disable : 4668)	// is not defined as a preprocessor macro, replacing with '0' for '#if/#elif
#pragma warning(disable : 4820)	// padding added after member
#pragma warning(disable : 4127)  // conditional expression constant
#endif
#endif //!_ATL_NO_PRAGMA_WARNINGS

#ifndef UNIX
#pragma warning(disable:4786)	// avoid 255-character limit warnings
#endif

#ifdef _MANAGED
#include <vcclr.h>  // For PtrToStringChars
#endif

#include <atlsimpstr.h>
#include <stddef.h>

#ifndef _INC_NEW
// ORIG: #include <new.h>
#endif

#include <stdio.h>
#include <wchar.h>
#include <limits.h>
#include <wctype.h>
#ifndef _WIN32
#define _mbsstr(a,b) strstr((char*)a, (char*) b)
#endif //!_WIN32
#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>

//ORIG sturct tagVARIANT
//ORIG typedef tagVARIANT VARIANT
#define VARIANT void*

#ifndef _AFX
#define _AFX_FUNCNAME(_Name) _Name
#endif

#if !defined(AIX)
#pragma push_macro("new")
#undef new
#endif // !defined(AIX)


#if defined(_AFX)
#pragma push_macro("FormatMessage")
#undef FormatMessage
#endif

/////////////////////////////////////////////////////////////////////////////
// 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
{

// This struct have the same memory layout as CString and is used to enable
// const statically initialized CString without making a copy on the heap
template <class StringType,int t_nChars> struct CConstFixedStringT
{
	CStringData m_data;
	typename StringType::XCHAR m_achData[t_nChars];
};

#define IMPLEMENT_CONST_STRING_PTR(StringType, value, name) const CConstFixedStringT<StringType, sizeof(value)/sizeof(StringType::XCHAR)> _init##name ={ 	{NULL,		sizeof(value)/sizeof(StringType::XCHAR)-1, 	sizeof(value)/sizeof(StringType::XCHAR)-1, 	-1},			value	};	const StringType::XCHAR* const _value##name = _init##name.m_achData;	extern const StringType* const name = CONST_STRING_PTR(StringType, name);
#define DECLARE_CONST_STRING_PTR(StringType, name) extern const StringType* const name;
#define CONST_STRING_PTR(StringType, name) reinterpret_cast<const StringType* const>(&_value##name)

/////////////////////////////////////////////////////////////////////////////
// inline helpers

inline int _wcstombsz(__out_ecount(count) char* mbstr, __in_z const wchar_t* wcstr, __in 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(__out_ecount_z(count) wchar_t* wcstr, __in_z const char* mbstr, __in ULONG count)
{
	// count is number of wchar_t's
	if (count == 0 && wcstr != NULL)
		return 0;

	int result = ::MultiByteToWideChar(_AtlGetConversionACP(), 0, mbstr, -1,
		wcstr, count);
	ATLENSURE(wcstr == NULL || result <= (int)count);
	if ((result > 0) && (wcstr != NULL))
	{
		wcstr[result-1] = 0;
	}

	return result;
}

// ORIG: #if 0 start
#if 0
#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).

#pragma warning( push )
#pragma warning( disable : 4793 )

inline void _AtlInstallStringThunk(void** ppThunk, void* pfnWin9x, void* pfnNT) throw()
{
#pragma warning (push)
#pragma warning (disable : 4640)	// construction of local static object is not thread-safe

	static bool s_bWin9x = (::GetVersion()&0x80000000) != 0;
	
#pragma warning (pop)

	void* pfn;
	if (s_bWin9x)
		pfn = pfnWin9x;
	else
	{
#ifdef _CSTRING_ALWAYS_THUNK
		pfn = pfnWin9x;
		(void)pfnNT;
#else
		pfn = pfnNT;
#endif
	}
	InterlockedExchangePointer(ppThunk, pfn);
}

#pragma warning( pop )

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(__in_z LPCWSTR pszName, 
	__out_ecount_part_opt(nSize, return) LPWSTR pszBuffer, __in DWORD nSize)
{
	ULONG nSizeA;
	ULONG nSizeW;
	CTempBuffer<char> pszBufferA;
	CW2A pszNameA(pszName);

	nSizeA = ::GetEnvironmentVariableA(pszNameA, NULL, 0);
	if( nSizeA == 0 || nSizeA==ULONG_MAX)
	{
		return 0;
	}

	pszBufferA.Allocate(nSizeA + 1);
	if( 0 == ::GetEnvironmentVariableA(pszNameA, pszBufferA, nSizeA))
	{
		return 0;
	}

	nSizeW = ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszBufferA, -1, NULL, 0);
	if( nSize == 0 )
	{
		return nSizeW;
	}
	
	if( nSize >= nSizeW )
	{
		nSizeW = ::MultiByteToWideChar(_AtlGetConversionACP(), 0, pszBufferA, -1, pszBuffer, nSizeW );
	}

	return nSizeW;
}

inline DWORD WINAPI GetEnvironmentVariableWThunk(__in_z LPCWSTR pszName, 
	__out_ecount_part_opt(nSize, return) LPWSTR pszBuffer, __in DWORD nSize)
{
	_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnGetEnvironmentVariableW), 
		GetEnvironmentVariableWFake, ::GetEnvironmentVariableW);

	return _strthunks.pfnGetEnvironmentVariableW(pszName, pszBuffer, nSize);
}

inline int WINAPI CompareStringWFake(__in LCID lcid, __in DWORD dwFlags, 
	__in_ecount(nLength1) LPCWSTR pszString1, __in int nLength1, __in_ecount(nLength2) LPCWSTR pszString2, __in int nLength2)
{
	USES_CONVERSION_EX;
	
	LPCSTR pszAString1 = NULL;
	if(pszString1 != NULL)
	{
		pszAString1 = W2A_EX(pszString1,_ATL_SAFE_ALLOCA_DEF_THRESHOLD);
		if(pszAString1 == NULL)
			AtlThrow(E_OUTOFMEMORY);
	}

	LPCSTR pszAString2 = NULL;
	if(pszString2 != NULL)
	{
		pszAString2 = W2A_EX(pszString2,_ATL_SAFE_ALLOCA_DEF_THRESHOLD);
		if(pszAString2 == NULL)
			AtlThrow(E_OUTOFMEMORY);
	}

	return ::CompareStringA(lcid, dwFlags, pszAString1, nLength1, pszAString2, nLength2);
}

inline int WINAPI CompareStringWThunk(__in LCID lcid, __in DWORD dwFlags, 
	__in_ecount(nLength1) LPCWSTR pszString1, __in int nLength1, __in_ecount(nLength2) LPCWSTR pszString2, __in int nLength2)
{
	_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnCompareStringW), CompareStringWFake, ::CompareStringW);

	return _strthunks.pfnCompareStringW(lcid, dwFlags, pszString1, nLength1, pszString2, nLength2);
}

inline BOOL WINAPI GetStringTypeExWFake(__in LCID lcid, __in DWORD dwInfoType, __in_ecount(nLength) LPCWSTR pszSrc,
	__in int nLength, __out LPWORD pwCharType)
{
	int nLengthA;
	CTempBuffer<char> pszA;

	nLengthA = ::WideCharToMultiByte(_AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0, NULL, NULL);
	pszA.Allocate(nLengthA);
	::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(__in LCID lcid, __in DWORD dwInfoType, __in_ecount(nLength) LPCWSTR pszSrc,
	__in int nLength, __out LPWORD pwCharType)
{
	_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnGetStringTypeExW), GetStringTypeExWFake, ::GetStringTypeExW);

	return _strthunks.pfnGetStringTypeExW(lcid, dwInfoType, pszSrc, nLength, pwCharType);
}

inline int WINAPI lstrcmpiWFake(__in_z LPCWSTR psz1, __in_z LPCWSTR psz2)
{
	USES_CONVERSION_EX;

	return ::lstrcmpiA(W2A_EX_DEF(psz1), W2A_EX_DEF(psz2));
}

inline int WINAPI lstrcmpiWThunk(__in_z LPCWSTR psz1, __in_z LPCWSTR psz2)
{
	_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnlstrcmpiW), lstrcmpiWFake, ::lstrcmpiW);

	return _strthunks.pfnlstrcmpiW(psz1, psz2);
}

inline LPWSTR WINAPI CharLowerWFake(__inout_z LPWSTR psz)
{
	ATLENSURE(psz);
	USES_CONVERSION_EX;
	LPSTR pszA;

	pszA = W2A_EX_DEF(psz);
	::CharLowerA(pszA);

	Checked::wcscpy_s(psz, wcslen(psz) + 1, A2W_EX_DEF(pszA));
	return psz;
}

inline LPWSTR WINAPI CharLowerWThunk(__inout LPWSTR psz)
{
	_AtlInstallStringThunk(reinterpret_cast<void**>(&_strthunks.pfnCharLowerW), CharLowerWFake, ::CharLowerW);

	return _strthunks.pfnCharLowerW(psz);
}

inline LPWSTR WINAPI CharUpperWFake(__inout_z LPWSTR psz)
{
	ATLENSURE(psz);
	USES_CONVERSION_EX;
	LPSTR pszA;

	pszA = W2A_EX_DEF(psz);
	::CharUpperA(pszA);

	Checked::wcscpy_s(psz, wcslen(psz) + 1, A2W_EX_DEF(pszA));
	return psz;
}

inline LPWSTR WINAPI CharUpperWThunk(__inout 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

// ORIG: #if 0 end
#endif // 0

/////////////////////////////////////////////////////////////////////////////
//

#ifndef _ATL_MIN_CRT
template< typename _CharType = char >
class ChTraitsCRT :
	public ChTraitsBase< _CharType >
{
public:
	static char* __cdecl CharNext( __in_z const char* p ) throw()
	{
		return reinterpret_cast< char* >( _mbsinc( reinterpret_cast< const unsigned char* >( p ) ) );
	}

	static int __cdecl IsDigit( __in char ch ) throw()
	{
		return _ismbcdigit( ch );
	}

	static int __cdecl IsSpace( __in char ch ) throw()
	{
		return _ismbcspace( ch );
	}

	static int __cdecl StringCompare( __in_z LPCSTR pszA, __in_z LPCSTR pszB ) throw()
	{
            return strcmp(pszA,pszB);
// ORIG:		return _mbscmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
	}

 	static int __cdecl StringCompareIgnore( __in_z LPCSTR pszA, __in_z LPCSTR pszB ) throw()
 	{
            return strcasecmp(pszA,pszB);
// ORIG: 		return _mbsicmp( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
 	}

	static int __cdecl StringCollate( __in_z LPCSTR pszA, __in_z LPCSTR pszB ) throw()
	{
		return _mbscoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
	}

// ORIG: 	static int __cdecl StringCollateIgnore( __in_z LPCSTR pszA, __in_z LPCSTR pszB ) throw()
// ORIG: 	{
// ORIG: 		return _mbsicoll( reinterpret_cast< const unsigned char* >( pszA ), reinterpret_cast< const unsigned char* >( pszB ) );
// ORIG: 	}

	static LPCSTR __cdecl StringFindString( __in_z LPCSTR pszBlock, __in_z LPCSTR pszMatch ) throw()
	{
		return reinterpret_cast< LPCSTR >( _mbsstr( reinterpret_cast< const unsigned char* >( pszBlock ),
			reinterpret_cast< const unsigned char* >( pszMatch ) ) );
	}

	static LPSTR __cdecl StringFindString( __in_z LPSTR pszBlock, __in_z LPCSTR pszMatch ) throw()
	{
		return( const_cast< LPSTR >( StringFindString( const_cast< LPCSTR >( pszBlock ), pszMatch ) ) );
	}

	static LPCSTR __cdecl StringFindChar( __in_z LPCSTR pszBlock, __in char chMatch ) throw()
	{
		return reinterpret_cast< LPCSTR >( _mbschr( reinterpret_cast< const unsigned char* >( pszBlock ), (unsigned char)chMatch ) );
	}

	static LPCSTR __cdecl StringFindCharRev( __in_z LPCSTR psz, __in char ch ) throw()
	{
		return reinterpret_cast< LPCSTR >( _mbsrchr( reinterpret_cast< const unsigned char* >( psz ), (unsigned char)ch ) );
	}

	static LPCSTR __cdecl StringScanSet( __in_z LPCSTR pszBlock, __in_z LPCSTR pszMatch ) throw()
	{
		return reinterpret_cast< LPCSTR >( _mbspbrk( reinterpret_cast< const unsigned char* >( pszBlock ),
			reinterpret_cast< const unsigned char* >( pszMatch ) ) );
	}

	static int __cdecl StringSpanIncluding( __in_z LPCSTR pszBlock, __in_z LPCSTR pszSet ) throw()
	{
		return (int)_mbsspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet ) );
	}

	static int __cdecl StringSpanExcluding( __in_z LPCSTR pszBlock, __in_z LPCSTR pszSet ) throw()
	{
		return (int)_mbscspn( reinterpret_cast< const unsigned char* >( pszBlock ), reinterpret_cast< const unsigned char* >( pszSet ) );
	}

// ORIG: 	_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::StringUppercase")
// ORIG: 	static LPSTR __cdecl StringUppercase( __inout LPSTR psz ) throw()
// ORIG: 	{
// ORIG: #pragma warning (push)
// ORIG: #pragma warning(disable : 4996)
// ORIG: 		return reinterpret_cast< LPSTR >( _mbsupr( reinterpret_cast< unsigned char* >( psz ) ) );
// ORIG: #pragma warning (pop)
// ORIG: 	}

// ORIG: 	_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::StringLowercase")
// ORIG: 	static LPSTR __cdecl StringLowercase( __inout LPSTR psz ) throw()
// ORIG: 	{
// ORIG: #pragma warning (push)
// ORIG: #pragma warning(disable : 4996)
// ORIG: 		return reinterpret_cast< LPSTR >( _mbslwr( reinterpret_cast< unsigned char* >( psz ) ) );
// ORIG: #pragma warning (pop)
// ORIG: 	}

// ORIG: 	static LPSTR __cdecl StringUppercase( __inout_ecount(size) LPSTR psz, __in size_t size ) throw()
// ORIG: 	{
// ORIG: 		Checked::mbsupr_s(reinterpret_cast< unsigned char* >( psz ), size);
// ORIG: 		return psz;
// ORIG: 	}

// ORIG: 	static LPSTR __cdecl StringLowercase( __inout_ecount(size) LPSTR psz, __in size_t size ) throw()
// ORIG: 	{
// ORIG: 		Checked::mbslwr_s( reinterpret_cast< unsigned char* >( psz ), size );
// ORIG: 		return psz;
// ORIG: 	}

// ORIG: 	static LPSTR __cdecl StringReverse( __inout LPSTR psz ) throw()
// ORIG: 	{
// ORIG: 		return reinterpret_cast< LPSTR >( _mbsrev( reinterpret_cast< unsigned char* >( psz ) ) );
// ORIG: 	}

// ORIG: 	static int __cdecl GetFormattedLength( __in __format_string LPCSTR pszFormat, va_list args ) throw()
// ORIG: 	{
// ORIG: 		return _vscprintf( pszFormat, args );
// ORIG: 	}

// ORIG: 	_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::Format")
// ORIG: 	static int __cdecl Format( __out LPSTR pszBuffer, __in __format_string LPCSTR pszFormat, va_list args ) throw()
// ORIG: 	{
// ORIG: 		#pragma warning (push)
// ORIG: 		#pragma warning(disable : 4996)
// ORIG: 		return vsprintf( pszBuffer, pszFormat, args );
// ORIG: 		#pragma warning (pop)
// ORIG: 
// ORIG: 	}
// ORIG: 	static int __cdecl Format
// ORIG: 		( __out_ecount_part(nlength, return) LPSTR pszBuffer, __in size_t nlength, __in __format_string LPCSTR pszFormat, va_list args ) throw()
// ORIG: 	{
// ORIG: 		return vsprintf_s( pszBuffer, nlength, pszFormat, args );
// ORIG: 	}

	static int __cdecl GetBaseTypeLength( __in_z LPCSTR pszSrc ) throw()
	{
		// Returns required buffer length in XCHARs
		return int( strlen( pszSrc ) );
	}

	static int __cdecl GetBaseTypeLength( __in_ecount(nLength) LPCSTR pszSrc, int nLength ) throw()
	{
		(void)pszSrc;
		// Returns required buffer length in XCHARs
		return nLength;
	}

	static int __cdecl GetBaseTypeLength( __in_z LPCWSTR pszSource ) throw()
	{
		// Returns required buffer length in XCHARs
		return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, -1, NULL, 0, NULL, NULL )-1;
	}

	static int __cdecl GetBaseTypeLength( __in_ecount(nLength) LPCWSTR pszSource, int nLength ) throw()
	{
		// Returns required buffer length in XCHARs
		return ::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSource, nLength, NULL, 0, NULL, NULL );
	}

	static void __cdecl ConvertToBaseType( __out_ecount(nDestLength) LPSTR pszDest, __in int nDestLength,
		__in_z LPCSTR pszSrc, int nSrcLength = -1 ) throw()
	{
		if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); }
		// nLen is in XCHARs
		Checked::memcpy_s( pszDest, nDestLength*sizeof( char ), 
			pszSrc, nSrcLength*sizeof( char ) );
	}

	static void __cdecl ConvertToBaseType( __out_ecount(nDestLength) LPSTR pszDest, __in int nDestLength,
		__in_z LPCWSTR pszSrc, __in int nSrcLength = -1) throw()
	{
		// nLen is in XCHARs
		::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL );
	}

// ORIG: 	_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::ConvertToOem")
// ORIG: 	static void ConvertToOem(__inout _CharType* pstrString) throw()
// ORIG: 	{
// ORIG: 		BOOL fSuccess=::CharToOemA(pstrString, pstrString);
// ORIG: 		// old version can't report error
// ORIG: 		ATLASSERT(fSuccess);
// ORIG: 	}

// ORIG: 	_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::ConvertToAnsi")
// ORIG: 	static void ConvertToAnsi(__inout _CharType* pstrString) throw()
// ORIG: 	{
// ORIG: 		BOOL fSuccess=::OemToCharA(pstrString, pstrString);
// ORIG: 		// old version can't report error
// ORIG: 		ATLASSERT(fSuccess);
// ORIG: 	}

// ORIG: 	static void ConvertToOem(__inout_ecount(size) _CharType* pstrString, __in size_t size)
// ORIG: 	{
// ORIG: 		if(size>UINT_MAX)
// ORIG: 		{
// ORIG: 			// API only allows DWORD size
// ORIG: 			AtlThrow(E_INVALIDARG);
// ORIG: 		}
// ORIG: 		DWORD dwSize=static_cast<DWORD>(size);
// ORIG: 		BOOL fSuccess=::CharToOemBuffA(pstrString, pstrString, dwSize);
// ORIG: 		if(!fSuccess)
// ORIG: 		{
// ORIG: 			AtlThrowLastWin32();
// ORIG: 		}
// ORIG: 	}

// ORIG: 	static void ConvertToAnsi(__inout_ecount(size) _CharType* pstrString, __in size_t size)
// ORIG: 	{
// ORIG: 		if(size>UINT_MAX)
// ORIG: 		{
// ORIG: 			// API only allows DWORD size
// ORIG: 			AtlThrow(E_INVALIDARG);
// ORIG: 		}
// ORIG: 		DWORD dwSize=static_cast<DWORD>(size);
// ORIG: 		BOOL fSuccess=::OemToCharBuffA(pstrString, pstrString, dwSize);
// ORIG: 		if(!fSuccess)
// ORIG: 		{
// ORIG: 			AtlThrowLastWin32();
// ORIG: 		}
// ORIG: 	}

	static void __cdecl FloodCharacters( __in char ch, __in int nLength, __out_ecount_full(nLength) char* pch ) throw()
	{
		// nLength is in XCHARs
		memset( pch, ch, nLength );
	}

// ORIG: 	static BSTR __cdecl AllocSysString( __in_ecount(nDataLength) const char* pchData, int nDataLength ) throw()
// ORIG: 	{
// ORIG: 		int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength,
// ORIG: 			NULL, NULL );
// ORIG: 		BSTR bstr = ::SysAllocStringLen( NULL, nLen );
// ORIG: 		if( bstr != NULL )
// ORIG: 		{
// ORIG: 			::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength,
// ORIG: 				bstr, nLen );
// ORIG: 		}
// ORIG: 
// ORIG: 		return bstr;
// ORIG: 	}
// ORIG: 
// ORIG: 	static BOOL __cdecl ReAllocSysString( __in_ecount(nDataLength) const char* pchData, __out BSTR* pbstr, __in int nDataLength ) throw()
// ORIG: 	{
// ORIG: 		int nLen = ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, NULL, NULL );
// ORIG: 		BOOL bSuccess = ::SysReAllocStringLen( pbstr, NULL, nLen );
// ORIG: 		if( bSuccess )
// ORIG: 		{
// ORIG: 			::MultiByteToWideChar( _AtlGetConversionACP(), 0, pchData, nDataLength, *pbstr, nLen );
// ORIG: 		}
// ORIG: 
// ORIG: 		return bSuccess;
// ORIG: 	}

// ORIG: 	static DWORD __cdecl _AFX_FUNCNAME(FormatMessage)( __in DWORD dwFlags, LPCVOID pSource,
// ORIG: 		__in DWORD dwMessageID, __in DWORD dwLanguageID, __out_ecount(nSize) LPSTR pszBuffer,
// ORIG: 		DWORD nSize, va_list* pArguments ) throw()
// ORIG: 	{
// ORIG: 		return ::FormatMessageA( dwFlags, pSource, dwMessageID, dwLanguageID,
// ORIG: 				pszBuffer, nSize, pArguments );
// ORIG: 	}

// ORIG: #if defined(_AFX)
// ORIG: 	static DWORD __cdecl FormatMessage( __in DWORD dwFlags, LPCVOID pSource,
// ORIG: 		__in DWORD dwMessageID, __in DWORD dwLanguageID, __out_ecount(nSize) LPSTR pszBuffer,
// ORIG: 		DWORD nSize, va_list* pArguments ) throw()
// ORIG: 	{
// ORIG: 		return _AFX_FUNCNAME(FormatMessage)(dwFlags, pSource, dwMessageID, dwLanguageID, pszBuffer, nSize, pArguments);
// ORIG: 	}
// ORIG: #endif

	static int __cdecl SafeStringLen( __in_z_opt LPCSTR psz ) throw()
	{
		// returns length in bytes
		return (psz != NULL) ? int( strlen( psz ) ) : 0;
	}

	static int __cdecl SafeStringLen( __in_z_opt LPCWSTR psz ) throw()
	{
		// returns length in wchar_ts
		return (psz != NULL) ? int( wcslen( psz ) ) : 0;
	}

	static int __cdecl GetCharLen( __in_z const wchar_t* pch ) throw()
	{
		(void)pch;
		// returns char length
		return 1;
	}

#if !defined UNIX
	static int __cdecl GetCharLen( __in_z const char* pch ) throw()
	{
		// returns char length
		return int( _mbclen( reinterpret_cast< const unsigned char* >( pch ) ) );
	}
#endif /* !UNIX */

// ORIG: 	static DWORD __cdecl GetEnvironmentVariable( __in_z LPCSTR pszVar,
// ORIG: 		__out_ecount_opt(dwSize) LPSTR pszBuffer, __in DWORD dwSize ) throw()
// ORIG: 	{
// ORIG: 		return ::GetEnvironmentVariableA( pszVar, pszBuffer, dwSize );
// ORIG: 	}
};

// specialization for wchar_t
template<>
class ChTraitsCRT< wchar_t > :
	public ChTraitsBase< wchar_t >
{
// ORIG: #if defined(_UNICODE) && !defined(_CSTRING_ALWAYS_THUNK)
// ORIG: 	static DWORD __cdecl _GetEnvironmentVariableW( __in_z LPCWSTR pszName, __out_ecount_part_opt(nSize, return) LPWSTR pszBuffer, __in DWORD nSize ) throw()
// ORIG: 	{
// ORIG: 		return ::GetEnvironmentVariableW( pszName, pszBuffer, nSize );
// ORIG: 	}
// ORIG: #else  // !_UNICODE
// ORIG: 	static DWORD WINAPI _GetEnvironmentVariableW( __in_z LPCWSTR pszName, 
// ORIG: 		__out_ecount_part_opt(nSize,return) LPWSTR pszBuffer, __in DWORD nSize ) throw()
// ORIG: 	{
// ORIG: 		return _strthunks.pfnGetEnvironmentVariableW( pszName, pszBuffer, nSize );
// ORIG: 	}
// ORIG: #endif  // !_UNICODE

public:
	static LPWSTR __cdecl CharNext( __in_z LPCWSTR psz ) throw()
	{
		return const_cast< LPWSTR >( psz+1 );
	}

	static int __cdecl IsDigit( __in wchar_t ch ) throw()
	{
		return iswdigit( static_cast<unsigned short>(ch) );
	}

	static int __cdecl IsSpace( __in wchar_t ch ) throw()
	{
		return iswspace( static_cast<unsigned short>(ch) );
	}

	static int __cdecl StringCompare( __in_z LPCWSTR pszA, __in_z LPCWSTR pszB ) throw()
	{
		return wcscmp( pszA, pszB );
	}

// ORIG: 	static int __cdecl StringCompareIgnore( __in_z LPCWSTR pszA, __in_z LPCWSTR pszB ) throw()
// ORIG: 	{
// ORIG: 		return _wcsicmp( pszA, pszB );
// ORIG: 	}

	static int __cdecl StringCollate( __in_z LPCWSTR pszA, __in_z LPCWSTR pszB ) throw()
	{
		return wcscoll( pszA, pszB );
	}

// ORIG: 	static int __cdecl StringCollateIgnore( __in_z LPCWSTR pszA, __in_z LPCWSTR pszB ) throw()
// ORIG: 	{
// ORIG: 		return _wcsicoll( pszA, pszB );
// ORIG: 	}

	static LPCWSTR __cdecl StringFindString( __in_z LPCWSTR pszBlock, __in_z LPCWSTR pszMatch ) throw()
	{
		return ::wcsstr( pszBlock, pszMatch );
	}

	static LPWSTR __cdecl StringFindString( __in_z LPWSTR pszBlock, __in_z LPCWSTR pszMatch ) throw()
	{
		return( const_cast< LPWSTR >( StringFindString( const_cast< LPCWSTR >( pszBlock ), pszMatch ) ) );
	}

	static LPCWSTR __cdecl StringFindChar( __in_z LPCWSTR pszBlock, __in wchar_t chMatch ) throw()
	{
		return ::wcschr( pszBlock, chMatch );
	}

	static LPCWSTR __cdecl StringFindCharRev( __in_z LPCWSTR psz, __in wchar_t ch ) throw()
	{
		return ::wcsrchr( psz, ch );
	}

	static LPCWSTR __cdecl StringScanSet( __in_z LPCWSTR pszBlock, __in_z LPCWSTR pszMatch ) throw()
	{
		return ::wcspbrk( pszBlock, pszMatch );
	}

	static int __cdecl StringSpanIncluding( __in_z LPCWSTR pszBlock, __in_z LPCWSTR pszSet ) throw()
	{
		return (int)wcsspn( pszBlock, pszSet );
	}

	static int __cdecl StringSpanExcluding( __in_z LPCWSTR pszBlock, __in_z LPCWSTR pszSet ) throw()
	{
		return (int)wcscspn( pszBlock, pszSet );
	}

// ORIG: 	_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::StringUppercase")
// ORIG: 	static LPWSTR __cdecl StringUppercase( __inout LPWSTR psz ) throw()
// ORIG: 	{
// ORIG: #pragma warning (push)
// ORIG: #pragma warning(disable : 4996)
// ORIG: 		return _wcsupr( psz );
// ORIG: #pragma warning (pop)
// ORIG: 	}

// ORIG: 	_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::StringLowercase")
// ORIG: 	static LPWSTR __cdecl StringLowercase( __inout LPWSTR psz ) throw()
// ORIG: 	{
// ORIG: #pragma warning (push)
// ORIG: #pragma warning(disable : 4996)
// ORIG: 		return _wcslwr( psz );
// ORIG: #pragma warning (pop)
// ORIG: 	}

// ORIG: 	static LPWSTR __cdecl StringUppercase( __inout_ecount(size) LPWSTR psz, __in size_t size ) throw()
// ORIG: 	{
// ORIG: #if _SECURE_ATL
// ORIG: 		errno_t err = _wcsupr_s( psz, size );
// ORIG: 		return (err == 0) ? psz : NULL;
// ORIG: #else
// ORIG: 		size;
// ORIG: 		return _wcsupr( psz );
// ORIG: #endif
// ORIG: 	}

// ORIG: 	static LPWSTR __cdecl StringLowercase( __inout_ecount(size) LPWSTR psz, __in size_t size ) throw()
// ORIG: 	{
// ORIG: #if _SECURE_ATL
// ORIG: 		errno_t err = _wcslwr_s( psz, size );
// ORIG: 		return (err == 0) ? psz : NULL;
// ORIG: #else
// ORIG: 		size;
// ORIG: 		return _wcslwr( psz );
// ORIG: #endif
// ORIG: 	}

// ORIG: 	static LPWSTR __cdecl StringReverse( __inout LPWSTR psz ) throw()
// ORIG: 	{
// ORIG: 		return _wcsrev( psz );
// ORIG: 	}

// ORIG: 	static int __cdecl GetFormattedLength( __in __format_string LPCWSTR pszFormat, va_list args) throw()
// ORIG: 	{
// ORIG: 		return _vscwprintf( pszFormat, args );
// ORIG: 	}

// ORIG: 	_ATL_INSECURE_DEPRECATE("You must pass an output size to ChTraitsCRT::Format")
// ORIG: 	static int __cdecl Format( __out LPWSTR pszBuffer, __in __format_string LPCWSTR pszFormat, va_list args) throw()
// ORIG: 	{
// ORIG: 		#pragma warning (push)
// ORIG: 		#pragma warning(disable : 4996)
// ORIG: 		return vswprintf( pszBuffer, pszFormat, args );
// ORIG: 		#pragma warning (pop)
// ORIG: 	}
// ORIG: 	static int __cdecl Format
// ORIG: 		( __out_ecount(nLength) LPWSTR pszBuffer, __in size_t nLength, __in __format_string LPCWSTR pszFormat, va_list args) throw()
// ORIG: 	{
// ORIG: 		return vswprintf_s( pszBuffer, nLength, pszFormat, args );
// ORIG: 	}

	static int __cdecl GetBaseTypeLength( __in_z LPCSTR pszSrc ) throw()
	{
		// Returns required buffer size in wchar_ts
		return ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, -1, NULL, 0 )-1;
	}

	static int __cdecl GetBaseTypeLength( __in_ecount(nLength) LPCSTR pszSrc, __in int nLength ) throw()
	{
		// Returns required buffer size in wchar_ts
		return ::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nLength, NULL, 0 );
	}

	static int __cdecl GetBaseTypeLength( __in_z LPCWSTR pszSrc ) throw()
	{
		// Returns required buffer size in wchar_ts
		return (int)wcslen( pszSrc );
	}

	static int __cdecl GetBaseTypeLength( __in_ecount(nLength) LPCWSTR pszSrc, __in int nLength ) throw()
	{
		(void)pszSrc;
		// Returns required buffer size in wchar_ts
		return nLength;
	}

	static void __cdecl ConvertToBaseType( __out_ecount(nDestLength) LPWSTR pszDest, __in int nDestLength,
		__in_z LPCSTR pszSrc, __in int nSrcLength = -1) throw()
	{
		// nLen is in wchar_ts
		::MultiByteToWideChar( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength );
	}

	static void __cdecl ConvertToBaseType( __out_ecount(nDestLength) LPWSTR pszDest, __in int nDestLength,
		__in_z LPCWSTR pszSrc, int nSrcLength = -1 ) throw()
	{		
		if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); }
		// nLen is in wchar_ts
		Checked::wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength);
	}

	static void __cdecl FloodCharacters( __in wchar_t ch, __in int nLength, __out_ecount_full(nLength) LPWSTR psz ) throw()
	{
		// nLength is in XCHARs
		for( int i = 0; i < nLength; i++ )
		{
			psz[i] = ch;
		}
	}

// ORIG: 	static BSTR __cdecl AllocSysString( __in_ecount(nDataLength) const wchar_t* pchData, __in int nDataLength ) throw()
// ORIG: 	{
// ORIG: 		return ::SysAllocStringLen( pchData, nDataLength );
// ORIG: 	}
// ORIG: 
// ORIG: 	static BOOL __cdecl ReAllocSysString( __in_ecount(nDataLength) const wchar_t* pchData, __inout BSTR* pbstr, __in int nDataLength ) throw()
// ORIG: 	{
// ORIG: 		return ::SysReAllocStringLen( pbstr, pchData, nDataLength );
// ORIG: 	}

	static int __cdecl SafeStringLen( __in_z_opt LPCSTR psz ) throw()
	{
		// returns length in bytes
		return (psz != NULL) ? (int)strlen( psz ) : 0;
	}

	static int __cdecl SafeStringLen( __in_opt LPCWSTR psz ) throw()
	{
		// returns length in wchar_ts
		return (psz != NULL) ? (int)wcslen( psz ) : 0;
	}

	static int __cdecl GetCharLen( __in_z const wchar_t* pch ) throw()
	{
		(void)pch;
		// returns char length
		return 1;
	}

#if !defined UNIX
	static int __cdecl GetCharLen( __in_z const char* pch ) throw()
	{
		// returns char length
		return (int)( _mbclen( reinterpret_cast< const unsigned char* >( pch ) ) );
	}
#endif /* !UNIX */

// ORIG: 	static DWORD __cdecl GetEnvironmentVariable( __in_z LPCWSTR pszVar, __out_ecount_opt(dwSize) LPWSTR pszBuffer, __in DWORD dwSize ) throw()
// ORIG: 	{
// ORIG: 		return _GetEnvironmentVariableW( pszVar, pszBuffer, dwSize );
// ORIG: 	}

// ORIG: 	static void __cdecl ConvertToOem( __reserved LPWSTR /*psz*/ )
// ORIG: 	{
// ORIG: 		ATLENSURE(FALSE); // Unsupported Feature 
// ORIG: 	}

// ORIG: 	static void __cdecl ConvertToAnsi( __reserved LPWSTR /*psz*/ )
// ORIG: 	{
// ORIG: 		ATLENSURE(FALSE); // Unsupported Feature 
// ORIG: 	}

// ORIG: 	static void __cdecl ConvertToOem( __reserved LPWSTR /*psz*/, size_t )
// ORIG: 	{
// ORIG: 		ATLENSURE(FALSE); // Unsupported Feature 
// ORIG: 	}

// ORIG: 	static void __cdecl ConvertToAnsi( __reserved LPWSTR /*psz*/, size_t ) 
// ORIG: 	{
// ORIG: 		ATLENSURE(FALSE); // Unsupported Feature 
// ORIG: 	}

#ifdef _UNICODE
public:
// ORIG: 	static DWORD __cdecl _AFX_FUNCNAME(FormatMessage)( __in DWORD dwFlags, LPCVOID pSource,
// ORIG: 		__in DWORD dwMessageID, __in DWORD dwLanguageID, __out_ecount(nSize) LPWSTR pszBuffer,
// ORIG: 		__in DWORD nSize, va_list* pArguments ) throw()
// ORIG: 	{
// ORIG: 		return ::FormatMessageW( dwFlags, pSource, dwMessageID, dwLanguageID,
// ORIG: 				pszBuffer, nSize, pArguments );
// ORIG: 	}

// ORIG: #if defined(_AFX)
// ORIG: 	static DWORD __cdecl FormatMessage( __in DWORD dwFlags, LPCVOID pSource,
// ORIG: 		__in DWORD dwMessageID, __in DWORD dwLanguageID, __out_ecount(nSize) LPWSTR pszBuffer,
// ORIG: 		__in DWORD nSize, va_list* pArguments ) throw()
// ORIG: 	{
// ORIG: 		return _AFX_FUNCNAME(FormatMessage)(dwFlags, pSource, dwMessageID, dwLanguageID, pszBuffer, nSize, pArguments);
// ORIG: 	}
// ORIG: #endif
// ORIG: 
// ORIG: #else
// ORIG: 	static DWORD __cdecl _AFX_FUNCNAME(FormatMessage)( DWORD /*dwFlags*/, LPCVOID /*pSource*/,
// ORIG: 		DWORD /*dwMessageID*/, DWORD /*dwLanguageID*/, __reserved LPWSTR /*pszBuffer*/,
// ORIG: 		DWORD /*nSize*/, va_list* /*pArguments*/ )
// ORIG: 	{
// ORIG: 		ATLENSURE(FALSE); // Unsupported Feature 
// ORIG: 		return 0;
// ORIG: 	}
// ORIG: 
// ORIG: #if defined(_AFX)
// ORIG: 	static DWORD __cdecl FormatMessage( DWORD dwFlags, LPCVOID pSource,
// ORIG: 		DWORD dwMessageID, DWORD dwLanguageID, __reserved LPWSTR pszBuffer,
// ORIG: 		DWORD nSize, va_list* pArguments )
// ORIG: 	{
// ORIG: 		return _AFX_FUNCNAME(FormatMessage)(dwFlags, pSource, dwMessageID, dwLanguageID, pszBuffer, nSize, pArguments);
// ORIG: 	}
// ORIG: #endif

#endif

};
#endif  // _ATL_MIN_CRT

}	// namespace ATL

#ifndef _ATL_MIN_CRT

// Forward declare
template< typename _CharType = char, class StringIterator = ATL::ChTraitsCRT< _CharType > >
class StrTraitMFC_DLL;

#endif	// _ATL_MIN_CRT

namespace ATL
{

// ORIG: namespace _CSTRING_IMPL_
// ORIG: {
// ORIG: template <typename _CharType, class StringTraits>
// ORIG: struct _MFCDLLTraitsCheck
// ORIG: {
// ORIG: 	const static bool c_bIsMFCDLLTraits = false;
// ORIG: };
// ORIG: 
// ORIG: #ifndef _ATL_MIN_CRT
// ORIG: 
// ORIG: template<typename _CharType> 
// ORIG: struct _MFCDLLTraitsCheck<_CharType, StrTraitMFC_DLL<_CharType, ATL::ChTraitsCRT< _CharType > > >
// ORIG: {
// ORIG: 	const static bool c_bIsMFCDLLTraits = true;
// ORIG: };
// ORIG: 
// ORIG: #endif	// _ATL_MIN_CRT
// ORIG: }

// The CStringT class has a few varargs member functions that will cause 4793
// warnings if compiled /clr. Because of the way template classes are parsed,
// we need to disable the warning for the entire class.
//#pragma warning( push )
//#pragma warning( disable : 4793 )


template< typename BaseType, class StringTraits >
class CStringT :
// ORIG: 	public CSimpleStringT< BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits >
	public CSimpleStringT< BaseType, false >
{
public:
// ORIG: 	typedef CSimpleStringT< BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits > CThisSimpleString;
	typedef CSimpleStringT< BaseType, false > CThisSimpleString;
	typedef StringTraits StrTraits;
	typedef typename CThisSimpleString::XCHAR XCHAR;
	typedef typename CThisSimpleString::PXSTR PXSTR;
	typedef typename CThisSimpleString::PCXSTR PCXSTR;
	typedef typename CThisSimpleString::YCHAR YCHAR;
	typedef typename CThisSimpleString::PYSTR PYSTR;
	typedef typename CThisSimpleString::PCYSTR PCYSTR;
	typedef CSimpleStringT< BaseType, false > base;
public:
	CStringT() throw() :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
	}
	explicit CStringT( IAtlStringMgr* pStringMgr ) throw() :
		CThisSimpleString( pStringMgr )
	{ 
	}

	CStringT( const VARIANT& varSrc );
	CStringT( const VARIANT& varSrc, IAtlStringMgr* pStringMgr );

	static void __cdecl Construct( CStringT* pString )
	{
		new( pString ) CStringT;
	}

	// Copy constructor
	CStringT( const CStringT& strSrc ) :
		CThisSimpleString( strSrc )
	{
	}

	// Construct from CSimpleStringT
// ORIG: 	operator CSimpleStringT<BaseType, !_CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits >&()
// ORIG: 	{
// ORIG: 		return *(CSimpleStringT<BaseType, !_CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits >*)this;
// ORIG: 	}
	operator CSimpleStringT<BaseType, true >&()
	{
		return *(CSimpleStringT<BaseType, true >*)this;
	}
	template <bool bMFCDLL>
	CStringT( __in const CSimpleStringT<BaseType, bMFCDLL>& strSrc ) :
		CThisSimpleString( strSrc )
	{
	}

	CStringT( __in const XCHAR* pszSrc ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		if( !CheckImplicitLoad( pszSrc ) )
		{
			// nDestLength is in XCHARs
			*this = pszSrc;
		}
	}

	CStringT( __in_z LPCSTR pszSrc, __in IAtlStringMgr* pStringMgr ) :
		CThisSimpleString( pStringMgr )
	{
		if( !CheckImplicitLoad( pszSrc ) )
		{
			// nDestLength is in XCHARs
			*this = pszSrc;
		}
	}

	CSTRING_EXPLICIT CStringT( __in const YCHAR* pszSrc ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		if( !CheckImplicitLoad( pszSrc ) )
		{
			*this = pszSrc;
		}
	}

	CStringT( __in_z LPCWSTR pszSrc, __in IAtlStringMgr* pStringMgr ) :
		CThisSimpleString( pStringMgr )
	{
		if( !CheckImplicitLoad( pszSrc ) )
		{
			*this = pszSrc;
		}
	}

	// This template will compile only for
	// class SystemString == System::String

#if defined(__cplusplus_cli)

	template <class SystemString>
	CStringT( SystemString^ pString ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		cli::pin_ptr<const System::Char> pChar = PtrToStringChars( pString );
		const wchar_t *psz = pChar;
		*this = psz;
	}

#elif defined(_MANAGED)

	template<class SystemString>
	CStringT( SystemString __gc* 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 );
	}
//ctors to prevent from oldSyntax template ctor (above) hijack certain types.
//MFC dll instantiate all CStringT methods inside the dll and declares dllimport for 
//all methods in user build (see afxstr.h), so need to include the methods in MFC dll builds.
#if defined(_AFXDLL) && defined(_MFC_DLL_BLD) || !defined(__cplusplus_cli) && defined(_MANAGED)

	/*CSTRING_EXPLICIT*/ CStringT( __in_z char* pszSrc ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		const char *psz = reinterpret_cast< const char* >( pszSrc );
		if (!CheckImplicitLoad( psz ))
		{
			*this = psz;
		}
	}

	CSTRING_EXPLICIT CStringT( __in unsigned char* pszSrc ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		const char *psz = reinterpret_cast< const char* >( pszSrc );
		if (!CheckImplicitLoad( psz ))
		{
			*this = psz;
		}
	}

	CSTRING_EXPLICIT CStringT( __in_z wchar_t* pszSrc ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		const wchar_t *psz = reinterpret_cast< const wchar_t* >( pszSrc );
		if (!CheckImplicitLoad( psz ))
		{
			*this = psz;
		}
	}
#endif

	CStringT( __in const unsigned char* pszSrc, __in IAtlStringMgr* pStringMgr ) :
		CThisSimpleString( pStringMgr )
	{
		*this = reinterpret_cast< const char* >( pszSrc );
	}

	CSTRING_EXPLICIT CStringT( __in char ch, __in int nLength = 1 ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		ATLASSERT( nLength >= 0 );
		if( nLength > 0 )
		{
			PXSTR pszBuffer = base::GetBuffer( nLength );
			StringTraits::FloodCharacters( XCHAR( ch ), nLength, pszBuffer );
			base::ReleaseBufferSetLength( nLength );
		}
	}

	CSTRING_EXPLICIT CStringT( __in wchar_t ch, __in int nLength = 1 ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		ATLASSERT( nLength >= 0 );
		if( nLength > 0 )
		{			
			//Convert ch to the BaseType
			wchar_t pszCh[2] = { ch , 0 };
			int nBaseTypeCharLen = 1;

			if(ch != L'\0')
			{
				nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh);
			}

			CTempBuffer<XCHAR,10> buffBaseTypeChar;			
			buffBaseTypeChar.Allocate(nBaseTypeCharLen+1);
			StringTraits::ConvertToBaseType( buffBaseTypeChar, nBaseTypeCharLen+1, pszCh, 1 );
			//Allocate enough characters in String and flood (replicate) with the (converted character)*nLength
			PXSTR pszBuffer = base::GetBuffer( nLength*nBaseTypeCharLen );
			if (nBaseTypeCharLen == 1)
			{   //Optimization for a common case - wide char translates to 1 ansi/wide char.
				StringTraits::FloodCharacters( buffBaseTypeChar[0], nLength, pszBuffer );				
			} else
			{
				XCHAR* p=pszBuffer;
				for (int i=0 ; i < nLength ;++i)
				{
					for (int j=0 ; j < nBaseTypeCharLen ;++j)
					{	
						*p=buffBaseTypeChar[j];
						++p;
					}
				}
			}
			base::ReleaseBufferSetLength( nLength*nBaseTypeCharLen );			
		}
	}

	CStringT( __in_ecount(nLength) const XCHAR* pch, __in int nLength ) :
		CThisSimpleString( pch, nLength, StringTraits::GetDefaultManager() )
	{
	}

	CStringT( __in_ecount(nLength) const XCHAR* pch, __in int nLength, __in IAtlStringMgr* pStringMgr ) :
		CThisSimpleString( pch, nLength, pStringMgr )
	{
	}

	CStringT( __in_ecount(nLength) const YCHAR* pch, __in int nLength ) :
		CThisSimpleString( StringTraits::GetDefaultManager() )
	{
		ATLASSERT( nLength >= 0 );
		if( nLength > 0 )
		{
			ATLASSERT( AtlIsValidAddress( pch, nLength*sizeof( YCHAR ), FALSE ) );
			if(pch == NULL)
				AtlThrow(E_INVALIDARG);

			int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength );
			PXSTR pszBuffer = base::GetBuffer( nDestLength );
			StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength );
			base::ReleaseBufferSetLength( nDestLength );
		}
	}

	CStringT( __in_ecount(nLength) const YCHAR* pch, __in int nLength, __in IAtlStringMgr* pStringMgr ) :
		CThisSimpleString( pStringMgr )
	{
		ATLASSERT( nLength >= 0 );
		if( nLength > 0 )
		{
			ATLASSERT( AtlIsValidAddress( pch, nLength*sizeof( YCHAR ), FALSE ) );
			if(pch == NULL)
				AtlThrow(E_INVALIDARG);

			int nDestLength = StringTraits::GetBaseTypeLength( pch, nLength );
			PXSTR pszBuffer = base::GetBuffer( nDestLength );
			StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pch, nLength );
			base::ReleaseBufferSetLength( nDestLength );
		}
	}

	// Destructor
	~CStringT() throw()
	{
	}

	// Assignment operators
	CStringT& operator=( __in const CStringT& strSrc )
	{
		CThisSimpleString::operator=( strSrc );

		return( *this );
	}
	
	template <bool bMFCDLL>
	CStringT& operator=( __in const CSimpleStringT<BaseType, bMFCDLL>& strSrc )
	{
		CThisSimpleString::operator=( strSrc );

		return( *this );
	}

	CStringT& operator=( __in PCXSTR pszSrc )
	{
		CThisSimpleString::operator=( pszSrc );

		return( *this );
	}

	CStringT& operator=( __in PCYSTR pszSrc )
	{
		// nDestLength is in XCHARs
		int nDestLength = (pszSrc != NULL) ? StringTraits::GetBaseTypeLength( pszSrc ) : 0;
		if( nDestLength > 0 )
		{
			PXSTR pszBuffer = base::GetBuffer( nDestLength );
			StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc);
			base::ReleaseBufferSetLength( nDestLength );
		}
		else
		{
			base::Empty();
		}

		return( *this );
	}

	CStringT& operator=( __in const unsigned char* pszSrc )
	{
		return( operator=( reinterpret_cast< const char* >( pszSrc ) ) );
	}

	CStringT& operator=( __in char ch )
	{
		char ach[2] = { ch, 0 };

		return( operator=( ach ) );
	}

	CStringT& operator=( __in wchar_t ch )
	{
		wchar_t ach[2] = { ch, 0 };

		return( operator=( ach ) );
	}

	CStringT& operator=( __in const VARIANT& var );

	CStringT& operator+=( __in const CThisSimpleString& str )
	{
		CThisSimpleString::operator+=( str );

		return( *this );
	}
	template <bool bMFCDLL>
	CStringT& operator+=( __in const CSimpleStringT<BaseType, bMFCDLL>& str )
	{
		CThisSimpleString::operator+=( str );

		return( *this );
	}
	
	CStringT& operator+=( __in PCXSTR pszSrc )
	{
		CThisSimpleString::operator+=( pszSrc );

		return( *this );
	}
	template< int t_nSize >
	CStringT& operator+=( __in const CStaticString< XCHAR, t_nSize >& strSrc )
	{
		CThisSimpleString::operator+=( strSrc );

		return( *this );
	}
	CStringT& operator+=( __in PCYSTR pszSrc )
	{
		CStringT str( pszSrc, GetManager() );

		return( operator+=( str ) );
	}

	CStringT& operator+=( __in char ch )
	{
		CThisSimpleString::operator+=( ch );

		return( *this );
	}

	CStringT& operator+=( __in unsigned char ch )
	{
		CThisSimpleString::operator+=( ch );

		return( *this );
	}

	CStringT& operator+=( __in wchar_t ch )
	{
		CThisSimpleString::operator+=( ch );

		return( *this );
	}

	CStringT& operator+=( __in const VARIANT& var );

	// Override from base class
	IAtlStringMgr* GetManager() const throw()
	{
		IAtlStringMgr* pStringMgr = CThisSimpleString::GetManager();
		if(pStringMgr) { return pStringMgr; }

		pStringMgr = StringTraits::GetDefaultManager();
		return pStringMgr->Clone();
	}

	// Comparison

	int Compare( __in PCXSTR psz ) const
	{
		ATLENSURE( AtlIsValidString( psz ) );
		return( StringTraits::StringCompare( base::GetString(), psz ) );
	}

 	int CompareNoCase( __in PCXSTR psz ) const throw()
 	{
 		ATLASSERT( AtlIsValidString( psz ) );
 		return( StringTraits::StringCompareIgnore( base::GetString(), psz ) );
 	}

	int Collate( __in PCXSTR psz ) const throw()
	{
		ATLASSERT( AtlIsValidString( psz ) );
		return( StringTraits::StringCollate( base::GetString(), psz ) );
	}

// ORIG: 	int CollateNoCase( __in PCXSTR psz ) const throw()
// ORIG: 	{
// ORIG: 		ATLASSERT( AtlIsValidString( psz ) );
// ORIG: 		return( StringTraits::StringCollateIgnore( base::GetString(), psz ) );
// ORIG: 	}

	// Advanced manipulation

	// Delete 'nCount' characters, starting at index 'iIndex'
	int Delete( __in int iIndex, __in int nCount = 1 )
	{
		if( iIndex < 0 )
			iIndex = 0;
		
		if( nCount < 0 )
			nCount = 0;

		int nLength = base::GetLength();
		if( (::ATL::AtlAddThrow(nCount, iIndex)) > nLength )
		{
			nCount = nLength-iIndex;
		}
		if( nCount > 0 )
		{
			int nNewLength = nLength-nCount;
			int nXCHARsToCopy = nLength-(iIndex+nCount)+1;
			PXSTR pszBuffer = base::GetBuffer();
			Checked::memmove_s( pszBuffer+iIndex, nXCHARsToCopy*sizeof( XCHAR ), 
				pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof( XCHAR ) );
			base::ReleaseBufferSetLength( nNewLength );
		}

		return( base::GetLength() );
	}

	// Insert character 'ch' before index 'iIndex'
	int Insert( __in int iIndex, __in XCHAR ch )
	{
		if( iIndex < 0 )
			iIndex = 0;
			
		if( iIndex > base::GetLength() )
		{
			iIndex = base::GetLength();
		}
		int nNewLength = base::GetLength()+1;

		PXSTR pszBuffer = base::GetBuffer( nNewLength );

		// move existing bytes down 
        Checked::memmove_s( pszBuffer+iIndex+1, (nNewLength-iIndex)*sizeof( XCHAR ), 
			pszBuffer+iIndex, (nNewLength-iIndex)*sizeof( XCHAR ) );
		pszBuffer[iIndex] = ch;

		base::ReleaseBufferSetLength( nNewLength );

		return( nNewLength );
	}

	// Insert string 'psz' before index 'iIndex'
	int Insert( __in int iIndex, __in PCXSTR psz )
	{
		if( iIndex < 0 )
			iIndex = 0;

		if( iIndex > base::GetLength() )
		{
			iIndex = base::GetLength();
		}

		// nInsertLength and nNewLength are in XCHARs
		int nInsertLength = StringTraits::SafeStringLen( psz );
		int nNewLength = base::GetLength();
		if( nInsertLength > 0 )
		{
			nNewLength += nInsertLength;

			PXSTR pszBuffer = base::GetBuffer( nNewLength );
			// move existing bytes down 
            Checked::memmove_s( pszBuffer+iIndex+nInsertLength, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ), 
				pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof( XCHAR ) );
			Checked::memcpy_s( pszBuffer+iIndex, nInsertLength*sizeof( XCHAR ), 
				psz, nInsertLength*sizeof( XCHAR ) );
			base::ReleaseBufferSetLength( nNewLength );
		}

		return( nNewLength );
	}

	// Replace all occurrences of character 'chOld' with character 'chNew'
	int Replace( __in XCHAR chOld, __in 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 >( base::GetString() );  // We don't actually write to pszBuffer until we've called GetBuffer().

			int nLength = base::GetLength();
			int iChar = 0;
			while( iChar < nLength )
			{
				// replace instances of the specified character only
				if( pszBuffer[iChar] == chOld )
				{
					if( !bCopied )
					{
						bCopied = true;
						pszBuffer = base::GetBuffer( nLength );
					}
					pszBuffer[iChar] = chNew;
					nCount++;
				}
				iChar = int( StringTraits::CharNext( pszBuffer+iChar )-pszBuffer );
			}
			if( bCopied )
			{
				base::ReleaseBufferSetLength( nLength );
			}
		}

		return( nCount );
	}

	// Replace all occurrences of string 'pszOld' with string 'pszNew'
	int Replace( __in PCXSTR pszOld, __in 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 = base::GetString();
			PCXSTR pszEnd = pszStart+base::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 = base::GetLength();
			int nNewLength = nOldLength+(nReplacementLen-nSourceLen)*nCount;

			PXSTR pszBuffer = base::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);
                    Checked::memmove_s( pszTarget+nReplacementLen, nBalance*sizeof( XCHAR ), 
						pszTarget+nSourceLen, nBalance*sizeof( XCHAR ) );
					Checked::memcpy_s( pszTarget, nReplacementLen*sizeof( XCHAR ), 
						pszNew, nReplacementLen*sizeof( XCHAR ) );
					pszStart = pszTarget+nReplacementLen;
					pszTarget[nReplacementLen+nBalance] = 0;
					nOldLength += (nReplacementLen-nSourceLen);
				}
				pszStart += StringTraits::SafeStringLen( pszStart )+1;
			}
			ATLASSERT( pszBuffer[nNewLength] == 0 );
			base::ReleaseBufferSetLength( nNewLength );
		}

		return( nCount );
	}

	// Remove all occurrences of character 'chRemove'
	int Remove( __in XCHAR chRemove )
	{
		int nLength = base::GetLength();
		PXSTR pszBuffer = base::GetBuffer( nLength );

		PXSTR pszSource = pszBuffer;
		PXSTR pszDest = pszBuffer;
		PXSTR pszEnd = pszBuffer+nLength;

		while( pszSource < pszEnd )
		{
			PXSTR pszNewSource = StringTraits::CharNext( pszSource );
			if( *pszSource != chRemove )
			{
				// Copy the source to the destination.  Remember to copy all bytes of an MBCS character
	   			// Copy the source to the destination.  Remember to copy all bytes of an MBCS character
				size_t NewSourceGap = (pszNewSource-pszSource);
				PXSTR pszNewDest = pszDest + NewSourceGap;
				size_t i = 0;
				for (i = 0;  pszDest != pszNewDest && i < NewSourceGap; i++)
				{
					*pszDest = *pszSource;
					pszSource++;
					pszDest++;
				}
			}
			pszSource = pszNewSource;
		}
		*pszDest = 0;
		int nCount = int( pszSource-pszDest );
		base::ReleaseBufferSetLength( nLength-nCount );

		return( nCount );
	}

	CStringT Tokenize( __in PCXSTR pszTokens, __inout int& iStart ) const
	{
		ATLASSERT( iStart >= 0 );
			
		if(iStart < 0)
			AtlThrow(E_INVALIDARG);			
			
		if( (pszTokens == NULL) || (*pszTokens == (XCHAR)0) )
		{
			if (iStart < base::GetLength())
			{
				return( CStringT( base::GetString()+iStart, GetManager() ) );
			}
		}
		else
		{
			PCXSTR pszPlace = base::GetString()+iStart;
			PCXSTR pszEnd = base::GetString()+base::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( __in XCHAR ch, __in int iStart = 0 ) const throw()
	{
		// iStart is in XCHARs
		ATLASSERT( iStart >= 0 );

		// nLength is in XCHARs
		int nLength = base::GetLength();
		if( iStart < 0 || iStart >= nLength)
		{
			return( -1 );
		}

		// find first single character
		PCXSTR psz = StringTraits::StringFindChar( base::GetString()+iStart, ch );

		// return -1 if not found and index otherwise
		return( (psz == NULL) ? -1 : int( psz-base::GetString() ) );
	}

	// look for a specific sub-string

	// Find the first occurrence of string 'pszSub', starting at index 'iStart'
	int Find( __in PCXSTR pszSub, __in int iStart = 0 ) const throw()
	{
		// iStart is in XCHARs
		ATLASSERT( iStart >= 0 );
		ATLASSERT( AtlIsValidString( pszSub ) );

		if(pszSub == NULL)
		{
			return( -1 );
		}
		// nLength is in XCHARs
		int nLength = base::GetLength();
		if( iStart < 0 || iStart > nLength )
		{
			return( -1 );
		}

		// find first matching substring
		PCXSTR psz = StringTraits::StringFindString( base::GetString()+iStart, pszSub );

		// return -1 for not found, distance from beginning otherwise
		return( (psz == NULL) ? -1 : int( psz-base::GetString() ) );
	}

	// Find the first occurrence of any of the characters in string 'pszCharSet'
	int FindOneOf( __in PCXSTR pszCharSet ) const throw()
	{
		ATLASSERT( AtlIsValidString( pszCharSet ) );
		PCXSTR psz = StringTraits::StringScanSet( base::GetString(), pszCharSet );
		return( (psz == NULL) ? -1 : int( psz-base::GetString() ) );
	}

	// Find the last occurrence of character 'ch'
	int ReverseFind( __in XCHAR ch ) const throw()
	{
		// find last single character
		PCXSTR psz = StringTraits::StringFindCharRev( base::GetString(), ch );

		// return -1 if not found, distance from beginning otherwise
		return( (psz == NULL) ? -1 : int( psz-base::GetString() ) );
	}

	// manipulation

	// Convert the string to uppercase
// ORIG: 	CStringT& MakeUpper()
// ORIG: 	{
// ORIG: 		int nLength = GetLength();
// ORIG: 		PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: 		StringTraits::StringUppercase( pszBuffer, nLength+1 );
// ORIG: 		ReleaseBufferSetLength( nLength );
// ORIG: 
// ORIG: 		return( *this );
// ORIG: 	}

	// Convert the string to lowercase
// ORIG: 	CStringT& MakeLower()
// ORIG: 	{
// ORIG: 		int nLength = GetLength();
// ORIG: 		PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: 		StringTraits::StringLowercase( pszBuffer, nLength+1 );
// ORIG: 		ReleaseBufferSetLength( nLength );
// ORIG: 
// ORIG: 		return( *this );
// ORIG: 	}

	// Reverse the string
// ORIG: 	CStringT& MakeReverse()
// ORIG: 	{
// ORIG: 		int nLength = GetLength();
// ORIG: 		PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: 		StringTraits::StringReverse( pszBuffer );
// ORIG: 		ReleaseBufferSetLength( nLength );
// ORIG: 
// ORIG: 		return( *this );
// ORIG: 	}

	// trimming

	// Remove all trailing whitespace
	CStringT& TrimRight()
	{
		// find beginning of trailing spaces by starting
		// at beginning (DBCS aware)

		PCXSTR psz = base::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-base::GetString() );

			base::Truncate( iLast );
		}

		return( *this );
	}

	// Remove all leading whitespace
	CStringT& TrimLeft()
	{
		// find first non-space character

		PCXSTR psz = base::GetString();

		while( StringTraits::IsSpace( *psz ) )
		{
			psz = StringTraits::CharNext( psz );
		}

		if( psz != base::GetString() )
		{
			// fix up data and length
			int iFirst = int( psz-base::GetString() );
			PXSTR pszBuffer = base::GetBuffer( base::GetLength() );
			psz = pszBuffer+iFirst;
			int nDataLength = base::GetLength()-iFirst;
            Checked::memmove_s( pszBuffer, (nDataLength+1)*sizeof( XCHAR ), 
				psz, (nDataLength+1)*sizeof( XCHAR ) );
			base::ReleaseBufferSetLength( 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( __in XCHAR chTarget )
	{
		return( TrimRight( chTarget ).TrimLeft( chTarget ) );
	}

	// Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets'
	CStringT& Trim( __in PCXSTR pszTargets )
	{
		return( TrimRight( pszTargets ).TrimLeft( pszTargets ) );
	}

	// trimming anything (either side)

	// Remove all trailing occurrences of character 'chTarget'
	CStringT& TrimRight( __in XCHAR chTarget )
	{
		// find beginning of trailing matches
		// by starting at beginning (DBCS aware)

		PCXSTR psz = base::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-base::GetString() );
			base::Truncate( iLast );
		}

		return( *this );
	}

	// Remove all trailing occurrences of any of the characters in string 'pszTargets'
	CStringT& TrimRight( __in 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 = base::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-base::GetString() );
			base::Truncate( iLast );
		}

		return( *this );
	}

	// Remove all leading occurrences of character 'chTarget'
	CStringT& TrimLeft( __in XCHAR chTarget )
	{
		// find first non-matching character
		PCXSTR psz = base::GetString();

		while( chTarget == *psz )
		{
			psz = StringTraits::CharNext( psz );
		}

		if( psz != base::GetString() )
		{
			// fix up data and length
			int iFirst = int( psz-base::GetString() );
			PXSTR pszBuffer = base::GetBuffer( base::GetLength() );
			psz = pszBuffer+iFirst;
			int nDataLength = base::GetLength()-iFirst;
            Checked::memmove_s( pszBuffer, (nDataLength+1)*sizeof( XCHAR ), 
				psz, (nDataLength+1)*sizeof( XCHAR ) );
			base::ReleaseBufferSetLength( nDataLength );
		}

		return( *this );
	}

	// Remove all leading occurrences of any of the characters in string 'pszTargets'
	CStringT& TrimLeft( __in PCXSTR pszTargets )
	{
		// if we're not trimming anything, we're not doing any work
		if( (pszTargets == NULL) || (*pszTargets == 0) )
		{
			return( *this );
		}

		PCXSTR psz = base::GetString();
		while( (*psz != 0) && (StringTraits::StringFindChar( pszTargets, *psz ) != NULL) )
		{
			psz = StringTraits::CharNext( psz );
		}

		if( psz != base::GetString() )
		{
			// fix up data and length
			int iFirst = int( psz-base::GetString() );
			PXSTR pszBuffer = base::GetBuffer( base::GetLength() );
			psz = pszBuffer+iFirst;
			int nDataLength = base::GetLength()-iFirst;
            Checked::memmove_s( pszBuffer, (nDataLength+1)*sizeof( XCHAR ), 
				psz, (nDataLength+1)*sizeof( XCHAR ) );
			base::ReleaseBufferSetLength( nDataLength );
		}

		return( *this );
	}

	// Convert the string to the OEM character set
// ORIG: 	void AnsiToOem()
// ORIG: 	{
// ORIG: 		int nLength = GetLength();
// ORIG: 		PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: 		StringTraits::ConvertToOem( pszBuffer, nLength+1 );
// ORIG: 		ReleaseBufferSetLength( nLength );
// ORIG: 	}

	// Convert the string to the ANSI character set
// ORIG: 	void OemToAnsi()
// ORIG: 	{
// ORIG: 		int nLength = GetLength();
// ORIG: 		PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: 		StringTraits::ConvertToAnsi( pszBuffer, nLength+1 );
// ORIG: 		ReleaseBufferSetLength( nLength );
// ORIG: 	}

	// Very simple sub-string extraction

	// Return the substring starting at index 'iFirst'
	CStringT Mid( __in int iFirst ) const
	{
		return( Mid( iFirst, base::GetLength()-iFirst ) );
	}

	// Return the substring starting at index 'iFirst', with length 'nCount'
	CStringT Mid( __in int iFirst, __in int nCount ) const
	{
		// nCount is in XCHARs

		// out-of-bounds requests return sensible things
		if (iFirst < 0)
			iFirst = 0;
		if (nCount < 0)
			nCount = 0;

		if( (::ATL::AtlAddThrow(iFirst,nCount)) > base::GetLength() )
		{
			nCount = base::GetLength()-iFirst;
		}
		if( iFirst > base::GetLength() )
		{
			nCount = 0;
		}

		ATLASSERT( (nCount == 0) || ((iFirst+nCount) <= base::GetLength()) );

		// optimize case of returning entire string
		if( (iFirst == 0) && ((iFirst+nCount) == base::GetLength()) )
		{
			return( *this );
		}

		return( CStringT( base::GetString()+iFirst, nCount, GetManager() ) );
	}

	// Return the substring consisting of the rightmost 'nCount' characters
	CStringT Right( __in int nCount ) const
	{
		// nCount is in XCHARs
		if (nCount < 0)
			nCount = 0;
                //cross: put volatile to supress "assuming signed overflow does not occur when
                //assuming that (X - c) > X is always false" warning when using right(GetLength()- const)
                volatile int nLength = base::GetLength();
		if( nCount >= nLength )
		{
			return( *this );
		}

		return( CStringT( base::GetString()+nLength-nCount, nCount, GetManager() ) );
	}

	// Return the substring consisting of the leftmost 'nCount' characters
	CStringT Left( __in int nCount ) const
	{
		// nCount is in XCHARs
		if (nCount < 0)
			nCount = 0;

		int nLength = base::GetLength();
		if( nCount >= nLength )
		{
			return( *this );
		}

		return( CStringT( base::GetString(), nCount, GetManager() ) );
	}

	// Return the substring consisting of the leftmost characters in the set 'pszCharSet'
	CStringT SpanIncluding( __in PCXSTR pszCharSet ) const
	{
		ATLASSERT( AtlIsValidString( pszCharSet ) );
		if(pszCharSet == NULL)
			AtlThrow(E_INVALIDARG);

		return( Left( StringTraits::StringSpanIncluding( base::GetString(), pszCharSet ) ) );
	}

	// Return the substring consisting of the leftmost characters not in the set 'pszCharSet'
	CStringT SpanExcluding( __in PCXSTR pszCharSet ) const
	{
		ATLASSERT( AtlIsValidString( pszCharSet ) );
		if(pszCharSet == NULL)
			AtlThrow(E_INVALIDARG);

		return( Left( StringTraits::StringSpanExcluding( base::GetString(), pszCharSet ) ) );
 	}

	// Format data using format string 'pszFormat'
// ORIG: 	void __cdecl Format( __in __format_string PCXSTR pszFormat, ... );

	// Format data using format string loaded from resource 'nFormatID'
// ORIG: 	void __cdecl Format( __format_string UINT nFormatID, ... );

	// Append formatted data using format string loaded from resource 'nFormatID'
// ORIG: 	void __cdecl AppendFormat( __in UINT nFormatID, ... );

	// Append formatted data using format string 'pszFormat'
// ORIG: 	void __cdecl AppendFormat( __in __format_string PCXSTR pszFormat, ... );
// ORIG: 	void AppendFormatV( __in __format_string PCXSTR pszFormat, va_list args )
// ORIG: 	{
// ORIG: 		ATLASSERT( AtlIsValidString( pszFormat ) );
// ORIG: 
// ORIG: 		int nCurrentLength = GetLength();
// ORIG: 		int nAppendLength = StringTraits::GetFormattedLength( pszFormat, args );
// ORIG: 		PXSTR pszBuffer = GetBuffer( nCurrentLength+nAppendLength );
// ORIG: #if _SECURE_ATL
// ORIG:         StringTraits::Format( pszBuffer+nCurrentLength, 
// ORIG: 			nAppendLength+1, pszFormat, args );
// ORIG: #else
// ORIG: 		StringTraits::Format( pszBuffer+nCurrentLength, pszFormat, args );
// ORIG: #endif
// ORIG: 		ReleaseBufferSetLength( nCurrentLength+nAppendLength );
// ORIG: 	}

// ORIG: 	void FormatV( __in __format_string PCXSTR pszFormat, va_list args )
// ORIG: 	{
// ORIG: 		ATLASSERT( AtlIsValidString( pszFormat ) );
// ORIG: 		if(pszFormat == NULL)
// ORIG: 			AtlThrow(E_INVALIDARG);
// ORIG: 
// ORIG: 		int nLength = StringTraits::GetFormattedLength( pszFormat, args );
// ORIG: 		PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: #if _SECURE_ATL
// ORIG:         StringTraits::Format( pszBuffer, nLength+1, pszFormat, args );
// ORIG: #else
// ORIG: 		StringTraits::Format( pszBuffer, pszFormat, args );
// ORIG: #endif
// ORIG: 		ReleaseBufferSetLength( nLength );
// ORIG: 	}

// ORIG: 	// Format a message using format string 'pszFormat'
// ORIG: 	void __cdecl _AFX_FUNCNAME(FormatMessage)( __in __format_string PCXSTR pszFormat, ... );

// ORIG: 	// Format a message using format string loaded from resource 'nFormatID'
// ORIG: 	void __cdecl _AFX_FUNCNAME(FormatMessage)( __in UINT nFormatID, ... );

// ORIG: #if defined(_AFX)
// ORIG: 	void __cdecl FormatMessage( __in __format_string PCXSTR pszFormat, ... );
// ORIG: 
// ORIG: 	void __cdecl FormatMessage( __in UINT nFormatID, ... );
// ORIG: #endif

	// Format a message using format string 'pszFormat' and va_list
// ORIG: 	void FormatMessageV( __in __format_string PCXSTR pszFormat, va_list* pArgList )
// ORIG: 	{
// ORIG: 		// format message into temporary buffer pszTemp
// ORIG: 		CHeapPtr< XCHAR, CLocalAllocator > pszTemp;
// ORIG: 		DWORD dwResult = StringTraits::_AFX_FUNCNAME(FormatMessage)( FORMAT_MESSAGE_FROM_STRING|
// ORIG: 			FORMAT_MESSAGE_ALLOCATE_BUFFER, pszFormat, 0, 0, reinterpret_cast< PXSTR >( &pszTemp ),
// ORIG: 			0, pArgList );
// ORIG: 		if( dwResult == 0 )
// ORIG: 		{
// ORIG: 			ThrowMemoryException();
// ORIG: 		}
// ORIG: 
// ORIG: 		*this = pszTemp;
// ORIG: 	}

	// OLE BSTR support

	// Allocate a BSTR containing a copy of the string
// ORIG: 	BSTR AllocSysString() const
// ORIG: 	{
// ORIG: 		BSTR bstrResult = StringTraits::AllocSysString( GetString(), GetLength() );
// ORIG: 
// ORIG: #pragma warning(push)
// ORIG: #pragma warning(disable:4068)
// ORIG: #pragma prefast(push)
// ORIG: #pragma prefast(disable:325, "We are deliberately checking if this has already been allocated")
// ORIG: 		if( bstrResult == NULL )
// ORIG: 		{
// ORIG: 			ThrowMemoryException();
// ORIG: 		}
// ORIG: #pragma prefast(pop)
// ORIG: #pragma warning(pop)
// ORIG: 
// ORIG: 		return( bstrResult );
// ORIG: 	}
// ORIG: 
// ORIG: 	BSTR SetSysString( __out BSTR* pbstr ) const
// ORIG: 	{
// ORIG: 		ATLASSERT( AtlIsValidAddress( pbstr, sizeof( BSTR ) ) );
// ORIG: 
// ORIG: 		if( !StringTraits::ReAllocSysString( GetString(), pbstr,
// ORIG: 			GetLength() ) )
// ORIG: 		{
// ORIG: 			ThrowMemoryException();
// ORIG: 		}
// ORIG: 
// ORIG: #pragma warning(push)
// ORIG: #pragma warning(disable:4068)
// ORIG: #pragma prefast(push)
// ORIG: #pragma prefast(disable:325, "We are deliberately checking if this has already been allocated")
// ORIG: 		ATLASSERT( *pbstr != NULL );
// ORIG: #pragma prefast(pop)
// ORIG: #pragma warning(pop)
// ORIG: 
// ORIG:         return( *pbstr );
// ORIG: 	}

	// Set the string to the value of environment variable 'pszVar'
// ORIG: 	__checkReturn BOOL GetEnvironmentVariable( __in PCXSTR pszVar )
// ORIG: 	{
// ORIG: 		ULONG nLength = StringTraits::GetEnvironmentVariable( pszVar, NULL, 0 );
// ORIG: 		BOOL bRetVal = FALSE;
// ORIG: 
// ORIG: 		if( nLength == 0 )
// ORIG: 		{
// ORIG: 			Empty();
// ORIG: 		}
// ORIG: 		else
// ORIG: 		{
// ORIG: 			PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: 			StringTraits::GetEnvironmentVariable( pszVar, pszBuffer, nLength );
// ORIG: 			ReleaseBuffer();
// ORIG: 			bRetVal = TRUE;
// ORIG: 		}
// ORIG: 
// ORIG: 		return( bRetVal );
// ORIG: 	}

	// Load the string from resource 'nID'
// ORIG: 	__checkReturn BOOL LoadString( __in UINT nID )
// ORIG: 	{
// ORIG: 		HINSTANCE hInst = StringTraits::FindStringResourceInstance( nID );
// ORIG: 		if( hInst == NULL )
// ORIG: 		{
// ORIG: 			return( FALSE );
// ORIG: 		}
// ORIG: 
// ORIG: 		return( LoadString( hInst, nID ) );		
// ORIG: 	}

	// Load the string from resource 'nID' in module 'hInstance'
// ORIG: 	__checkReturn BOOL LoadString( __in HINSTANCE hInstance, __in UINT nID )
// ORIG: 	{
// ORIG: 		const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage( hInstance, nID );
// ORIG: 		if( pImage == NULL )
// ORIG: 		{
// ORIG: 			return( FALSE );
// ORIG: 		}
// ORIG: 
// ORIG: 		int nLength = StringTraits::GetBaseTypeLength( pImage->achString, pImage->nLength );
// ORIG: 		PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: 		StringTraits::ConvertToBaseType( pszBuffer, nLength, pImage->achString, pImage->nLength );
// ORIG: 		ReleaseBufferSetLength( nLength );
// ORIG: 
// ORIG: 		return( TRUE );
// ORIG: 	}

	// Load the string from resource 'nID' in module 'hInstance', using language 'wLanguageID'
// ORIG: 	__checkReturn BOOL LoadString( __in HINSTANCE hInstance, __in UINT nID, __in WORD wLanguageID )
// ORIG: 	{
// ORIG: 		const ATLSTRINGRESOURCEIMAGE* pImage = AtlGetStringResourceImage( hInstance, nID, wLanguageID );
// ORIG: 		if( pImage == NULL )
// ORIG: 		{
// ORIG: 			return( FALSE );
// ORIG: 		}
// ORIG: 
// ORIG: 		int nLength = StringTraits::GetBaseTypeLength( pImage->achString, pImage->nLength );
// ORIG: 		PXSTR pszBuffer = GetBuffer( nLength );
// ORIG: 		StringTraits::ConvertToBaseType( pszBuffer, nLength, pImage->achString, pImage->nLength );
// ORIG: 		ReleaseBufferSetLength( nLength );
// ORIG: 
// ORIG: 		return( TRUE );
// ORIG: 	}

	friend CStringT operator+( __in const CStringT& str1, __in const CStringT& str2 )
	{
		CStringT strResult( str1.GetManager() );

		CStringT::Concatenate( strResult, str1, str1.GetLength(), str2, str2.GetLength() );

		return( strResult );
	}

	friend CStringT operator+( __in const CStringT& str1, __in PCXSTR psz2 )
	{
		CStringT strResult( str1.GetManager() );

		CStringT::Concatenate( strResult, str1, str1.GetLength(), psz2, CStringT::StringLength( psz2 ) );

		return( strResult );
	}

	friend CStringT operator+( __in PCXSTR psz1, __in const CStringT& str2 )
	{
		CStringT strResult( str2.GetManager() );

		CStringT::Concatenate( strResult, psz1, CStringT::StringLength( psz1 ), str2, str2.GetLength() );

		return( strResult );
	}

	friend CStringT operator+( __in const CStringT& str1, __in wchar_t ch2 )
	{
		CStringT strResult( str1.GetManager() );
		XCHAR chTemp = XCHAR( ch2 );

		Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 );

		return( strResult );
	}

	friend CStringT operator+( __in const CStringT& str1, __in char ch2 )
	{
		CStringT strResult( str1.GetManager() );
		XCHAR chTemp = XCHAR( ch2 );

		Concatenate( strResult, str1, str1.GetLength(), &chTemp, 1 );

		return( strResult );
	}

	friend CStringT operator+( __in wchar_t ch1, __in const CStringT& str2 )
	{
		CStringT strResult( str2.GetManager() );
		XCHAR chTemp = XCHAR( ch1 );

		Concatenate( strResult, &chTemp, 1, str2, str2.GetLength() );

		return( strResult );
	}

	friend CStringT operator+( __in char ch1, __in const CStringT& str2 )
	{
		CStringT strResult( str2.GetManager() );
		XCHAR chTemp = XCHAR( ch1 );

		Concatenate( strResult, &chTemp, 1, str2, str2.GetLength() );

		return( strResult );
	}

	friend bool operator==( __in const CStringT& str1, __in const CStringT& str2 ) throw()
	{
		return( str1.Compare( str2 ) == 0 );
	}

	friend bool operator==(
		__in const CStringT& str1, __in PCXSTR psz2 ) throw()
	{
		return( str1.Compare( psz2 ) == 0 );
	}

	friend bool operator==(
		__in PCXSTR psz1, __in const CStringT& str2 ) throw()
	{
		return( str2.Compare( psz1 ) == 0 );
	}

	friend bool operator==(
		__in const CStringT& str1, __in PCYSTR psz2 ) /* throw(...) */
	{
		CStringT str2( psz2, str1.GetManager() );

		return( str1 == str2 );
	}

	friend bool operator==(
		__in PCYSTR psz1, __in const CStringT& str2 ) /* throw(...) */
	{
		CStringT str1( psz1, str2.GetManager() );

		return( str1 == str2 );
	}

	friend bool operator!=(
		__in const CStringT& str1, __in const CStringT& str2 ) throw()
	{
		return( str1.Compare( str2 ) != 0 );
	}

	friend bool operator!=(
		__in const CStringT& str1, __in PCXSTR psz2 ) throw()
	{
		return( str1.Compare( psz2 ) != 0 );
	}

	friend bool operator!=(
		__in PCXSTR psz1, __in const CStringT& str2 ) throw()
	{
		return( str2.Compare( psz1 ) != 0 );
	}

	friend bool operator!=(
		__in const CStringT& str1, __in PCYSTR psz2 ) /* throw(...) */
	{
		CStringT str2( psz2, str1.GetManager() );

		return( str1 != str2 );
	}

	friend bool operator!=(
		__in PCYSTR psz1, __in const CStringT& str2 ) /* throw(...) */
	{
		CStringT str1( psz1, str2.GetManager() );

		return( str1 != str2 );
	}

	friend bool operator<( __in const CStringT& str1, __in const CStringT& str2 ) throw()
	{
		return( str1.Compare( str2 ) < 0 );
	}

	friend bool operator<( __in const CStringT& str1, __in PCXSTR psz2 ) throw()
	{
		return( str1.Compare( psz2 ) < 0 );
	}

	friend bool operator<( __in PCXSTR psz1, __in const CStringT& str2 ) throw()
	{
		return( str2.Compare( psz1 ) > 0 );
	}

	friend bool operator>( __in const CStringT& str1, __in const CStringT& str2 ) throw()
	{
		return( str1.Compare( str2 ) > 0 );
	}

	friend bool operator>( __in const CStringT& str1, __in PCXSTR psz2 ) throw()
	{
		return( str1.Compare( psz2 ) > 0 );
	}

	friend bool operator>( __in PCXSTR psz1, __in const CStringT& str2 ) throw()
	{
		return( str2.Compare( psz1 ) < 0 );
	}

	friend bool operator<=( __in const CStringT& str1, __in const CStringT& str2 ) throw()
	{
		return( str1.Compare( str2 ) <= 0 );
	}

	friend bool operator<=( __in const CStringT& str1, __in PCXSTR psz2 ) throw()
	{
		return( str1.Compare( psz2 ) <= 0 );
	}

	friend bool operator<=( __in PCXSTR psz1, __in const CStringT& str2 ) throw()
	{
		return( str2.Compare( psz1 ) >= 0 );
	}

	friend bool operator>=( __in const CStringT& str1, __in const CStringT& str2 ) throw()
	{
		return( str1.Compare( str2 ) >= 0 );
	}

	friend bool operator>=( __in const CStringT& str1, __in PCXSTR psz2 ) throw()
	{
		return( str1.Compare( psz2 ) >= 0 );
	}

	friend bool operator>=( __in PCXSTR psz1, __in const CStringT& str2 ) throw()
	{
		return( str2.Compare( psz1 ) <= 0 );
	}

	friend bool operator==( __in XCHAR ch1, __in const CStringT& str2 ) throw()
	{
		return( (str2.GetLength() == 1) && (str2[0] == ch1) );
	}

	friend bool operator==( __in const CStringT& str1, __in XCHAR ch2 ) throw()
	{
		return( (str1.GetLength() == 1) && (str1[0] == ch2) );
	}

	friend bool operator!=( __in XCHAR ch1, __in const CStringT& str2 ) throw()
	{
		return( (str2.GetLength() != 1) || (str2[0] != ch1) );
	}

	friend bool operator!=( __in const CStringT& str1, __in XCHAR ch2 ) throw()
	{
		return( (str1.GetLength() != 1) || (str1[0] != ch2) );
	}

private:
	bool CheckImplicitLoad( __in_opt const void* pv )
	{
                ((void)pv);
		bool bRet = false;

// ORIG: 		if( (pv != NULL) && IS_INTRESOURCE( pv ) )
// ORIG: 		{
// ORIG: 			UINT nID = LOWORD( reinterpret_cast< DWORD_PTR >( pv ) );
// ORIG: 			if( !LoadString( nID ) )
// ORIG: 			{
// ORIG: 				ATLTRACE( atlTraceString, 2, _TEXT( "Warning: implicit LoadString(%u) failed\n" ), nID );
// ORIG: 			}
// ORIG: 			bRet = true;
// ORIG: 		}

		return( bRet );
	}

};

#ifndef _CSTRING_BUFFER_SIZE
#define _CSTRING_BUFFER_SIZE(_CStringObj) ((_CStringObj).GetAllocLength() + 1)
#endif

#pragma warning(push)
#pragma warning(disable : 4793)
// Format data using format string 'pszFormat'
// ORIG: template< typename BaseType, class StringTraits >
// ORIG: inline void __cdecl CStringT<BaseType, StringTraits>::Format( __in __format_string PCXSTR pszFormat, ... )
// ORIG: {
// ORIG: 	ATLASSERT( AtlIsValidString( pszFormat ) );
// ORIG: 
// ORIG: 	va_list argList;
// ORIG: 	va_start( argList, pszFormat );
// ORIG: 	FormatV( pszFormat, argList );
// ORIG: 	va_end( argList );
// ORIG: }

// Format data using format string loaded from resource 'nFormatID'
// ORIG: template< typename BaseType, class StringTraits >
// ORIG: inline void __cdecl CStringT<BaseType, StringTraits>::Format( __format_string UINT nFormatID, ... )
// ORIG: {
// ORIG: 	CStringT strFormat( GetManager() );
// ORIG: 	ATLVERIFY( strFormat.LoadString( nFormatID ) );
// ORIG: 
// ORIG: 	va_list argList;
// ORIG: 	va_start( argList, nFormatID );
// ORIG: 	FormatV( strFormat, argList );
// ORIG: 	va_end( argList );
// ORIG: }

// Append formatted data using format string loaded from resource 'nFormatID'
// ORIG: template< typename BaseType, class StringTraits >
// ORIG: inline void __cdecl CStringT<BaseType, StringTraits>::AppendFormat( __in UINT nFormatID, ... )
// ORIG: {
// ORIG: 	va_list argList;
// ORIG: 	va_start( argList, nFormatID );
// ORIG: 
// ORIG: 	CStringT strFormat( GetManager() );
// ORIG: 	ATLVERIFY( strFormat.LoadString( nFormatID ) ); 
// ORIG: 
// ORIG: 	AppendFormatV( strFormat, argList );
// ORIG: 
// ORIG: 	va_end( argList );
// ORIG: }


// Append formatted data using format string 'pszFormat'
// ORIG: template< typename BaseType, class StringTraits >
// ORIG: inline void __cdecl CStringT<BaseType, StringTraits>::AppendFormat( __in __format_string PCXSTR pszFormat, ... )
// ORIG: {
// ORIG: 	ATLASSERT( AtlIsValidString( pszFormat ) );
// ORIG: 
// ORIG: 	va_list argList;
// ORIG: 	va_start( argList, pszFormat );
// ORIG: 
// ORIG: 	AppendFormatV( pszFormat, argList );
// ORIG: 
// ORIG: 	va_end( argList );
// ORIG: }

// ORIG: // Format a message using format string 'pszFormat'
// ORIG: template< typename BaseType, class StringTraits >
// ORIG: inline void __cdecl CStringT<BaseType, StringTraits>::_AFX_FUNCNAME(FormatMessage)( __in __format_string PCXSTR pszFormat, ... )
// ORIG: {
// ORIG: 	if(pszFormat == NULL)
// ORIG: 		AtlThrow(E_INVALIDARG);
// ORIG: 
// ORIG: 	va_list argList;
// ORIG: 	va_start( argList, pszFormat );
// ORIG: 
// ORIG: 	FormatMessageV( pszFormat, &argList );
// ORIG: 
// ORIG: 	va_end( argList );
// ORIG: }

// ORIG: #if defined(_AFX)
// ORIG: template< typename BaseType, class StringTraits >
// ORIG: inline void __cdecl CStringT<BaseType, StringTraits>::FormatMessage( __in __format_string PCXSTR pszFormat, ... )
// ORIG: {
// ORIG: 	if(pszFormat == NULL)
// ORIG: 		AtlThrow(E_INVALIDARG);
// ORIG: 
// ORIG: 	va_list argList;
// ORIG: 	va_start( argList, pszFormat );
// ORIG: 
// ORIG: 	FormatMessageV( pszFormat, &argList );
// ORIG: 
// ORIG: 	va_end( argList );
// ORIG: }
// ORIG: #endif

// Format a message using format string loaded from resource 'nFormatID'
// ORIG: template< typename BaseType, class StringTraits >
// ORIG: inline void __cdecl CStringT<BaseType, StringTraits>::_AFX_FUNCNAME(FormatMessage)( __in UINT nFormatID, ... )
// ORIG: {
// ORIG: 	// get format string from string table
// ORIG: 	CStringT strFormat( GetManager() );
// ORIG: 	ATLVERIFY( strFormat.LoadString( nFormatID ) );
// ORIG: 
// ORIG: 	if(strFormat.GetLength() == 0)
// ORIG: 		AtlThrow(E_INVALIDARG);
// ORIG: 
// ORIG: 	va_list argList;
// ORIG: 	va_start( argList, nFormatID );
// ORIG: 
// ORIG: 	FormatMessageV( strFormat, &argList );
// ORIG: 
// ORIG: 	va_end( argList );
// ORIG: }

// ORIG: #if defined(_AFX)
// ORIG: template< typename BaseType, class StringTraits >
// ORIG: inline void __cdecl CStringT<BaseType, StringTraits>::FormatMessage( __in UINT nFormatID, ... )
// ORIG: {
// ORIG: 	// get format string from string table
// ORIG: 	CStringT strFormat( GetManager() );
// ORIG: 	ATLVERIFY( strFormat.LoadString( nFormatID ) );
// ORIG: 
// ORIG: 	if(strFormat.GetLength() == 0)
// ORIG: 		AtlThrow(E_INVALIDARG);
// ORIG: 
// ORIG: 	va_list argList;
// ORIG: 	va_start( argList, nFormatID );
// ORIG: 
// ORIG: 	FormatMessageV( strFormat, &argList );
// ORIG: 
// ORIG: 	va_end( argList );
// ORIG: }
// ORIG: #endif

#pragma warning( pop )

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;
	virtual ~IFixedStringLog() {}
};

class CFixedStringMgr :
	public IAtlStringMgr
{
public:
	CFixedStringMgr( __in CStringData* pData, __in int nChars, __in_opt IAtlStringMgr* pMgr = NULL ) throw() :
		m_pMgr( pMgr ),
		m_pData( pData )
	{
		m_pData->nRefs = -1;
		m_pData->nDataLength = 0;
		m_pData->nAllocLength = nChars;
		m_pData->pStringMgr = this;
		*static_cast< wchar_t* >( m_pData->data() ) = 0;
	}
	virtual ~CFixedStringMgr() throw()
	{
	}

// IAtlStringMgr
public:
	virtual CStringData* Allocate( __in int nChars, __in int nCharSize ) throw()
	{
		ATLASSUME( m_pData->nRefs == -1 );
		ATLASSUME( 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( __inout 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( __inout CStringData* pData, __in int nChars, __in 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 
                Checked::memcpy_s( pNewData->data(), nChars*nCharSize, 
					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()
	{
		ATLASSUME( m_pData->nRefs == -1 );
		ATLASSUME( 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;
};

#ifdef _WIN32
__declspec( selectany ) IFixedStringLog* CFixedStringMgr::s_pLog = NULL;
#elif SOLARIS
__declspec( selectany ) IFixedStringLog* CFixedStringMgr::s_pLog = NULL;
  #pragma weak "__1cDATLPCFixedStringMgrGs_pLog_"
#else
__declspec( selectany ) IFixedStringLog* CFixedStringMgr::s_pLog __attribute__ ((weak)) = NULL;
#endif /* _WIN32, SOLARIS */

#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
{
	typedef typename StringType::StrTraits StrTraitsT;
	typedef StringType base;
public:
	CFixedStringT() throw() :
// ORIG: 		CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
		CFixedStringMgr( &m_data, t_nChars, StrTraitsT::GetDefaultManager() ),
		StringType( static_cast< IAtlStringMgr* >( this ) )
	{
	}

	explicit CFixedStringT( __in IAtlStringMgr* pStringMgr ) throw() :
		CFixedStringMgr( &m_data, t_nChars, pStringMgr ),
		StringType( static_cast< IAtlStringMgr* >( this ) )
	{
	}

	CFixedStringT( __in const CFixedStringT< StringType, t_nChars >& str ) :
// ORIG: 		CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
		CFixedStringMgr( &m_data, t_nChars, StrTraitsT::GetDefaultManager() ),
		StringType( str.GetString(), str.GetLength(), static_cast< CFixedStringMgr* >( this ) )
	{
	}

	CFixedStringT( __in const StringType& str ) :
// ORIG: 		CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
		CFixedStringMgr( &m_data, t_nChars, StrTraitsT::GetDefaultManager() ),
		StringType( str.GetString(), str.GetLength(), static_cast< CFixedStringMgr* >( this ) )
	{
	}

	CFixedStringT( __in const typename StringType::XCHAR* psz ) :
// ORIG: 		CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
		CFixedStringMgr( &m_data, t_nChars, StrTraitsT::GetDefaultManager() ),
		StringType( psz, static_cast< CFixedStringMgr* >( this ) )
	{
	}

	CFixedStringT( __in_ecount(nLength) const typename StringType::XCHAR* psz, __in int nLength ) :
// ORIG: 		CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
		CFixedStringMgr( &m_data, t_nChars, StrTraitsT::GetDefaultManager() ),
		StringType( psz, nLength, static_cast< CFixedStringMgr* >( this ) )
	{
	}

	explicit CFixedStringT( __in const typename StringType::YCHAR* psz ) :
// ORIG: 		CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
		CFixedStringMgr( &m_data, t_nChars, StrTraitsT::GetDefaultManager() ),
		StringType( psz, static_cast< CFixedStringMgr* >( this ) )
	{
	}

	explicit CFixedStringT( __in const unsigned char* psz ) :
// ORIG: 		CFixedStringMgr( &m_data, t_nChars, StrTraits::GetDefaultManager() ),
		CFixedStringMgr( &m_data, t_nChars, StrTraitsT::GetDefaultManager() ),
		StringType( psz, static_cast< CFixedStringMgr* >( this ) )
	{
	}

	~CFixedStringT() throw()
	{
		base::Empty();
	}

	CFixedStringT< StringType, t_nChars >& operator=( __in const CFixedStringT< StringType, t_nChars >& str )
	{
		StringType::operator=( str );
		return *this;
	}

	CFixedStringT< StringType, t_nChars >& operator=( __in_z const char* psz )
	{
		StringType::operator=( psz );
		return *this;
	}

	CFixedStringT< StringType, t_nChars >& operator=( __in_z const wchar_t* psz )
	{
		StringType::operator=( psz );
		return *this;
	}

	CFixedStringT< StringType, t_nChars >& operator=( __in_z const unsigned char* psz )
	{
		StringType::operator=( psz );
		return *this;
	}

	CFixedStringT< StringType, t_nChars >& operator=( __in const StringType& str )
	{
		StringType::operator=( str );
		return *this;
	}

// Implementation
protected:
	CStringData m_data;
	typename StringType::XCHAR m_achData[t_nChars+1];
};

#pragma warning( pop )
class CFixedStringLog :
	public IFixedStringLog
{
public:
	CFixedStringLog() throw()
	{
		CFixedStringMgr::s_pLog = this;
	}
	virtual ~CFixedStringLog() throw()
	{
		CFixedStringMgr::s_pLog = NULL;
	}

public:
	void OnAllocateSpill( __in int nActualChars, __in int nFixedChars, __in const CStringData* pData ) throw()
	{
		(void)nActualChars;
		(void)nFixedChars;
		(void)pData;
		ATLTRACE( atlTraceString, 0, _TEXT( "CFixedStringMgr::Allocate() spilling to heap.  %d chars (fixed size = %d chars)\n" ), nActualChars, nFixedChars );
	}
	void OnReallocateSpill( __in int nActualChars, __in int nFixedChars, __in const CStringData* pData ) throw()
	{
		(void)nActualChars;
		(void)nFixedChars;
		(void)pData;
		ATLTRACE( atlTraceString, 0, _TEXT( "CFixedStringMgr::Reallocate() spilling to heap.  %d chars (fixed size = %d chars)\n" ), nActualChars, nFixedChars );
	}
};

template< typename T >
class CStringElementTraits
{
public:
	typedef typename T::PCXSTR INARGTYPE;
	typedef T& OUTARGTYPE;
	typedef typename T::XCHAR XCHAR_T;
	typedef typename T::StrTraits StrTraitsT;

	static void __cdecl CopyElements( __out_ecount_full(nElements) T* pDest, const __in_ecount(nElements) T* pSrc, __in size_t nElements )
	{
		for( size_t iElement = 0; iElement < nElements; iElement++ )
		{
			pDest[iElement] = pSrc[iElement];
		}
	}

	static void __cdecl RelocateElements( __out_ecount_full(nElements) T* pDest, __in_ecount(nElements) T* pSrc, __in size_t nElements )
	{
		Checked::memmove_s( pDest, nElements*sizeof( T ), pSrc, nElements*sizeof( T ) );
	}

	static ULONG __cdecl Hash( __in INARGTYPE str )
	{
		ATLENSURE( str != NULL );
		ULONG nHash = 0;
// ORIG: 		const T::XCHAR* pch = str;
		const XCHAR_T* pch = str;
		while( *pch != 0 )
		{
			nHash = (nHash<<5)+nHash+(*pch);
			pch++;
		}

		return( nHash );
	}

	static bool __cdecl CompareElements( __in INARGTYPE str1, __in INARGTYPE str2 )
	{
// ORIG: 		return( T::StrTraits::StringCompare( str1, str2 ) == 0 );
		return( StrTraitsT::StringCompare( str1, str2 ) == 0 );
	}

	static int __cdecl CompareElementsOrdered( __in INARGTYPE str1, __in INARGTYPE str2 )
	{
// ORIG::		return( T::StrTraits::StringCompare( str1, str2 ) );
		return( StrTraitsT::StringCompare( str1, str2 ) );
	}
};

#if !defined(AIX)
#pragma pop_macro("new")
#endif // !defined(AIX)

#if defined(_AFX)
#pragma pop_macro("FormatMessage")
#endif

};  // namespace ATL



#ifdef __ATLCOMCLI_H__
// ORIG: #include <cstringt.inl>
#endif	// __ATLCOMCLI_H__


#ifndef _ATL_NO_PRAGMA_WARNINGS
#pragma warning (pop)
#endif



#endif	// __CSTRINGT_H__ (whole file)
