///////////////////////////////////////////////////////////////////
// EnBSTR
// Copyright (C) 2001 Morten Abrahamsen (mabraha@online.no)
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
///////////////////////////////////////////////////////////////////
// 2001-02-25:
// - Initial Release
// 2001-02-28:
// - Added upper, lower, reverse
// - Added replace, spanInclude, spanExclude
///////////////////////////////////////////////////////////////////
#ifndef __ENBSTR_H__
#define __ENBSTR_H__
#pragma once
#ifndef __cplusplus
#error ATL requires C++ compilation (use a .cpp suffix)
#endif
#include "comdef.h"
class CEnBSTR : public _bstr_t
{
public:
// Constructors
CEnBSTR() : _bstr_t() {}
CEnBSTR(const char* s) : _bstr_t(s) {}
CEnBSTR(const CEnBSTR& s) : _bstr_t(s) {}
CEnBSTR(const _bstr_t& s) : _bstr_t(s) {}
CEnBSTR(const wchar_t* s) : _bstr_t(s) {}
CEnBSTR(const _variant_t& var) : _bstr_t(var) {}
CEnBSTR(BSTR bstr, bool fCopy) : _bstr_t(bstr, fCopy) {}
// Analysis
int find(const _bstr_t& bstr) const
{
const wchar_t* pstr = _bstr_t::operator const wchar_t*();
wchar_t* pdest = wcsstr(pstr, bstr);
return pdest ? pdest - pstr : -1;
}
int find(const wint_t& ch) const
{
const wchar_t* pstr = _bstr_t::operator const wchar_t*();
wchar_t* pdest = wcschr(pstr, ch);
return pdest ? pdest - pstr : -1;
}
int find(const _bstr_t& bstr, const unsigned int nStart) const
{
const wchar_t* pstr = _bstr_t::operator const wchar_t*();
if (nStart >= length()) return -1;
wchar_t* pdest = wcsstr(pstr+nStart, bstr);
return pdest ? pdest - pstr : -1;
}
int find(const wint_t& ch, const unsigned int nStart) const
{
const wchar_t* pstr = _bstr_t::operator const wchar_t*();
if (nStart >= length()) return -1;
wchar_t* pdest = wcschr(pstr+nStart, ch);
return pdest ? pdest - pstr : -1;
}
/////////////////////////////////////////////////////////////////////
// Extraction
CEnBSTR mid(const unsigned int nFirst, unsigned int nCount = 0) const
{
unsigned int nLength = _bstr_t::length();
if (nCount == 0)
nCount = nLength-nFirst;
if (nFirst == 0 && nCount >= nLength)
return *this;
const wchar_t* pstr = _bstr_t::operator const wchar_t*();
CEnBSTR bstr;
if (nLength >= (nFirst+nCount))
{
wchar_t* pNewStr = new wchar_t[nCount+1];
ZeroMemory(pNewStr, sizeof(wchar_t)*(nCount+1));
wcsncpy(pNewStr, pstr+nFirst, nCount);
bstr = pNewStr;
delete [] pNewStr;
}
return bstr;
}
CEnBSTR left(const unsigned int nCount) const
{
return mid(0, nCount);
}
CEnBSTR right(const unsigned int nCount) const
{
unsigned int nLength = _bstr_t::length();
if (nLength >= nCount)
return mid(nLength-nCount, nCount);
return *this;
}
CEnBSTR spanInclude(const _bstr_t& bstrCharset) const
{
const wchar_t* pstr = _bstr_t::operator const wchar_t*();
unsigned int nLen = wcsspn(pstr, bstrCharset);
return nLen ? mid(0, nLen) : "";
}
CEnBSTR spanExclude(const _bstr_t& bstrCharset) const
{
const wchar_t* pstr = _bstr_t::operator const wchar_t*();
unsigned int nLen = wcscspn(pstr, bstrCharset);
return nLen ? mid(0, nLen) : "";
}
/////////////////////////////////////////////////////////////////////
// Manipulation
void upper()
{
_bstr_t bstr(*this, true);
_wcsupr((wchar_t*)bstr);
*this = bstr;
}
void lower()
{
_bstr_t bstr(*this, true);
_wcslwr((wchar_t*)bstr);
*this = bstr;
}
void reverse()
{
_bstr_t bstr(*this, true);
_wcsrev((wchar_t*)bstr);
*this = bstr;
}
unsigned int replace(const wint_t& chFind, const wint_t& chReplace)
{
const wchar_t* pstr = _bstr_t::operator const wchar_t*();
if (pstr == NULL) return 0;
if (chFind == chReplace) return 0;
// Make a copy of the string to avoid reference counting problems.
_bstr_t bstrNew(*this, true);
pstr = (wchar_t*)bstrNew;
unsigned int nCount = 0;
wchar_t* pSearchPos = 0;
while (pSearchPos = wcschr(pSearchPos ? pSearchPos : pstr, chFind))
{
*pSearchPos = chReplace;
++nCount;
}
// Assign the new string (avoids refcount and deletes cached char-string)
*this = bstrNew;
return nCount;
}
unsigned int replace(const _bstr_t& bstrFind, const _bstr_t& bstrReplace)
{
const wchar_t* pSrcStr = _bstr_t::operator const wchar_t*();
if (pSrcStr == NULL) return 0;
unsigned int nCount = 0;
unsigned int nSearchStrLen = bstrFind.length();
// Calculate new length
wchar_t* pSearchPos = 0;
while (pSearchPos = wcsstr(pSearchPos ? pSearchPos : pSrcStr, bstrFind))
{
pSearchPos += nSearchStrLen;
++nCount;
}
// Replace bstrFind substrings with bstrReplace substrings
if (nCount)
{
unsigned int nReplaceStrLen = bstrReplace.length();
unsigned int nOrgStrLen = length();
unsigned int nNewStrLength = nOrgStrLen - (nSearchStrLen - nReplaceStrLen)*nCount;
nCount = 0;
wchar_t* pNewStr = SysAllocStringLen(0, nNewStrLength);
wchar_t* pSrcPos = (wchar_t*)pSrcStr;
wchar_t* pDestPos = pNewStr;
wchar_t* pNextSrcPos = 0;
while (pNextSrcPos = wcsstr(pSrcPos, bstrFind))
{
if (pSrcPos != pNextSrcPos)
{
unsigned int nCopyLength = pNextSrcPos-pSrcPos;
wcsncpy(pDestPos, pSrcPos, nCopyLength);
pDestPos += nCopyLength;
pSrcPos = pNextSrcPos;
}
wcsncpy(pDestPos, bstrReplace, nReplaceStrLen);
pDestPos += nReplaceStrLen;
pSrcPos += nSearchStrLen;
++nCount;
}
wcsncpy(pDestPos, pSrcPos, nOrgStrLen - (pSrcPos-pSrcStr));
*this = bstr_t(pNewStr, false);
}
return nCount;
}
};
///////////////////////////////////////////////////////////////////
// CBSTRStream
// Copyright (C) 2001 Morten Abrahamsen (mabraha@online.no)
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
///////////////////////////////////////////////////////////////////
// 2001-04-13:
// - Initial Release
///////////////////////////////////////////////////////////////////
// Notes:
// - This class is NOT threadsafe
///////////////////////////////////////////////////////////////////
class CBSTRStream
{
public:
CBSTRStream(const CBSTRStream& bsSrc, long nInitialBufferSize = 50, long nChunkSize = 50)
{
init(nInitialBufferSize, nChunkSize);
operator << (bsSrc);
}
CBSTRStream(long nInitialBufferSize = 50, long nChunkSize = 50)
{
init(nInitialBufferSize, nChunkSize);
}
virtual ~CBSTRStream()
{
clearCache();
if (m_bstr)
::SysFreeString(m_bstr);
#ifdef _DEBUG
if (m_nReAllocCount > 1)
{
ATLTRACE("CBSTRStream::%d buffer reallocations were performed. You might want to increase the buffersize\n",
m_nReAllocCount);
}
#endif
}
CBSTRStream& operator << (const _bstr_t& bstrData)
{
appendBSTR(bstrData);
return *this;
}
CBSTRStream& operator << (wchar_t* pstr)
{
long nLength = wcslen(pstr);
appendWCHAR(pstr, nLength);
return *this;
}
CBSTRStream& operator << (REFGUID src)
{
LPOLESTR szGUID;
HRESULT hr = ::StringFromCLSID(src, &szGUID);
if (FAILED(hr)) throw _com_error(hr);
appendWCHAR(szGUID, wcslen(szGUID));
::CoTaskMemFree(szGUID);
return *this;
}
CBSTRStream& operator << (long nData)
{
wchar_t szBuf[33];
ZeroMemory(szBuf, sizeof(wchar_t)*33);
_ltow(nData, szBuf, 10);
appendWCHAR(szBuf, wcslen(szBuf));
return *this;
}
CBSTRStream& operator << (unsigned long nData)
{
wchar_t szBuf[33];
ZeroMemory(szBuf, sizeof(wchar_t)*33);
_ultow(nData, szBuf, 10);
appendWCHAR(szBuf, wcslen(szBuf));
return *this;
}
CBSTRStream& operator << (int nData)
{
wchar_t szBuf[33];
ZeroMemory(szBuf, sizeof(wchar_t)*33);
_itow(nData, szBuf, 10);
appendWCHAR(szBuf, wcslen(szBuf));
return *this;
}
CBSTRStream& operator << (double dValue)
{
char buffer[50];
ZeroMemory(buffer, 50);
_gcvt(dValue, 10, buffer);
_bstr_t bstrData(buffer);
appendBSTR(bstrData);
return *this;
}
CBSTRStream& operator << (const CBSTRStream& bsSrc)
{
appendWCHAR(bsSrc.m_bstr, bsSrc.m_nSize);
return *this;
}
void reset()
{
m_nSize = 0;
}
operator BSTR()
{
if (m_nSize == m_nAllocatedSize) return m_bstr;
if (m_bstrCache == NULL)
m_bstrCache = ::SysAllocStringLen(m_bstr, m_nSize);
return m_bstrCache;
}
operator _bstr_t() const
{
return _bstr_t(::SysAllocStringLen(m_bstr, m_nSize), false);
}
long length() const
{
return m_nSize;
}
bool operator == (const CBSTRStream& bsSrc) const
{
if (bsSrc.m_bstr == NULL && m_bstr == NULL)
return true;
if (m_nSize != bsSrc.m_nSize)
return false;
if (bsSrc.m_bstr != NULL && m_bstr != NULL)
return wcsncmp(m_bstr, bsSrc.m_bstr, m_nSize) == 0;
return false;
}
CBSTRStream& operator = (const CBSTRStream& bsSrc)
{
reset();
appendWCHAR(bsSrc.m_bstr, bsSrc.m_nSize);
return *this;
}
protected:
void appendBSTR(BSTR bstr)
{
clearCache();
long nLength = ::SysStringLen(bstr);
manageBuffer(nLength);
wcsncpy(m_bstr+m_nSize, bstr, nLength);
m_nSize += nLength;
}
void appendWCHAR(wchar_t* pstr, long nLength)
{
clearCache();
manageBuffer(nLength);
wcsncpy(m_bstr+m_nSize, pstr, nLength);
m_nSize += nLength;
}
void manageBuffer(long nExtraSize)
{
long nFreeSpace = m_nAllocatedSize - m_nSize;
if (nFreeSpace >= nExtraSize) return;
long nAppendLength = m_nAllocatedSize == 0 ? m_nInitialBufferSize : m_nChunkSize;
if (nExtraSize > nAppendLength+nFreeSpace)
nAppendLength += nExtraSize-nFreeSpace;
if (m_nAllocatedSize == 0)
{
m_bstr = ::SysAllocStringLen(0, nAppendLength);
m_nAllocatedSize = nAppendLength;
}
else
{
long nNewSize = m_nAllocatedSize + nAppendLength;
BSTR bstrTmp = ::SysAllocStringLen(m_bstr, nNewSize);
::SysFreeString(m_bstr);
m_bstr = bstrTmp;
m_nAllocatedSize = nNewSize;
#ifdef _DEBUG
++m_nReAllocCount;
#endif
}
}
// the cached bstr is used with the BSTR operator. As the allocated string is probably larger than the
// actual string.
void clearCache()
{
if (m_bstrCache)
{
::SysFreeString(m_bstrCache);
m_bstrCache = NULL;
}
}
void init(long nInitialBufferSize, long nChunkSize)
{
m_nChunkSize = nChunkSize;
m_bstrCache = 0;
m_nInitialBufferSize = nInitialBufferSize;
m_nSize = 0;
m_bstr = 0;
m_nAllocatedSize = 0;
#ifdef _DEBUG
m_nReAllocCount = 0;
#endif
}
private:
BSTR m_bstr;
BSTR m_bstrCache;
long m_nChunkSize;
long m_nAllocatedSize;
long m_nInitialBufferSize;
long m_nSize;
#ifdef _DEBUG
long m_nReAllocCount;
#endif
};
#endif (__ENBSTR_H__)