//////////////////////////////////////////////////////////////////////////////// // // Filename : VarStr.h // Purpose : To hold definition for CVarString // // Project : Persistent Query // Component: Common // // Author : urib // // Log: // Feb 2 1997 urib Creation // Jun 19 1997 urib Add counted operators. // Jun 24 1997 urib Fix bad const declarations. // Dec 29 1997 urib Add includes. // Feb 2 1999 yairh fix bug in SetMinimalSize. // Feb 8 1999 urib Enable different built in sizes. // Feb 25 1999 urib Add SizedStringCopy. // Jul 5 1999 urib Fix SizedStringCopy.. // May 1 2000 urib Cleanup. // Nov 23 2000 urib Fix a bug in counted copy and cat. // //////////////////////////////////////////////////////////////////////////////// #ifndef VARSTR_H #define VARSTR_H #pragma once #include "AutoPtr.h" #include "Excption.h" //////////////////////////////////////////////////////////////////////////////// // // CVarString class definition // //////////////////////////////////////////////////////////////////////////////// template class TVarString { public: // Constructor - tips the implementation on the string size. TVarString(ULONG ulInitialSize = 0); // Constructor - copy this string. TVarString(PCWSTR); // Constructor - convert to UNICODE and copy this string. TVarString(const PSZ); // Copy Constructor TVarString(const TVarString&); ~TVarString(); // Copy/Convert and copy the string. TVarString& Cpy(PCWSTR); TVarString& Cpy(const ULONG, PCWSTR); TVarString& Cpy(const PSZ); // Concatenate/Convert and concatenate the string to the existing string. TVarString& Cat(PCWSTR); TVarString& Cat(const ULONG, PCWSTR); TVarString& Cat(const PSZ); // Compare/Convert and compare the string to the existing string. int Cmp(PCWSTR) const; int Cmp(const PSZ) const; // Return the string length. ULONG Len() const; // Allow access to the string memory. operator PWSTR() const; // Hint the implementation about the string size. void SetMinimalSize(ULONG); // Set a specific character void SetCharacter(ULONG, WCHAR); // Appends a backslash to the string if the last character is not a // backslash. void AppendBackslash(); // Appends a slash to the string if the last character is not a // slash. void AppendSlash(); protected: // A predicate to see if memory is allocated or not. bool IsAllocated(); // The allocation size ULONG m_ulSize; // This is the place for the standard string. WCHAR m_rwchNormalString[ulStackSize + 1]; // If the string is becoming too big we will allocate space for it. WCHAR* m_pTheString; private: TVarString& operator=(const TVarString& vsOther) { Cpy(vsOther); return *this; } }; template inline TVarString::TVarString(ULONG ulInitialSize) :m_pTheString(m_rwchNormalString) ,m_ulSize(ulStackSize) { SetMinimalSize(ulInitialSize); m_pTheString[0] = L'\0'; } template inline TVarString::TVarString(PCWSTR pwsz) :m_pTheString(m_rwchNormalString) ,m_ulSize(ulStackSize) { Cpy(pwsz); } template inline TVarString::TVarString(const PSZ psz) :m_pTheString(m_rwchNormalString) ,m_ulSize(ulStackSize) { Cpy(psz); } template inline TVarString::TVarString(const TVarString& vsOther) :m_pTheString(m_rwchNormalString) ,m_ulSize(ulStackSize) { Cpy(vsOther); } template inline TVarString::~TVarString() { if (IsAllocated()) { free(m_pTheString); } } template inline bool TVarString::IsAllocated() { return m_pTheString != m_rwchNormalString; } template inline void TVarString::SetMinimalSize(ULONG ulNewSize) { // We allocate a little more so if someone would like to add a slash // or something, it will not cause us to realocate. // On debug builds, I want to check for string overflows so I don't // want the extra memory. Activating the reallocation mechanism is also' // a good thing in debug builds. #if !(defined(DEBUG)) ulNewSize++; #endif // // if the new size is smaller then what we have - bye bye // if (ulNewSize > m_ulSize) { // // We already allocated a string. Should change it's size // if (IsAllocated()) { PWSTR pwszTemp = (PWSTR) realloc( m_pTheString, (ulNewSize + 1) * sizeof(WCHAR)); if (NULL == pwszTemp) { THROW_MEMORY_EXCEPTION(); } // // Save the new memory block. // m_pTheString = pwszTemp; } else { // // We move the string from the buffer to the allocation. // Note that this is dangerous if someone took the buffer address. // The user must always use the access method and never cache the // string pointer. // m_pTheString = (PWSTR) malloc(sizeof(WCHAR) * (ulNewSize + 1)); if (NULL == m_pTheString) { THROW_MEMORY_EXCEPTION(); } wcsncpy(m_pTheString, m_rwchNormalString, m_ulSize + 1); } m_ulSize = ulNewSize; } } template inline TVarString& TVarString::Cpy(PCWSTR pwsz) { return Cpy(wcslen(pwsz), pwsz); } template inline TVarString& TVarString::Cpy(const ULONG ulCount, PCWSTR pwsz) { SetMinimalSize(ulCount + 1); wcsncpy(m_pTheString, pwsz, ulCount); m_pTheString[ulCount] = L'\0'; return *this; } template inline TVarString& TVarString::Cpy(const PSZ psz) { int iLen; iLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, psz, -1, NULL, 0); if (0 == iLen) { Assert(0 == iLen); THROW_HRESULT_EXCEPTION(HRESULT_FROM_WIN32(GetLastError())); } SetMinimalSize(iLen); iLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, psz, -1, m_pTheString, iLen); if (0 == iLen) { Assert(0 == iLen); THROW_HRESULT_EXCEPTION(HRESULT_FROM_WIN32(GetLastError())); } return *this; } template inline TVarString& TVarString::Cat(PCWSTR pwsz) { ULONG ulLength = wcslen(pwsz); return Cat(ulLength, pwsz); } template inline TVarString& TVarString::Cat(const ULONG ulLength, PCWSTR pwsz) { ULONG ulCurrentLength = Len(); SetMinimalSize(ulCurrentLength + ulLength + 1); wcsncpy(m_pTheString + ulCurrentLength, pwsz, ulLength); m_pTheString[ulCurrentLength + ulLength] = L'\0'; return *this; } template inline TVarString& TVarString::Cat(const PSZ psz) { ULONG ulCurrentLength = Len(); int iLen; iLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, psz, -1, NULL, 0); if (0 == iLen) { Assert(0 == iLen); THROW_HRESULT_EXCEPTION(HRESULT_FROM_WIN32(GetLastError())); } SetMinimalSize(iLen + ulCurrentLength); iLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, psz, -1, m_pTheString + ulCurrentLength, iLen); if (0 == iLen) { Assert(0 == iLen); THROW_HRESULT_EXCEPTION(HRESULT_FROM_WIN32(GetLastError())); } return *this; } template inline int TVarString::Cmp(PCWSTR pwsz) const { return wcscmp(m_pTheString, pwsz); } template inline int TVarString::Cmp(const PSZ psz) const { int iLen; iLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, psz, -1, NULL, 0); if (0 == iLen) { Assert(0 == iLen); THROW_HRESULT_EXCEPTION(HRESULT_FROM_WIN32(GetLastError())); } CAutoMallocPointer apBuffer = (PWSTR) malloc((iLen) * sizeof(WCHAR)); iLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, psz, -1, apBuffer.Get(), iLen); if (0 == iLen) { Assert(0 == iLen); THROW_HRESULT_EXCEPTION(HRESULT_FROM_WIN32(GetLastError())); } return Cmp(apBuffer.Get()); } template inline ULONG TVarString::Len() const { return wcslen(m_pTheString); } template inline TVarString::operator PWSTR() const { return m_pTheString; } template inline void TVarString::SetCharacter(ULONG ulIndex, WCHAR wch) { SetMinimalSize(ulIndex + 2); // index to size + null if (L'\0' == m_pTheString[ulIndex]) { m_pTheString[ulIndex + 1] = L'\0'; } else if (L'\0' == wch) { } m_pTheString[ulIndex] = wch; } template inline void TVarString::AppendSlash() { if (L'/' != m_pTheString[Len() - 1]) Cat(L"/"); } template inline void TVarString::AppendBackslash() { if (L'\\' != m_pTheString[Len() - 1]) Cat(L"\\"); } typedef TVarString<4> CShortVarString; typedef TVarString<16> CVarString; typedef TVarString<256> CLongVarString; typedef TVarString<1024> CHugeVarString; //////////////////////////////////////////////////////////////////////////////// // // String related utilities definition // //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // // Name : ::SizedStringCopy // Purpose : This function copies ulSize wide characters from the source // to the destination. It does not treat '\0' characters as // end of string and does not append the end of string mark // to the destination. Intended to be used instead of memcpy // when copying wide string characters. // // Parameters: // [in] PWSTR pwszTarget // [in] PCWSTR pwszSource // [in] ULONG ulSize // // Returns : PWSTR // // Log: // Jan 2 2001 urib Creation // //////////////////////////////////////////////////////////////////////////////// inline PWSTR SizedStringCopy(PWSTR pwszTarget, PCWSTR pwszSource, ULONG ulSize) { return (PWSTR) memcpy( (void*)pwszTarget, (void*)pwszSource, ulSize * sizeof(pwszSource[0])); } //////////////////////////////////////////////////////////////////////////////// // // Name : ::CoTaskDuplicateString // Purpose : strdup. Throwing though. // // Parameters: // [in] PCWSTR pwsz // // Returns : PWSTR // // Log: // Dec 25 2000 urib Creation // //////////////////////////////////////////////////////////////////////////////// inline PWSTR CoTaskDuplicateString(PCWSTR pwsz) { CAutoTaskPointer apTempName = (PWSTR)CoTaskMemAlloc(sizeof(WCHAR) * (1 + wcslen(pwsz))); if (!apTempName.IsValid()) { THROW_MEMORY_EXCEPTION(); } wcscpy(apTempName.Get(), pwsz); return apTempName.Detach(); } #endif /* VARSTR_H */