Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1194 lines
19 KiB

/*++
Copyright (C) Microsoft Corporation 1999
Module Name:
buffers
Abstract:
This module provides the implementation for the high-performance buffer
management class.
Author:
Doug Barlow (dbarlow) 9/2/1999
Notes:
?Notes?
--*/
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <stdlib.h>
#include "cspUtils.h"
#define DALC_STATIC 0
#define DALC_HEAP 1
//
//==============================================================================
//
// CBufferReference
//
class CBufferReference
{
protected:
typedef void (__cdecl *deallocator)(LPBYTE pbBuffer);
static const deallocator Static; // The data was statically referenced.
static const deallocator Heap; // The data came from the process heap.
// Constructors & Destructor
CBufferReference(void);
virtual ~CBufferReference();
// Properties
ULONG m_nReferenceCount;
ULONG m_cbBufferLength;
LPBYTE m_pbBuffer;
deallocator m_pfDeallocator;
// Methods
ULONG AddRef(void);
ULONG Release(void);
void Clear(void);
void Set(LPCBYTE pbData, ULONG cbLength, deallocator pfDealloc = Static);
LPCBYTE Value(void) const
{ return m_pbBuffer; };
LPBYTE Access(void) const
{ return m_pbBuffer; };
ULONG Space(void) const
{ return m_cbBufferLength; };
LPBYTE Preallocate(ULONG cbLength);
LPBYTE Reallocate(ULONG cbLength);
// Operators
// Friends
friend class CBuffer;
};
//
//==============================================================================
//
// Static definitions
//
const CBufferReference::deallocator
CBufferReference::Static = (CBufferReference::deallocator)DALC_STATIC,
CBufferReference::Heap = (CBufferReference::deallocator)DALC_HEAP;
/*++
NoMemory:
This routine controls the action to be taken when no memory can be
allocated for use.
Arguments:
None
Return Value:
None
Throws:
Throws a DWORD or raises an exception.
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("NoMemory")
static void
NoMemory(
void)
{
throw (DWORD)ERROR_OUTOFMEMORY;
}
//
//==============================================================================
//
// CBufferReference
//
// This class is hidden from normal use. It actually mantains the buffer
// and it's reference count. It knows how to release the buffer when there
// is noone referring to it.
//
/*++
CBufferReference::CBufferReference:
This is the default constructor for the CBufferReference object.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
Note that the object is not automatically referenced upon creation!
Delete it using the Release method.
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBufferReference::CBufferReference")
CBufferReference::CBufferReference(
void)
{
m_nReferenceCount = 0;
m_cbBufferLength = 0;
m_pbBuffer = NULL;
m_pfDeallocator = CBufferReference::Static;
}
/*++
CBufferReference::~CBufferReference:
This is the destructor for the CBufferReference object. It is called only
by the Release method.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBufferReference::~CBufferReference")
CBufferReference::~CBufferReference()
{
Clear();
}
/*++
CBufferReference::AddRef:
This method increments the reference count of the object.
Arguments:
None
Return Value:
The new number of outstanding references.
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBufferReference::AddRef")
ULONG
CBufferReference::AddRef(
void)
{
m_nReferenceCount += 1;
return m_nReferenceCount;
}
/*++
CBufferReference::Release:
This method decrements the object's reference count, and if it reaches zero,
the object is automatically deleted.
Arguments:
None
Return Value:
The new reference count. A Return code of zero imples the object was
deleted.
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBufferReference::Release")
ULONG
CBufferReference::Release(
void)
{
ULONG nReturn;
ASSERT(0 < m_nReferenceCount);
m_nReferenceCount -= 1;
nReturn = m_nReferenceCount;
if (0 == m_nReferenceCount)
delete this;
return nReturn;
}
/*++
CBufferReference::Clear:
This method clears out any existing buffer in preparation for adding a new
one, or to delete the object.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBufferReference::Clear")
void
CBufferReference::Clear(
void)
{
if (NULL != m_pbBuffer)
{
switch ((ULONG_PTR)m_pfDeallocator)
{
case DALC_STATIC:
break;
case DALC_HEAP:
HeapFree(GetProcessHeap(), 0, m_pbBuffer);
break;
default:
ASSERT(NULL != m_pfDeallocator);
(*m_pfDeallocator)(m_pbBuffer);
}
}
m_pbBuffer = NULL;
m_cbBufferLength = 0;
m_pfDeallocator = Static;
}
/*++
CBufferReference::Set:
This method establishes the contents of the buffer.
Arguments:
pbData supplies the new data to be loaded.
cbLength supplies the length of the data, in bytes.
pfDealloc supplies the deallocator to be called when the data is no longer
needed.
Return Value:
None
Throws:
None
Remarks:
The value is changed for all referencers of the buffer.
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBufferReference::Set")
void
CBufferReference::Set(
LPCBYTE pbData,
ULONG cbLength,
deallocator pfDealloc)
{
Clear();
m_cbBufferLength = cbLength;
m_pbBuffer = const_cast<LPBYTE>(pbData);
m_pfDeallocator = pfDealloc;
}
/*++
CBufferReference::Preallocate:
This method prepares an empty buffer to be managed.
Arguments:
cbLength supplies the length of the requested buffer, in bytes.
Return Value:
The address of the allocated buffer.
Throws:
?exceptions?
Remarks:
The value is changed for all referencers of the buffer.
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBufferReference::Preallocate")
LPBYTE
CBufferReference::Preallocate(
ULONG cbLength)
{
LPBYTE pbBuf = (LPBYTE)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
cbLength);
if (NULL == pbBuf)
NoMemory();
Set(pbBuf, cbLength, Heap);
return pbBuf;
}
/*++
CBufferReference::Reallocate:
This method changes the size of the allocated buffer. No data is lost.
Arguments:
cbLength supplies the length of the buffer.
Return Value:
The address of the buffer.
Throws:
?exceptions?
Remarks:
The value is changed for all referencers of the buffer.
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBufferReference::Reallocate")
LPBYTE
CBufferReference::Reallocate(
ULONG cbLength)
{
LPBYTE pbBuf;
if (NULL == m_pbBuffer)
pbBuf = Preallocate(cbLength);
else
{
switch ((ULONG_PTR)m_pfDeallocator)
{
case DALC_HEAP:
pbBuf = (LPBYTE)HeapReAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
m_pbBuffer,
cbLength);
if (NULL == pbBuf)
NoMemory();
m_pbBuffer = pbBuf;
m_cbBufferLength = cbLength;
m_pfDeallocator = Heap;
case DALC_STATIC:
m_pfDeallocator = NULL;
// Fall through to default case
default:
pbBuf = (LPBYTE)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
cbLength);
if (NULL == pbBuf)
NoMemory();
CopyMemory(pbBuf, m_pbBuffer, __min(cbLength, m_cbBufferLength));
Set(pbBuf, cbLength, Heap);
}
}
return pbBuf;
}
//
//==============================================================================
//
// CBuffer
//
// This class exposes access to the CBufferReference class.
//
/*++
CBuffer::CBuffer:
These methods are the constructors of the CBuffer object.
Arguments:
pbData supplies static data with which to initialize the object.
cbLength supplies the length of the initialization data.
Return Value:
None
Throws:
?exceptions?
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::CBuffer")
CBuffer::CBuffer(
void)
{
Init();
}
CBuffer::CBuffer(
ULONG cbLength)
{
Init();
Space(cbLength);
}
CBuffer::CBuffer(
LPCBYTE pbData,
ULONG cbLength)
{
Init();
Set(pbData, cbLength);
}
/*++
CBuffer::~CBuffer:
This is the destructor for the CBuffer object.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::~CBuffer")
CBuffer::~CBuffer()
{
if (NULL != m_pbfr)
m_pbfr->Release();
}
/*++
CBuffer::Init:
This is a common routine shared between all the constructors. It does
all the preliminary initialization. It should only be called by
constructors.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Init")
void
CBuffer::Init(
void)
{
m_pbfr = NULL;
m_cbDataLength = 0;
}
/*++
CBuffer::Empty:
This routine sets the buffer to an empty state.
Arguments:
None
Return Value:
None
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Empty")
void
CBuffer::Empty(
void)
{
if (NULL != m_pbfr)
{
m_pbfr->Release();
m_pbfr = NULL;
}
m_cbDataLength = 0;
}
/*++
CBuffer::Set:
This method sets the object to the specified value.
Arguments:
pbData supplies the value to be set, as static data.
cbLength supplies the length of the pbData buffer, in bytes.
pbfr supplies a buffer reference object to use.
Return Value:
None
Throws:
?exceptions?
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Set")
void
CBuffer::Set(
LPCBYTE pbData,
ULONG cbLength)
{
CBufferReference *pbfr = new CBufferReference;
if (NULL == pbfr)
NoMemory();
pbfr->Set(pbData, cbLength);
Set(pbfr); // That will AddRef it.
m_cbDataLength = cbLength;
}
void
CBuffer::Set(
CBufferReference *pbfr)
{
if (NULL != m_pbfr)
m_pbfr->Release();
m_cbDataLength = 0;
m_pbfr = pbfr;
m_pbfr->AddRef();
}
/*++
CBuffer::Copy:
This method forces the object to make a private copy of the specified
value.
Arguments:
pbData supplies the value to be set, as static data.
cbLength supplies the length of the pbData buffer, in bytes.
Return Value:
None
Throws:
?exceptions?
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Copy")
void
CBuffer::Copy(
LPCBYTE pbData,
ULONG cbLength)
{
CBufferReference *pbfr = new CBufferReference;
if (NULL == pbfr)
NoMemory();
pbfr->Preallocate(cbLength);
CopyMemory(pbfr->Access(), pbData, cbLength);
Set(pbfr); // That will AddRef it.
m_cbDataLength = cbLength;
}
/*++
CBuffer::Append:
This method appends additional data onto existing data, creating a new
CBufferReference if necessary.
Arguments:
pbData supplies the data to be appended onto the existing buffer.
cbLength supplies the length of that data, in bytes.
Return Value:
None
Throws:
?exceptions?
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Append")
void
CBuffer::Append(
LPCBYTE pbData,
ULONG cbLength)
{
ULONG cbDesired = Length() + cbLength;
if (NULL == m_pbfr)
Set(pbData, cbLength);
else if (cbDesired < m_pbfr->Space())
{
CopyMemory(m_pbfr->Access() + Length(), pbData, cbLength);
m_cbDataLength = cbDesired;
}
else
{
m_pbfr->Reallocate(cbDesired);
CopyMemory(m_pbfr->Access() + Length(), pbData, cbLength);
m_cbDataLength = cbDesired;
}
}
/*++
CBuffer::Space:
This method returns the size of the existing buffer, in bytes. This is the
length of the actual buffer, not the length of any data stored within the
buffer. Note that it is possible for the stored data to be shorter than
the buffer.
Arguments:
None
Return Value:
The length of the buffer, in bytes.
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Space")
ULONG
CBuffer::Space(
void)
const
{
ULONG cbLen = 0;
if (NULL != m_pbfr)
cbLen = m_pbfr->Space();
return cbLen;
}
/*++
CBuffer::Space:
This method forces the referenced buffer to be at least as long as the
length supplied. Data will be lost.
Arguments:
cbLength supplies the requested minimum length of the buffer.
Return Value:
The address of the allocated buffer.
Throws:
?exceptions?
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Space")
LPBYTE
CBuffer::Space(
ULONG cbLength)
{
CBufferReference *pbfr = new CBufferReference;
if (NULL == pbfr)
NoMemory();
pbfr->Preallocate(cbLength);
Set(pbfr);
return Access();
}
/*++
CBuffer::Extend:
This method provides more space in the buffer without losing the data
that's already there.
Arguments:
cbLength supplies the required buffer length, in bytes.
Return Value:
None
Throws:
?exceptions?
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/3/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Extend")
LPBYTE
CBuffer::Extend(
ULONG cbLength)
{
ULONG cbLen = m_cbDataLength;
CBufferReference *pbfr = new CBufferReference;
if (NULL == pbfr)
NoMemory();
pbfr->Preallocate(cbLength);
CopyMemory(pbfr->Access(), Value(), cbLen);
Set(pbfr);
m_cbDataLength = cbLen;
return Access();
}
/*++
CBuffer::Length:
This method returns the number of bytes of actual data stored within the
internal buffer.
Arguments:
None
Return Value:
The length of the data in the buffer, in bytes.
Throws:
None
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Length")
ULONG
CBuffer::Length(
void)
const
{
return m_cbDataLength;
}
/*++
CBuffer::Length:
This method resizes the length of the data stored in the buffer. It does
not attempt to resize the buffer itself. The purpose of this routine is to
declare the size of data written into a the buffer by an outside source.
Arguments:
cbLength supplies the actual length of useful data currently in the buffer.
Return Value:
The address of the buffer.
Throws:
None
Remarks:
The data length is set to at most the length of the underlying buffer.
Use Extend if the buffer needs to be longer.
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Length")
LPCBYTE
CBuffer::Length(
ULONG cbLength)
{
ULONG cbActLen = cbLength;
if (NULL != m_pbfr)
{
if (cbActLen > m_pbfr->Space())
cbActLen = m_pbfr->Space();
}
else
cbActLen = 0;
m_cbDataLength = cbActLen;
ASSERT(cbLength == cbActLen); // Catch mistakes
return Value();
}
/*++
CBuffer::Value:
This method returns the contents of the buffer as a Read Only Byte Array.
Arguments:
nOffset supplies an offset into the data, in bytes.
Return Value:
The address of the data, offset by the supplied parameter.
Throws:
None
Remarks:
If no buffer exists, or the offset exceeds the data, then a temporary
value is supplied.
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Value")
LPCBYTE
CBuffer::Value(
ULONG nOffset)
const
{
static const LPVOID pvDefault = NULL;
LPCBYTE pbRet = (LPCBYTE)&pvDefault;
if (NULL != m_pbfr)
{
if (nOffset < Length())
pbRet = m_pbfr->Value() + nOffset;
}
return pbRet;
}
/*++
CBuffer::Access:
This method supplies the the buffer as a writable space. The expected
length must have been preset.
Arguments:
nOffset supplies an offset into the buffer, in bytes.
Return Value:
The address of the buffer, offset by the supplied parameter.
Throws:
?exceptions?
Remarks:
?Remarks?
Author:
Doug Barlow (dbarlow) 9/2/1999
--*/
#undef __SUBROUTINE__
#define __SUBROUTINE__ TEXT("CBuffer::Access")
LPBYTE
CBuffer::Access(
ULONG nOffset)
const
{
LPBYTE pbRet = NULL;
if (NULL != m_pbfr)
{
if (nOffset <= m_pbfr->Space())
pbRet = m_pbfr->Access() + nOffset;
else
pbRet = NULL;
}
return pbRet;
}