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

1496 lines
40 KiB

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORPORATION, 1998
*
* TITLE: SIMSTR.H
*
* VERSION: 1.0
*
* AUTHOR: ShaunIv
*
* DATE: 5/12/1998
*
* DESCRIPTION: Simple string classes
*
*******************************************************************************/
#ifndef _SIMSTR_H_INCLUDED
#define _SIMSTR_H_INCLUDED
/*
* Simple string class.
*
* Template class:
* CSimpleStringBase<CharType>
* Implementations:
* CSimpleStringBase<wchar_t> CSimpleStringWide
* CSimpleStringBase<char> CSimpleStringAnsi
* CSimpleString = CSimpleString[Ansi|Wide] depending on UNICODE macro
* Inline functions:
* CSimpleStringAnsi CSimpleStringConvert::AnsiString(CharType n)
* CSimpleStringWide CSimpleStringConvert::WideString(CharType n)
* CSimpleString CSimpleStringConvert::NaturalString(CharType n)
* Macros:
* IS_CHAR(CharType)
* IS_WCHAR(CharType)
*/
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include <tchar.h>
//
// Disable the "conditional expression is constant" warning that is caused by
// the IS_CHAR and IS_WCHAR macros
//
#pragma warning( push )
#pragma warning( disable : 4127 )
#define IS_CHAR(x) (sizeof(x) & sizeof(char))
#define IS_WCHAR(x) (sizeof(x) & sizeof(wchar_t))
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
template <class CharType>
class CSimpleStringBase
{
private:
enum
{
c_nDefaultGranularity = 16, // Default number of extra characters to allocate when we have to grow
c_nMaxLoadStringBuffer = 1024, // Maximum length of .RC string
c_nMaxAutoDataLength = 128 // Length of non-dynamically allocated string
};
private:
//
// If the string is less than c_nMaxAutoDataLength characters, it will be
// stored here, instead of in a dynamically allocated buffer
//
CharType m_pstrAutoData[c_nMaxAutoDataLength];
//
// If we have to allocated data, it will be stored here
//
CharType *m_pstrData;
//
// Current maximum buffer size
//
UINT m_nMaxSize;
//
// Amount of extra space we allocate when we have to grow the buffer
//
UINT m_nGranularity;
private:
//
// Min, in case it isn't already defined
//
template <class NumberType>
static NumberType Min( const NumberType &a, const NumberType &b )
{
return (a < b) ? a : b;
}
public:
//
// Replacements (in some cases just wrappers) for strlen, strcpy, ...
//
static inline CharType *GenericCopy( CharType *pstrTarget, const CharType *pstrSource );
static inline CharType *GenericCopyLength( CharType *pstrTarget, const CharType *pstrSource, UINT nSize );
static inline UINT GenericLength( const CharType *pstrStr );
static inline CharType *GenericConcatenate( CharType *pstrTarget, const CharType *pstrSource );
static inline int GenericCompare( const CharType *pstrTarget, const CharType *pstrSource );
static inline int GenericCompareNoCase( const CharType *pstrStrA, const CharType *pstrStrB );
static inline int GenericCompareLength( const CharType *pstrTarget, const CharType *pstrSource, UINT nLength );
static inline CharType *GenericCharNext( const CharType *pszStr );
private:
//
// Internal only helpers
//
bool EnsureLength( UINT nMaxSize );
void DeleteStorage();
static inline CharType *CreateStorage( UINT nCount );
void Destroy();
public:
//
// Constructors and destructor
//
CSimpleStringBase();
CSimpleStringBase( const CSimpleStringBase & );
CSimpleStringBase( const CharType *szStr );
CSimpleStringBase( CharType ch );
CSimpleStringBase( UINT nResId, HMODULE hModule );
virtual ~CSimpleStringBase();
//
// Various helpers
//
UINT Length() const;
void Concat( const CSimpleStringBase &other );
int Resize();
UINT Truncate( UINT nLen );
bool Assign( const CharType *szStr );
bool Assign( const CSimpleStringBase & );
void SetAt( UINT nIndex, CharType chValue );
CharType &operator[](int index);
const CharType &operator[](int index) const;
//
// Handy Win32 wrappers
//
CSimpleStringBase &Format( const CharType *strFmt, ... );
CSimpleStringBase &Format( int nResId, HINSTANCE hInst, ... );
CSimpleStringBase &GetWindowText( HWND hWnd );
bool SetWindowText( HWND hWnd );
bool LoadString( UINT nResId, HMODULE hModule );
bool Load( HKEY hRegKey, const CharType *pszValueName, const CharType *pszDefault=NULL );
bool Store( HKEY hRegKey, const CharType *pszValueName, DWORD nType = REG_SZ );
//
// Operators
//
CSimpleStringBase &operator=( const CSimpleStringBase &other );
CSimpleStringBase &operator=( const CharType *other );
CSimpleStringBase &operator+=( const CSimpleStringBase &other );
//
// Convert this string and return the converted string
//
CSimpleStringBase ToUpper() const;
CSimpleStringBase ToLower() const;
//
// Convert in place
//
CSimpleStringBase &MakeUpper();
CSimpleStringBase &MakeLower();
//
// Remove leading and trailing spaces
//
CSimpleStringBase &TrimRight();
CSimpleStringBase &TrimLeft();
CSimpleStringBase &Trim();
//
// Reverse
//
CSimpleStringBase &Reverse();
//
// Searching
//
int Find( CharType cChar ) const;
int Find( const CSimpleStringBase &other, UINT nStart=0 ) const;
int ReverseFind( CharType cChar ) const;
int ReverseFind( const CSimpleStringBase &other ) const;
//
// Substring copies
//
CSimpleStringBase SubStr( int nStart, int nCount=-1 ) const;
CSimpleStringBase Left( int nCount ) const
{
return SubStr( 0, nCount );
}
CSimpleStringBase Right( int nCount ) const
{
return SubStr( max(0,(int)Length()-nCount), -1 );
}
//
// Comparison functions
//
int CompareNoCase( const CSimpleStringBase &other, int nLength=-1 ) const;
int Compare( const CSimpleStringBase &other, int nLength=-1 ) const;
bool MatchLastCharacter( CharType cChar ) const;
//
// Direct manipulation
//
CharType *GetBuffer( int nLength )
{
//
// If the user passed 0, or we are able to allocate a string of the
// requested length, return a pointer to the actual data.
//
if (!nLength || EnsureLength(nLength+1))
{
return m_pstrData;
}
return NULL;
}
//
// Useful inlines
//
const CharType *String() const
{
return m_pstrData;
}
UINT MaxSize() const
{
return m_nMaxSize;
}
UINT Granularity( UINT nGranularity )
{
if (nGranularity>0)
{
m_nGranularity = nGranularity;
}
return m_nGranularity;
}
UINT Granularity() const
{
return m_nGranularity;
}
//
// Implicit cast operator
//
operator const CharType *() const
{
return String();
}
//
// Sanity check
//
bool IsValid() const
{
return(NULL != m_pstrData);
}
};
template <class CharType>
inline CharType *CSimpleStringBase<CharType>::GenericCopy( CharType *pszDest, const CharType *pszSource )
{
CopyMemory( pszDest, pszSource, sizeof(CharType) * (GenericLength(pszSource) + 1) );
return pszDest;
}
template <class CharType>
inline CharType *CSimpleStringBase<CharType>::GenericCharNext( const CharType *pszStr )
{
if (IS_CHAR(*pszStr))
return(CharType*)CharNextA((LPCSTR)pszStr);
else if (!*pszStr)
return(CharType*)pszStr;
else return(CharType*)((LPWSTR)pszStr + 1);
}
template <class CharType>
inline CharType *CSimpleStringBase<CharType>::GenericCopyLength( CharType *pszTarget, const CharType *pszSource, UINT nCount )
{
UINT nCopyLen = min( nCount, GenericLength(pszSource) + 1 );
CopyMemory( pszTarget, pszSource, nCopyLen * sizeof(CharType) );
if (nCopyLen < nCount)
{
pszTarget[nCopyLen] = 0;
}
return pszTarget;
}
template <class CharType>
inline UINT CSimpleStringBase<CharType>::GenericLength( const CharType *pszString )
{
const CharType *eos = pszString;
while (*eos++)
;
return((UINT)(eos - pszString - 1));
}
template <class CharType>
inline CharType*CSimpleStringBase<CharType>::GenericConcatenate( CharType *pszDest, const CharType *pszSource )
{
CharType *pCurr = pszDest;
while (*pCurr)
pCurr++;
CopyMemory( pCurr, pszSource, sizeof(CharType) * (GenericLength(pszSource) + 1) );
return pszDest;
}
template <class CharType>
inline int CSimpleStringBase<CharType>::GenericCompare( const CharType *pszSource, const CharType *pszDest )
{
#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
if (sizeof(CharType) == sizeof(wchar_t))
{
OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
}
#endif
int nRes = IS_CHAR(*pszSource) ?
CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszSource, -1, (LPCSTR)pszDest, -1 ) :
CompareStringW( LOCALE_USER_DEFAULT, 0, (LPCWSTR)pszSource, -1, (LPCWSTR)pszDest, -1 );
switch (nRes)
{
case CSTR_LESS_THAN:
return -1;
case CSTR_GREATER_THAN:
return 1;
default:
return 0;
}
}
template <class CharType>
inline int CSimpleStringBase<CharType>::GenericCompareNoCase( const CharType *pszSource, const CharType *pszDest )
{
#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
if (sizeof(CharType) == sizeof(wchar_t))
{
OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
}
#endif
int nRes = IS_CHAR(*pszSource) ?
CompareStringA( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCSTR)pszSource, -1, (LPCSTR)pszDest, -1 ) :
CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCWSTR)pszSource, -1, (LPCWSTR)pszDest, -1 );
switch (nRes)
{
case CSTR_LESS_THAN:
return -1;
case CSTR_GREATER_THAN:
return 1;
default:
return 0;
}
}
template <class CharType>
inline int CSimpleStringBase<CharType>::GenericCompareLength( const CharType *pszStringA, const CharType *pszStringB, UINT nLength )
{
#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
if (sizeof(CharType) == sizeof(wchar_t))
{
OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
}
#endif
if (!nLength)
return(0);
int nRes = IS_CHAR(*pszStringA) ?
CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszStringA, Min(nLength,CSimpleStringBase<CHAR>::GenericLength((LPCSTR)pszStringA)), (LPCSTR)pszStringB, Min(nLength,CSimpleStringBase<CHAR>::GenericLength((LPCSTR)pszStringB)) ) :
CompareStringW( LOCALE_USER_DEFAULT, 0, (LPWSTR)pszStringA, Min(nLength,CSimpleStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringA)), (LPCWSTR)pszStringB, Min(nLength,CSimpleStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringB)) );
switch (nRes)
{
case CSTR_LESS_THAN:
return -1;
case CSTR_GREATER_THAN:
return 1;
default:
return 0;
}
}
template <class CharType>
bool CSimpleStringBase<CharType>::EnsureLength( UINT nMaxSize )
{
//
// If the string is already long enough, just return true
//
if (m_nMaxSize >= nMaxSize)
{
return true;
}
// Get the new size
//
UINT nNewMaxSize = nMaxSize + m_nGranularity;
//
// Allocate the new buffer
//
CharType *pszTmp = CreateStorage(nNewMaxSize);
//
// Make sure the allocation succeded
//
if (pszTmp)
{
//
// If we have an existing string, copy it and delete it
//
if (m_pstrData)
{
GenericCopy(pszTmp,m_pstrData);
DeleteStorage();
}
//
// Save the new max size
//
m_nMaxSize = nNewMaxSize;
//
// Save this new string
//
m_pstrData = pszTmp;
//
// Return success
//
return true;
}
//
// Couldn't allocate memory
//
return false;
}
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::GetWindowText( HWND hWnd )
{
Destroy();
// Assume it didn't work
bool bSuccess = false;
int nLen = ::GetWindowTextLength(hWnd);
if (nLen)
{
if (EnsureLength(nLen+1))
{
if (::GetWindowText( hWnd, m_pstrData, (nLen+1) ))
{
bSuccess = true;
}
}
}
if (!bSuccess)
Destroy();
return *this;
}
template <class CharType>
bool CSimpleStringBase<CharType>::SetWindowText( HWND hWnd )
{
return(::SetWindowText( hWnd, String() ) != FALSE);
}
template <class CharType>
UINT CSimpleStringBase<CharType>::Truncate( UINT nLen )
{
if (Length() < nLen)
return Length();
if (!nLen)
return 0;
m_pstrData[nLen-1] = 0;
Resize();
return Length();
}
template <class CharType>
int CSimpleStringBase<CharType>::Resize()
{
m_nMaxSize = m_pstrData ? GenericLength(m_pstrData) : 0;
++m_nMaxSize;
CharType *pszTmp = CreateStorage(m_nMaxSize);
if (pszTmp)
{
if (m_pstrData)
{
GenericCopy(pszTmp,m_pstrData);
DeleteStorage();
}
else *pszTmp = 0;
m_pstrData = pszTmp;
}
return Length();
}
template <class CharType>
CSimpleStringBase<CharType>::CSimpleStringBase()
: m_pstrData(m_pstrAutoData),
m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
m_nGranularity(c_nDefaultGranularity)
{
m_pstrAutoData[0] = 0;
CharType szTmp[1] = { 0};
Assign(szTmp);
}
template <class CharType>
CSimpleStringBase<CharType>::CSimpleStringBase( const CSimpleStringBase &other )
: m_pstrData(m_pstrAutoData),
m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
m_nGranularity(c_nDefaultGranularity)
{
m_pstrAutoData[0] = 0;
Assign(other.String());
}
template <class CharType>
CSimpleStringBase<CharType>::CSimpleStringBase( const CharType *szStr )
: m_pstrData(m_pstrAutoData),
m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
m_nGranularity(c_nDefaultGranularity)
{
m_pstrAutoData[0] = 0;
Assign(szStr);
}
template <class CharType>
CSimpleStringBase<CharType>::CSimpleStringBase( CharType ch )
: m_pstrData(m_pstrAutoData),
m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
m_nGranularity(c_nDefaultGranularity)
{
m_pstrAutoData[0] = 0;
CharType szTmp[2];
szTmp[0] = ch;
szTmp[1] = 0;
Assign(szTmp);
}
template <class CharType>
CSimpleStringBase<CharType>::CSimpleStringBase( UINT nResId, HMODULE hModule )
: m_pstrData(m_pstrAutoData),
m_nMaxSize(ARRAYSIZE(m_pstrAutoData)),
m_nGranularity(c_nDefaultGranularity)
{
m_pstrAutoData[0] = 0;
LoadString( nResId, hModule );
}
template <>
inline CSimpleStringBase<WCHAR> &CSimpleStringBase<WCHAR>::Format( const WCHAR *strFmt, ... )
{
WCHAR szTmp[1024] = {0};
va_list arglist;
va_start(arglist, strFmt);
_vsnwprintf( szTmp, ARRAYSIZE(szTmp)-1, strFmt, arglist );
va_end(arglist);
Assign(szTmp);
return *this;
}
template <>
inline CSimpleStringBase<CHAR> &CSimpleStringBase<CHAR>::Format( const CHAR *strFmt, ... )
{
CHAR szTmp[1024] = {0};
va_list arglist;
va_start(arglist, strFmt);
_vsnprintf( szTmp, ARRAYSIZE(szTmp)-1, strFmt, arglist );
va_end(arglist);
Assign(szTmp);
return *this;
}
template <>
inline CSimpleStringBase<CHAR> &CSimpleStringBase<CHAR>::Format( int nResId, HINSTANCE hInst, ... )
{
CSimpleStringBase<CHAR> strFmt;
if (strFmt.LoadString(nResId,hInst))
{
CHAR szTmp[1024] = {0};
va_list arglist;
va_start(arglist, hInst);
_vsnprintf( szTmp, ARRAYSIZE(szTmp)-1, strFmt, arglist );
va_end(arglist);
Assign(szTmp);
}
else Assign(NULL);
return *this;
}
template <>
inline CSimpleStringBase<WCHAR> &CSimpleStringBase<WCHAR>::Format( int nResId, HINSTANCE hInst, ... )
{
CSimpleStringBase<WCHAR> strFmt;
if (strFmt.LoadString(nResId,hInst))
{
WCHAR szTmp[1024] = {0};
va_list arglist;
va_start(arglist, hInst);
_vsnwprintf( szTmp, ARRAYSIZE(szTmp)-1, strFmt, arglist );
va_end(arglist);
Assign(szTmp);
}
else Assign(NULL);
return *this;
}
template <>
inline bool CSimpleStringBase<CHAR>::LoadString( UINT nResId, HMODULE hModule )
{
if (!hModule)
{
hModule = GetModuleHandle(NULL);
}
CHAR szTmp[c_nMaxLoadStringBuffer] = {0};
int nRet = ::LoadStringA( hModule, nResId, szTmp, ARRAYSIZE(szTmp));
return nRet ? Assign(szTmp) : Assign(NULL);
}
template <>
inline bool CSimpleStringBase<WCHAR>::LoadString( UINT nResId, HMODULE hModule )
{
if (!hModule)
{
hModule = GetModuleHandle(NULL);
}
WCHAR szTmp[c_nMaxLoadStringBuffer] = {0};
int nRet = ::LoadStringW( hModule, nResId, szTmp, ARRAYSIZE(szTmp));
return nRet ? Assign(szTmp) : Assign(NULL);
}
template <class CharType>
CSimpleStringBase<CharType>::~CSimpleStringBase()
{
Destroy();
}
template <class CharType>
void CSimpleStringBase<CharType>::DeleteStorage()
{
//
// Only delete the string if it is non-NULL and not pointing to our non-dynamically allocated buffer
//
if (m_pstrData && m_pstrData != m_pstrAutoData)
{
delete[] m_pstrData;
}
m_pstrData = NULL;
}
template <class CharType>
CharType *CSimpleStringBase<CharType>::CreateStorage( UINT nCount )
{
return new CharType[nCount];
}
template <class CharType>
void CSimpleStringBase<CharType>::Destroy()
{
DeleteStorage();
m_nMaxSize = 0;
}
template <class CharType>
UINT CSimpleStringBase<CharType>::Length() const
{
return(m_pstrData ? GenericLength(m_pstrData) : 0);
}
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::operator=( const CSimpleStringBase &other )
{
if (&other != this)
{
Assign(other.String());
}
return *this;
}
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::operator=( const CharType *other )
{
if (other != String())
{
Assign(other);
}
return *this;
}
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::operator+=( const CSimpleStringBase &other )
{
Concat(other.String());
return *this;
}
template <class CharType>
bool CSimpleStringBase<CharType>::Assign( const CharType *szStr )
{
if (szStr && EnsureLength(GenericLength(szStr)+1))
{
GenericCopy(m_pstrData,szStr);
}
else if (EnsureLength(1))
{
*m_pstrData = 0;
}
else Destroy();
return(NULL != m_pstrData);
}
template <class CharType>
bool CSimpleStringBase<CharType>::Assign( const CSimpleStringBase &other )
{
return Assign( other.String() );
}
template <class CharType>
void CSimpleStringBase<CharType>::SetAt( UINT nIndex, CharType chValue )
{
//
// Make sure we don't go off the end of the string or overwrite the '\0'
//
if (m_pstrData && Length() > nIndex)
{
m_pstrData[nIndex] = chValue;
}
}
template <class CharType>
void CSimpleStringBase<CharType>::Concat( const CSimpleStringBase &other )
{
if (EnsureLength( Length() + other.Length() + 1 ))
{
GenericConcatenate(m_pstrData,other.String());
}
}
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::MakeUpper()
{
//
// Make sure the string is not NULL
//
if (m_pstrData)
{
IS_CHAR(*m_pstrData) ? CharUpperBuffA( (LPSTR)m_pstrData, Length() ) : CharUpperBuffW( (LPWSTR)m_pstrData, Length() );
}
return *this;
}
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::MakeLower()
{
//
// Make sure the string is not NULL
//
if (m_pstrData)
{
IS_CHAR(*m_pstrData) ? CharLowerBuffA( (LPSTR)m_pstrData, Length() ) : CharLowerBuffW( (LPWSTR)m_pstrData, Length() );
}
return *this;
}
template <class CharType>
CSimpleStringBase<CharType> CSimpleStringBase<CharType>::ToUpper() const
{
CSimpleStringBase str(*this);
str.MakeUpper();
return str;
}
template <class CharType>
CSimpleStringBase<CharType> CSimpleStringBase<CharType>::ToLower() const
{
CSimpleStringBase str(*this);
str.MakeLower();
return str;
}
template <class CharType>
CharType &CSimpleStringBase<CharType>::operator[](int nIndex)
{
return m_pstrData[nIndex];
}
template <class CharType>
const CharType &CSimpleStringBase<CharType>::operator[](int index) const
{
return m_pstrData[index];
}
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::TrimRight()
{
CharType *pFirstWhitespaceCharacterInSequence = NULL;
bool bInWhiteSpace = false;
CharType *pszPtr = m_pstrData;
while (pszPtr && *pszPtr)
{
if (*pszPtr == L' ' || *pszPtr == L'\t' || *pszPtr == L'\n' || *pszPtr == L'\r')
{
if (!bInWhiteSpace)
{
pFirstWhitespaceCharacterInSequence = pszPtr;
bInWhiteSpace = true;
}
}
else
{
bInWhiteSpace = false;
}
pszPtr = GenericCharNext(pszPtr);
}
if (pFirstWhitespaceCharacterInSequence && bInWhiteSpace)
*pFirstWhitespaceCharacterInSequence = 0;
return *this;
}
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::TrimLeft()
{
CharType *pszPtr = m_pstrData;
while (pszPtr && *pszPtr)
{
if (*pszPtr == L' ' || *pszPtr == L'\t' || *pszPtr == L'\n' || *pszPtr == L'\r')
{
pszPtr = GenericCharNext(pszPtr);
}
else break;
}
Assign(CSimpleStringBase<CharType>(pszPtr).String());
return *this;
}
template <class CharType>
inline CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::Trim()
{
TrimLeft();
TrimRight();
return *this;
}
//
// Note that this function WILL NOT WORK CORRECTLY for multi-byte characters in ANSI strings
//
template <class CharType>
CSimpleStringBase<CharType> &CSimpleStringBase<CharType>::Reverse()
{
UINT nLen = Length();
for (UINT i = 0;i<nLen/2;i++)
{
CharType tmp = m_pstrData[i];
m_pstrData[i] = m_pstrData[nLen-i-1];
m_pstrData[nLen-i-1] = tmp;
}
return *this;
}
template <class CharType>
int CSimpleStringBase<CharType>::Find( CharType cChar ) const
{
CharType strTemp[2] = { cChar, 0};
return Find(strTemp);
}
template <class CharType>
int CSimpleStringBase<CharType>::Find( const CSimpleStringBase &other, UINT nStart ) const
{
if (!m_pstrData)
return -1;
if (nStart > Length())
return -1;
CharType *pstrCurr = m_pstrData+nStart, *pstrSrc, *pstrSubStr;
while (*pstrCurr)
{
pstrSrc = pstrCurr;
pstrSubStr = (CharType *)other.String();
while (*pstrSrc && *pstrSubStr && *pstrSrc == *pstrSubStr)
{
pstrSrc = GenericCharNext(pstrSrc);
pstrSubStr = GenericCharNext(pstrSubStr);
}
if (!*pstrSubStr)
return static_cast<int>(pstrCurr-m_pstrData);
pstrCurr = GenericCharNext(pstrCurr);
}
return -1;
}
template <class CharType>
int CSimpleStringBase<CharType>::ReverseFind( CharType cChar ) const
{
CharType strTemp[2] = { cChar, 0};
return ReverseFind(strTemp);
}
template <class CharType>
int CSimpleStringBase<CharType>::ReverseFind( const CSimpleStringBase &srcStr ) const
{
int nLastFind = -1, nFind=0;
while ((nFind = Find( srcStr, nFind )) >= 0)
{
nLastFind = nFind;
++nFind;
}
return nLastFind;
}
template <class CharType>
CSimpleStringBase<CharType> CSimpleStringBase<CharType>::SubStr( int nStart, int nCount ) const
{
if (nStart >= (int)Length() || nStart < 0)
{
return CSimpleStringBase<CharType>();
}
if (nCount < 0)
{
nCount = Length() - nStart;
}
CSimpleStringBase<CharType> strTmp;
CharType *pszTmp = CreateStorage(nCount+1);
if (pszTmp)
{
GenericCopyLength( pszTmp, m_pstrData+nStart, nCount+1 );
pszTmp[nCount] = 0;
strTmp = pszTmp;
delete[] pszTmp;
}
return strTmp;
}
template <class CharType>
int CSimpleStringBase<CharType>::CompareNoCase( const CSimpleStringBase &other, int nLength ) const
{
if (nLength < 0)
{
//
// Make sure both strings are non-NULL
//
if (!String() && !other.String())
{
return 0;
}
else if (!String())
{
return -1;
}
else if (!other.String())
{
return 1;
}
else return GenericCompareNoCase(m_pstrData,other.String());
}
CSimpleStringBase<CharType> strSrc(*this);
CSimpleStringBase<CharType> strTgt(other);
strSrc.MakeUpper();
strTgt.MakeUpper();
//
// Make sure both strings are non-NULL
//
if (!strSrc.String() && !strTgt.String())
{
return 0;
}
else if (!strSrc.String())
{
return -1;
}
else if (!strTgt.String())
{
return 1;
}
else return GenericCompareLength(strSrc.String(),strTgt.String(),nLength);
}
template <class CharType>
int CSimpleStringBase<CharType>::Compare( const CSimpleStringBase &other, int nLength ) const
{
//
// Make sure both strings are non-NULL
//
if (!String() && !other.String())
{
return 0;
}
else if (!String())
{
return -1;
}
else if (!other.String())
{
return 1;
}
if (nLength < 0)
{
return GenericCompare(String(),other.String());
}
return GenericCompareLength(String(),other.String(),nLength);
}
template <class CharType>
bool CSimpleStringBase<CharType>::MatchLastCharacter( CharType cChar ) const
{
int nFind = ReverseFind(cChar);
if (nFind < 0)
return false;
if (nFind == (int)Length()-1)
return true;
else return false;
}
template <class CharType>
bool CSimpleStringBase<CharType>::Load( HKEY hRegKey, const CharType *pszValueName, const CharType *pszDefault )
{
bool bResult = false;
Assign(pszDefault);
DWORD nType=0;
DWORD nSize=0;
LONG nRet;
if (IS_CHAR(*m_pstrData))
nRet = RegQueryValueExA( hRegKey, (LPCSTR)pszValueName, NULL, &nType, NULL, &nSize);
else nRet = RegQueryValueExW( hRegKey, (LPCWSTR)pszValueName, NULL, &nType, NULL, &nSize);
if (ERROR_SUCCESS == nRet)
{
if ((nType == REG_SZ) || (nType == REG_EXPAND_SZ))
{
// Round up to the nearest 2
nSize = ((nSize + 1) & 0xFFFFFFFE);
CharType *pstrTemp = CreateStorage(nSize / sizeof(CharType));
if (pstrTemp)
{
if (IS_CHAR(*m_pstrData))
nRet = RegQueryValueExA( hRegKey, (LPCSTR)pszValueName, NULL, &nType, (PBYTE)pstrTemp, &nSize);
else nRet = RegQueryValueExW( hRegKey, (LPCWSTR)pszValueName, NULL, &nType, (PBYTE)pstrTemp, &nSize);
if (ERROR_SUCCESS == nRet)
{
Assign(pstrTemp);
bResult = true;
}
delete pstrTemp;
}
}
}
return bResult;
}
template <class CharType>
bool CSimpleStringBase<CharType>::Store( HKEY hRegKey, const CharType *pszValueName, DWORD nType )
{
long nRet;
if (Length())
{
if (IS_CHAR(*m_pstrData))
{
nRet = RegSetValueExA( hRegKey, (LPCSTR)pszValueName, 0, nType, (PBYTE)m_pstrData, sizeof(*m_pstrData)*(Length()+1) );
}
else
{
nRet = RegSetValueExW( hRegKey, (LPCWSTR)pszValueName, 0, nType, (PBYTE)m_pstrData, sizeof(*m_pstrData)*(Length()+1) );
}
}
else
{
CharType strBlank = 0;
if (IS_CHAR(*m_pstrData))
{
nRet = RegSetValueExA( hRegKey, (LPCSTR)pszValueName, 0, nType, (PBYTE)&strBlank, sizeof(CharType) );
}
else
{
nRet = RegSetValueExW( hRegKey, (LPCWSTR)pszValueName, 0, nType, (PBYTE)&strBlank, sizeof(CharType) );
}
}
return(ERROR_SUCCESS == nRet);
}
//
// Two main typedefs
//
typedef CSimpleStringBase<char> CSimpleStringAnsi;
typedef CSimpleStringBase<wchar_t> CSimpleStringWide;
//
// LPCTSTR equivalents
//
#if defined(UNICODE) || defined(_UNICODE)
typedef CSimpleStringWide CSimpleString;
#else
typedef CSimpleStringAnsi CSimpleString;
#endif
//
// Operators
//
inline bool operator<( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
{
return a.Compare(b) < 0;
}
inline bool operator<( const CSimpleStringWide &a, const CSimpleStringWide &b )
{
return a.Compare(b) < 0;
}
inline bool operator<=( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
{
return a.Compare(b) <= 0;
}
inline bool operator<=( const CSimpleStringWide &a, const CSimpleStringWide &b )
{
return a.Compare(b) <= 0;
}
inline bool operator==( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
{
return a.Compare(b) == 0;
}
inline bool operator==( const CSimpleStringWide &a, const CSimpleStringWide &b )
{
return a.Compare(b) == 0;
}
inline bool operator!=( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
{
return a.Compare(b) != 0;
}
inline bool operator!=( const CSimpleStringWide &a, const CSimpleStringWide &b )
{
return a.Compare(b) != 0;
}
inline bool operator>=( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
{
return a.Compare(b) >= 0;
}
inline bool operator>=( const CSimpleStringWide &a, const CSimpleStringWide &b )
{
return a.Compare(b) >= 0;
}
inline bool operator>( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
{
return a.Compare(b) > 0;
}
inline bool operator>( const CSimpleStringWide &a, const CSimpleStringWide &b )
{
return a.Compare(b) > 0;
}
inline CSimpleStringWide operator+( const CSimpleStringWide &a, const CSimpleStringWide &b )
{
CSimpleStringWide strResult(a);
strResult.Concat(b);
return strResult;
}
inline CSimpleStringAnsi operator+( const CSimpleStringAnsi &a, const CSimpleStringAnsi &b )
{
CSimpleStringAnsi strResult(a);
strResult.Concat(b);
return strResult;
}
namespace CSimpleStringConvert
{
inline
CSimpleStringWide WideString( const CSimpleStringWide &strSource )
{
//
// Just return the source string
//
return strSource;
}
inline
CSimpleStringAnsi AnsiString( const CSimpleStringAnsi &strSource )
{
//
// Just return the source string
//
return strSource;
}
inline
CSimpleStringWide WideString( const CSimpleStringAnsi &strSource )
{
//
// Declare the return value. If anything goes wrong, it will contain an empty string
//
CSimpleStringWide strResult;
//
// Make sure we have a string
//
if (strSource.Length())
{
//
// Find out how long it needs to be
//
int nLength = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, strSource.String(), strSource.Length()+1, NULL, 0 );
if (nLength)
{
//
// Allocate a temporary buffer to hold the converted string
//
LPWSTR pwszBuffer = new WCHAR[nLength];
if (pwszBuffer)
{
//
// Convert the string
//
if (MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, strSource.String(), strSource.Length()+1, pwszBuffer, nLength ))
{
//
// Save the result
//
strResult = pwszBuffer;
}
//
// Free the temporary buffer
//
delete[] pwszBuffer;
}
}
}
//
// Return the result
//
return strResult;
}
inline
CSimpleStringAnsi AnsiString( const CSimpleStringWide &strSource )
{
//
// Declare the return value. If anything goes wrong, it will contain an empty string
//
CSimpleStringAnsi strResult;
//
// Make sure we have a valid string
//
if (strSource.Length())
{
//
// Figure out how long it needs to be
//
int nLength = WideCharToMultiByte( CP_ACP, 0, strSource, strSource.Length()+1, NULL, 0, NULL, NULL );
if (nLength)
{
//
// Allocate a temporary buffer to hold it
//
LPSTR pszBuffer = new CHAR[nLength];
if (pszBuffer)
{
//
// Convert the string
//
if (WideCharToMultiByte( CP_ACP, 0, strSource, strSource.Length()+1, pszBuffer, nLength, NULL, NULL ))
{
//
// Save the result
//
strResult = pszBuffer;
}
//
// Save the temporary buffer
//
delete[] pszBuffer;
}
}
}
//
// Return the result
//
return strResult;
}
inline
CSimpleStringWide FromUtf8( const CSimpleStringAnsi &strSource )
{
//
// Declare the return value. If anything goes wrong, it will contain an empty string
//
CSimpleStringWide strResult;
//
// Make sure we have a valid source string
//
if (strSource.Length())
{
//
// Find the required target string length
//
int nLength = MultiByteToWideChar( CP_UTF8, 0, strSource, strSource.Length()+1, NULL, 0 );
if (nLength)
{
//
// Allocate a temporary buffer
//
LPWSTR pwszBuffer = new WCHAR[nLength];
if (pwszBuffer)
{
//
// Convert the string
//
if (MultiByteToWideChar( CP_UTF8, 0, strSource.String(), strSource.Length()+1, pwszBuffer, nLength ))
{
//
// Save the result
//
strResult = pwszBuffer;
}
//
// Delete the temporary buffer
//
delete[] pwszBuffer;
}
}
}
//
// Return the result
//
return strResult;
}
inline
CSimpleStringAnsi ToUtf8( const CSimpleStringWide &strSource )
{
//
// Declare the return value. If anything goes wrong, it will contain an empty string
//
CSimpleStringAnsi strResult;
//
// Make sure we have a valid source string
//
if (strSource.Length())
{
int nLength = WideCharToMultiByte( CP_UTF8, 0, strSource, strSource.Length()+1, NULL, 0, NULL, NULL );
if (nLength)
{
//
// Find the required target string length
//
LPSTR pszBuffer = new CHAR[nLength];
if (pszBuffer)
{
//
// Convert the string
//
if (WideCharToMultiByte( CP_UTF8, 0, strSource, strSource.Length()+1, pszBuffer, nLength, NULL, NULL ))
{
//
// Save the result
//
strResult = pszBuffer;
}
//
// Delete the temporary buffer
//
delete[] pszBuffer;
}
}
}
//
// Return the result
//
return strResult;
}
#if defined(_UNICODE) || defined(UNICODE)
template <class CharType>
CSimpleStringWide NaturalString(const CharType &strSource)
{
return WideString(strSource);
}
#else
template <class CharType>
CSimpleStringAnsi NaturalString(const CharType &strSource)
{
return AnsiString(strSource);
}
#endif
inline CSimpleString NumberToString( int nNumber, LCID Locale=LOCALE_USER_DEFAULT )
{
//
// This turns a string into a number, like so: 3;2;0=32 or 3;0 = 3 or 1;2;3;4;5;6;0 = 123456. Got it?
//
TCHAR szDigitGrouping[32] = {0};
GetLocaleInfo( Locale, LOCALE_SGROUPING, szDigitGrouping, ARRAYSIZE(szDigitGrouping));
//
// Initialize the number format
//
NUMBERFMT NumberFormat = {0};
for (LPTSTR pszCurr = szDigitGrouping; *pszCurr && *pszCurr >= TEXT('1') && *pszCurr <= TEXT('9'); pszCurr += 2)
{
NumberFormat.Grouping *= 10;
NumberFormat.Grouping += (*pszCurr - TEXT('0'));
}
//
// Get the thousands separator
//
TCHAR szThousandsSeparator[32] = {0};
GetLocaleInfo( Locale, LOCALE_STHOUSAND, szThousandsSeparator, ARRAYSIZE(szThousandsSeparator));
NumberFormat.lpThousandSep = szThousandsSeparator;
//
// Get the decimal separator
//
TCHAR szDecimalSeparator[32] = {0};
GetLocaleInfo( Locale, LOCALE_SDECIMAL, szDecimalSeparator, ARRAYSIZE(szDecimalSeparator));
NumberFormat.lpDecimalSep = szDecimalSeparator;
//
// Create the raw number string
//
TCHAR szRawNumber[MAX_PATH] = {0};
_sntprintf( szRawNumber, ARRAYSIZE(szRawNumber)-1, TEXT("%d"), nNumber );
//
// Format the string
//
TCHAR szNumberStr[MAX_PATH] = {0};
if (GetNumberFormat( Locale, 0, szRawNumber, &NumberFormat, szNumberStr, ARRAYSIZE(szNumberStr)))
{
return szNumberStr;
}
else
{
return TEXT("");
}
}
} // End CSimpleStringConvert namespace
//
// Restore the warning state
//
#pragma warning( pop )
#endif // ifndef _SIMSTR_H_INCLUDED