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.
718 lines
25 KiB
718 lines
25 KiB
/*++
|
|
|
|
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
|
|
|
|
|
|
// ************************************************************************************
|