|
|
#if !defined(_FUSION_INC_FUSIONBYTEBUFFER_H_INCLUDED_)
#define _FUSION_INC_FUSIONBYTEBUFFER_H_INCLUDED_
#pragma once
typedef const BYTE *LPCBYTE; typedef const BYTE *PCBYTE;
class CGenericByteBufferDefaultAllocator { public: static inline BYTE *Allocate(SIZE_T cb) { return reinterpret_cast<LPBYTE>(::LocalAlloc(LMEM_FIXED, cb)); } static inline VOID Deallocate(LPBYTE prgb) { ::LocalFree(prgb); } };
enum ByteComparisonResult { BCR_LESS_THAN, BCR_EQUAL_TO, BCR_GREATER_THAN };
template<SIZE_T nInlineBytes = MAX_PATH, class TAllocator = CGenericByteBufferDefaultAllocator> class CGenericByteBuffer { public: CGenericByteBuffer() : m_prgbBuffer(m_rgbInlineBuffer), m_cbBuffer(nInlineBytes), m_cb(0) { }
//
// Note that somewhat counter-intuitively, there is neither an assignment operator,
// copy constructor or constructor taking a TConstantString. This is necessary
// because such a constructor would need to perform a dynamic allocation
// if the path passed in were longer than nInlineBytes which could fail and
// since we do not throw exceptions, constructors may not fail. Instead the caller
// must just perform the default construction and then use the Assign() member
// function, remembering of course to check its return status.
//
~CGenericByteBuffer() { if (m_prgbBuffer != m_rgbInlineBuffer) { TAllocator::Deallocate(m_prgbBuffer); m_prgbBuffer = NULL; } }
HRESULT Assign(LPCBYTE prgb, SIZE_T cb) { HRESULT hr = NOERROR;
// Only force the buffer to be dynamically grown if the new contents do not
// fit in the old buffer.
if (cb > m_cbBuffer) { // Resize the buffer, preserving the old contents in case the copy fails.
hr = this->ResizeBuffer(cb, true); if (FAILED(hr)) goto Exit; }
// if we have a dynamically allocated buffer and the string fits in the
// inline buffer, get rid of the dynamically allocated buffer.
if ((m_prgbBuffer != m_rgbInlineBuffer) && (cb <= nInlineBytes)) { memcpy(m_rgbInlineBuffer, prgb, cb); TAllocator::Deallocate(m_prgbBuffer);
m_prgbBuffer = m_rgbInlineBuffer; m_cbBuffer = nInlineBytes; } else { memcpy(m_prgbBuffer, prgb, cb); }
hr = NOERROR;
Exit: return hr; }
#if defined(_FUSION_INC_FUSIONBLOB_H_INCLUDED_)
HRESULT Assign(const BLOB &rblob) { return this->Assign(rblob.m_pBlobData, rblob.m_cbData); } #endif
HRESULT Append(LPCBYTE prgb, SIZE_T cb) { HRESULT hr = NOERROR;
if ((cb + m_cb) > m_cbBuffer) { hr = this->ResizeBuffer(cb + m_cb, true); if (FAILED(hr)) goto Exit; }
memcpy(&m_prgbBuffer[m_cb], prgb, cb); m_cb += cb;
hr = NOERROR;
Exit: return hr; }
#if defined(_FUSION_INC_FUSIONBLOB_H_INCLUDED_)
HRESULT Append(const BLOB &rblob) { return this->Append(rblob.m_pBlobData, rblob.m_cbData); } #endif
HRESULT LeftShift(ULONG cb) { HRESULT hr = NOERROR;
if (m_cb < cb) { hr = E_INVALIDARG; goto Exit; }
// Just do the simple memcpy. Perhaps we should see if can lose the
// allocated buffer, but we might just need it again soon anyways.
memcpy(&m_prgbBuffer[0], &m_prgbBuffer[cb], m_cb - cb); m_cb -= cb;
hr = NOERROR; Exit: return hr; }
HRESULT TakeValue(CGenericByteBuffer<nInlineBytes, TAllocator> &r) { if (r.m_prgbBuffer == r.m_rgbInlineBuffer) { // The source has an inline buffer; since we know we're the same type,
// just copy the bits, free our dynamic buffer if appropriate and
// go.
memcpy(m_rgbInlineBuffer, r.m_rgbInlineBuffer, r.m_cb); m_cbBuffer = r.m_cbBuffer; m_cb = r.m_cb;
if (m_prgbBuffer != m_rgbInlineBuffer) { TAllocator::Deallocate(m_prgbBuffer); m_prgbBuffer = m_rgbInlineBuffer; } } else { // If we have a dynamically allocated buffer, free it...
if (m_prgbBuffer != m_rgbInlineBuffer) { TAllocator::Deallocate(m_prgbBuffer); m_prgbBuffer = NULL; }
// avast ye mateys, we're taking control of yer buffers!
m_prgbBuffer = r.m_prgbBuffer; m_cbBuffer = r.m_cbBuffer; m_cb = r.m_cb;
// Point the other buffer back to its built-in storage...
r.m_prgbBuffer = r.m_rgbInlineBuffer; r.m_cbBuffer = nInlineBytes; }
return NOERROR; }
operator LPCBYTE() const { return m_prgbBuffer; }
VOID Clear(bool fFreeStorage = false) { if (fFreeStorage) { if (m_prgbBuffer != NULL) { if (m_prgbBuffer != m_rgbInlineBuffer) { TAllocator::Deallocate(m_prgbBuffer); m_prgbBuffer = m_rgbInlineBuffer; m_cbBuffer = nInlineBytes; } } }
m_cb = 0; }
HRESULT Compare(LPCBYTE prgbCandidate, SIZE_T cbCandidate, ByteComparisonResult &rbcrOut) { SIZE_T cbToCompare = (m_cb < cbCandidate) ? m_cb : cbCandidate; int iResult = memcmp(m_prgbBuffer, prgbCandidate, cbToCompare);
if (iResult < 0) rbcrOut = BCS_LESS_THAN; else if (iResult > 0) rbcrOut = BCS_GREATER_THAN; else if (m_cb < cbCandidate) rbcrOut = BCS_LESS_THAN; else if (m_cb > cbCandidate) rbcrOut = BCS_GREATER_THAN; else rbcrOut = BCS_EQUAL_TO;
return NOERROR; }
SIZE_T GetBufferCb() const { return m_cbBuffer; } SIZE_T GetCurrentCb() const { return m_cb; }
LPBYTE GetBufferPtr() { return m_prgbBuffer; }
HRESULT ResizeBuffer(SIZE_T cb, bool fPreserveContents = false) { HRESULT hr = NOERROR;
if (cb > m_cbBuffer) { LPBYTE prgbBufferNew = TAllocator::Allocate(cb); if (prgbBufferNew == NULL) { hr = E_OUTOFMEMORY; goto Exit; }
if (fPreserveContents) memcpy(prgbBufferNew, m_prgbBuffer, m_cb); else m_cb = 0;
if (m_prgbBuffer != m_rgbInlineBuffer) TAllocator::Deallocate(m_prgbBuffer);
m_prgbBuffer = prgbBufferNew; m_cbBuffer = cb; } else if ((m_prgbBuffer != m_rgbInlineBuffer) && (cb <= nInlineBytes)) { // The buffer is small enough to fit into the inline buffer, so get rid of
// the dynamically allocated one.
if (fPreserveContents) { memcpy(m_rgbInlineBuffer, m_prgbBuffer, nInlineBytes); m_cb = nInlineBytes; } else m_cb = 0;
TAllocator::Deallocate(m_prgbBuffer); m_prgbBuffer = m_rgbInlineBuffer; m_cbBuffer = nInlineBytes; }
hr = NOERROR;
Exit: return hr; }
private: BYTE m_rgbInlineBuffer[nInlineBytes]; LPBYTE m_prgbBuffer; SIZE_T m_cbBuffer; SIZE_T m_cb; };
// 128 is just an arbitrary size. The current use of this is to buffer attributes
// streaming in from the service, so 64 seems like as good a guess as any.
typedef CGenericByteBuffer<128> CByteBuffer;
#endif
|