#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(::LocalAlloc(LMEM_FIXED, cb)); } static inline VOID Deallocate(LPBYTE prgb) { ::LocalFree(prgb); } }; enum ByteComparisonResult { BCR_LESS_THAN, BCR_EQUAL_TO, BCR_GREATER_THAN }; template 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 &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