#include #include #include #include #include //+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1999 - 1999 // // File: cstr.h // //-------------------------------------------------------------------------- #ifndef __STR_H__ #define __STR_H__ #include #define STRAPI __stdcall struct _STR_DOUBLE { BYTE doubleBits[sizeof(double)]; }; BOOL STRAPI IsValidString(LPCSTR lpsz, int nLength); BOOL STRAPI IsValidString(LPCWSTR lpsz, int nLength); BOOL STRAPI IsValidAddressz(const void* lp, UINT nBytes, BOOL bReadWrite=TRUE); int STRAPI StrLoadString(HINSTANCE hInst, UINT nID, LPTSTR lpszBuf); class CStr { public: // Constructors CStr(); CStr(const CStr& stringSrc); CStr(TCHAR ch, int nRepeat = 1); CStr(LPCSTR lpsz); CStr(LPCWSTR lpsz); CStr(LPCTSTR lpch, int nLength); CStr(const unsigned char* psz); // Attributes & Operations // as an array of characters int GetLength() const; BOOL IsEmpty() const; void Empty(); // free up the data TCHAR GetAt(int nIndex) const; // 0 based TCHAR operator[](int nIndex) const; // same as GetAt void SetAt(int nIndex, TCHAR ch); operator LPCTSTR() const; // as a C string // overloaded assignment const CStr& operator=(const CStr& stringSrc); const CStr& operator=(TCHAR ch); #ifdef UNICODE const CStr& operator=(char ch); #endif const CStr& operator=(LPCSTR lpsz); const CStr& operator=(LPCWSTR lpsz); const CStr& operator=(const unsigned char* psz); // string concatenation const CStr& operator+=(const CStr& string); const CStr& operator+=(TCHAR ch); #ifdef UNICODE const CStr& operator+=(char ch); #endif const CStr& operator+=(LPCTSTR lpsz); friend CStr STRAPI operator+(const CStr& string1, const CStr& string2); friend CStr STRAPI operator+(const CStr& string, TCHAR ch); friend CStr STRAPI operator+(TCHAR ch, const CStr& string); #ifdef UNICODE friend CStr STRAPI operator+(const CStr& string, char ch); friend CStr STRAPI operator+(char ch, const CStr& string); #endif friend CStr STRAPI operator+(const CStr& string, LPCTSTR lpsz); friend CStr STRAPI operator+(LPCTSTR lpsz, const CStr& string); // string comparison int Compare(LPCTSTR lpsz) const; // straight character int CompareNoCase(LPCTSTR lpsz) const; // ignore case int Collate(LPCTSTR lpsz) const; // NLS aware // simple sub-string extraction CStr Mid(int nFirst, int nCount) const; CStr Mid(int nFirst) const; CStr Left(int nCount) const; CStr Right(int nCount) const; CStr SpanIncluding(LPCTSTR lpszCharSet) const; CStr SpanExcluding(LPCTSTR lpszCharSet) const; // upper/lower/reverse conversion void MakeUpper(); void MakeLower(); void MakeReverse(); // trimming whitespace (either side) void TrimRight(); void TrimLeft(); // searching (return starting index, or -1 if not found) // look for a single character match int Find(TCHAR ch) const; // like "C" strchr int ReverseFind(TCHAR ch) const; int FindOneOf(LPCTSTR lpszCharSet) const; // look for a specific sub-string int Find(LPCTSTR lpszSub) const; // like "C" strstr // simple formatting void Format(LPCTSTR lpszFormat, ...); #ifndef _MAC // formatting for localization (uses FormatMessage API) void __cdecl FormatMessage(LPCTSTR lpszFormat, ...); void __cdecl FormatMessage(UINT nFormatID, ...); #endif // Windows support BOOL LoadString(HINSTANCE hInst, UINT nID); // load from string resource // 255 chars max #ifndef UNICODE // ANSI <-> OEM support (convert string in place) void AnsiToOem(); void OemToAnsi(); #endif BSTR AllocSysString(); BSTR SetSysString(BSTR* pbstr); // Access to string implementation buffer as "C" character array LPTSTR GetBuffer(int nMinBufLength); void ReleaseBuffer(int nNewLength = -1); LPTSTR GetBufferSetLength(int nNewLength); void FreeExtra(); // Implementation public: ~CStr(); int GetAllocLength() const; protected: // lengths/sizes in characters // (note: an extra character is always allocated) LPTSTR m_pchData; // actual string (zero terminated) int m_nDataLength; // does not include terminating 0 int m_nAllocLength; // does not include terminating 0 // implementation helpers void Init(); void AllocCopy(CStr& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const; void AllocBuffer(int nLen); void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData); void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data); void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData); static void SafeDelete(LPTSTR lpch); static int SafeStrlen(LPCTSTR lpsz); }; // Compare helpers BOOL STRAPI operator==(const CStr& s1, const CStr& s2); BOOL STRAPI operator==(const CStr& s1, LPCTSTR s2); BOOL STRAPI operator==(LPCTSTR s1, const CStr& s2); BOOL STRAPI operator!=(const CStr& s1, const CStr& s2); BOOL STRAPI operator!=(const CStr& s1, LPCTSTR s2); BOOL STRAPI operator!=(LPCTSTR s1, const CStr& s2); BOOL STRAPI operator<(const CStr& s1, const CStr& s2); BOOL STRAPI operator<(const CStr& s1, LPCTSTR s2); BOOL STRAPI operator<(LPCTSTR s1, const CStr& s2); BOOL STRAPI operator>(const CStr& s1, const CStr& s2); BOOL STRAPI operator>(const CStr& s1, LPCTSTR s2); BOOL STRAPI operator>(LPCTSTR s1, const CStr& s2); BOOL STRAPI operator<=(const CStr& s1, const CStr& s2); BOOL STRAPI operator<=(const CStr& s1, LPCTSTR s2); BOOL STRAPI operator<=(LPCTSTR s1, const CStr& s2); BOOL STRAPI operator>=(const CStr& s1, const CStr& s2); BOOL STRAPI operator>=(const CStr& s1, LPCTSTR s2); BOOL STRAPI operator>=(LPCTSTR s1, const CStr& s2); // conversion helpers int mmc_wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count); int mmc_mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count); // Globals extern const CStr strEmptyString; extern TCHAR strChNil; // Compiler doesn't inline for DBG ///////////////////////////////////////////////////////////////////////////// // Inline function declarations inline int CStr::SafeStrlen(LPCTSTR lpsz) { return (lpsz == NULL) ? NULL : _tcslen(lpsz); } inline CStr::CStr(const unsigned char* lpsz) { Init(); *this = (LPCSTR)lpsz; } inline const CStr& CStr::operator=(const unsigned char* lpsz) { *this = (LPCSTR)lpsz; return *this; } #ifdef _UNICODE inline const CStr& CStr::operator+=(char ch) { *this += (TCHAR)ch; return *this; } inline const CStr& CStr::operator=(char ch) { *this = (TCHAR)ch; return *this; } inline CStr STRAPI operator+(const CStr& string, char ch) { return string + (TCHAR)ch; } inline CStr STRAPI operator+(char ch, const CStr& string) { return (TCHAR)ch + string; } #endif inline int CStr::GetLength() const { return m_nDataLength; } inline int CStr::GetAllocLength() const { return m_nAllocLength; } inline BOOL CStr::IsEmpty() const { return m_nDataLength == 0; } inline CStr::operator LPCTSTR() const { return (LPCTSTR)m_pchData; } // String support (windows specific) inline int CStr::Compare(LPCTSTR lpsz) const { return _tcscmp(m_pchData, lpsz); } // MBCS/Unicode aware inline int CStr::CompareNoCase(LPCTSTR lpsz) const { return _tcsicmp(m_pchData, lpsz); } // MBCS/Unicode aware // CStr::Collate is often slower than Compare but is MBSC/Unicode // aware as well as locale-sensitive with respect to sort order. inline int CStr::Collate(LPCTSTR lpsz) const { return _tcscoll(m_pchData, lpsz); } // locale sensitive inline void CStr::MakeUpper() { ::CharUpper(m_pchData); } inline void CStr::MakeLower() { ::CharLower(m_pchData); } inline void CStr::MakeReverse() { _tcsrev(m_pchData); } inline TCHAR CStr::GetAt(int nIndex) const { ASSERT(nIndex >= 0); ASSERT(nIndex < m_nDataLength); return m_pchData[nIndex]; } inline TCHAR CStr::operator[](int nIndex) const { // same as GetAt ASSERT(nIndex >= 0); ASSERT(nIndex < m_nDataLength); return m_pchData[nIndex]; } inline void CStr::SetAt(int nIndex, TCHAR ch) { ASSERT(nIndex >= 0); ASSERT(nIndex < m_nDataLength); ASSERT(ch != 0); m_pchData[nIndex] = ch; } inline BOOL STRAPI operator==(const CStr& s1, const CStr& s2) { return s1.Compare(s2) == 0; } inline BOOL STRAPI operator==(const CStr& s1, LPCTSTR s2) { return s1.Compare(s2) == 0; } inline BOOL STRAPI operator==(LPCTSTR s1, const CStr& s2) { return s2.Compare(s1) == 0; } inline BOOL STRAPI operator!=(const CStr& s1, const CStr& s2) { return s1.Compare(s2) != 0; } inline BOOL STRAPI operator!=(const CStr& s1, LPCTSTR s2) { return s1.Compare(s2) != 0; } inline BOOL STRAPI operator!=(LPCTSTR s1, const CStr& s2) { return s2.Compare(s1) != 0; } inline BOOL STRAPI operator<(const CStr& s1, const CStr& s2) { return s1.Compare(s2) < 0; } inline BOOL STRAPI operator<(const CStr& s1, LPCTSTR s2) { return s1.Compare(s2) < 0; } inline BOOL STRAPI operator<(LPCTSTR s1, const CStr& s2) { return s2.Compare(s1) > 0; } inline BOOL STRAPI operator>(const CStr& s1, const CStr& s2) { return s1.Compare(s2) > 0; } inline BOOL STRAPI operator>(const CStr& s1, LPCTSTR s2) { return s1.Compare(s2) > 0; } inline BOOL STRAPI operator>(LPCTSTR s1, const CStr& s2) { return s2.Compare(s1) < 0; } inline BOOL STRAPI operator<=(const CStr& s1, const CStr& s2) { return s1.Compare(s2) <= 0; } inline BOOL STRAPI operator<=(const CStr& s1, LPCTSTR s2) { return s1.Compare(s2) <= 0; } inline BOOL STRAPI operator<=(LPCTSTR s1, const CStr& s2) { return s2.Compare(s1) >= 0; } inline BOOL STRAPI operator>=(const CStr& s1, const CStr& s2) { return s1.Compare(s2) >= 0; } inline BOOL STRAPI operator>=(const CStr& s1, LPCTSTR s2) { return s1.Compare(s2) >= 0; } inline BOOL STRAPI operator>=(LPCTSTR s1, const CStr& s2) { return s2.Compare(s1) <= 0; } #ifndef UNICODE inline void CStr::AnsiToOem() { ::AnsiToOem(m_pchData, m_pchData); } inline void CStr::OemToAnsi() { ::OemToAnsi(m_pchData, m_pchData); } #endif // UNICODE // General Exception for memory class MemoryException { public: MemoryException(){} void DisplayMessage() { ::MessageBox(NULL, _T("Memory Exception"), _T("System Out of Memory"), MB_OK|MB_ICONSTOP); } }; // General Exception for memory class ResourceException { public: ResourceException() { ::MessageBox(NULL, _T("Resource Exception"), _T("Unable to Load Resource"), MB_OK|MB_ICONSTOP); } }; #endif // __STR_H__ ///////////////////////////////////////////////////////////////////////////// //____________________________________________________________________________ // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1995 - 1999 // // File: macros.h // // Contents: Useful macros // // Macros: ARRAYLEN // // BREAK_ON_FAIL(hresult) // BREAK_ON_FAIL(hresult) // // DECLARE_IUNKNOWN_METHODS // DECLARE_STANDARD_IUNKNOWN // IMPLEMENT_STANDARD_IUNKNOWN // // SAFE_RELEASE // // DECLARE_SAFE_INTERFACE_PTR_MEMBERS // // History: 6/3/1996 RaviR Created // 7/23/1996 JonN Added exception handling macros // //____________________________________________________________________________ #ifndef _MACROS_H_ #define _MACROS_H_ //____________________________________________________________________________ // // Macro: ARRAYLEN // // Purpose: To determine the length of an array. //____________________________________________________________________________ // #define ARRAYLEN(a) (sizeof(a) / sizeof((a)[0])) //____________________________________________________________________________ // // Macros: BREAK_ON_FAIL(hresult), BREAK_ON_ERROR(lastError) // // Purpose: To break out of a loop on error. //____________________________________________________________________________ // #define BREAK_ON_FAIL(hr) if (FAILED(hr)) { break; } else 1; #define BREAK_ON_ERROR(lr) if (lr != ERROR_SUCCESS) { break; } else 1; #define RETURN_ON_FAIL(hr) if (FAILED(hr)) { return(hr); } else 1; #define THROW_ON_FAIL(hr) if (FAILED(hr)) { _com_issue_error(hr); } else 1; //____________________________________________________________________________ // // Macros: DwordAlign(n) //____________________________________________________________________________ // #define DwordAlign(n) (((n) + 3) & ~3) //____________________________________________________________________________ // // Macros: SAFE_RELEASE //____________________________________________________________________________ // #ifndef SAFE_RELEASE #define SAFE_RELEASE(punk) \ if (punk != NULL) \ { \ punk##->Release(); \ punk = NULL; \ } \ else \ { \ TRACE(_T("Release called on NULL interface ptr")); \ } #endif // SAFE_RELEASE //____________________________________________________________________________ // // Macros: IF_NULL_RETURN_INVALIDARG //____________________________________________________________________________ // #define IF_NULL_RETURN_INVALIDARG(x) \ { \ ASSERT((x) != NULL); \ if ((x) == NULL) \ return E_INVALIDARG; \ } #define IF_NULL_RETURN_INVALIDARG2(x, y) \ IF_NULL_RETURN_INVALIDARG(x) \ IF_NULL_RETURN_INVALIDARG(y) #define IF_NULL_RETURN_INVALIDARG3(x, y, z) \ IF_NULL_RETURN_INVALIDARG(x) \ IF_NULL_RETURN_INVALIDARG(y) \ IF_NULL_RETURN_INVALIDARG(z) #endif // _MACROS_H_ HRESULT ExtractString( IDataObject* piDataObject, CLIPFORMAT cfClipFormat, CStr* pstr, // OUT: Pointer to CStr to store data DWORD cchMaxLength) { IF_NULL_RETURN_INVALIDARG2( piDataObject, pstr ); ASSERT( cchMaxLength > 0 ); HRESULT hr = S_OK; FORMATETC formatetc = {cfClipFormat, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL}; stgmedium.hGlobal = ::GlobalAlloc(GPTR, sizeof(WCHAR)*cchMaxLength); do // false loop { if (NULL == stgmedium.hGlobal) { ASSERT(FALSE); ////AfxThrowMemoryException(); hr = E_OUTOFMEMORY; break; } hr = piDataObject->GetDataHere( &formatetc, &stgmedium ); if ( FAILED(hr) ) { // This failure happens when 'searching' for // clipboard format supported by the IDataObject. // t-danmo (24-Oct-96) // Skipping ASSERT( FALSE ); break; } LPWSTR pszNewData = reinterpret_cast(stgmedium.hGlobal); if (NULL == pszNewData) { ASSERT(FALSE); hr = E_UNEXPECTED; break; } pszNewData[cchMaxLength-1] = L'\0'; // just to be safe USES_CONVERSION; *pstr = OLE2T(pszNewData); } while (FALSE); // false loop if (NULL != stgmedium.hGlobal) { #if (_MSC_VER >= 1200) #pragma warning (push) #endif #pragma warning(disable: 4553) // "==" operator has no effect VERIFY( NULL == ::GlobalFree(stgmedium.hGlobal) ); #if (_MSC_VER >= 1200) #pragma warning (pop) #endif } return hr; } // ExtractString() TCHAR strChNil = '\0'; void CStr::Init() { m_nDataLength = m_nAllocLength = 0; m_pchData = (LPTSTR)&strChNil; } // declared static void CStr::SafeDelete(LPTSTR lpch) { if (lpch != (LPTSTR)&strChNil) delete[] lpch; } ////////////////////////////////////////////////////////////////////////////// // Construction/Destruction // begin_extractstring CStr::CStr() { Init(); } CStr::CStr(const CStr& stringSrc) { // if constructing a String from another String, we make a copy of the // original string data to enforce value semantics (i.e. each string // gets a copy of its own stringSrc.AllocCopy(*this, stringSrc.m_nDataLength, 0, 0); } void CStr::AllocBuffer(int nLen) // always allocate one extra character for '\0' termination // assumes [optimistically] that data length will equal allocation length { ASSERT(nLen >= 0); if (nLen == 0) { Init(); } else { m_pchData = new TCHAR[nLen+1]; //REVIEW may throw an exception m_pchData[nLen] = '\0'; m_nDataLength = nLen; m_nAllocLength = nLen; } } void CStr::Empty() { SafeDelete(m_pchData); Init(); ASSERT(m_nDataLength == 0); ASSERT(m_nAllocLength == 0); } CStr::~CStr() // free any attached data { SafeDelete(m_pchData); } ////////////////////////////////////////////////////////////////////////////// // Helpers for the rest of the implementation static inline int SafeStrlen(LPCTSTR lpsz) { ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE)); return (lpsz == NULL) ? 0 : lstrlen(lpsz); } void CStr::AllocCopy(CStr& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const { // will clone the data attached to this string // allocating 'nExtraLen' characters // Places results in uninitialized string 'dest' // Will copy the part or all of original data to start of new string int nNewLen = nCopyLen + nExtraLen; if (nNewLen == 0) { dest.Init(); } else { dest.AllocBuffer(nNewLen); memcpy(dest.m_pchData, &m_pchData[nCopyIndex], nCopyLen*sizeof(TCHAR)); } } ////////////////////////////////////////////////////////////////////////////// // More sophisticated construction CStr::CStr(LPCTSTR lpsz) { if (lpsz != NULL && (DWORD_PTR)lpsz <= 0xffff) { Init(); UINT nID = LOWORD((DWORD_PTR)lpsz); // REVIEW hInstance for LoadString(hInst, nID); } else { int nLen; if ((nLen = SafeStrlen(lpsz)) == 0) Init(); else { AllocBuffer(nLen); memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR)); } } } ////////////////////////////////////////////////////////////////////////////// // Assignment operators // All assign a new value to the string // (a) first see if the buffer is big enough // (b) if enough room, copy on top of old buffer, set size and type // (c) otherwise free old string data, and create a new one // // All routines return the new string (but as a 'const CStr&' so that // assigning it again will cause a copy, eg: s1 = s2 = "hi there". // void CStr::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData) { // check if it will fit if (nSrcLen > m_nAllocLength) { // it won't fit, allocate another one Empty(); AllocBuffer(nSrcLen); } if (nSrcLen != 0) memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR)); m_nDataLength = nSrcLen; m_pchData[nSrcLen] = '\0'; } const CStr& CStr::operator=(const CStr& stringSrc) { AssignCopy(stringSrc.m_nDataLength, stringSrc.m_pchData); return *this; } const CStr& CStr::operator=(LPCTSTR lpsz) { ASSERT(lpsz == NULL || IsValidString(lpsz, FALSE)); AssignCopy(SafeStrlen(lpsz), lpsz); return *this; } HRESULT ExtractString( IDataObject* piDataObject, CLIPFORMAT cfClipFormat, CString* pstr, // OUT: Pointer to CStr to store data DWORD cchMaxLength) { if (pstr == NULL) return E_POINTER; CStr cstr(*pstr); HRESULT hr = ExtractString(piDataObject, cfClipFormat, &cstr, cchMaxLength); *pstr = cstr; return hr; } BOOL STRAPI IsValidString(LPCSTR lpsz, int nLength) { if (lpsz == NULL) return FALSE; return ::IsBadStringPtrA(lpsz, nLength) == 0; } BOOL STRAPI IsValidString(LPCWSTR lpsz, int nLength) { if (lpsz == NULL) return FALSE; return ::IsBadStringPtrW(lpsz, nLength) == 0; }