|
|
/*++
Copyright (c) 2000-2001 Microsoft Corporation
Module Name:
CString.h
Abstract: A CString class, pure UNICODE internally.
History:
02/22/2001 robkenny Ported from MFC 08/14/2001 robkenny Inserted inside the ShimLib namespace. --*/
#pragma once
#include <limits.h>
namespace ShimLib {
// Use the standard exception handler, if this is not defined
// the C++ exception handler will be used instead.
//#define USE_SEH
#ifndef AFXAPI
#define AFXAPI __stdcall
#endif
#ifndef AFXISAPI
#define AFXISAPI __stdcall
#endif
#ifndef AFXISAPI_CDECL
#define AFXISAPI_CDECL __cdecl
#endif
#ifndef AFX_CDECL
#define AFX_CDECL __cdecl
#endif
#ifndef AFX_INLINE
#define AFX_INLINE __inline
#endif
#ifndef AFX_CORE_DATA
#define AFX_CORE_DATA
#endif
#ifndef AFX_DATA
#define AFX_DATA
#endif
#ifndef AFX_DATADEF
#define AFX_DATADEF
#endif
#ifndef AFX_API
#define AFX_API
#endif
#ifndef AFX_COMDAT
#define AFX_COMDAT
#endif
#ifndef AFX_STATIC
#define AFX_STATIC static
#endif
BOOL AFXAPI AfxIsValidString(LPCWSTR lpsz, int nLength = -1); BOOL AFXAPI AfxIsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite = TRUE);
inline size_t strlenChars(const char* s1) { const char * send = s1; while (*send) { // Can't use CharNextA, since User32 might not be initialized
if (IsDBCSLeadByte(*send)) { ++send; } ++send; } return send - s1; }
// Prototype for a string comparison routine.
typedef WCHAR * (__cdecl *_pfn_wcsstr)(const WCHAR * s1, const WCHAR * s2);
template <class CharType> class CStringData { public: long nRefs; // reference count
int nDataLength; // length of data (including terminator) re
int nAllocLength; // length of allocation
// CharType data[nAllocLength]
CharType* data() // CharType* to managed data
{ return (CharType*)(this+1); } };
class CString { public: #ifdef USE_SEH
// SEH Exception information
enum { eCStringNoMemoryException = STATUS_NO_MEMORY, eCStringExceptionValue = 0x12345678, }; static int ExceptionFilter(PEXCEPTION_POINTERS pexi); static const ULONG_PTR m_CStringExceptionValue;
#else
// A class used only for throwing C++ exceptions
class CStringError { public: CStringError() {}; ~CStringError() {}; }; #endif
public: static WCHAR ChNil;
public: // Constructors
// constructs empty CString
CString(); // copy constructor
CString(const CString & stringSrc); // from a single character
CString(WCHAR ch, int nRepeat = 1); // allocate nLen WCHARs space.
CString(int nLength); CString(const WCHAR * lpsz); // subset of characters from an ANSI string (converts to WCHAR)
CString(const WCHAR * lpch, int nLength);
// Create from an ANSI string
CString(LPCSTR lpsz); CString(LPCSTR lpsz, int nCharacters);
// Attributes & Operations
// get data length, number of characters
int GetLength() const; // TRUE if zero length
BOOL IsEmpty() const; // clear contents to empty
void Empty();
// return pointer to const string
operator const WCHAR * () const; const WCHAR * Get() const; // Get, return NULL if string is empty
const WCHAR * GetNIE() const; char * GetAnsi() const; // Get ANSI string: caller is responsible for freeing the string
char * ReleaseAnsi() const; // Get, return NULL if string is empty
char * GetAnsiNIE() const;
// return single character at zero-based index
WCHAR GetAt(int nIndex) const; // return single character at zero-based index
WCHAR operator[](int nIndex) const; // set a single character at zero-based index
void SetAt(int nIndex, WCHAR ch);
// overloaded assignment
// copy string content from UNICODE string
const CString & operator=(const WCHAR * lpsz); // ref-counted copy from another CString
const CString & operator=(const CString & stringSrc); // set string content to single character
const CString & operator=(WCHAR ch); // copy string content from unsigned chars
//const CString & operator=(const unsigned WCHAR* psz);
const CString& CString::operator=(LPCSTR lpsz);
// string concatenation
// concatenate from another CString
const CString & operator+=(const CString & string);
// concatenate a single character
const CString & operator+=(WCHAR ch); // concatenate a string
const CString & operator+=(const WCHAR * lpsz);
friend CString AFXAPI operator+(const CString & string1, const CString & string2); friend CString AFXAPI operator+(const CString & string, WCHAR ch); friend CString AFXAPI operator+(WCHAR ch, const CString & string); friend CString AFXAPI operator+(const CString & string, const WCHAR * lpsz); friend CString AFXAPI operator+(const WCHAR * lpsz, const CString & string);
// string comparison
// straight character comparison
int Compare(const WCHAR * lpsz) const; // compare ignoring case
int CompareNoCase(const WCHAR * lpsz) const; // NLS aware comparison, case sensitive
int Collate(const WCHAR * lpsz) const; // NLS aware comparison, case insensitive
int CollateNoCase(const WCHAR * lpsz) const;
int ComparePart(const WCHAR * lpsz, int start, int nChars) const; int ComparePartNoCase(const WCHAR * lpsz, int start, int nChars) const;
int EndsWith(const WCHAR * lpsz) const; int EndsWithNoCase(const WCHAR * lpsz) const;
// simple sub-string extraction
// return nCount characters starting at zero-based nFirst
CString Mid(int nFirst, int nCount) const; // return all characters starting at zero-based nFirst
CString Mid(int nFirst) const; // return first nCount characters in string
CString Left(int nCount) const; // return nCount characters from end of string
CString Right(int nCount) const;
// characters from beginning that are also in passed string
CString SpanIncluding(const WCHAR * lpszCharSet) const; // characters from beginning that are not also in passed string
CString SpanExcluding(const WCHAR * lpszCharSet) const;
// upper/lower/reverse conversion
// NLS aware conversion to uppercase
void MakeUpper(); // NLS aware conversion to lowercase
void MakeLower(); // reverse string right-to-left
void MakeReverse();
// trimming whitespace (either side)
// remove whitespace starting from right edge
void TrimRight(); // remove whitespace starting from left side
void TrimLeft();
// trimming anything (either side)
// remove continuous occurrences of chTarget starting from right
void TrimRight(WCHAR chTarget); // remove continuous occcurrences of characters in passed string,
// starting from right
void TrimRight(const WCHAR * lpszTargets); // remove continuous occurrences of chTarget starting from left
void TrimLeft(WCHAR chTarget); // remove continuous occcurrences of characters in
// passed string, starting from left
void TrimLeft(const WCHAR * lpszTargets);
// advanced manipulation
// replace occurrences of chOld with chNew
int Replace(WCHAR chOld, WCHAR chNew);
// replace occurrences of substring lpszOld with lpszNew;
// empty lpszNew removes instances of lpszOld
int Replace(const WCHAR * lpszOld, const WCHAR * lpszNew); // Case insensitive version of Replace
int ReplaceI(const WCHAR * lpszOld, const WCHAR * lpszNew);
// remove occurrences of chRemove
int Remove(WCHAR chRemove); // insert character at zero-based index; concatenates
// if index is past end of string
int Insert(int nIndex, WCHAR ch); // insert substring at zero-based index; concatenates
// if index is past end of string
int Insert(int nIndex, const WCHAR * pstr); // delete nCount characters starting at zero-based index
int Delete(int nIndex, int nCount = 1); // delete all characters to the right of nIndex
void Truncate(int nIndex);
// searching
// find character starting at left, -1 if not found
int Find(WCHAR ch) const; // find character starting at right
int ReverseFind(WCHAR ch) const; // find character starting at zero-based index and going right
int Find(WCHAR ch, int nStart) const; // find first instance of any character in passed string
int FindOneOf(const WCHAR * lpszCharSet) const; // find first instance of any character in passed string starting at zero-based index
int FindOneOf(const WCHAR * lpszCharSet, int nCount) const; // find first instance of substring
int Find(const WCHAR * lpszSub) const; // find first instance of substring starting at zero-based index
int Find(const WCHAR * lpszSub, int nStart) const;
// find first instance of any character *not* in passed string starting at zero-based index
int FindOneNotOf(const WCHAR * lpszCharSet, int nCount) const;
// simple formatting
// printf-like formatting using passed string
void AFX_CDECL Format(const WCHAR * lpszFormat, ...); // printf-like formatting using referenced string resource
//void AFX_CDECL Format(UINT nFormatID, ...);
// printf-like formatting using variable arguments parameter
void FormatV(const WCHAR * lpszFormat, va_list argList);
// Format routines that accept ANSI args
void AFX_CDECL Format(const char * lpszFormat, ...); void FormatV(const char * lpszFormat, va_list argList);
// formatting for localization (uses FormatMessage API)
// format using FormatMessage API on passed string
void AFX_CDECL FormatMessage(const WCHAR * lpszFormat, ...);
// input and output
#ifdef _DEBUG
friend CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CString & string); #endif
// friend CArchive& AFXAPI operator<<(CArchive& ar, const CString & string);
// friend CArchive& AFXAPI operator>>(CArchive& ar, CString & string);
// friend const CString & AFXAPI AfxGetEmptyString();
// Access to string implementation buffer as "C" character array
// get pointer to modifiable buffer at least as long as nMinBufLength
WCHAR * GetBuffer(int nMinBufLength); // release buffer, setting length to nNewLength (or to first nul if -1)
void ReleaseBuffer(int nNewLength = -1); // get pointer to modifiable buffer exactly as long as nNewLength
WCHAR * GetBufferSetLength(int nNewLength); // release memory allocated to but unused by string
void FreeExtra();
// Use LockBuffer/UnlockBuffer to turn refcounting off
// turn refcounting back on
WCHAR * LockBuffer(); // turn refcounting off
void UnlockBuffer();
// ======================================================================
// CString extensions: making life easier.
//
// Win32 API
// NOTE: The return values are different from Win32
// Return 0 for failure or number of chars for success
DWORD GetModuleFileNameW(HMODULE hModule); DWORD GetShortPathNameW(void); DWORD GetLongPathNameW(void); DWORD GetFullPathNameW(void); DWORD GetSystemDirectoryW(void); DWORD GetSystemWindowsDirectoryW(void); DWORD GetWindowsDirectoryW(void); DWORD GetTempPathW(void); DWORD GetTempFileNameW(LPCWSTR lpPathName, LPCWSTR lpPrefixString, UINT uUnique ); DWORD ExpandEnvironmentStringsW(void); DWORD GetCurrentDirectoryW(void); DWORD GetLocaleInfoW(LCID Locale, LCTYPE LCType);
// Returns NtStatus
DWORD NtReqQueryValueExW(const WCHAR * lpszKey, const WCHAR * lpszValue);
// Split this into the seperate path components
void SplitPath(CString * csDrive, CString * csDir, CString * csName, CString * csExt) const; void MakePath(const CString * csDrive, const CString * csDir, const CString * csName, const CString * csExt); // Properly append csPath onto the end of this path
void AppendPath(const WCHAR * lpszPath); // Find the trailing path component
// Return index of the last path seperator or -1 if none found
int FindLastPathComponent() const; // Get the "file" portion of this path
void GetLastPathComponent(CString & pathComponent) const; // Get what's not the "file" portion of this path
void GetNotLastPathComponent(CString & pathComponent) const; // Remove the trailing path component
void StripPath(); // Get the drive portion either c:\ or \\machine\ // Note this is different from SplitPath
void GetDrivePortion(CString & csDrivePortion) const;
// Does this string match the pattern
BOOL PatternMatch(const WCHAR * lpszPattern) const;
BOOL IsPathSep(int index) const;
// More efficient versions of above
void Mid(int nFirst, int nCount, CString & csMid) const; void Mid(int nFirst, CString & csMid) const; void Left(int nCount, CString & csLeft) const; void Right(int nCount, CString & csRight) const; void SpanIncluding(const WCHAR * lpszCharSet, CString & csSpanInc) const; void SpanExcluding(const WCHAR * lpszCharSet, CString & csSpanExc) const;
//
// End of extensions
//
// ======================================================================
// Implementation
public: ~CString(); int GetAllocLength() const;
protected: WCHAR * m_pchData; // pointer to ref counted string data
mutable char * m_pchDataAnsi; // pointer to non-UNICODE version of string
// implementation helpers
CStringData<WCHAR> * GetData() const; void Init(); void AllocCopy(CString & dest, int nCopyLen, int nCopyIndex, int nExtraLen) const; void AllocBuffer(int nLen); void AssignCopy(int nSrcLen, const WCHAR * lpszSrcData); void ConcatCopy(int nSrc1Len, const WCHAR * lpszSrc1Data, int nSrc2Len, const WCHAR * lpszSrc2Data); void ConcatInPlace(int nSrcLen, const WCHAR * lpszSrcData); void CopyBeforeWrite(); void AllocBeforeWrite(int nLen); void Release();
//============================================================
// Used by Replace and ReplaceI
int ReplaceRoutine(LPCWSTR lpszOld, LPCWSTR lpszNew, _pfn_wcsstr tcsstr);
static void Release(CStringData<WCHAR>* pData); static int SafeStrlen(const WCHAR * lpsz); static void FreeData(CStringData<WCHAR>* pData);
static int _afxInitData[]; static CStringData<WCHAR>* _afxDataNil; static const WCHAR * _afxPchNil; };
/*
End of class definitions.
Below are routines that are candidates for inlining.
*/ #ifdef afxEmptyString
#undef afxEmptyString
#endif
#define afxEmptyString ((CString &)*(CString*)&CString::_afxPchNil)
inline BOOL IsPathSep(WCHAR ch) { return ch == L'\\' || ch == L'/'; }
// Compare helpers
AFX_INLINE bool AFXAPI operator==(const CString & s1, const CString & s2) { return s1.Compare(s2) == 0; } AFX_INLINE bool AFXAPI operator==(const CString & s1, const WCHAR * s2) { return s1.Compare(s2) == 0; } AFX_INLINE bool AFXAPI operator==(const WCHAR * s1, const CString & s2) { return s2.Compare(s1) == 0; } AFX_INLINE bool AFXAPI operator!=(const CString & s1, const CString & s2) { return s1.Compare(s2) != 0; } AFX_INLINE bool AFXAPI operator!=(const CString & s1, const WCHAR * s2) { return s1.Compare(s2) != 0; } AFX_INLINE bool AFXAPI operator!=(const WCHAR * s1, const CString & s2) { return s2.Compare(s1) != 0; } AFX_INLINE bool AFXAPI operator<(const CString & s1, const CString & s2) { return s1.Compare(s2) < 0; } AFX_INLINE bool AFXAPI operator<(const CString & s1, const WCHAR * s2) { return s1.Compare(s2) < 0; } AFX_INLINE bool AFXAPI operator<(const WCHAR * s1, const CString & s2) { return s2.Compare(s1) > 0; } AFX_INLINE bool AFXAPI operator>(const CString & s1, const CString & s2) { return s1.Compare(s2) > 0; } AFX_INLINE bool AFXAPI operator>(const CString & s1, const WCHAR * s2) { return s1.Compare(s2) > 0; } AFX_INLINE bool AFXAPI operator>(const WCHAR * s1, const CString & s2) { return s2.Compare(s1) < 0; } AFX_INLINE bool AFXAPI operator<=(const CString & s1, const CString & s2) { return s1.Compare(s2) <= 0; } AFX_INLINE bool AFXAPI operator<=(const CString & s1, const WCHAR * s2) { return s1.Compare(s2) <= 0; } AFX_INLINE bool AFXAPI operator<=(const WCHAR * s1, const CString & s2) { return s2.Compare(s1) >= 0; } AFX_INLINE bool AFXAPI operator>=(const CString & s1, const CString & s2) { return s1.Compare(s2) >= 0; } AFX_INLINE bool AFXAPI operator>=(const CString & s1, const WCHAR * s2) { return s1.Compare(s2) >= 0; } AFX_INLINE bool AFXAPI operator>=(const WCHAR * s1, const CString & s2) { return s2.Compare(s1) <= 0; }
// CString
AFX_INLINE CStringData<WCHAR>* CString::GetData() const { ASSERT(m_pchData != NULL, "CString::GetData: NULL m_pchData"); return ((CStringData<WCHAR>*)m_pchData)-1; } AFX_INLINE void CString::Init() { m_pchData = afxEmptyString.m_pchData; m_pchDataAnsi = NULL; } AFX_INLINE CString::CString() { Init(); } //AFX_INLINE CString::CString(const unsigned WCHAR* lpsz) { Init(); *this = (LPCSTR)lpsz; }
//AFX_INLINE const CString & CString::operator=(const unsigned WCHAR* lpsz) { *this = (LPCSTR)lpsz; return *this; }
AFX_INLINE int CString::GetLength() const { return GetData()->nDataLength; } AFX_INLINE int CString::GetAllocLength() const { return GetData()->nAllocLength; } AFX_INLINE BOOL CString::IsEmpty() const { return GetData()->nDataLength == 0; } AFX_INLINE CString::operator const WCHAR *() const { return m_pchData; } AFX_INLINE const WCHAR * CString::Get() const { return m_pchData; } AFX_INLINE const WCHAR * CString::GetNIE() const { return IsEmpty() ? NULL : m_pchData; } AFX_INLINE char * CString::GetAnsiNIE() const { return IsEmpty() ? NULL : GetAnsi(); } AFX_INLINE char * CString::ReleaseAnsi() const { char * lpsz = GetAnsi(); m_pchDataAnsi = NULL; return lpsz; } AFX_INLINE int CString::SafeStrlen(const WCHAR * lpsz) { if ( lpsz == NULL ) return 0; else { SIZE_T ilen = wcslen(lpsz); if ( ilen <= INT_MAX ) return (int) ilen; return 0; } } AFX_INLINE void CString::FreeData(CStringData<WCHAR>* pData) { delete [] ((BYTE *)pData); } AFX_INLINE int CString::Compare(const WCHAR * lpsz) const { ASSERT(AfxIsValidString(lpsz), "CString::Compare: Invalid string"); return wcscmp(m_pchData, lpsz); } // MBCS/Unicode aware
AFX_INLINE int CString::CompareNoCase(const WCHAR * lpsz) const { ASSERT(AfxIsValidString(lpsz), "CString::CompareNoCase: Invalid string"); return _wcsicmp(m_pchData, lpsz); } // MBCS/Unicode aware
AFX_INLINE int CString::Collate(const WCHAR * lpsz) const { ASSERT(AfxIsValidString(lpsz), "CString::Collate: Invalid string"); return wcscoll(m_pchData, lpsz); } // locale sensitive
AFX_INLINE int CString::CollateNoCase(const WCHAR * lpsz) const { ASSERT(AfxIsValidString(lpsz), "CString::CollateNoCase: Invalid string"); return _wcsicoll(m_pchData, lpsz); } // locale sensitive
AFX_INLINE int CString::ComparePart(const WCHAR * lpsz, int start, int nChars) const { ASSERT(AfxIsValidString(lpsz), "CString::CompareNoCase: Invalid string"); return wcsncmp(m_pchData+start, lpsz, nChars); } // MBCS/Unicode aware
AFX_INLINE int CString::ComparePartNoCase(const WCHAR * lpsz, int start, int nChars) const { ASSERT(AfxIsValidString(lpsz), "CString::CompareNoCase: Invalid string"); return _wcsnicmp(m_pchData+start, lpsz, nChars); } // MBCS/Unicode aware
AFX_INLINE int CString::EndsWith(const WCHAR * lpsz) const { int ilen = SafeStrlen(lpsz); int start = GetLength() - ilen; if (start < 0) { start = 0; } return ComparePart(lpsz, start, ilen); } AFX_INLINE int CString::EndsWithNoCase(const WCHAR * lpsz) const { int ilen = SafeStrlen(lpsz); int start = GetLength() - ilen; if (start < 0) { start = 0; } return ComparePartNoCase(lpsz, start, ilen); }
AFX_INLINE WCHAR CString::GetAt(int nIndex) const { ASSERT(nIndex >= 0, "CString::GetAt: negative index"); ASSERT(nIndex < GetData()->nDataLength, "CString::GetData: index larger than string"); return m_pchData[nIndex]; } AFX_INLINE WCHAR CString::operator[](int nIndex) const { // same as GetAt
ASSERT(nIndex >= 0, "CString::operator[]: negative index"); ASSERT(nIndex < GetData()->nDataLength, "CString::GetData: index larger than string"); return m_pchData[nIndex]; }
AFX_INLINE BOOL CString::IsPathSep(int index) const { return ShimLib::IsPathSep(GetAt(index)); }
#undef afxEmptyString
// ************************************************************************************
// Exception filter for CString __try/__except blocks
// Return EXCEPTION_EXECUTE_HANDLER if this is a CString exception
// otherwise return EXCEPTION_CONTINUE_SEARCH
extern int CStringExceptionFilter(PEXCEPTION_POINTERS pexi);
#if defined(USE_SEH)
#define CSTRING_THROW_EXCEPTION RaiseException((DWORD)ShimLib::CString::eCStringNoMemoryException, 0, 1, &ShimLib::CString::m_CStringExceptionValue); // Continuable, CString specific memory exception
#define CSTRING_TRY __try
#define CSTRING_CATCH __except( ShimLib::CString::ExceptionFilter(GetExceptionInformation()) )
#else
// If we use the C++ exception handler, we need to make sure we have the /GX compile flag
#define CSTRING_THROW_EXCEPTION throw ShimLib::CString::CStringError();
#define CSTRING_TRY try
#define CSTRING_CATCH catch( ShimLib::CString::CStringError & /* cse */ )
#endif
}; // end of namespace ShimLib
// ************************************************************************************
namespace ShimLib {
/*++
Read a registry value into this CString. REG_EXPAND_SZ is automatically expanded and the type is changed to REG_SZ If the type is not REG_SZ or REG_EXPAND_SZ, then csRegValue.GetLength() is the number of *bytes* in the string. This is typically used to only read REG_SZ/REG_EXPAND_SZ registry values. Note: This API may only be called after SHIM_STATIC_DLLS_INITIALIZED --*/
LONG RegQueryValueExW( CString & csValue, HKEY hKeyRoot, const WCHAR * lpszKey, const WCHAR * lpszValue);
/*++
Get the ShSpecial folder name. Note: This API may only be called after SHIM_STATIC_DLLS_INITIALIZED --*/
BOOL SHGetSpecialFolderPathW( CString & csFolder, int nFolder, HWND hwndOwner = NULL );
// ************************************************************************************
/*++
A tokenizer--a replacement for strtok.
Init the class with the string and token delimiter. Call GetToken to peel off the next token.
++*/
class CStringToken { public: CStringToken(const CString & csToken, const CString & csDelimit);
// Get the next token
BOOL GetToken(CString & csNextToken);
// Count the number of remaining tokens.
int GetCount() const;
protected: int m_nPos; CString m_csToken; CString m_csDelimit;
BOOL GetToken(CString & csNextToken, int & nPos) const; };
// ************************************************************************************
/*++
A simple class to assist in command line parsing
--*/
class CStringParser { public: CStringParser(const WCHAR * lpszCl, const WCHAR * lpszSeperators); ~CStringParser();
int GetCount() const; // Return the current number of args
CString & Get(int nIndex); CString & operator[](int nIndex);
// Give ownership of the CString array to the caller
// Caller must call delete [] cstring
CString * ReleaseArgv();
protected: int m_ncsArgList; CString * m_csArgList;
void SplitSeperator(const CString & csCl, const CString & csSeperator); void SplitWhite(const CString & csCl); };
inline int CStringParser::GetCount() const { return m_ncsArgList; }
inline CString & CStringParser::Get(int nIndex) { return m_csArgList[nIndex]; }
inline CString & CStringParser::operator[](int nIndex) { return m_csArgList[nIndex]; }
inline CString * CStringParser::ReleaseArgv() { CString * argv = m_csArgList;
m_csArgList = NULL; m_ncsArgList = 0;
return argv; }
}; // end of namespace ShimLib
// ************************************************************************************
|