#pragma once // Two flavors of allocator. #define CRT_ALLOC 0 #define COM_ALLOC 1 // Buffer alloc chungks must be a power of 2. #define BUFFER_ALLOCATION_SIZE 0x40 #define ROUNDUPTOPOWEROF2(bytesize, powerof2) (((bytesize) + (powerof2) - 1) & ~((powerof2) - 1)) // MAXCHARCOUNT is nice for simple overflow calculations; it allows rollover checks only on the character // counts themselves and not also again on the underlying byte counts passed to memcpy. // Find the right include for this. #define ULONG_MAX 0xffffffff #define MAXCHARCOUNT (ULONG_MAX / sizeof(WCHAR)) #define BADMATH HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW) #define OVERFLOW_CHECK1(_x) do { if (_x > MAXCHARCOUNT) { _hr = BADMATH; ASSERT(PREDICATE); goto exit; } } while (0) #define OVERFLOW_CHECK2(_x, _y) do { if ((_y > MAXCHARCOUNT) || (_y < _x)) { _hr = BADMATH; ASSERT(PREDICATE); goto exit; } } while (0) #define DEFAULT_STACK_SIZE 32 ////////////////////////////////////////////////////////////////////////////// // // CBaseString // ////////////////////////////////////////////////////////////////////////////// template class CBaseString { public: enum AllocFlags { COM_Allocator = 0, CRT_Allocator }; enum HashFlags { CaseInsensitive = 0, CaseSensitive }; DWORD _dwSig; HRESULT _hr; WCHAR _wz[T]; LPWSTR _pwz; // Str ptr. DWORD _cc; // String length DWORD _ccBuf; // Buffer length AllocFlags _eAlloc; // Allocator BOOL _fLocked; // Accessor lock // ctor CBaseString(); // ctor w/ allocator CBaseString(AllocFlags eAlloc); // dtor ~CBaseString(); operator LPCWSTR ( ) const; // Used by accessor. HRESULT Lock(); HRESULT UnLock(); // Allocations HRESULT ResizeBuffer(DWORD ccNew); // Deallocations VOID FreeBuffer(); // Assume control for a buffer. HRESULT TakeOwnership(WCHAR* pwz, DWORD cc = 0); // Release control. HRESULT ReleaseOwnership(LPWSTR *ppwz); // Direct copy assign from string. HRESULT Assign(LPCWSTR pwzSource, DWORD ccSource = 0); // Direct copy assign from CBaseString HRESULT Assign(CBaseString& sSource); // Append given wchar string. HRESULT Append(LPCWSTR pwzSource, DWORD ccSource = 0); // Append given CBaseString HRESULT Append(CBaseString& sSource); // Append given number (DWORD) HRESULT Append(DWORD dwValue); // Compare to string HRESULT CompareString(CBaseString& s); HRESULT CompareString(LPCWSTR pwz); HRESULT LastElement(CBaseString &sSource); HRESULT RemoveLastElement(); HRESULT SplitLastElement(WCHAR wcSeparator, CBaseString &sSource); HRESULT StartsWith(LPCWSTR pwzPrefix); HRESULT EndsWith(LPCWSTR pwzSuffix); DWORD ByteCount(); DWORD CharCount(); // / -> \ in string HRESULT PathNormalize(); HRESULT GetHash(LPDWORD pdwhash, DWORD dwFlags); HRESULT Get65599Hash(LPDWORD pdwHash, DWORD dwFlags); }; //----------------------------------------------------------------------------- // ctor //----------------------------------------------------------------------------- template CBaseString::CBaseString() { _dwSig = 'NRTS'; _wz[0] = 'L\0'; _pwz = NULL; _cc = 0; _ccBuf = 0; _eAlloc = CRT_Allocator; _hr = S_OK; _fLocked = FALSE; } //----------------------------------------------------------------------------- // ctor w/ allocator //----------------------------------------------------------------------------- template CBaseString::CBaseString(AllocFlags eAlloc) { _dwSig = 'NRTS'; _wz[0] = L'\0'; _pwz = NULL; _cc = 0; _ccBuf = 0; _eAlloc = eAlloc; _hr = S_OK; _fLocked = FALSE; } //----------------------------------------------------------------------------- // dtor //----------------------------------------------------------------------------- template CBaseString::~CBaseString() { FreeBuffer(); } //----------------------------------------------------------------------------- // operator LPCWSTR //----------------------------------------------------------------------------- template CBaseString::operator LPCWSTR () const { return _pwz; } //----------------------------------------------------------------------------- // Lock //----------------------------------------------------------------------------- templateHRESULT CBaseString::Lock() { IF_FALSE_EXIT(_fLocked != TRUE, E_UNEXPECTED); _fLocked = TRUE; exit: return _hr; } //----------------------------------------------------------------------------- // Lock //----------------------------------------------------------------------------- template HRESULT CBaseString::UnLock() { IF_FALSE_EXIT(_fLocked != FALSE, E_UNEXPECTED); _fLocked = FALSE; exit: return _hr; } //----------------------------------------------------------------------------- // ResizeBuffer // NOTICE: Does not decrease buffer size. //----------------------------------------------------------------------------- template HRESULT CBaseString::ResizeBuffer(DWORD ccNew) { LPWSTR pwzNew = NULL; DWORD ccOriginal = 0; DWORD ccNewRoundUp = 0; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_TRUE_EXIT((ccNew <= _ccBuf), S_OK); if (!_pwz && (ccNew <= T)) { _pwz = _wz; _ccBuf = T; goto exit; } ccNewRoundUp = ROUNDUPTOPOWEROF2(ccNew, BUFFER_ALLOCATION_SIZE); OVERFLOW_CHECK2(ccNew, ccNewRoundUp); if (_eAlloc == CRT_Allocator) pwzNew = new WCHAR[ccNewRoundUp]; else if (_eAlloc == COM_Allocator) pwzNew = (LPWSTR) CoTaskMemAlloc(ccNewRoundUp * sizeof(WCHAR)); IF_ALLOC_FAILED_EXIT(pwzNew); if (_pwz && _cc) memcpy(pwzNew, _pwz, _cc * sizeof(WCHAR)); ccOriginal = _cc; FreeBuffer(); _pwz = pwzNew; _cc = ccOriginal; _ccBuf = ccNewRoundUp; exit: return _hr; } //----------------------------------------------------------------------------- // FreeBuffer //----------------------------------------------------------------------------- template VOID CBaseString::FreeBuffer() { IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); if (_pwz == _wz) goto exit; if (_eAlloc == CRT_Allocator) { SAFEDELETEARRAY(_pwz); } else if (_eAlloc == COM_Allocator) { if (_pwz) CoTaskMemFree(_pwz); } exit: _pwz = NULL; _cc = 0; _ccBuf = 0; return; } //----------------------------------------------------------------------------- // TakeOwnership // // Working assumption here is that incoming buffer size if not // specified is equal to strlen + 1. If it's bigger, that's fine but // we won't know about the extra. //----------------------------------------------------------------------------- template HRESULT CBaseString::TakeOwnership(WCHAR* pwz, DWORD cc) { DWORD ccNew = 0, ccLen = 0; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_NULL_EXIT(pwz, E_INVALIDARG); OVERFLOW_CHECK1(cc); if (cc) { ccNew = cc; } else { ccLen = lstrlen(pwz); ccNew = ccLen+1; OVERFLOW_CHECK2(ccLen, ccNew); } FreeBuffer(); _pwz = pwz; _cc = _ccBuf = ccNew; exit: return _hr; } //----------------------------------------------------------------------------- // ReleaseOwnership //----------------------------------------------------------------------------- templateHRESULT CBaseString::ReleaseOwnership(LPWSTR *ppwz) { IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); if (_pwz == _wz) { IF_ALLOC_FAILED_EXIT(*ppwz = new WCHAR[_ccBuf]); memcpy(*ppwz, _wz, _ccBuf * sizeof(WCHAR)); } else *ppwz = _pwz; _pwz = NULL; _cc = 0; _ccBuf = 0; exit: return _hr; } //----------------------------------------------------------------------------- // Assign //----------------------------------------------------------------------------- template HRESULT CBaseString::Assign(LPCWSTR pwzSource, DWORD ccSource) { DWORD ccSourceLen = 0; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_NULL_EXIT(pwzSource, E_INVALIDARG); OVERFLOW_CHECK1(ccSource); if (!ccSource) { ccSourceLen = lstrlen(pwzSource); ccSource = ccSourceLen + 1; OVERFLOW_CHECK2(ccSourceLen, ccSource); } IF_FAILED_EXIT(ResizeBuffer(ccSource)); _cc = ccSource; memcpy(_pwz, pwzSource, _cc * sizeof(WCHAR)); exit: return _hr; } //----------------------------------------------------------------------------- // Assign //----------------------------------------------------------------------------- template HRESULT CBaseString::Assign(CBaseString& sSource) { return Assign(sSource._pwz, sSource._cc); } //----------------------------------------------------------------------------- // Append //----------------------------------------------------------------------------- template HRESULT CBaseString::Append(LPCWSTR pwzSource, DWORD ccSource) { DWORD ccRequired = 0, ccSourceLen = 0; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_NULL_EXIT(pwzSource, E_INVALIDARG); OVERFLOW_CHECK1(ccSource); if (!ccSource) { ccSourceLen = lstrlen(pwzSource); ccSource = ccSourceLen + 1; OVERFLOW_CHECK2(ccSourceLen, ccSource); } if (_cc) { ccRequired = _cc -1 + ccSource; OVERFLOW_CHECK2(ccSource, ccRequired); } else { ccRequired = ccSource; } IF_FAILED_EXIT(ResizeBuffer(ccRequired)); memcpy(_pwz + (_cc ? _cc-1 : 0), pwzSource, ccSource * sizeof(WCHAR)); _cc = ccRequired; exit: return _hr; } //----------------------------------------------------------------------------- // Append //----------------------------------------------------------------------------- template HRESULT CBaseString::Append(CBaseString& sSource) { IF_NULL_EXIT(sSource._pwz, E_INVALIDARG); IF_FAILED_EXIT(Append(sSource._pwz, sSource._cc)); exit: return _hr; } //----------------------------------------------------------------------------- // Append //----------------------------------------------------------------------------- template HRESULT CBaseString::Append(DWORD dwValue) { LPWSTR pwzBuf = NULL; // ISSUE-05/31/02-felixybc optimize by using internal buffer if not currently used // 2^32 has 10 digits(base 10) + sign + '\0' = 12 WCHAR IF_ALLOC_FAILED_EXIT(pwzBuf = new WCHAR[12]); pwzBuf[0] = L'\0'; // ISSUE- check error? _ultow(dwValue, pwzBuf, 10); IF_FAILED_EXIT(Append(pwzBuf)); exit: SAFEDELETEARRAY(pwzBuf); return _hr; } //----------------------------------------------------------------------------- // CompareString //----------------------------------------------------------------------------- template HRESULT CBaseString::CompareString(CBaseString& s) { return CompareString(s._pwz); } //----------------------------------------------------------------------------- // CompareString //----------------------------------------------------------------------------- template HRESULT CBaseString::CompareString(LPCWSTR pwz) { DWORD iCompare = 0; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); iCompare = ::CompareString(LOCALE_USER_DEFAULT, 0, _pwz, -1, pwz, -1); IF_WIN32_FALSE_EXIT(iCompare); _hr = (iCompare == CSTR_EQUAL) ? S_OK : S_FALSE; exit: return _hr; } //----------------------------------------------------------------------------- // LastElement //----------------------------------------------------------------------------- template HRESULT CBaseString::LastElement(CBaseString &sSource) { LPWSTR pwz = NULL; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_FALSE_EXIT((_pwz && _cc), E_UNEXPECTED); pwz = _pwz + _cc - 1; while (1) { pwz = CharPrev(_pwz, pwz); if (*pwz == L'\\' || *pwz == L'/') break; IF_FALSE_EXIT((pwz != _pwz), E_FAIL); } sSource.Assign(pwz+1); exit: return _hr; } //----------------------------------------------------------------------------- // RemoveLastElement // remove last element, also the L'\\' or L'/' //----------------------------------------------------------------------------- template HRESULT CBaseString::RemoveLastElement() { DWORD cc = 0; LPWSTR pwz = NULL; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_FALSE_EXIT((_pwz && _cc), E_UNEXPECTED); pwz = _pwz + _cc - 1; while (1) { pwz = CharPrev(_pwz, pwz); cc++; if (*pwz == L'\\' || *pwz == L'/' || (pwz == _pwz) ) break; // IF_FALSE_EXIT((pwz != _pwz), E_FAIL); } *pwz = L'\0'; _cc -= cc; exit: return _hr; } //----------------------------------------------------------------------------- // SplitLastElement // remove last element, also the separator //----------------------------------------------------------------------------- template HRESULT CBaseString::SplitLastElement(WCHAR wcSeparator, CBaseString &sSource) { DWORD cc = 0; LPWSTR pwz = NULL; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_FALSE_EXIT((_pwz && _cc), E_UNEXPECTED); pwz = _pwz + _cc - 1; while (1) { pwz = CharPrev(_pwz, pwz); cc++; if (*pwz == wcSeparator) break; IF_FALSE_EXIT((pwz != _pwz), E_FAIL); } sSource.Assign(pwz+1); *pwz = L'\0'; _cc -= cc; exit: return _hr; } //----------------------------------------------------------------------------- // ByteCount //----------------------------------------------------------------------------- template DWORD CBaseString::ByteCount() { IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); exit: return (_cc * sizeof(WCHAR)); } //----------------------------------------------------------------------------- // CharCount //----------------------------------------------------------------------------- template DWORD CBaseString::CharCount() { IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); exit: return _cc; } //----------------------------------------------------------------------------- // StartsWith //----------------------------------------------------------------------------- template HRESULT CBaseString::StartsWith(LPCWSTR pwzPrefix) { DWORD ccPrefixLen = 0, iCompare = 0; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_FALSE_EXIT((_pwz && _cc), E_UNEXPECTED); IF_NULL_EXIT(pwzPrefix, E_INVALIDARG); ccPrefixLen = lstrlen(pwzPrefix); IF_FALSE_EXIT((ccPrefixLen < _cc-1), E_INVALIDARG); iCompare = ::CompareString(LOCALE_USER_DEFAULT, 0, _pwz, ccPrefixLen, pwzPrefix, ccPrefixLen); IF_WIN32_FALSE_EXIT(iCompare); _hr = (iCompare == CSTR_EQUAL) ? S_OK : S_FALSE; exit: return _hr; } //----------------------------------------------------------------------------- // EndsWith //----------------------------------------------------------------------------- template HRESULT CBaseString::EndsWith(LPCWSTR pwzSuffix) { DWORD ccSuffixLen = 0, iCompare = 0; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_FALSE_EXIT((_pwz && _cc), E_UNEXPECTED); IF_NULL_EXIT(pwzSuffix, E_INVALIDARG); ccSuffixLen = lstrlen(pwzSuffix); IF_FALSE_EXIT((ccSuffixLen < _cc-1), E_INVALIDARG); iCompare = ::CompareString(LOCALE_USER_DEFAULT, 0, _pwz+_cc-1-ccSuffixLen, ccSuffixLen, pwzSuffix, ccSuffixLen); IF_WIN32_FALSE_EXIT(iCompare); _hr = (iCompare == CSTR_EQUAL) ? S_OK : S_FALSE; exit: return _hr; } //----------------------------------------------------------------------------- // PathNormalize // / -> \ in string //----------------------------------------------------------------------------- template HRESULT CBaseString::PathNormalize() { LPWSTR pwz = NULL; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_FALSE_EXIT((_pwz && _cc), E_UNEXPECTED); pwz = _pwz; if (*pwz == L'/') *pwz = L'\\'; while ((pwz = CharNext(pwz)) && *pwz) { if (*pwz == L'/') *pwz = L'\\'; } exit: return _hr; } //----------------------------------------------------------------------------- // GetHash //----------------------------------------------------------------------------- template HRESULT CBaseString::GetHash(LPDWORD pdwHash, DWORD dwFlags) { IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); _hr = Get65599Hash(pdwHash, dwFlags); exit: return _hr; } //----------------------------------------------------------------------------- // Get65599Hash //----------------------------------------------------------------------------- template HRESULT CBaseString::Get65599Hash(LPDWORD pdwHash, DWORD dwFlags) { ULONG TmpHashValue = 0; DWORD cc = 0; LPWSTR pwz = 0; IF_FALSE_EXIT(!_fLocked, E_UNEXPECTED); IF_FALSE_EXIT((_pwz && _cc), E_UNEXPECTED); if (pdwHash != NULL) *pdwHash = 0; cc = _cc; pwz = _pwz; if (dwFlags == CaseSensitive) { while (cc-- != 0) { WCHAR Char = *pwz++; TmpHashValue = (TmpHashValue * 65599) + (WCHAR) ::CharUpperW((PWSTR) Char); } } else { while (cc-- != 0) TmpHashValue = (TmpHashValue * 65599) + *pwz++; } *pdwHash = TmpHashValue; exit: return _hr; } ////////////////////////////////////////////////////////////////////////////// // // CString // ////////////////////////////////////////////////////////////////////////////// class CString : public CBaseString { public: CString() : CBaseString (){} CString(AllocFlags eAllocFlags) : CBaseString(eAllocFlags) {} }; ////////////////////////////////////////////////////////////////////////////// // // CStringAccessor // ////////////////////////////////////////////////////////////////////////////// template class CStringAccessor { private: HRESULT _hr; T* _ps; public: CStringAccessor(); ~CStringAccessor(); HRESULT Attach(T& s); HRESULT Detach(DWORD cc = 0); LPWSTR* operator &(); LPWSTR GetBuf(); }; //----------------------------------------------------------------------------- // ctor //----------------------------------------------------------------------------- template CStringAccessor::CStringAccessor() : _ps(NULL), _hr(S_OK) {} //----------------------------------------------------------------------------- // dtor //----------------------------------------------------------------------------- template CStringAccessor::~CStringAccessor() {} //----------------------------------------------------------------------------- // Attach //----------------------------------------------------------------------------- template HRESULT CStringAccessor::Attach(T &s) { _ps = &s; IF_FAILED_EXIT(_ps->Lock()); exit: return _hr; } //----------------------------------------------------------------------------- // Detach //----------------------------------------------------------------------------- template HRESULT CStringAccessor::Detach(DWORD cc) { DWORD ccLen = 0; IF_NULL_EXIT(_ps, E_UNEXPECTED); IF_NULL_EXIT(_ps->_pwz, E_UNEXPECTED); if (!cc) { ccLen = lstrlen(_ps->_pwz); cc = ccLen+1; OVERFLOW_CHECK2(ccLen, cc); } else { IF_FALSE_EXIT((*(_ps->_pwz + cc - 1) == L'\0'), E_INVALIDARG); } _ps->_cc = _ps->_ccBuf = cc; IF_FAILED_EXIT(_ps->UnLock()); exit: return _hr; } //----------------------------------------------------------------------------- // operator & //----------------------------------------------------------------------------- template LPWSTR* CStringAccessor::operator &() { if (!_ps) { ASSERT(FALSE); } return (_ps ? &(_ps->_pwz) : NULL); } //----------------------------------------------------------------------------- // GetBuf //----------------------------------------------------------------------------- template LPWSTR CStringAccessor::GetBuf() { if (!_ps) { ASSERT(FALSE); } return (_ps ? (_ps->_pwz) : NULL); }