mirror of https://github.com/lianthony/NT4.0
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.
332 lines
6.0 KiB
332 lines
6.0 KiB
#ifndef __BUFFER_INCLUDED__
|
|
#define __BUFFER_INCLUDED__
|
|
|
|
#ifndef __POOL_INCLUDED__
|
|
#include "pool.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
class Buffer {
|
|
public:
|
|
Buffer(void (*pfn)(void*, void*, void*) = 0, void* pfnArg = 0, BOOL fAllocPadding_ = TRUE ) {
|
|
cbAlloc = 0;
|
|
pbStart = 0;
|
|
pbEnd = 0;
|
|
pfnMove = pfn;
|
|
pfnMoveArg = pfnArg;
|
|
fAllocPadding = fAllocPadding_;
|
|
}
|
|
~Buffer() {
|
|
if (pbStart)
|
|
Free();
|
|
}
|
|
BOOL SetInitAlloc(CB cbIn);
|
|
BOOL Append(PB pbIn, CB cbIn, OUT PB* ppbOut = 0);
|
|
BOOL AppendFmt(SZ szFmt, ...);
|
|
BOOL Reserve(CB cbIn, OUT PB* ppbOut = 0);
|
|
PB Start() const {
|
|
return pbStart;
|
|
}
|
|
PB End() const {
|
|
return pbEnd;
|
|
}
|
|
CB Size() const {
|
|
return pbEnd - pbStart;
|
|
}
|
|
void Reset() {
|
|
pbEnd = pbStart;
|
|
}
|
|
BOOL Truncate(CB cb) {
|
|
return 0 <= cb && cb <= Size() && setPbExtent(pbStart, pbStart + cb);
|
|
}
|
|
void Free() {
|
|
if (pbStart)
|
|
delete [] pbStart;
|
|
setPbExtent(0, 0);
|
|
cbAlloc = 0;
|
|
}
|
|
void Clear() {
|
|
if (pbStart) {
|
|
memset(pbStart, 0, pbEnd - pbStart);
|
|
setPbExtent(pbStart, pbStart);
|
|
}
|
|
}
|
|
BOOL save(Buffer* pbuf) const {
|
|
CB cb = Size();
|
|
#ifdef _MIPS_
|
|
if (!pbuf->Append((PB)&cb, sizeof cb))
|
|
return FALSE;
|
|
else if (cb == 0)
|
|
return TRUE;
|
|
else if (!pbuf->Append(Start(), cb))
|
|
return FALSE;
|
|
else if (dcbAlign(cb) == 0)
|
|
return TRUE;
|
|
else {
|
|
// Add padding to ensure that which follows
|
|
// in this buffer is properly aligned.
|
|
static unsigned char rgchZeroes[3];
|
|
assert(0 <= dcbAlign(cb) && dcbAlign(cb) <= sizeof(rgchZeroes));
|
|
return pbuf->Append(rgchZeroes, dcbAlign(cb));
|
|
}
|
|
#else
|
|
return pbuf->Append((PB)&cb, sizeof cb) &&
|
|
(Size() == 0 || pbuf->Append(Start(), Size()));
|
|
#endif
|
|
|
|
}
|
|
BOOL reload(PB* ppb) {
|
|
// can only reload in a pristine buffer
|
|
if (Size() != 0)
|
|
return FALSE;
|
|
|
|
CB cb = *((CB*&)*ppb)++;
|
|
if (Append(*ppb, cb)) {
|
|
#ifdef _MIPS_
|
|
*ppb += cbAlign(cb);
|
|
#else
|
|
*ppb += cb;
|
|
#endif
|
|
return TRUE;
|
|
} else
|
|
return FALSE;
|
|
}
|
|
private:
|
|
enum { cbPage = 4096 };
|
|
CB cbRoundUp(CB cb, CB cbMult) { return (cb + cbMult-1) & ~(cbMult-1); }
|
|
BOOL grow(CB dcbGrow);
|
|
BOOL setPbExtent(PB pbStartNew, PB pbEndNew) {
|
|
if (!pbStartNew) {
|
|
pbStart = pbEnd = NULL;
|
|
return FALSE;
|
|
}
|
|
PB pbStartOld = pbStart;
|
|
pbStart = pbStartNew;
|
|
pbEnd = pbEndNew;
|
|
if (pbStartOld != pbStartNew && pfnMove)
|
|
(*pfnMove)(pfnMoveArg, pbStartOld, pbStartNew);
|
|
return TRUE;
|
|
}
|
|
|
|
PB pbStart;
|
|
PB pbEnd;
|
|
CB cbAlloc;
|
|
void (*pfnMove)(void* pArg, void* pOld, void* pNew);
|
|
void* pfnMoveArg;
|
|
BOOL fAllocPadding;
|
|
};
|
|
|
|
inline BOOL Buffer::SetInitAlloc(CB cbNew)
|
|
{
|
|
dassert(cbNew > 0);
|
|
|
|
if (pbStart)
|
|
return FALSE;
|
|
|
|
PB pbNew = new (zeroed) BYTE[cbNew];
|
|
|
|
if (setPbExtent(pbNew, pbNew)) {
|
|
cbAlloc = cbNew;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
inline BOOL Buffer::grow(CB dcbGrow)
|
|
{
|
|
CB cbNew;
|
|
if (fAllocPadding)
|
|
{
|
|
cbNew = cbRoundUp(cbAlloc + __max(cbPage + dcbGrow, cbAlloc/2), cbPage);
|
|
}
|
|
else
|
|
{
|
|
cbNew = cbAlloc + dcbGrow;
|
|
}
|
|
|
|
PB pbNew = new BYTE[cbNew];
|
|
|
|
if (pbNew) {
|
|
cbAlloc = cbNew;
|
|
CB cbUsed = pbEnd - pbStart;
|
|
memcpy(pbNew, pbStart, cbUsed);
|
|
memset(pbNew + cbUsed, 0, cbAlloc - cbUsed);
|
|
|
|
delete [] pbStart;
|
|
setPbExtent(pbNew, pbNew + cbUsed);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
inline BOOL Buffer::Reserve(CB cbIn, OUT PB* ppbOut)
|
|
{
|
|
dassert(cbIn >= 0);
|
|
|
|
if (pbEnd + cbIn > pbStart + cbAlloc && !grow(cbIn))
|
|
return FALSE;
|
|
|
|
if (ppbOut)
|
|
*ppbOut = pbEnd;
|
|
|
|
setPbExtent(pbStart, pbEnd + cbIn);
|
|
return TRUE;
|
|
}
|
|
|
|
inline BOOL Buffer::Append(PB pbIn, CB cbIn, OUT PB* ppbOut)
|
|
{
|
|
if (!pbIn)
|
|
return FALSE;
|
|
|
|
PB pb;
|
|
if (!Reserve(cbIn, &pb))
|
|
return FALSE;
|
|
|
|
if (ppbOut)
|
|
*ppbOut = pb;
|
|
|
|
memcpy(pb, pbIn, cbIn);
|
|
return TRUE;
|
|
}
|
|
|
|
inline BOOL Buffer::AppendFmt(SZ szFmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, szFmt);
|
|
|
|
for (;;) {
|
|
switch (*szFmt++) {
|
|
case 0:
|
|
va_end(args);
|
|
return TRUE;
|
|
case 'b': {
|
|
BYTE b = va_arg(args, BYTE);
|
|
if (!Append(&b, sizeof b, 0))
|
|
goto fail;
|
|
break;
|
|
}
|
|
case 's': {
|
|
USHORT us = va_arg(args, USHORT);
|
|
if (!Append((PB)&us, sizeof us, 0))
|
|
goto fail;
|
|
break;
|
|
}
|
|
case 'l': {
|
|
ULONG ul = va_arg(args, ULONG);
|
|
if (!Append((PB)&ul, sizeof ul, 0))
|
|
goto fail;
|
|
break;
|
|
}
|
|
case 'f': {
|
|
static BYTE zeroes[3] = { 0, 0, 0 };
|
|
int cb = va_arg(args, int);
|
|
assert(cb <= sizeof(zeroes));
|
|
if (cb != 0 && !Append(zeroes, cb, 0))
|
|
goto fail;
|
|
break;
|
|
}
|
|
case 'z': {
|
|
SZ sz = va_arg(args, SZ);
|
|
int cb = strlen(sz);
|
|
if (!Append((PB)sz, cb, 0))
|
|
goto fail;
|
|
break;
|
|
}
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
fail:
|
|
va_end(args);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// This class basically allows a Buffer object to use virtual memory
|
|
//
|
|
// If fUseVirtualMem is TRUE, this buffer will use virtual memory.
|
|
// If fUseVirtualMem is FALSE, then the base class Buffer functions will be used.
|
|
class VirtualBuffer : Buffer
|
|
{
|
|
public:
|
|
VirtualBuffer(BOOL fUseVirtualMem_, void (*pfn)(void*, void*, void*) = 0, void* pfnArg = 0)
|
|
: Buffer(pfn, pfnArg)
|
|
{
|
|
fUseVirtualMem = fUseVirtualMem_;
|
|
pbStart = NULL;
|
|
cb = 0;
|
|
}
|
|
|
|
PB Start() const;
|
|
CB Size() const;
|
|
BOOL Reserve(CB cbIn, OUT PB* ppbOut = 0);
|
|
void Commit(PB pbIn, CB cbIn);
|
|
BOOL Append(PB pbIn, CB cbIn, OUT PB* ppbOut = 0);
|
|
|
|
private:
|
|
PB pbStart;
|
|
CB cb;
|
|
BOOL fUseVirtualMem;
|
|
};
|
|
|
|
|
|
inline PB VirtualBuffer::Start() const
|
|
{
|
|
if (!fUseVirtualMem)
|
|
{
|
|
return Buffer::Start();
|
|
}
|
|
|
|
return pbStart;
|
|
}
|
|
|
|
inline CB VirtualBuffer::Size() const
|
|
{
|
|
if (!fUseVirtualMem)
|
|
{
|
|
return Buffer::Size();
|
|
}
|
|
|
|
return cb;
|
|
}
|
|
|
|
inline BOOL VirtualBuffer::Reserve(CB cbIn, OUT PB* ppbOut)
|
|
{
|
|
if (!fUseVirtualMem)
|
|
{
|
|
return Buffer::Reserve(cbIn, ppbOut);
|
|
}
|
|
|
|
// We currently only support one call to reserve...
|
|
assert(cb == 0 && pbStart == NULL);
|
|
|
|
pbStart = (PB) VirtualAlloc(NULL, cbIn, MEM_RESERVE, PAGE_READWRITE);
|
|
if (pbStart)
|
|
{
|
|
cb = cbIn;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
inline void VirtualBuffer::Commit(PB pbIn, CB cbIn)
|
|
{
|
|
if (fUseVirtualMem)
|
|
{
|
|
VirtualAlloc(pbIn, cbIn, MEM_COMMIT, PAGE_READWRITE);
|
|
}
|
|
}
|
|
|
|
inline BOOL VirtualBuffer::Append(PB pbIn, CB cbIn, OUT PB* ppbOut)
|
|
{
|
|
assert(!fUseVirtualMem);
|
|
return Buffer::Append(pbIn, cbIn, ppbOut);
|
|
}
|
|
|
|
#endif // !__BUFFER_INCLUDED__
|