Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1832 lines
36 KiB

/*++
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;
}