windows-nt/Source/XPSP1/NT/windows/winstate/cobra/utils/main/growbuf.c
2020-09-26 16:20:57 +08:00

718 lines
12 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
growbuf.c
Abstract:
Simple buffer management functions that allow variable blocks to
be added as an array. (Initially used to build a SID array, where
each SID can be a different size.)
Author:
Jim Schmidt (jimschm) 05-Feb-1997
Revision History:
marcw 2-Sep-1999 Moved over from Win9xUpg project.
jimschm 11-Aug-1998 Added GrowBufAppendString
calinn 15-Jan-1998 modified MultiSzAppend
--*/
#include "pch.h"
//
// Includes
//
// None
#define DBG_GROWBUF "GrowBuffer"
//
// Strings
//
// None
//
// Constants
//
#define DEFAULT_GROW_SIZE 8192
//
// Macros
//
// None
//
// Types
//
// None
//
// Globals
//
#ifdef DEBUG
DWORD g_GbCurrActiveAlloc = 0;
DWORD g_GbCurrUsedAlloc = 0;
DWORD g_GbMaxActiveAlloc = 0;
DWORD g_GbMaxUsedAlloc = 0;
#endif
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
// None
//
// Macro expansion definition
//
// None
//
// Code
//
PBYTE
RealGbGrow (
IN OUT PGROWBUFFER GrowBuf,
IN DWORD SpaceNeeded
)
/*++
Routine Description:
GrowBuffer makes sure there is enough bytes in the buffer
to accomodate SpaceNeeded. It allocates an initial buffer
when no buffer is allocated, and it reallocates the buffer
in increments of GrowBuf->Size (or DEFAULT_GROW_SIZE) when
needed.
Arguments:
GrowBuf - A pointer to a GROWBUFFER structure.
Initialize this structure to zero for
the first call to GrowBuffer.
SpaceNeeded - The number of free bytes needed in the buffer
Return Value:
A pointer to the SpaceNeeded bytes, or NULL if a memory allocation
error occurred.
--*/
{
PBYTE NewBuffer;
DWORD TotalSpaceNeeded;
DWORD GrowTo;
MYASSERT(SpaceNeeded);
if (!GrowBuf->Buf) {
GrowBuf->Size = 0;
GrowBuf->End = 0;
#ifdef DEBUG
GrowBuf->StatEnd = 0;
#endif
}
if (!GrowBuf->GrowSize) {
GrowBuf->GrowSize = DEFAULT_GROW_SIZE;
}
#ifdef DEBUG
g_GbCurrActiveAlloc -= GrowBuf->Size;
g_GbCurrUsedAlloc -= GrowBuf->StatEnd;
#endif
TotalSpaceNeeded = GrowBuf->End + SpaceNeeded;
if (TotalSpaceNeeded > GrowBuf->Size) {
GrowTo = (TotalSpaceNeeded + GrowBuf->GrowSize) - (TotalSpaceNeeded % GrowBuf->GrowSize);
} else {
GrowTo = 0;
}
if (!GrowBuf->Buf) {
GrowBuf->Buf = (PBYTE) MemAlloc (g_hHeap, 0, GrowTo);
if (!GrowBuf->Buf) {
DEBUGMSG ((DBG_ERROR, "GbGrow: Initial alloc failed"));
return NULL;
}
GrowBuf->Size = GrowTo;
} else if (GrowTo) {
NewBuffer = MemReAlloc (g_hHeap, 0, GrowBuf->Buf, GrowTo);
if (!NewBuffer) {
DEBUGMSG ((DBG_ERROR, "GbGrow: Realloc failed"));
return NULL;
}
#ifdef DEBUG
if (GrowBuf->Buf != NewBuffer) {
DEBUGMSG ((
DBG_WARNING,
"GbGrow: Realloc caused growbuffer to move %u bytes to new location; "
"any pointers inside old buffer are now invalid",
GrowBuf->Size
));
if (GrowBuf->Size > 32767) {
TRACKDUMP();
}
}
#endif
GrowBuf->Size = GrowTo;
GrowBuf->Buf = NewBuffer;
}
NewBuffer = GrowBuf->Buf + GrowBuf->End;
GrowBuf->End += SpaceNeeded;
#ifdef DEBUG
GrowBuf->StatEnd = GrowBuf->End;
g_GbCurrActiveAlloc += GrowBuf->Size;
if (g_GbMaxActiveAlloc < g_GbCurrActiveAlloc) {
g_GbMaxActiveAlloc = g_GbCurrActiveAlloc;
}
g_GbCurrUsedAlloc += GrowBuf->StatEnd;
if (g_GbMaxUsedAlloc < g_GbCurrUsedAlloc) {
g_GbMaxUsedAlloc = g_GbCurrUsedAlloc;
}
#endif
return NewBuffer;
}
VOID
GbFree (
IN PGROWBUFFER GrowBuf
)
/*++
Routine Description:
FreeGrowBuffer frees a buffer allocated by GrowBuffer.
Arguments:
GrowBuf - A pointer to the same structure passed to GrowBuffer
Return Value:
none
--*/
{
MYASSERT(GrowBuf);
#ifdef DEBUG
g_GbCurrActiveAlloc -= GrowBuf->Size;
g_GbCurrUsedAlloc -= GrowBuf->StatEnd;
#endif
if (GrowBuf->Buf) {
MemFree (g_hHeap, 0, GrowBuf->Buf);
ZeroMemory (GrowBuf, sizeof (GROWBUFFER));
}
}
/*++
Routine Descriptions:
MultiSzAppend
This function is a general-purpose function to append a string
to a grow buffer.
MultiSzAppendVal
This function adds a key=decimal_val string, where key is a
specified string, and decimal_val is a specified DWORD.
MultiSzAppendString
This function adds key=string to the grow buffer, where key
is a specified string, and string is a specified string value.
Arguments:
GrowBuf - The buffer to append the string or key/value pair
Key - The key part of the key=val pair
Val - The val part of the key=val pair
Return Value:
TRUE if the function succeeded, or FALSE if a memory allocation
failure occurred.
--*/
BOOL
RealGbMultiSzAppendA (
PGROWBUFFER GrowBuf,
PCSTR String
)
{
PSTR p;
p = (PSTR) GbGrow (GrowBuf, SizeOfStringA (String) + sizeof(CHAR));
if (!p) {
return FALSE;
}
StringCopyA (p, String);
GrowBuf->End -= sizeof (CHAR);
GrowBuf->Buf[GrowBuf->End] = 0;
return TRUE;
}
BOOL
RealGbMultiSzAppendValA (
PGROWBUFFER GrowBuf,
PCSTR Key,
DWORD Val
)
{
CHAR KeyValPair[256];
wsprintfA (KeyValPair, "%s=%u", Key, Val);
return GbMultiSzAppendA (GrowBuf, KeyValPair);
}
BOOL
RealGbMultiSzAppendStringA (
PGROWBUFFER GrowBuf,
PCSTR Key,
PCSTR Val
)
{
CHAR KeyValPair[1024];
wsprintfA (KeyValPair, "%s=%s", Key, Val);
return GbMultiSzAppendA (GrowBuf, KeyValPair);
}
BOOL
RealGbMultiSzAppendW (
PGROWBUFFER GrowBuf,
PCWSTR String
)
{
PWSTR p;
p = (PWSTR) GbGrow (GrowBuf, SizeOfStringW (String) + sizeof(WCHAR));
if (!p) {
return FALSE;
}
StringCopyW (p, String);
GrowBuf->End -= sizeof (WCHAR);
*((PWCHAR) (GrowBuf->Buf + GrowBuf->End)) = 0;
return TRUE;
}
BOOL
RealGbMultiSzAppendValW (
PGROWBUFFER GrowBuf,
PCWSTR Key,
DWORD Val
)
{
WCHAR KeyValPair[256];
wsprintfW (KeyValPair, L"%s=%u", Key, Val);
return GbMultiSzAppendW (GrowBuf, KeyValPair);
}
BOOL
RealGbMultiSzAppendStringW (
PGROWBUFFER GrowBuf,
PCWSTR Key,
PCWSTR Val
)
{
WCHAR KeyValPair[1024];
wsprintfW (KeyValPair, L"%s=%s", Key, Val);
return GbMultiSzAppendW (GrowBuf, KeyValPair);
}
BOOL
RealGbAppendDword (
PGROWBUFFER GrowBuf,
DWORD d
)
{
PDWORD p;
p = (PDWORD) GbGrow (GrowBuf, sizeof (DWORD));
if (!p) {
return FALSE;
}
*p = d;
return TRUE;
}
BOOL
RealGbAppendPvoid (
PGROWBUFFER GrowBuf,
PCVOID Ptr
)
{
PCVOID *p;
p = (PVOID *) GbGrow (GrowBuf, sizeof (PVOID));
if (!p) {
return FALSE;
}
*p = Ptr;
return TRUE;
}
/*++
Routine Description:
GrowBufAppendString copies the specified string to the end of the grow
buffer. This is the equivalent of strcat. The grow buffer is
automatically expanded as necessary.
Arguments:
GrowBuf - Specifies the destination grow buffer
String - Specifies the string to append
Return Value:
Always TRUE.
--*/
BOOL
RealGbAppendStringA (
IN OUT PGROWBUFFER GrowBuf,
IN PCSTR String
)
{
UINT OldEnd;
PSTR p;
UINT Bytes;
if (String) {
Bytes = SizeOfStringA (String);
OldEnd = GrowBuf->End;
if (OldEnd) {
p = (PSTR) (GrowBuf->Buf + OldEnd - sizeof (CHAR));
if (*p == 0) {
OldEnd -= sizeof (CHAR);
}
}
RealGbGrow (GrowBuf, Bytes);
p = (PSTR) (GrowBuf->Buf + OldEnd);
StringCopyA (p, String);
GrowBuf->End = OldEnd + Bytes;
}
return TRUE;
}
BOOL
RealGbAppendStringW (
IN OUT PGROWBUFFER GrowBuf,
IN PCWSTR String
)
{
UINT OldEnd;
PWSTR p;
UINT Bytes;
if (String) {
Bytes = SizeOfStringW (String);
OldEnd = GrowBuf->End;
if (OldEnd) {
p = (PWSTR) (GrowBuf->Buf + OldEnd - sizeof (WCHAR));
if (*p == 0) {
OldEnd -= sizeof (WCHAR);
}
}
RealGbGrow (GrowBuf, Bytes);
p = (PWSTR) (GrowBuf->Buf + OldEnd);
StringCopyW (p, String);
GrowBuf->End = OldEnd + Bytes;
}
return TRUE;
}
/*++
Routine Description:
GrowBufAppendStringAB copies the specified string range to the
end of the grow buffer. This concatenates the string to the
existing buffer contents, and keeps the buffer terminated.
Arguments:
GrowBuf - Specifies the destination grow buffer
Start - Specifies the start of string to append
EndPlusOne - Specifies one logical character beyond the end of
the string, and can point to a nul.
Return Value:
Always TRUE.
--*/
BOOL
RealGbAppendStringABA (
IN OUT PGROWBUFFER GrowBuf,
IN PCSTR Start,
IN PCSTR EndPlusOne
)
{
UINT OldEnd;
PSTR p;
UINT Bytes;
if (Start && Start < EndPlusOne) {
Bytes = (UINT)((UBINT) EndPlusOne - (UBINT) Start);
OldEnd = GrowBuf->End;
if (OldEnd) {
p = (PSTR) (GrowBuf->Buf + OldEnd - sizeof (CHAR));
if (*p == 0) {
OldEnd -= sizeof (CHAR);
}
}
RealGbGrow (GrowBuf, Bytes + sizeof (CHAR));
p = (PSTR) (GrowBuf->Buf + OldEnd);
CopyMemory (p, Start, Bytes);
p = (PSTR) ((PBYTE) p + Bytes);
*p = 0;
GrowBuf->End = OldEnd + Bytes + sizeof (CHAR);
}
return TRUE;
}
BOOL
RealGbAppendStringABW (
IN OUT PGROWBUFFER GrowBuf,
IN PCWSTR Start,
IN PCWSTR EndPlusOne
)
{
UINT OldEnd;
PWSTR p;
UINT Bytes;
if (Start && Start < EndPlusOne) {
Bytes = (UINT)((UBINT) EndPlusOne - (UBINT) Start);
OldEnd = GrowBuf->End;
if (OldEnd > sizeof (WCHAR)) {
p = (PWSTR) (GrowBuf->Buf + OldEnd - sizeof (WCHAR));
if (*p == 0) {
OldEnd -= sizeof (WCHAR);
}
}
RealGbGrow (GrowBuf, Bytes + sizeof (WCHAR));
p = (PWSTR) (GrowBuf->Buf + OldEnd);
CopyMemory (p, Start, Bytes);
p = (PWSTR) ((PBYTE) p + Bytes);
*p = 0;
GrowBuf->End = OldEnd + Bytes + sizeof (WCHAR);
}
return TRUE;
}
/*++
Routine Description:
GrowBufCopyString copies the specified string to the end of the grow buffer.
Arguments:
GrowBuf - Specifies the grow buffer to add to, receives the updated buffer
String - Specifies the string to add to GrowBuf
Return Value:
--*/
BOOL
RealGbCopyStringA (
IN OUT PGROWBUFFER GrowBuf,
IN PCSTR String
)
{
PBYTE Buf;
UINT Size;
Size = SizeOfStringA (String);
Buf = RealGbGrow (GrowBuf, Size);
if (!Buf) {
return FALSE;
}
CopyMemory (Buf, String, Size);
return TRUE;
}
BOOL
RealGbCopyStringW (
IN OUT PGROWBUFFER GrowBuf,
IN PCWSTR String
)
{
PBYTE Buf;
UINT Size;
Size = SizeOfStringW (String);
Buf = RealGbGrow (GrowBuf, Size);
if (!Buf) {
return FALSE;
}
CopyMemory (Buf, String, Size);
return TRUE;
}
BOOL
RealGbCopyQuotedStringA (
IN OUT PGROWBUFFER GrowBuf,
IN PCSTR String
)
{
PBYTE Buf;
UINT Size;
Size = SizeOfStringA (String);
Buf = RealGbGrow (GrowBuf, Size + 2 * sizeof (CHAR));
if (!Buf) {
return FALSE;
}
*((CHAR *)(Buf)) = '\"';
CopyMemory (Buf + sizeof (CHAR), String, Size);
*((CHAR *)(Buf + Size)) = '\"';
*((CHAR *)(Buf + Size + sizeof (CHAR))) = 0;
return TRUE;
}
BOOL
RealGbCopyQuotedStringW (
IN OUT PGROWBUFFER GrowBuf,
IN PCWSTR String
)
{
PBYTE Buf;
UINT Size;
Size = SizeOfStringW (String);
Buf = RealGbGrow (GrowBuf, Size + 2 * sizeof (WCHAR));
if (!Buf) {
return FALSE;
}
*((WCHAR *)(Buf)) = L'\"';
CopyMemory (Buf + sizeof (WCHAR), String, Size);
*((WCHAR *)(Buf + Size)) = L'\"';
*((WCHAR *)(Buf + Size + sizeof (WCHAR))) = 0;
return TRUE;
}
#ifdef DEBUG
VOID
GbDumpStatistics (
VOID
)
{
DEBUGMSG ((
DBG_STATS,
"Grow buffers usage:\nPeak : Usable:%-8d Used:%-8d\nCurrent: Usable:%-8d Leak:%-8d",
g_GbMaxActiveAlloc,
g_GbMaxUsedAlloc,
g_GbCurrActiveAlloc,
g_GbCurrUsedAlloc
));
}
#endif