747 lines
22 KiB
C
747 lines
22 KiB
C
/*++
|
||
|
||
Copyright (c) 1991-92 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
packstr.c
|
||
|
||
Abstract:
|
||
|
||
Contains utilities for allocating and/or packing buffers that contain
|
||
a fixed section and a variable (string) section. The following
|
||
functions are available:
|
||
|
||
NetpPackString
|
||
NetpCopyStringToBuffer
|
||
NetpCopyDataToBuffer
|
||
NetpAllocateEnumBuffer
|
||
|
||
Author:
|
||
|
||
various
|
||
|
||
Environment:
|
||
|
||
User Mode -Win32
|
||
|
||
Revision History:
|
||
|
||
30-Apr-1991 danl
|
||
NetpAllocateEnumBuffer: Removed use of NetApiBufferFree. It has
|
||
been changed to use MIDL_user_allocate and MIDL_user_free.
|
||
Also added NT-style headers where needed.
|
||
16-Apr-1991 JohnRo
|
||
Clarify UNICODE handling of pack and copy routines. Got rid of tabs
|
||
in source file.
|
||
21-Nov-1991 JohnRo
|
||
Removed NT dependencies to reduce recompiles.
|
||
15-Apr-1992 JohnRo
|
||
FORMAT_POINTER is obsolete.
|
||
|
||
--*/
|
||
|
||
// These must be included first:
|
||
|
||
#include <windef.h> // IN, OUT, etc.
|
||
#include <lmcons.h> // Needed by <netlib.h>.
|
||
#include <lmerr.h> // NERR_*
|
||
#include <rpcutil.h> // MIDL_user_allocate & MIDL_user_free
|
||
|
||
// These may be included in any order:
|
||
|
||
#include <align.h> // ROUND_UP_COUNT().
|
||
#include <debuglib.h> // IF_DEBUG().
|
||
#include <netdebug.h> // NetpKdPrint(), FORMAT_ equates.
|
||
#include <netlib.h> // My prototype.
|
||
#include <tstring.h> // STRCPY(), STRLEN(), STRNCPY().
|
||
|
||
|
||
DWORD
|
||
NetpPackString(
|
||
IN OUT LPTSTR * string, // pointer by reference: string to be copied.
|
||
IN LPBYTE dataend, // pointer to end of fixed size data.
|
||
IN OUT LPTSTR * laststring // pointer by reference: top of string data.
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
NetPackString is used to stuff variable-length data, which
|
||
is pointed to by (surpise!) a pointer. The data is assumed
|
||
to be a nul-terminated string (ASCIIZ). Repeated calls to
|
||
this function are used to pack data from an entire structure.
|
||
|
||
Upon first call, the laststring pointer should point to just
|
||
past the end of the buffer. Data will be copied into the buffer from
|
||
the end, working towards the beginning. If a data item cannot
|
||
fit, the pointer will be set to NULL, else the pointer will be
|
||
set to the new data location.
|
||
|
||
Pointers which are passed in as NULL will be set to be pointer
|
||
to and empty string, as the NULL-pointer is reserved for
|
||
data which could not fit as opposed to data not available.
|
||
|
||
See the test case for sample usage. (tst/packtest.c)
|
||
|
||
|
||
Arguments:
|
||
|
||
string - pointer by reference: string to be copied.
|
||
|
||
dataend - pointer to end of fixed size data.
|
||
|
||
laststring - pointer by reference: top of string data.
|
||
|
||
Return Value:
|
||
|
||
0 - if it could not fit data into the buffer. Or...
|
||
|
||
sizeOfData - the size of data stuffed (guaranteed non-zero)
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD size;
|
||
|
||
IF_DEBUG(PACKSTR) {
|
||
NetpKdPrint(("NetpPackString:\n"));
|
||
NetpKdPrint((" string=" FORMAT_LPVOID
|
||
", *string=" FORMAT_LPVOID
|
||
", **string='" FORMAT_LPSTR "'\n",
|
||
(LPVOID) string, (LPVOID) *string, *string));
|
||
NetpKdPrint((" end=" FORMAT_LPVOID "\n", (LPVOID) dataend));
|
||
NetpKdPrint((" last=" FORMAT_LPVOID
|
||
", *last=" FORMAT_LPVOID
|
||
", **last='" FORMAT_LPSTR "'\n",
|
||
(LPVOID) laststring, (LPVOID) *laststring, *laststring));
|
||
}
|
||
|
||
//
|
||
// convert NULL ptr to pointer to NULL string
|
||
//
|
||
|
||
if (*string == NULL) {
|
||
// BUG 20.1160 - replaced (dataend +1) with dataend
|
||
// to allow for a NULL ptr to be packed
|
||
// (as a NULL string) with one byte left in the
|
||
// buffer. - ERICPE
|
||
//
|
||
|
||
if ( *laststring > (LPTSTR)dataend ) {
|
||
*(--(*laststring)) = 0;
|
||
*string = *laststring;
|
||
return 1;
|
||
} else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// is there room for the string?
|
||
//
|
||
|
||
size = STRLEN(*string) + 1;
|
||
if ( ((DWORD)(*laststring - (LPTSTR)dataend)) < size) {
|
||
*string = NULL;
|
||
return(0);
|
||
} else {
|
||
*laststring -= size;
|
||
STRCPY(*laststring, *string);
|
||
*string = *laststring;
|
||
return(size);
|
||
}
|
||
} // NetpPackString
|
||
|
||
|
||
BOOL
|
||
NetpCopyStringToBuffer (
|
||
IN LPTSTR String OPTIONAL,
|
||
IN DWORD CharacterCount,
|
||
IN LPBYTE FixedDataEnd,
|
||
IN OUT LPTSTR *EndOfVariableData,
|
||
OUT LPTSTR *VariableDataPointer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine puts a single variable-length string into an output buffer.
|
||
The string is not written if it would overwrite the last fixed structure
|
||
in the buffer.
|
||
|
||
The code is swiped from svcsupp.c written by DavidTr.
|
||
|
||
Sample usage:
|
||
|
||
LPBYTE FixedDataEnd = OutputBuffer + sizeof(WKSTA_INFO_202);
|
||
LPTSTR EndOfVariableData = OutputBuffer + OutputBufferSize;
|
||
|
||
//
|
||
// Copy user name
|
||
//
|
||
|
||
NetpCopyStringToBuffer(
|
||
UserInfo->UserName.Buffer;
|
||
UserInfo->UserName.Length;
|
||
FixedDataEnd,
|
||
&EndOfVariableData,
|
||
&WkstaInfo->wki202_username
|
||
);
|
||
|
||
Arguments:
|
||
|
||
String - Supplies a pointer to the source string to copy into the
|
||
output buffer. If String is null then a pointer to a zero terminator
|
||
is inserted into output buffer.
|
||
|
||
CharacterCount - Supplies the length of String, not including zero
|
||
terminator.
|
||
|
||
FixedDataEnd - Supplies a pointer to just after the end of the last
|
||
fixed structure in the buffer.
|
||
|
||
EndOfVariableData - Supplies an address to a pointer to just after the
|
||
last position in the output buffer that variable data can occupy.
|
||
Returns a pointer to the string written in the output buffer.
|
||
|
||
VariableDataPointer - Supplies a pointer to the place in the fixed
|
||
portion of the output buffer where a pointer to the variable data
|
||
should be written.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if string fits into output buffer, FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
DWORD BytesNeeded = (CharacterCount + 1) * sizeof(TCHAR);
|
||
|
||
IF_DEBUG(PACKSTR) {
|
||
NetpKdPrint(("NetpStringToBuffer: String at " FORMAT_LPVOID
|
||
", CharacterCount=" FORMAT_DWORD
|
||
",\n FixedDataEnd at " FORMAT_LPVOID
|
||
", *EndOfVariableData at " FORMAT_LPVOID
|
||
",\n VariableDataPointer at " FORMAT_LPVOID
|
||
", BytesNeeded=" FORMAT_DWORD ".\n",
|
||
(LPVOID) String, CharacterCount, FixedDataEnd,
|
||
(LPVOID) *EndOfVariableData,
|
||
(LPVOID) VariableDataPointer, BytesNeeded));
|
||
}
|
||
|
||
//
|
||
// Determine if string will fit, allowing for a zero terminator. If no,
|
||
// just set the pointer to NULL.
|
||
//
|
||
|
||
if ((*EndOfVariableData - (CharacterCount+1)) >= (LPTSTR)FixedDataEnd) {
|
||
|
||
//
|
||
// It fits. Move EndOfVariableData pointer up to the location where
|
||
// we will write the string.
|
||
//
|
||
|
||
*EndOfVariableData -= (CharacterCount+1);
|
||
|
||
//
|
||
// Copy the string to the buffer if it is not null.
|
||
//
|
||
|
||
if (CharacterCount > 0 && String != NULL) {
|
||
|
||
STRNCPY(*EndOfVariableData, String, CharacterCount);
|
||
}
|
||
|
||
//
|
||
// Set the zero terminator.
|
||
//
|
||
|
||
*(*EndOfVariableData + CharacterCount) = TCHAR_EOS;
|
||
|
||
//
|
||
// Set up the pointer in the fixed data portion to point to where the
|
||
// string is written.
|
||
//
|
||
|
||
*VariableDataPointer = *EndOfVariableData;
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
else {
|
||
|
||
//
|
||
// It doesn't fit. Set the offset to NULL.
|
||
//
|
||
|
||
*VariableDataPointer = NULL;
|
||
|
||
return FALSE;
|
||
}
|
||
} // NetpCopyStringToBuffer
|
||
|
||
|
||
BOOL
|
||
NetpCopyDataToBuffer (
|
||
IN LPBYTE Data,
|
||
IN DWORD ByteCount,
|
||
IN LPBYTE FixedDataEnd,
|
||
IN OUT LPBYTE *EndOfVariableData,
|
||
OUT LPBYTE *VariableDataPointer,
|
||
IN DWORD Alignment
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine puts the specified data into an output buffer.
|
||
The data is not written if it would overwrite the last fixed structure
|
||
in the buffer.
|
||
|
||
The output buffer is aligned as requested.
|
||
|
||
Sample usage:
|
||
|
||
LPBYTE FixedDataEnd = OutputBuffer + sizeof(WKSTA_INFO_202);
|
||
LPBYTE EndOfVariableData = OutputBuffer + OutputBufferSize;
|
||
|
||
//
|
||
// Copy Logon hours
|
||
//
|
||
|
||
NetpCopyDataToBuffer(
|
||
StructurePointer,
|
||
sizeof( STRUCTURE_TYPE),
|
||
FixedDataEnd,
|
||
&EndOfVariableData,
|
||
&UserInfo->usri2->LogonHours,
|
||
sizeof(ULONG)
|
||
);
|
||
|
||
Arguments:
|
||
|
||
Data - Supplies a pointer to the source data to copy into the
|
||
output buffer. If Data is null then a null pointer is returned in
|
||
VariableDataPointer.
|
||
|
||
ByteCount - Supplies the length of Data.
|
||
|
||
FixedDataEnd - Supplies a pointer to just after the end of the last
|
||
fixed structure in the buffer.
|
||
|
||
EndOfVariableData - Supplies an address to a pointer to just after the
|
||
last position in the output buffer that variable data can occupy.
|
||
Returns a pointer to the data written in the output buffer.
|
||
|
||
VariableDataPointer - Supplies a pointer to the place in the fixed
|
||
portion of the output buffer where a pointer to the variable data
|
||
should be written.
|
||
|
||
Alignment - Supplies the required alignment of the data expressed
|
||
as the number of bytes in the primitive datatype (e.g., 1 for byte,
|
||
2 for short, 4 for long, and 8 for quad).
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if data fits into output buffer, FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
|
||
LPBYTE NewEndOfVariableData;
|
||
|
||
//
|
||
// If there is no data to copy, just return success.
|
||
//
|
||
|
||
if ( Data == NULL ) {
|
||
*VariableDataPointer = NULL;
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Compute where the data will be copied to (taking alignment into
|
||
// consideration).
|
||
//
|
||
// We may end up with a few unused byte after the copied data.
|
||
//
|
||
|
||
NetpAssert((Alignment == 1) || (Alignment == 2) ||
|
||
(Alignment == 4) || (Alignment == 8));
|
||
|
||
NewEndOfVariableData = (LPBYTE)
|
||
(((DWORD_PTR)(*EndOfVariableData - ByteCount)) & ~((LONG)Alignment - 1));
|
||
|
||
//
|
||
// If the data doesn't fit into the buffer, error out
|
||
//
|
||
|
||
if ( NewEndOfVariableData < FixedDataEnd) {
|
||
*VariableDataPointer = NULL;
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Copy the data to the buffer
|
||
//
|
||
|
||
if (ByteCount > 0) {
|
||
NetpMoveMemory(NewEndOfVariableData, Data, ByteCount);
|
||
}
|
||
|
||
//
|
||
// Return the pointer to the new data and update the pointer to
|
||
// how much of the buffer we've used so far.
|
||
//
|
||
|
||
*VariableDataPointer = NewEndOfVariableData;
|
||
*EndOfVariableData = NewEndOfVariableData;
|
||
|
||
return TRUE;
|
||
|
||
} // NetpCopyDataToBuffer
|
||
|
||
|
||
NET_API_STATUS
|
||
NetpAllocateEnumBuffer(
|
||
IN OUT PBUFFER_DESCRIPTOR BufferDescriptor,
|
||
IN BOOL IsGet,
|
||
IN DWORD PrefMaxSize,
|
||
IN DWORD NeededSize,
|
||
IN VOID (*RelocationRoutine)( IN DWORD RelocationParameter,
|
||
IN OUT PBUFFER_DESCRIPTOR BufferDescriptor,
|
||
IN PTRDIFF_T Offset ),
|
||
IN DWORD RelocationParameter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Ensures a buffer is allocated which contains the needed size.
|
||
|
||
Arguments:
|
||
|
||
BufferDescriptor - Points to a structure which describes the allocated
|
||
buffer. On the first call, pass in BufferDescriptor->Buffer set
|
||
to NULL. On subsequent calls (in the 'enum' case), pass in the
|
||
structure just as it was passed back on a previous call.
|
||
|
||
The caller must deallocate the BufferDescriptor->Buffer using
|
||
MIDL_user_free if it is non-null.
|
||
|
||
IsGet - TRUE iff this is a 'get' rather than an 'enum' operation.
|
||
|
||
PrefMaxSize - Callers prefered maximum size
|
||
|
||
NeededSize - the number of bytes which must be available in the allocated
|
||
buffer.
|
||
|
||
RelocationRoutine - Supplies a pointer to a routine that will be called
|
||
when the buffer needs to be relocated. The routine is called with
|
||
both the fixed portion and the strings already copied. Merely,
|
||
the pointers to the strings need to be adjusted.
|
||
|
||
The 'Offset' parameter to the relocation routine merely needs to
|
||
be added to the each pointer within the allocated buffer which points
|
||
to a place within the allocated buffer. It is a byte-offset. This
|
||
design depends on a 'flat' address space where the addresses of two
|
||
unrelated pointers can simply be subtracted.
|
||
|
||
RelocationParameter - Supplies a parameter which will (in turn) be passed
|
||
to the relocation routine.
|
||
|
||
Return Value:
|
||
|
||
Error code for the operation.
|
||
|
||
If this is an Enum call, the status can be ERROR_MORE_DATA implying that
|
||
the Buffer has grown to PrefMaxSize and that this much data should
|
||
be returned to the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
return NetpAllocateEnumBufferEx(
|
||
BufferDescriptor,
|
||
IsGet,
|
||
PrefMaxSize,
|
||
NeededSize,
|
||
RelocationRoutine,
|
||
RelocationParameter,
|
||
NETP_ENUM_GUESS );
|
||
}
|
||
|
||
|
||
NET_API_STATUS
|
||
NetpAllocateEnumBufferEx(
|
||
IN OUT PBUFFER_DESCRIPTOR BufferDescriptor,
|
||
IN BOOL IsGet,
|
||
IN DWORD PrefMaxSize,
|
||
IN DWORD NeededSize,
|
||
IN VOID (*RelocationRoutine)( IN DWORD RelocationParameter,
|
||
IN OUT PBUFFER_DESCRIPTOR BufferDescriptor,
|
||
IN PTRDIFF_T Offset ),
|
||
IN DWORD RelocationParameter,
|
||
IN DWORD IncrementalSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Ensures a buffer is allocated which contains the needed size.
|
||
|
||
Arguments:
|
||
|
||
BufferDescriptor - Points to a structure which describes the allocated
|
||
buffer. On the first call, pass in BufferDescriptor->Buffer set
|
||
to NULL. On subsequent calls (in the 'enum' case), pass in the
|
||
structure just as it was passed back on a previous call.
|
||
|
||
The caller must deallocate the BufferDescriptor->Buffer using
|
||
MIDL_user_free if it is non-null.
|
||
|
||
IsGet - TRUE iff this is a 'get' rather than an 'enum' operation.
|
||
|
||
PrefMaxSize - Callers prefered maximum size
|
||
|
||
NeededSize - the number of bytes which must be available in the allocated
|
||
buffer.
|
||
|
||
RelocationRoutine - Supplies a pointer to a routine that will be called
|
||
when the buffer needs to be relocated. The routine is called with
|
||
both the fixed portion and the strings already copied. Merely,
|
||
the pointers to the strings need to be adjusted.
|
||
|
||
The 'Offset' parameter to the relocation routine merely needs to
|
||
be added to the each pointer within the allocated buffer which points
|
||
to a place within the allocated buffer. It is a byte-offset. This
|
||
design depends on a 'flat' address space where the addresses of two
|
||
unrelated pointers can simply be subtracted.
|
||
|
||
RelocationParameter - Supplies a parameter which will (in turn) be passed
|
||
to the relocation routine.
|
||
|
||
IncrementalSize - Mimimum number of bytes to extend the buffer by when it
|
||
needs extending.
|
||
|
||
Return Value:
|
||
|
||
Error code for the operation.
|
||
|
||
If this is an Enum call, the status can be ERROR_MORE_DATA implying that
|
||
the Buffer has grown to PrefMaxSize and that this much data should
|
||
be returned to the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
PBUFFER_DESCRIPTOR Desc = BufferDescriptor;
|
||
|
||
IF_DEBUG(PACKSTR) {
|
||
NetpKdPrint((
|
||
"NetpAllocateEnumBuffer: Isget: " FORMAT_DWORD " PrefMaxSize: "
|
||
FORMAT_HEX_DWORD " NeededSize: " FORMAT_HEX_DWORD "\n",
|
||
IsGet, PrefMaxSize, NeededSize ));
|
||
|
||
NetpKdPrint((
|
||
"+BufferDescriptor: Buffer: " FORMAT_HEX_DWORD " AllocSize: "
|
||
FORMAT_HEX_DWORD " AllocIncr: " FORMAT_HEX_DWORD "\n",
|
||
Desc->Buffer, Desc->AllocSize, Desc->AllocIncrement ));
|
||
NetpKdPrint(( " variable: " FORMAT_HEX_DWORD " Fixed:"
|
||
FORMAT_HEX_DWORD "\n",
|
||
Desc->EndOfVariableData, Desc->FixedDataEnd ));
|
||
}
|
||
|
||
//
|
||
// If this is not a resume, initialize a buffer descriptor.
|
||
//
|
||
|
||
if ( Desc->Buffer == NULL ) {
|
||
|
||
//
|
||
// Allocate the return buffer.
|
||
//
|
||
// If this is a Getinfo call, allocate the buffer the correct size.
|
||
//
|
||
// If the is an Enum call, this is an initial allocation which
|
||
// might be reallocated later if this size isn't big enough.
|
||
// The initial allocation is the user's prefered maximum
|
||
// length unless that length is deemed to be very large.
|
||
// In that case we allocate a good sized buffer and will
|
||
// reallocate later as needed.
|
||
//
|
||
|
||
if ( IsGet ) {
|
||
|
||
Desc->AllocSize = NeededSize;
|
||
|
||
} else {
|
||
|
||
if ( PrefMaxSize < NeededSize ) {
|
||
NetStatus = NERR_BufTooSmall;
|
||
goto Cleanup;
|
||
}
|
||
|
||
Desc->AllocSize = min(PrefMaxSize, IncrementalSize);
|
||
Desc->AllocSize = max(NeededSize, Desc->AllocSize );
|
||
|
||
}
|
||
|
||
// Some callers pack data on that top end of this buffer so
|
||
// ensure the buffer size allows for proper alignment.
|
||
Desc->AllocSize = ROUND_UP_COUNT( Desc->AllocSize, ALIGN_WORST );
|
||
|
||
Desc->AllocIncrement = Desc->AllocSize;
|
||
IF_DEBUG(PACKSTR) {
|
||
NetpKdPrint((" Allocated size : " FORMAT_HEX_DWORD "\n",
|
||
Desc->AllocSize ));
|
||
}
|
||
|
||
Desc->Buffer = MIDL_user_allocate(Desc->AllocSize);
|
||
|
||
if (Desc->Buffer == NULL) {
|
||
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
|
||
IF_DEBUG(PACKSTR) {
|
||
NetpKdPrint((" Allocated: " FORMAT_HEX_DWORD "\n", Desc->Buffer ));
|
||
}
|
||
|
||
Desc->FixedDataEnd = Desc->Buffer;
|
||
Desc->EndOfVariableData = Desc->Buffer + Desc->AllocSize;
|
||
|
||
//
|
||
// If this is a resume, get the buffer descriptor that the caller passed in.
|
||
//
|
||
|
||
} else {
|
||
|
||
//
|
||
// If the entry doesn't fit, reallocate a larger return buffer
|
||
//
|
||
|
||
if ((DWORD)(Desc->EndOfVariableData - Desc->FixedDataEnd) < NeededSize){
|
||
|
||
BUFFER_DESCRIPTOR OldDesc;
|
||
DWORD FixedSize; // Total size of the fixed data
|
||
DWORD StringSize; // Total size of the string data
|
||
|
||
//
|
||
// If the buffer is as big as is allowed,
|
||
// we're all done for now.
|
||
//
|
||
|
||
if ( Desc->AllocSize >= PrefMaxSize ) {
|
||
NetStatus = ERROR_MORE_DATA;
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate a larger return buffer.
|
||
//
|
||
|
||
OldDesc = *Desc;
|
||
|
||
Desc->AllocSize += max( NeededSize, Desc->AllocIncrement );
|
||
Desc->AllocSize = min( Desc->AllocSize, PrefMaxSize );
|
||
Desc->AllocSize = ROUND_UP_COUNT( Desc->AllocSize, ALIGN_WORST );
|
||
IF_DEBUG(PACKSTR) {
|
||
NetpKdPrint(("Re-Allocated size : " FORMAT_HEX_DWORD "\n",
|
||
Desc->AllocSize ));
|
||
}
|
||
Desc->Buffer = MIDL_user_allocate( Desc->AllocSize );
|
||
|
||
if ( Desc->Buffer == NULL ) {
|
||
MIDL_user_free( OldDesc.Buffer );
|
||
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
IF_DEBUG(PACKSTR) {
|
||
NetpKdPrint(("ReAllocated: " FORMAT_HEX_DWORD "\n",
|
||
Desc->Buffer ));
|
||
}
|
||
|
||
//
|
||
// Copy the fixed length portion of the data to the new buffer
|
||
//
|
||
|
||
FixedSize = (DWORD)(OldDesc.FixedDataEnd - OldDesc.Buffer);
|
||
|
||
RtlCopyMemory( Desc->Buffer,
|
||
OldDesc.Buffer,
|
||
FixedSize );
|
||
|
||
Desc->FixedDataEnd = Desc->Buffer + FixedSize ;
|
||
|
||
//
|
||
// Copy the string portion of the data to the new buffer
|
||
//
|
||
|
||
StringSize = OldDesc.AllocSize -
|
||
(DWORD)(OldDesc.EndOfVariableData - OldDesc.Buffer);
|
||
|
||
Desc->EndOfVariableData = Desc->Buffer + Desc->AllocSize - StringSize;
|
||
|
||
RtlCopyMemory( Desc->EndOfVariableData, OldDesc.EndOfVariableData, StringSize );
|
||
|
||
//
|
||
// Callback to allow the pointers into the string data to be
|
||
// relocated.
|
||
//
|
||
// The callback routine merely needs to add the value I pass it
|
||
// to all of the pointers from the fixed area to the string area.
|
||
//
|
||
|
||
(*RelocationRoutine)(
|
||
RelocationParameter,
|
||
Desc,
|
||
(Desc->EndOfVariableData - OldDesc.EndOfVariableData) );
|
||
|
||
//
|
||
// Free the old buffer.
|
||
//
|
||
|
||
MIDL_user_free( OldDesc.Buffer );
|
||
}
|
||
}
|
||
|
||
NetStatus = NERR_Success;
|
||
|
||
//
|
||
// Clean up
|
||
//
|
||
|
||
Cleanup:
|
||
//
|
||
//
|
||
//
|
||
|
||
if ( NetStatus != NERR_Success && NetStatus != ERROR_MORE_DATA &&
|
||
Desc->Buffer != NULL ) {
|
||
|
||
MIDL_user_free (Desc->Buffer );
|
||
Desc->Buffer = NULL;
|
||
}
|
||
|
||
IF_DEBUG(PACKSTR) {
|
||
NetpKdPrint((
|
||
"BufferDescriptor: Buffer: " FORMAT_HEX_DWORD " AllocSize: "
|
||
FORMAT_HEX_DWORD " AllocIncr: " FORMAT_HEX_DWORD "\n",
|
||
Desc->Buffer, Desc->AllocSize, Desc->AllocIncrement ));
|
||
NetpKdPrint(( " variable: " FORMAT_HEX_DWORD " Fixed:"
|
||
FORMAT_HEX_DWORD "\n",
|
||
Desc->EndOfVariableData, Desc->FixedDataEnd ));
|
||
}
|
||
|
||
return NetStatus;
|
||
|
||
} // NetpAllocateEnumBuffer
|