windows-nt/Source/XPSP1/NT/base/win32/fusion/inc/fusionbytebuffer.h

273 lines
7.7 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#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