1833 lines
36 KiB
C
1833 lines
36 KiB
C
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
blobs.c
|
|
|
|
Abstract:
|
|
|
|
Implements a set of APIs to manage BLOBS and arrays of BLOBS.
|
|
|
|
Author:
|
|
|
|
Ovidiu Temereanca (ovidiut) 24-Nov-1999
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
// None
|
|
|
|
#define DBG_BLOBS "Blobs"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define BLOB_SIGNATURE 0x79563442
|
|
#define BLOB_GROWDATASIZE_DEFAULT 1024
|
|
#define BLOBS_GROWCOUNT_DEFAULT 64
|
|
#define BLOBS_SIGNATURE 0x12567841
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
typedef struct {
|
|
DWORD BlobSignature;
|
|
DWORD DataSize;
|
|
DWORD Flags;
|
|
} BLOBHDR, *PBLOBHDR;
|
|
|
|
typedef struct {
|
|
DWORD BlobsArraySignature;
|
|
DWORD BlobsCount;
|
|
} BLOBSARRAYHDR, *PBLOBSARRAYHDR;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define ASSERT_VALID_BLOB(b) MYASSERT (pIsValidBlob (b))
|
|
#define ASSERT_VALID_BLOBS_ARRAY(a) MYASSERT (pIsValidBlobsArray (a))
|
|
|
|
BOOL
|
|
pIsValidBlob (
|
|
IN POURBLOB Blob
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pIsValidBlob checks if the passed-in blob points to a valid OURBLOB blob structure
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies a pointer to the blob to be checked
|
|
|
|
Return Value:
|
|
|
|
TRUE if the check was successful.
|
|
FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b = TRUE;
|
|
|
|
if (!Blob) {
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
b = !Blob->Data && !Blob->End && !Blob->Index && !Blob->AllocSize ||
|
|
Blob->Data && Blob->AllocSize && Blob->End <= Blob->AllocSize && Blob->Index <= Blob->AllocSize;
|
|
}
|
|
__except (TRUE) {
|
|
b = FALSE;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
pIsValidBlobsArray (
|
|
IN PBLOBS BlobsArray
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pIsValidBlobsArray checks if the passed-in bloba array points to a valid BLOBS array structure
|
|
|
|
Arguments:
|
|
|
|
BlobsArray - Specifies a pointer to the blobs array to be checked
|
|
|
|
Return Value:
|
|
|
|
TRUE if the check was successful.
|
|
FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL b = TRUE;
|
|
|
|
if (!BlobsArray) {
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
b = !BlobsArray->Blobs && !BlobsArray->BlobsCount && !BlobsArray->BlobsAllocated ||
|
|
BlobsArray->Signature == BLOBS_SIGNATURE &&
|
|
BlobsArray->Blobs &&
|
|
BlobsArray->BlobsAllocated &&
|
|
BlobsArray->BlobsGrowCount &&
|
|
BlobsArray->BlobsCount <= BlobsArray->BlobsAllocated;
|
|
}
|
|
__except (TRUE) {
|
|
b = FALSE;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
#else
|
|
|
|
#define ASSERT_VALID_BLOB(b)
|
|
#define ASSERT_VALID_BLOBS_ARRAY(a)
|
|
|
|
#endif
|
|
|
|
|
|
PVOID
|
|
pBlobAllocateMemory (
|
|
IN DWORD Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pBlobAllocateMemory is a private function that allocates space from the process heap
|
|
|
|
Arguments:
|
|
|
|
Size - Specifies the size (in bytes) to allocate.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the successfully allocated memory or NULL if not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT (Size);
|
|
return HeapAlloc (g_hHeap, 0, Size);
|
|
}
|
|
|
|
|
|
static
|
|
PVOID
|
|
pReAllocateMemory (
|
|
IN PVOID OldBuffer,
|
|
IN DWORD NewSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pReAllocateMemory is a private function that re-allocates space from the process heap
|
|
|
|
Arguments:
|
|
|
|
OldBuffer - Specifies the buffer to be re-allocated
|
|
Size - Specifies the size (in bytes) to allocate.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the successfully re-allocated memory or NULL if not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT (OldBuffer);
|
|
MYASSERT (NewSize);
|
|
return HeapReAlloc (g_hHeap, 0, OldBuffer, NewSize);
|
|
}
|
|
|
|
|
|
VOID
|
|
pBlobFreeMemory (
|
|
IN PVOID Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pBlobFreeMemory is a private function that frees space allocated from the process heap
|
|
|
|
Arguments:
|
|
|
|
Buffer - Specifies a pointer to buffer to free.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
MYASSERT (Buffer);
|
|
HeapFree (g_hHeap, 0, Buffer);
|
|
}
|
|
|
|
|
|
POURBLOB
|
|
BlobCreate (
|
|
VOID
|
|
)
|
|
{
|
|
POURBLOB newBlob;
|
|
|
|
newBlob = pBlobAllocateMemory (DWSIZEOF (OURBLOB));
|
|
if (newBlob) {
|
|
ZeroMemory (newBlob, DWSIZEOF (OURBLOB));
|
|
}
|
|
return newBlob;
|
|
}
|
|
|
|
|
|
POURBLOB
|
|
BlobDuplicate (
|
|
IN POURBLOB SourceBlob
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobDuplicate duplicates the data in the source blob, so the resulting blob will
|
|
have an identical copy of data
|
|
|
|
Arguments:
|
|
|
|
SourceBlob - Specifies the blob source of data
|
|
|
|
Return Value:
|
|
|
|
Pointer to the new blob if duplicate was successful; NULL if not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
POURBLOB newBlob;
|
|
DWORD dataSize;
|
|
|
|
newBlob = BlobCreate ();
|
|
if (newBlob && SourceBlob->Data) {
|
|
dataSize = BlobGetDataSize (SourceBlob);
|
|
newBlob->Data = pBlobAllocateMemory (dataSize);
|
|
if (!newBlob->Data) {
|
|
BlobDestroy (newBlob);
|
|
return NULL;
|
|
}
|
|
newBlob->AllocSize = dataSize;
|
|
newBlob->End = dataSize;
|
|
CopyMemory (newBlob->Data, SourceBlob->Data, dataSize);
|
|
newBlob->Flags = SourceBlob->Flags;
|
|
}
|
|
return newBlob;
|
|
}
|
|
|
|
|
|
VOID
|
|
BlobClear (
|
|
IN OUT POURBLOB Blob
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobClear clears the specified blob (frees its associated data)
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to clear
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Blob && Blob->Data) {
|
|
pBlobFreeMemory (Blob->Data);
|
|
ZeroMemory (Blob, DWSIZEOF (OURBLOB));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
BlobDestroy (
|
|
IN OUT POURBLOB Blob
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobDestroy destroys the specified blob (frees its associated data and the blob itself)
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to destroy
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Blob) {
|
|
BlobClear (Blob);
|
|
pBlobFreeMemory (Blob);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobSetIndex (
|
|
IN OUT POURBLOB Blob,
|
|
IN DWORD Index
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobSetIndex sets the current read/write pointer
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob
|
|
Index - Specifies the new index value
|
|
|
|
Return Value:
|
|
|
|
TRUE if the index move was successful
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT_VALID_BLOB (Blob);
|
|
|
|
if (Index > Blob->End) {
|
|
DEBUGMSG ((DBG_BLOBS, "BlobSetIndex: invalid Index specified (%lu)", Index));
|
|
MYASSERT (FALSE); //lint !e506
|
|
return FALSE;
|
|
}
|
|
|
|
Blob->Index = Index;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
BlobGetRecordedDataType (
|
|
IN POURBLOB Blob
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobGetRecordedDataType returns the data type recorded at current read position
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob
|
|
|
|
Return Value:
|
|
|
|
The current data type if the blob records data type and the read position is valid;
|
|
BDT_NONE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PBYTE p;
|
|
|
|
if (BlobRecordsDataType (Blob)) {
|
|
p = BlobGetPointer (Blob);
|
|
if (p) {
|
|
return *(DWORD*)p;
|
|
}
|
|
}
|
|
return BDT_NONE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobWriteEx (
|
|
IN OUT POURBLOB Blob,
|
|
IN DWORD DataType, OPTIONAL
|
|
IN BOOL RecordDataSize,
|
|
IN DWORD DataSize,
|
|
IN PCVOID Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobWriteEx writes data at the current index position, growing the blob if necessary
|
|
and adjusting it's size.
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob
|
|
DataType - Specifies the type of data to be stored; can be zero only if the blob
|
|
doesn't record data types
|
|
RecordDataSize - Specifies TRUE if this size has to be recorded in the blob
|
|
DataSize - Specifies the size, in bytes, of the data to be stored
|
|
Data - Specifies the data
|
|
|
|
Return Value:
|
|
|
|
TRUE if write was successful; FALSE if not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
PBYTE p;
|
|
DWORD totalDataSize;
|
|
DWORD growTo;
|
|
DWORD d;
|
|
|
|
ASSERT_VALID_BLOB (Blob);
|
|
MYASSERT (DataSize);
|
|
|
|
MYASSERT (DataType || !BlobRecordsDataType (Blob));
|
|
if (!DataType && BlobRecordsDataType (Blob)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Blob->GrowSize) {
|
|
Blob->GrowSize = BLOB_GROWDATASIZE_DEFAULT;
|
|
}
|
|
|
|
totalDataSize = Blob->Index + DataSize;
|
|
if (BlobRecordsDataType (Blob)) {
|
|
//
|
|
// add the size of a DWORD
|
|
//
|
|
totalDataSize += DWSIZEOF (DWORD);
|
|
}
|
|
if (BlobRecordsDataSize (Blob) || RecordDataSize) {
|
|
//
|
|
// add the size of a DWORD
|
|
//
|
|
totalDataSize += DWSIZEOF (DWORD);
|
|
}
|
|
if (totalDataSize > Blob->AllocSize) {
|
|
d = totalDataSize + Blob->GrowSize - 1;
|
|
growTo = d - d % Blob->GrowSize;
|
|
} else {
|
|
growTo = 0;
|
|
}
|
|
|
|
if (!Blob->Data) {
|
|
Blob->Data = (PBYTE) pBlobAllocateMemory (growTo);
|
|
if (!Blob->Data) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobWriteEx: pBlobAllocateMemory (%lu) failed", growTo));
|
|
return FALSE;
|
|
}
|
|
|
|
Blob->AllocSize = growTo;
|
|
} else if (growTo) {
|
|
p = pReAllocateMemory (Blob->Data, growTo);
|
|
if (!p) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobWriteEx: pReAllocateMemory (%lu) failed", growTo));
|
|
return FALSE;
|
|
}
|
|
|
|
Blob->AllocSize = growTo;
|
|
Blob->Data = p;
|
|
}
|
|
|
|
p = BlobGetPointer (Blob);
|
|
|
|
if (BlobRecordsDataType (Blob)) {
|
|
*(PDWORD)p = DataType;
|
|
p += DWSIZEOF (DWORD);
|
|
Blob->Index += DWSIZEOF (DWORD);
|
|
}
|
|
if (BlobRecordsDataSize (Blob) || RecordDataSize) {
|
|
*(PDWORD)p = DataSize;
|
|
p += DWSIZEOF (DWORD);
|
|
Blob->Index += DWSIZEOF (DWORD);
|
|
}
|
|
|
|
CopyMemory (p, Data, DataSize);
|
|
Blob->Index += DataSize;
|
|
|
|
//
|
|
// adjust EOF
|
|
//
|
|
if (Blob->Index > Blob->End) {
|
|
Blob->End = Blob->Index;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PBYTE
|
|
BlobReadEx (
|
|
IN OUT POURBLOB Blob,
|
|
IN DWORD ExpectedDataType, OPTIONAL
|
|
IN DWORD ExpectedDataSize, OPTIONAL
|
|
IN BOOL RecordedDataSize,
|
|
OUT PDWORD ActualDataSize, OPTIONAL
|
|
OUT PVOID Data, OPTIONAL
|
|
IN PMHANDLE Pool OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobReadEx reads data from the specified blob, at the current index position
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to read from
|
|
ExpectedDataType - Specifies the expected data type; optional
|
|
ExpectedDataSize - Specifies the expected data size; optional
|
|
RecordedDataSize - Specifies TRUE if the data size was recorded in the blob
|
|
ActualDataSize - Receives the actual data size; optional
|
|
Data - Receives the actual data; optional; if NULL, a buffer will be allocated
|
|
Pool - Specifies the pool to use for memory allocations; optional;
|
|
if NULL, the process heap will be used
|
|
|
|
Return Value:
|
|
|
|
A pointer to the buffer containing the data; NULL if an error occured
|
|
or some data conditions don't match
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD initialIndex;
|
|
PBYTE readPtr;
|
|
DWORD actualDataType;
|
|
DWORD actualDataSize = 0;
|
|
|
|
ASSERT_VALID_BLOB (Blob);
|
|
|
|
readPtr = BlobGetPointer (Blob);
|
|
if (!readPtr) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// data size must be available some way
|
|
//
|
|
MYASSERT (BlobRecordsDataSize (Blob) || RecordedDataSize || ExpectedDataSize);
|
|
|
|
initialIndex = BlobGetIndex (Blob);
|
|
|
|
if (BlobRecordsDataType (Blob)) {
|
|
|
|
if (readPtr + DWSIZEOF (DWORD) > BlobGetEOF (Blob)) {
|
|
return NULL;
|
|
}
|
|
//
|
|
// check actual data type
|
|
//
|
|
actualDataType = *(DWORD*)readPtr;
|
|
|
|
if (ExpectedDataType && ExpectedDataType != actualDataType) {
|
|
|
|
DEBUGMSG ((
|
|
DBG_ERROR,
|
|
"BlobReadEx: Actual data type (%lu) different than expected data type (%lu)",
|
|
actualDataType,
|
|
ExpectedDataType
|
|
));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Blob->Index += DWSIZEOF (DWORD);
|
|
readPtr += DWSIZEOF (DWORD);
|
|
}
|
|
|
|
if (BlobRecordsDataSize (Blob) || RecordedDataSize) {
|
|
|
|
if (readPtr + DWSIZEOF (DWORD) > BlobGetEOF (Blob)) {
|
|
BlobSetIndex (Blob, initialIndex);
|
|
return NULL;
|
|
}
|
|
//
|
|
// read actual data size
|
|
//
|
|
actualDataSize = *(DWORD*)readPtr;
|
|
|
|
if (ExpectedDataSize && ExpectedDataSize != actualDataSize) {
|
|
|
|
DEBUGMSG ((
|
|
DBG_ERROR,
|
|
"BlobReadEx: Actual data size (%lu) different than expected data size (%lu)",
|
|
actualDataSize,
|
|
ExpectedDataSize
|
|
));
|
|
|
|
BlobSetIndex (Blob, initialIndex);
|
|
return NULL;
|
|
}
|
|
|
|
Blob->Index += DWSIZEOF (DWORD);
|
|
readPtr += DWSIZEOF (DWORD);
|
|
|
|
} else {
|
|
actualDataSize = ExpectedDataSize;
|
|
}
|
|
|
|
if (!actualDataSize) {
|
|
BlobSetIndex (Blob, initialIndex);
|
|
return NULL;
|
|
}
|
|
|
|
if (ActualDataSize) {
|
|
*ActualDataSize = actualDataSize;
|
|
}
|
|
|
|
//
|
|
// don't read over end of file
|
|
//
|
|
if (readPtr + actualDataSize > BlobGetEOF (Blob)) {
|
|
//
|
|
// corrupt blob; undo anyway
|
|
//
|
|
MYASSERT (FALSE); //lint !e506
|
|
BlobSetIndex (Blob, initialIndex);
|
|
return NULL;
|
|
}
|
|
|
|
if (!Data) {
|
|
|
|
if (Pool) {
|
|
Data = PmGetMemory (Pool, actualDataSize);
|
|
} else {
|
|
Data = pBlobAllocateMemory (actualDataSize);
|
|
}
|
|
|
|
if (!Data) {
|
|
BlobSetIndex (Blob, initialIndex);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
CopyMemory (Data, readPtr, actualDataSize);
|
|
|
|
Blob->Index += actualDataSize;
|
|
|
|
return Data;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobWriteDword (
|
|
IN OUT POURBLOB Blob,
|
|
IN DWORD Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobWriteDword writes a DWORD at the current writing position in the specified blob
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to write to
|
|
Data - Specifies the DWORD
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully stored in the blob
|
|
|
|
--*/
|
|
|
|
{
|
|
return BlobWriteEx (Blob, BDT_DWORD, FALSE, DWSIZEOF (DWORD), &Data);
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobReadDword (
|
|
IN OUT POURBLOB Blob,
|
|
OUT PDWORD Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobReadDword reads a DWORD from the current reading position in the specified blob
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to read from
|
|
Data - Receives the DWORD
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully read from the blob
|
|
|
|
--*/
|
|
|
|
{
|
|
return BlobReadEx (Blob, BDT_DWORD, DWSIZEOF (DWORD), FALSE, NULL, Data, NULL) != NULL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobWriteQword (
|
|
IN OUT POURBLOB Blob,
|
|
IN DWORDLONG Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobWriteQword writes a DWORDLONG at the current writing position in the specified blob
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to write to
|
|
Data - Specifies the DWORDLONG
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully stored in the blob
|
|
|
|
--*/
|
|
|
|
{
|
|
return BlobWriteEx (Blob, BDT_QWORD, FALSE, DWSIZEOF (DWORDLONG), &Data);
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobReadQword (
|
|
IN OUT POURBLOB Blob,
|
|
OUT PDWORDLONG Data
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobReadQword reads a DWORDLONG from the current reading position in the specified blob
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to read from
|
|
Data - Receives the DWORDLONG
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully read from the blob
|
|
|
|
--*/
|
|
|
|
{
|
|
return BlobReadEx (Blob, BDT_QWORD, DWSIZEOF (DWORDLONG), FALSE, NULL, Data, NULL) != NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobWriteString writes a string at the current writing position in the specified blob;
|
|
the string is stored in UNICODE inside the blob if BF_UNICODESTRINGS is set
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to write to
|
|
Data - Specifies the string
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully stored in the blob
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
BlobWriteStringA (
|
|
IN OUT POURBLOB Blob,
|
|
IN PCSTR Data
|
|
)
|
|
{
|
|
PCWSTR unicodeString;
|
|
BOOL b;
|
|
|
|
if (BlobRecordsUnicodeStrings (Blob)) {
|
|
unicodeString = ConvertAtoW (Data);
|
|
b = BlobWriteStringW (Blob, unicodeString);
|
|
FreeConvertedStr (unicodeString);
|
|
return b;
|
|
}
|
|
return BlobWriteEx (Blob, BDT_SZA, TRUE, SizeOfStringA (Data), Data);
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobWriteStringW (
|
|
IN OUT POURBLOB Blob,
|
|
IN PCWSTR Data
|
|
)
|
|
{
|
|
return BlobWriteEx (Blob, BDT_SZW, TRUE, SizeOfStringW (Data), Data);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobReadString reads a string from the current reading position in the specified blob;
|
|
the string may be converted to the ANSI/UNICODE format.
|
|
If the blob doesn't store data types, this is assumed to be BDT_SZA for the ANSI version
|
|
and BDT_SZW for the UNICODE version of this function
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to read from
|
|
Data - Receives a pointer to the new allocated string
|
|
Pool - Specifies the pool to use for allocating memory;
|
|
if NULL, the process heap will be used
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully read from the blob
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
BlobReadStringA (
|
|
IN OUT POURBLOB Blob,
|
|
OUT PCSTR* Data,
|
|
IN PMHANDLE Pool OPTIONAL
|
|
)
|
|
{
|
|
PSTR ansiString;
|
|
PCWSTR unicodeString;
|
|
DWORD dataType;
|
|
DWORD index;
|
|
DWORD length = 0;
|
|
|
|
//
|
|
// save initial index; in case of failure it will be restored
|
|
//
|
|
index = BlobGetIndex (Blob);
|
|
if (!index) {
|
|
return FALSE;
|
|
}
|
|
|
|
ansiString = NULL;
|
|
unicodeString = NULL;
|
|
|
|
if (BlobRecordsDataType (Blob)) {
|
|
|
|
dataType = BlobGetRecordedDataType (Blob);
|
|
|
|
if (dataType == BDT_SZA) {
|
|
|
|
ansiString = BlobReadEx (Blob, BDT_SZA, 0, TRUE, NULL, NULL, Pool);
|
|
|
|
} else if (dataType == BDT_SZW) {
|
|
|
|
unicodeString = (PCWSTR)BlobReadEx (Blob, BDT_SZW, 0, TRUE, &length, NULL, Pool);
|
|
|
|
} else {
|
|
|
|
DEBUGMSG ((DBG_ERROR, "BlobReadStringA: unexpected data type (%lu)", dataType));
|
|
return FALSE;
|
|
|
|
}
|
|
} else {
|
|
if (BlobRecordsUnicodeStrings (Blob)) {
|
|
|
|
unicodeString = (PCWSTR)BlobReadEx (Blob, BDT_SZW, 0, TRUE, &length, NULL, Pool);
|
|
|
|
} else {
|
|
//
|
|
// assume an ANSI string is stored there
|
|
//
|
|
ansiString = BlobReadEx (Blob, BDT_SZA, 0, TRUE, NULL, NULL, Pool);
|
|
}
|
|
}
|
|
|
|
if (!ansiString) {
|
|
|
|
if (!unicodeString) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Pool) {
|
|
ansiString = PmGetMemory (Pool, length);
|
|
} else {
|
|
ansiString = pBlobAllocateMemory (length);
|
|
}
|
|
|
|
if (ansiString) {
|
|
DirectUnicodeToDbcsN (ansiString, unicodeString, length);
|
|
}
|
|
|
|
if (Pool) {
|
|
PmReleaseMemory (Pool, (PVOID)unicodeString);
|
|
} else {
|
|
pBlobFreeMemory ((PVOID)unicodeString);
|
|
}
|
|
|
|
if (!ansiString) {
|
|
//
|
|
// recover prev state
|
|
//
|
|
BlobSetIndex (Blob, index);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
*Data = ansiString;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
BlobReadStringW (
|
|
IN OUT POURBLOB Blob,
|
|
OUT PCWSTR* Data,
|
|
IN PMHANDLE Pool OPTIONAL
|
|
)
|
|
{
|
|
PWSTR unicodeString;
|
|
PCSTR ansiString;
|
|
DWORD dataType;
|
|
DWORD index;
|
|
DWORD length;
|
|
|
|
//
|
|
// save initial index; in case of failure it will be restored
|
|
//
|
|
index = BlobGetIndex (Blob);
|
|
if (!index) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (BlobRecordsDataType (Blob)) {
|
|
|
|
dataType = BlobGetRecordedDataType (Blob);
|
|
|
|
if (dataType == BDT_SZW) {
|
|
|
|
unicodeString = (PWSTR)BlobReadEx (Blob, BDT_SZW, 0, TRUE, NULL, NULL, Pool);
|
|
|
|
} else if (dataType == BDT_SZA) {
|
|
|
|
ansiString = BlobReadEx (Blob, BDT_SZA, 0, TRUE, &length, NULL, Pool);
|
|
|
|
if (!ansiString) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Pool) {
|
|
unicodeString = PmGetMemory (Pool, length * DWSIZEOF (WCHAR));
|
|
} else {
|
|
unicodeString = pBlobAllocateMemory (length * DWSIZEOF (WCHAR));
|
|
}
|
|
if (unicodeString) {
|
|
DirectDbcsToUnicodeN (unicodeString, ansiString, length);
|
|
}
|
|
|
|
if (Pool) {
|
|
PmReleaseMemory (Pool, (PVOID)ansiString);
|
|
} else {
|
|
pBlobFreeMemory ((PVOID)ansiString);
|
|
}
|
|
|
|
if (!unicodeString) {
|
|
//
|
|
// recover prev state
|
|
//
|
|
BlobSetIndex (Blob, index);
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
DEBUGMSG ((DBG_ERROR, "BlobReadStringW: unexpected data type (%lu)", dataType));
|
|
return FALSE;
|
|
|
|
}
|
|
} else {
|
|
//
|
|
// assume an UNICODE string is stored there
|
|
//
|
|
unicodeString = (PWSTR)BlobReadEx (Blob, BDT_SZW, 0, TRUE, NULL, NULL, Pool);
|
|
}
|
|
|
|
if (!unicodeString) {
|
|
return FALSE;
|
|
}
|
|
|
|
*Data = unicodeString;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobWriteMultiSz writes a multisz at the current writing position in the specified blob;
|
|
the multisz is stored in UNICODE inside the blob if BF_UNICODESTRINGS is set
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to write to
|
|
Data - Specifies the multisz
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully stored in the blob
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
BlobWriteMultiSzA (
|
|
IN OUT POURBLOB Blob,
|
|
IN PCSTR Data
|
|
)
|
|
{
|
|
PWSTR unicodeString;
|
|
BOOL b;
|
|
DWORD stringSize = SizeOfMultiSzA (Data);
|
|
|
|
if (BlobRecordsUnicodeStrings (Blob)) {
|
|
unicodeString = AllocTextW (stringSize);
|
|
DirectDbcsToUnicodeN (unicodeString, Data, stringSize);
|
|
b = BlobWriteMultiSzW (Blob, unicodeString);
|
|
FreeTextW (unicodeString);
|
|
return b;
|
|
}
|
|
|
|
return BlobWriteEx (Blob, BDT_MULTISZA, TRUE, stringSize, Data);
|
|
}
|
|
|
|
BOOL
|
|
BlobWriteMultiSzW (
|
|
IN OUT POURBLOB Blob,
|
|
IN PCWSTR Data
|
|
)
|
|
{
|
|
return BlobWriteEx (Blob, BDT_MULTISZW, TRUE, SizeOfMultiSzW (Data), Data);
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobReadMultiSz reads a multisz from the current reading position in the specified blob;
|
|
the string may be converted to the ANSI/UNICODE format.
|
|
If the blob doesn't store data types, this is assumed to be BDT_MULTISZA for the ANSI version
|
|
and BDT_MULTISZW for the UNICODE version of this function
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to read from
|
|
Data - Receives a pointer to the new allocated multisz
|
|
Pool - Specifies the pool to use for allocating memory;
|
|
if NULL, the process heap will be used
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully read from the blob
|
|
|
|
--*/
|
|
|
|
BOOL
|
|
BlobReadMultiSzA (
|
|
IN OUT POURBLOB Blob,
|
|
OUT PCSTR* Data,
|
|
IN PMHANDLE Pool OPTIONAL
|
|
)
|
|
{
|
|
PSTR ansiString;
|
|
PCWSTR unicodeString;
|
|
DWORD dataType;
|
|
DWORD index;
|
|
DWORD length = 0;
|
|
|
|
//
|
|
// save initial index; in case of failure it will be restored
|
|
//
|
|
index = BlobGetIndex (Blob);
|
|
if (!index) {
|
|
return FALSE;
|
|
}
|
|
|
|
ansiString = NULL;
|
|
unicodeString = NULL;
|
|
|
|
if (BlobRecordsDataType (Blob)) {
|
|
|
|
dataType = BlobGetRecordedDataType (Blob);
|
|
|
|
if (dataType == BDT_MULTISZA) {
|
|
|
|
ansiString = BlobReadEx (Blob, BDT_MULTISZA, 0, TRUE, NULL, NULL, Pool);
|
|
|
|
} else if (dataType == BDT_MULTISZW) {
|
|
|
|
unicodeString = (PCWSTR)BlobReadEx (Blob, BDT_MULTISZW, 0, TRUE, &length, NULL, Pool);
|
|
|
|
} else {
|
|
|
|
DEBUGMSG ((DBG_ERROR, "BlobReadMultiSzA: unexpected data type (%lu)", dataType));
|
|
return FALSE;
|
|
|
|
}
|
|
} else {
|
|
if (BlobRecordsUnicodeStrings (Blob)) {
|
|
|
|
unicodeString = (PCWSTR)BlobReadEx (Blob, BDT_MULTISZW, 0, TRUE, &length, NULL, Pool);
|
|
|
|
} else {
|
|
//
|
|
// assume an ANSI string is stored there
|
|
//
|
|
ansiString = BlobReadEx (Blob, BDT_MULTISZA, 0, TRUE, NULL, NULL, Pool);
|
|
}
|
|
}
|
|
|
|
if (!ansiString) {
|
|
if (!unicodeString) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Pool) {
|
|
ansiString = PmGetMemory (Pool, length);
|
|
} else {
|
|
ansiString = pBlobAllocateMemory (length);
|
|
}
|
|
|
|
if (ansiString) {
|
|
DirectUnicodeToDbcsN (ansiString, unicodeString, length);
|
|
}
|
|
|
|
if (Pool) {
|
|
PmReleaseMemory (Pool, (PVOID)unicodeString);
|
|
} else {
|
|
pBlobFreeMemory ((PVOID)unicodeString);
|
|
}
|
|
|
|
if (!ansiString) {
|
|
//
|
|
// recover prev state
|
|
//
|
|
BlobSetIndex (Blob, index);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
*Data = ansiString;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
BlobReadMultiSzW (
|
|
IN OUT POURBLOB Blob,
|
|
OUT PCWSTR* Data,
|
|
IN PMHANDLE Pool OPTIONAL
|
|
)
|
|
{
|
|
PWSTR unicodeString;
|
|
PCSTR ansiString;
|
|
DWORD dataType;
|
|
DWORD index;
|
|
DWORD length;
|
|
|
|
//
|
|
// save initial index; in case of failure it will be restored
|
|
//
|
|
index = BlobGetIndex (Blob);
|
|
if (!index) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (BlobRecordsDataType (Blob)) {
|
|
|
|
dataType = BlobGetRecordedDataType (Blob);
|
|
|
|
if (dataType == BDT_MULTISZW) {
|
|
|
|
unicodeString = (PWSTR)BlobReadEx (Blob, BDT_MULTISZW, 0, TRUE, NULL, NULL, Pool);
|
|
|
|
} else if (dataType == BDT_MULTISZA) {
|
|
|
|
ansiString = BlobReadEx (Blob, BDT_MULTISZA, 0, TRUE, &length, NULL, Pool);
|
|
|
|
if (!ansiString) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (Pool) {
|
|
unicodeString = PmGetMemory (Pool, length * DWSIZEOF (WCHAR));
|
|
} else {
|
|
unicodeString = pBlobAllocateMemory (length * DWSIZEOF (WCHAR));
|
|
}
|
|
|
|
if (unicodeString) {
|
|
DirectDbcsToUnicodeN (unicodeString, ansiString, length);
|
|
}
|
|
|
|
if (Pool) {
|
|
PmReleaseMemory (Pool, (PVOID)ansiString);
|
|
} else {
|
|
pBlobFreeMemory ((PVOID)ansiString);
|
|
}
|
|
|
|
if (!unicodeString) {
|
|
//
|
|
// recover prev state
|
|
//
|
|
BlobSetIndex (Blob, index);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
DEBUGMSG ((DBG_ERROR, "BlobReadMultiSzW: unexpected data type (%lu)", dataType));
|
|
return FALSE;
|
|
|
|
}
|
|
} else {
|
|
//
|
|
// assume an UNICODE string is stored there
|
|
//
|
|
unicodeString = (PWSTR)BlobReadEx (Blob, BDT_MULTISZW, 0, TRUE, NULL, NULL, Pool);
|
|
}
|
|
|
|
if (!unicodeString) {
|
|
return FALSE;
|
|
}
|
|
|
|
*Data = unicodeString;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobWriteBinaryEx (
|
|
IN OUT POURBLOB Blob,
|
|
IN PBYTE Data,
|
|
IN DWORD Size,
|
|
IN BOOL RecordDataSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobWriteBinary writes a buffer at the current writing position in the specified blob
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to write to
|
|
Data - Specifies the source buffer
|
|
Size - Specifies the size of the buffer
|
|
RecordDataSize - Specifies TRUE if data size should be recorded, too
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully stored in the blob
|
|
|
|
--*/
|
|
|
|
{
|
|
return BlobWriteEx (Blob, BDT_BINARY, RecordDataSize, Size, Data);
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobReadBinary (
|
|
IN OUT POURBLOB Blob,
|
|
OUT PBYTE* Data,
|
|
OUT PDWORD Size,
|
|
IN PMHANDLE Pool OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobReadBinary reads a buffer from the current reading position in the specified blob
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to read from
|
|
Data - Receives a pointer to the new allocated buffer
|
|
Size - Receives the size of the buffer
|
|
Pool - Specifies the pool to use for allocating memory;
|
|
if NULL, the process heap will be used
|
|
|
|
Return Value:
|
|
|
|
TRUE if data was successfully read from the blob
|
|
|
|
--*/
|
|
|
|
{
|
|
*Data = BlobReadEx (Blob, BDT_BINARY, 0, TRUE, Size, NULL, Pool);
|
|
return *Data != NULL;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobWriteToFile (
|
|
IN POURBLOB Blob,
|
|
IN HANDLE File
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobWriteToFile writes the specified blob to the given file
|
|
|
|
Arguments:
|
|
|
|
Blob - Specifies the blob to save
|
|
File - Specifies the handle of the file to write the blob to
|
|
|
|
Return Value:
|
|
|
|
TRUE if blob was successfully written to the file
|
|
|
|
--*/
|
|
|
|
{
|
|
BLOBHDR header;
|
|
DWORD d;
|
|
|
|
if (!Blob->End) {
|
|
DEBUGMSG ((DBG_BLOBS, "BlobWriteToFile: Did not write empty blob to file"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// save blob's Flags and End position
|
|
//
|
|
header.BlobSignature = BLOB_SIGNATURE;
|
|
header.DataSize = Blob->End;
|
|
header.Flags = Blob->Flags;
|
|
|
|
if (!WriteFile (File, &header, DWSIZEOF (BLOBHDR), &d, NULL) || d != DWSIZEOF (BLOBHDR)) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobWriteToFile: Error writing blob header!"));
|
|
return FALSE;
|
|
}
|
|
if (!WriteFile (File, Blob->Data, Blob->End, &d, NULL) || d != Blob->End) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobWriteToFile: Error writing blob data!"));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobReadFromFile (
|
|
OUT POURBLOB Blob,
|
|
IN HANDLE File
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobReadFromFile reads data from the given file in the specified blob
|
|
|
|
Arguments:
|
|
|
|
Blob - Receives the data
|
|
File - Specifies the handle of the file to read from
|
|
|
|
Return Value:
|
|
|
|
TRUE if blob was successfully read from the file
|
|
|
|
--*/
|
|
|
|
{
|
|
BLOBHDR header;
|
|
DWORD d;
|
|
|
|
//
|
|
// read blob's Flags and End position
|
|
//
|
|
if (!ReadFile (File, &header, DWSIZEOF (BLOBHDR), &d, NULL) || d != DWSIZEOF (BLOBHDR)) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobReadFromFile: Error reading blob header!"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (header.BlobSignature != BLOB_SIGNATURE) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobReadFromFile: Not a valid blob signature!"));
|
|
return FALSE;
|
|
}
|
|
|
|
Blob->Data = pBlobAllocateMemory (header.DataSize);
|
|
if (!Blob->Data) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ReadFile (File, Blob->Data, header.DataSize, &d, NULL) || d != header.DataSize) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobReadFromFile: Error reading blob data!"));
|
|
pBlobFreeMemory (Blob->Data);
|
|
Blob->Data = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
Blob->AllocSize = header.DataSize;
|
|
Blob->End = header.DataSize;
|
|
Blob->Flags = header.Flags;
|
|
Blob->Index = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobsAdd (
|
|
IN OUT PBLOBS BlobsArray,
|
|
IN POURBLOB Blob
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobsAdd adds the specified Blob to a blobs array
|
|
|
|
Arguments:
|
|
|
|
BlobsArray - Specifies the array to add to
|
|
Blob - Specifies the blob to add
|
|
|
|
Return Value:
|
|
|
|
TRUE if the new blob pointer was added successfully
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT_VALID_BLOBS_ARRAY (BlobsArray);
|
|
|
|
if (!BlobsArray->BlobsGrowCount) {
|
|
BlobsArray->BlobsGrowCount = BLOBS_GROWCOUNT_DEFAULT;
|
|
}
|
|
|
|
if (!BlobsArray->Blobs) {
|
|
|
|
BlobsArray->Blobs = (POURBLOB*)pBlobAllocateMemory (
|
|
BlobsArray->BlobsGrowCount * DWSIZEOF (POURBLOB)
|
|
);
|
|
if (!BlobsArray->Blobs) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobsAddE: Initial alloc failed"));
|
|
return FALSE;
|
|
}
|
|
BlobsArray->Signature = BLOBS_SIGNATURE;
|
|
BlobsArray->BlobsAllocated = BlobsArray->BlobsGrowCount;
|
|
BlobsArray->BlobsCount = 0;
|
|
|
|
} else if (BlobsArray->BlobsCount == BlobsArray->BlobsAllocated) {
|
|
|
|
BlobsArray->BlobsAllocated += BlobsArray->BlobsGrowCount;
|
|
BlobsArray->Blobs = (POURBLOB*)pReAllocateMemory (
|
|
BlobsArray->Blobs,
|
|
BlobsArray->BlobsAllocated * DWSIZEOF (POURBLOB)
|
|
);
|
|
if (!BlobsArray->Blobs) {
|
|
BlobsArray->BlobsAllocated -= BlobsArray->BlobsGrowCount;
|
|
DEBUGMSG ((DBG_ERROR, "BlobsAdd: Realloc failed"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
*(BlobsArray->Blobs + BlobsArray->BlobsCount) = Blob;
|
|
BlobsArray->BlobsCount++;
|
|
|
|
ASSERT_VALID_BLOBS_ARRAY (BlobsArray);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
BlobsFree (
|
|
IN OUT PBLOBS BlobsArray,
|
|
IN BOOL DestroyBlobs
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobsFree destroys the array and optionally destroys all blobs in it
|
|
|
|
Arguments:
|
|
|
|
BlobsArray - Specifies the array to delete
|
|
DestroyBlobs - Specifies TRUE if the component blobs are to be deleted, too
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
BLOB_ENUM e;
|
|
|
|
ASSERT_VALID_BLOBS_ARRAY (BlobsArray);
|
|
|
|
if (DestroyBlobs) {
|
|
if (EnumFirstBlob (&e, BlobsArray)) {
|
|
do {
|
|
BlobDestroy (e.CurrentBlob);
|
|
} while (EnumNextBlob (&e));
|
|
}
|
|
}
|
|
|
|
pBlobFreeMemory (BlobsArray->Blobs);
|
|
ZeroMemory (BlobsArray, DWSIZEOF (BLOBS));
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumFirstBlob (
|
|
OUT PBLOB_ENUM BlobEnum,
|
|
IN PBLOBS BlobsArray
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumFirstBlob enumerates the first blob in the given array
|
|
|
|
Arguments:
|
|
|
|
BlobEnum - Receives enum info
|
|
BlobsArray - Specifies the array to enum from
|
|
|
|
Return Value:
|
|
|
|
TRUE if a first blob was found; FALSE if array is empty
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT_VALID_BLOBS_ARRAY (BlobsArray);
|
|
|
|
BlobEnum->Index = 0;
|
|
BlobEnum->Array = BlobsArray;
|
|
return EnumNextBlob (BlobEnum);
|
|
}
|
|
|
|
|
|
BOOL
|
|
EnumNextBlob (
|
|
IN OUT PBLOB_ENUM BlobEnum
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
EnumNextBlob enumerates the next blob in the given array
|
|
|
|
Arguments:
|
|
|
|
BlobEnum - Specifies/receives enum info
|
|
|
|
Return Value:
|
|
|
|
TRUE if a next blob was found; FALSE if no more blobs
|
|
|
|
--*/
|
|
|
|
{
|
|
if (BlobEnum->Index >= BlobEnum->Array->BlobsCount) {
|
|
return FALSE;
|
|
}
|
|
|
|
BlobEnum->CurrentBlob = *(BlobEnum->Array->Blobs + BlobEnum->Index);
|
|
BlobEnum->Index++;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobsWriteToFile (
|
|
IN PBLOBS BlobsArray,
|
|
IN HANDLE File
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobsWriteToFile writes the specified blobs array to the given file
|
|
|
|
Arguments:
|
|
|
|
BlobsArray - Specifies the blobs array to save
|
|
File - Specifies the handle of the file to write the array to
|
|
|
|
Return Value:
|
|
|
|
TRUE if array was successfully written to the file
|
|
|
|
--*/
|
|
|
|
{
|
|
BLOBSARRAYHDR header;
|
|
DWORD d;
|
|
POURBLOB* blob;
|
|
|
|
if (!BlobsArray->BlobsCount) {
|
|
DEBUGMSG ((DBG_BLOBS, "BlobsWriteToFile: Did not write empty blobs array to file"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// save blobs count
|
|
//
|
|
header.BlobsArraySignature = BLOBS_SIGNATURE;
|
|
header.BlobsCount = BlobsArray->BlobsCount;
|
|
|
|
if (!WriteFile (File, &header, DWSIZEOF (BLOBSARRAYHDR), &d, NULL) ||
|
|
d != DWSIZEOF (BLOBSARRAYHDR)
|
|
) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobsWriteToFile: Error writing blobs array header!"));
|
|
return FALSE;
|
|
}
|
|
for (blob = BlobsArray->Blobs; blob < BlobsArray->Blobs + BlobsArray->BlobsCount; blob++) {
|
|
if (!BlobWriteToFile (*blob, File)) {
|
|
DEBUGMSG ((
|
|
DBG_BLOBS,
|
|
"BlobsWriteToFile: Error writing blob # %lu to file",
|
|
blob - BlobsArray->Blobs
|
|
));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
BlobsReadFromFile (
|
|
OUT PBLOBS BlobsArray,
|
|
IN HANDLE File
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BlobsReadFromFile reads data from the given file in the specified blobs array
|
|
|
|
Arguments:
|
|
|
|
BlobsArray - Receives the data
|
|
File - Specifies the handle of the file to read from
|
|
|
|
Return Value:
|
|
|
|
TRUE if array was successfully read from the file
|
|
|
|
--*/
|
|
|
|
{
|
|
BLOBSARRAYHDR header;
|
|
DWORD d;
|
|
UINT u;
|
|
POURBLOB blob;
|
|
|
|
//
|
|
// read blobs count
|
|
//
|
|
if (!ReadFile (File, &header, DWSIZEOF (BLOBSARRAYHDR), &d, NULL) ||
|
|
d != DWSIZEOF (BLOBSARRAYHDR)
|
|
) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobsReadFromFile: Error reading blobs array header!"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (header.BlobsArraySignature != BLOBS_SIGNATURE) {
|
|
DEBUGMSG ((DBG_ERROR, "BlobsReadFromFile: Not a valid blobs array signature!"));
|
|
return FALSE;
|
|
}
|
|
|
|
BlobsArray->Blobs = (POURBLOB*)pBlobAllocateMemory (header.BlobsCount * DWSIZEOF (POURBLOB*));
|
|
if (!BlobsArray->Blobs) {
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory (BlobsArray->Blobs, header.BlobsCount * DWSIZEOF (POURBLOB));
|
|
|
|
BlobsArray->Signature = BLOBS_SIGNATURE;
|
|
BlobsArray->BlobsAllocated = header.BlobsCount;
|
|
BlobsArray->BlobsCount = 0;
|
|
BlobsArray->BlobsGrowCount = BLOBS_GROWCOUNT_DEFAULT;
|
|
|
|
for (u = 0; u < header.BlobsCount; u++) {
|
|
|
|
blob = BlobCreate ();
|
|
if (!blob) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!BlobReadFromFile (blob, File)) {
|
|
|
|
DEBUGMSG ((
|
|
DBG_BLOBS,
|
|
"BlobsReadFromFile: Error reading blob # %lu from file",
|
|
u
|
|
));
|
|
|
|
BlobsFree (BlobsArray, TRUE);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!BlobsAdd (BlobsArray, blob)) {
|
|
DEBUGMSG ((
|
|
DBG_BLOBS,
|
|
"BlobsReadFromFile: Error adding blob # %lu to array",
|
|
u
|
|
));
|
|
|
|
BlobsFree (BlobsArray, TRUE);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|