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