//***************************************************************************** // // Support Class: CSTRING // // Purpose: Handle strings for the application. CSTRING does smart memory // management for strings. // // Notes: For more information, see CompatAdmin.DOC // // History // // A-COWEN Dec 12, 2000 Wrote it. // //***************************************************************************** #define MAX_STRING_SIZE 2048 #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #include "stdarg.h" class CMemException { private: TCHAR m_szMessageHeading[100]; TCHAR m_szMessage[512] ; public: CMemException() { _tcscpy(m_szMessageHeading,TEXT("Insufficient Memory Exception")); _tcscpy(m_szMessage, TEXT("Insufficient Memory Exception")); } void SetString(TCHAR* szMsg ) { int nch = _sntprintf(m_szMessage, sizeof(m_szMessage)/sizeof(TCHAR), TEXT("%s : %s"), m_szMessageHeading, szMsg); #ifdef __DEBUG if (nch < 0) { MessageBox(NULL,TEXT("Please make the error message Short"),TEXT("Long Error Message"), MB_ICONWARNING); } #endif } TCHAR* GetString() { return m_szMessage; } }; class CSTRING { public: WCHAR * pszString; LPSTR pszANSI; public: CSTRING() { Init(); } CSTRING(CSTRING & Str) { Init(); SetString(Str.pszString); } CSTRING(LPTSTR szString) { Init(); SetString(szString); } CSTRING(UINT uID) { Init(); SetString(uID); } ~CSTRING() { Release(); } void Init() { pszString = NULL; pszANSI = NULL; } void Release(void) { if ( NULL != pszString ) delete pszString; if ( NULL != pszANSI ) delete pszANSI; pszString = NULL; pszANSI = NULL; } BOOL SetString(UINT uID) { TCHAR szString[MAX_STRING_SIZE]; if ( 0 != LoadString(GetModuleHandle(NULL), uID, szString, MAX_STRING_SIZE) ) return SetString(szString); return FALSE; } BOOL SetString(LPCTSTR szStringIn) { if ( pszString == szStringIn ) return TRUE; Release(); if ( NULL == szStringIn ) return TRUE; UINT uLen = _tcslen(szStringIn) + 1; pszString = new TCHAR[uLen]; if ( NULL != pszString ) _tcscpy(pszString,szStringIn); else { CMemException memException; throw memException; return FALSE; } return TRUE; } operator LPCSTR() { if (pszANSI != NULL) delete pszANSI; int cbSize = WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,this->pszString, -1, NULL, 0, NULL, NULL); pszANSI = (LPSTR) new CHAR [cbSize+1]; ZeroMemory(pszANSI,sizeof(pszANSI) ); if (pszANSI == NULL) { MEM_ERR; return NULL; } WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,this->pszString, -1, pszANSI, cbSize+1, NULL, NULL); return pszANSI; } operator LPWSTR() { return pszString; } operator LPCWSTR() { return pszString; } CSTRING& operator =(LPCWSTR szStringIn) { #ifndef UNICODE TCHAR szTemp[MAX_STRING_SIZE]; int nLength = lstrlenW(szStringIn); WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,szStringIn,nLength,szTemp,MAX_STRING_SIZE,NULL,NULL); szTemp[nLength] = 0; SetString(szTemp); #else SetString(szStringIn); #endif return *this; } CSTRING& operator =(CSTRING & szStringIn) { SetString(szStringIn.pszString); return *this; } BOOL operator == (CSTRING & szString) { if (NULL == pszString && NULL == szString.pszString) { return TRUE; } if ( NULL == pszString || NULL == szString.pszString) return FALSE; if ( 0 == lstrcmpi(szString.pszString,pszString) ) return TRUE; return FALSE; } BOOL operator == (LPCTSTR szString) { if (NULL == pszString && NULL == szString) { return TRUE; } if ( NULL == pszString || NULL == szString) return FALSE; if ( 0 == lstrcmpi(szString,pszString) ) return TRUE; return FALSE; } BOOL operator != (CSTRING & szString) { if (NULL == pszString && NULL == szString.pszString) { return FALSE; } if ( NULL == pszString || NULL == szString.pszString) return TRUE; if ( 0 == lstrcmpi(szString.pszString,pszString) ) return FALSE; return TRUE; } BOOL operator != (LPCTSTR szString) { if ( NULL == pszString ) return TRUE; if ( 0 == lstrcmpi(szString,pszString) ) return FALSE; return TRUE; } BOOL operator <= (CSTRING &szString) { return ( (lstrcmpi (*this,szString) <= 0 ) ? TRUE : FALSE); } BOOL operator < (CSTRING &szString) { return ( (lstrcmpi (*this,szString) < 0 ) ? TRUE : FALSE); } BOOL operator >= (CSTRING &szString) { return ( (lstrcmpi (*this,szString) >= 0 ) ? TRUE : FALSE); } BOOL operator > (CSTRING &szString) { return ( (lstrcmpi (*this,szString) > 0 ) ? TRUE : FALSE); } void __cdecl sprintf(LPCTSTR szFormat, ...) { va_list list; TCHAR szTemp[MAX_STRING_SIZE]; va_start(list,szFormat); int cch = _vsntprintf(szTemp, sizeof(szTemp)/sizeof(szTemp[0]), szFormat, list); #ifdef __DEBUG if (cch < 0) { DBGPRINT((sdlError,("CSTRING::sprintf"), ("%s"), TEXT("Too long for _vsntprintf()") ) ); } #endif SetString(szTemp); } UINT Trim() { CSTRING szTemp = *this; UINT uOrig_length = Length(); TCHAR *pStart = szTemp.pszString, *pEnd = szTemp.pszString + uOrig_length - 1; while ( *pStart== TEXT(' ') ) ++pStart; while ( (pEnd >= pStart) && ( *pEnd == TEXT(' ') ) ) --pEnd; *( pEnd + 1) = TEXT('\0');//Keep it safe UINT nLength = pEnd - pStart; ++nLength; // For the character // //If no trimming has been done, return right away // if ( uOrig_length == nLength ) { return nLength; } SetString(pStart); return ( nLength); } BOOL SetChar(int nPos, TCHAR chValue) { //Pos is 0 based int length = Length(); if (nPos >= length || length <= 0 ) { return FALSE; } this->pszString[nPos] = chValue; return TRUE; } static Trim(IN OUT LPTSTR str) { UINT uOrig_length = lstrlen(str); // Original length TCHAR *pStart = str, *pEnd = str + uOrig_length - 1; while ( *pStart== TEXT(' ') ) ++pStart; while ( (pEnd >= pStart) && ( *pEnd == TEXT(' ') ) ) --pEnd; *( pEnd + 1) = TEXT('\0');//Keep it safe UINT nLength = pEnd - pStart; ++nLength; // For the character // //If no trimming has been done, return right away // if ( uOrig_length == nLength ) { return nLength; } wmemmove(str,pStart, (nLength+1) * sizeof(TCHAR) ); // +1 for the 0 character. return (nLength); } BOOL EndsWith(LPCTSTR szSuffix) { const TCHAR* pStr = this->pszString; const TCHAR* pPos = NULL; pPos = _tcsrchr(pStr,TEXT('.')); if (pPos != NULL ) if (_tcsicmp(pPos,szSuffix) == 0 ) return TRUE; return FALSE; } PCTSTR strcat(CSTRING & szStr) { return strcat((LPCTSTR)szStr); } LPCTSTR strcat(LPCTSTR pString) { if (pString == NULL) { return pszString; } int nLengthCat = _tcslen(pString); int nLengthStr = Length(); TCHAR *szTemp = new TCHAR [nLengthStr + nLengthCat + 1]; if ( szTemp == NULL ) { CMemException memException; throw memException; return NULL; } szTemp[0] = 0; // // Copy only if pszString != NULL. Otherwise we will get mem exception/garbage value // if (nLengthStr ) _tcsncpy(szTemp, pszString, nLengthStr); _tcsncpy(szTemp+nLengthStr, pString, nLengthCat); szTemp[nLengthStr + nLengthCat] = TEXT('\0'); Release(); pszString = szTemp; return pszString; }//strcat BOOL isNULL() { return(this->pszString == NULL); } int Length(void) { if ( NULL == pszString ) return 0; return lstrlen(pszString); } void GUID(GUID & Guid) { TCHAR szGUID[80]; // NOTE: We could use StringFromGUID2, or StringfromIID, but that // would require loading OLE32.DLL. Unless we have to, avoid it. // OR you could use functions in SDBAPI _stprintf(szGUID, TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"), Guid.Data1, Guid.Data2, Guid.Data3, Guid.Data4[0], Guid.Data4[1], Guid.Data4[2], Guid.Data4[3], Guid.Data4[4], Guid.Data4[5], Guid.Data4[6], Guid.Data4[7]); SetString(szGUID); } void ShortFilename(void) { TCHAR szTemp[MAX_PATH_BUFFSIZE]; LPTSTR szHold; // BUGBUG consider using shlwapi PathFindFileName _tcscpy(szTemp,pszString); LPTSTR szWalk = szTemp; szHold = szWalk; while ( 0 != *szWalk ) { // // use _tcsrchr BUGBUG // if ( TEXT('\\') == *szWalk ) szHold = szWalk+1; ++szWalk; } SetString(szHold); } BOOL RelativeFile(CSTRING & szPath) { return RelativeFile((LPCTSTR)szPath); } // // BUGBUG : consider using shlwapi PathRelativePathTo // BOOL RelativeFile(LPCTSTR pExeFile) { LPCTSTR pMatchFile = pszString; int nLenExe = 0; int nLenMatch = 0; LPCTSTR pExe = NULL; LPCTSTR pMatch = NULL; LPTSTR pReturn = NULL; TCHAR result[MAX_PATH_BUFFSIZE]; LPTSTR resultIdx = result; BOOL bCommonBegin = FALSE; // Indicates if the paths have a common beginning *result = TEXT('\0'); // // Ensure that the beginning of the path matches between the two files // // BUGBUG this code has to go -- look into replacing this with Shlwapi Path* // // pExe = _tcschr(pExeFile, TEXT('\\')); pMatch = _tcschr(pMatchFile, TEXT('\\')); while ( pExe && pMatch ) { nLenExe = pExe - pExeFile; nLenMatch = pMatch - pMatchFile; if ( nLenExe != nLenMatch ) { break; } if ( !(_tcsnicmp(pExeFile, pMatchFile, nLenExe) == 0) ) { break; } bCommonBegin = TRUE; pExeFile = pExe + 1; pMatchFile = pMatch + 1; pExe = _tcschr(pExeFile, TEXT('\\')); pMatch = _tcschr(pMatchFile, TEXT('\\')); } // // Walk the path and put '..\' where necessary // if ( bCommonBegin ) { while ( pExe ) { _tcscpy(resultIdx, TEXT("..\\")); resultIdx = resultIdx + 3; pExeFile = pExe + 1; pExe = _tcschr(pExeFile, TEXT('\\')); } _tcscpy(resultIdx, pMatchFile); SetString(result); } else{ return FALSE; } return TRUE; } }; // // BUGBUG: consider using list class from STL // // template class CList { protected: typedef struct _tagList { T Entry; struct _tagList * pNext; } LIST, *PLIST; PLIST m_pHead; PLIST m_pCurrent; PLIST m_pFindPrev; private: PLIST Find(T * pData) { PLIST pWalk = m_pHead; m_pFindPrev = NULL; while ( NULL != pWalk ) { if ( pData == &pWalk->Entry ) return pWalk; m_pFindPrev = pWalk; pWalk = pWalk->pNext; } return NULL; } public: CList() { Init(); } ~CList() { Release(); } void Init(void) { m_pHead = NULL; m_pCurrent = NULL; } void Release(void) { while ( NULL != m_pHead ) { PLIST pHold = m_pHead->pNext; delete m_pHead; m_pHead = pHold; } } T * First(void) { m_pCurrent = m_pHead; if ( NULL == m_pHead ) return NULL; return &m_pHead->Entry; } T * Next(void) { if ( NULL != m_pCurrent ) { m_pCurrent = m_pCurrent->pNext; if ( NULL != m_pCurrent ) return &m_pCurrent->Entry; } return NULL; } BOOL Insert(T * pInsert, T * pAfter = NULL) { PLIST pNew = new LIST; if ( NULL == pNew ) return FALSE; pNew->Entry = *pInsert; if ( NULL == pAfter ) { pNew->pNext = m_pHead; m_pHead = pNew; } else { PLIST pHold = Find(pAfter); if ( NULL == pHold ) { delete pNew; return FALSE; } pNew->pNext = pHold->pNext; pHold->pNext = pNew; } return TRUE; } T * Insert(T * pAfter = NULL) { PLIST pNew = new LIST; if ( NULL == pNew ) return NULL; if ( NULL == pAfter ) { pNew->pNext = m_pHead; m_pHead = pNew; } else { PLIST pHold = Find(pAfter); if ( NULL == pHold ) { delete pNew; return NULL; } pNew->pNext = pHold->pNext; pHold->pNext = pNew; } return &pNew->Entry; } BOOL Delete(T * pEntry) { PLIST pHold = Find(pEntry); if ( NULL == pHold ) return FALSE; if ( NULL != m_pFindPrev ) { m_pFindPrev->pNext = pHold->pNext; delete pHold; } else { m_pHead = m_pHead->pNext; delete m_pHead; } m_pCurrent = NULL; return TRUE; } }; typedef struct _tagSList { CSTRING szStr; union { PVOID pExtraData; UINT uExtraData; DWORD dwExtraData; int nExtraData; }; struct _tagSList * pNext; } STRLIST, *PSTRLIST; class CSTRINGList { public: PSTRLIST m_pHead; PSTRLIST m_pTail; public: CSTRINGList() { m_pHead = NULL; m_pTail = NULL; } ~CSTRINGList() { while ( NULL != m_pHead ) { PSTRLIST pHold = m_pHead->pNext; delete m_pHead; m_pHead = pHold; } } BOOL AddString(CSTRING & Str, PVOID pExtraData = NULL) { return AddString((LPCTSTR)Str,pExtraData); } BOOL AddString(LPCTSTR pStr, PVOID pExtraData = NULL) { PSTRLIST pNew = new STRLIST; if ( NULL == pNew ) return FALSE; pNew->szStr = pStr; pNew->pExtraData = pExtraData; pNew->pNext = NULL; if ( NULL == m_pTail ) { m_pHead = m_pTail = pNew; } else { m_pTail->pNext = pNew; m_pTail = pNew; } return TRUE; } };