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

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. blobs.c
  5. Abstract:
  6. Implements a set of APIs to manage BLOBS and arrays of BLOBS.
  7. Author:
  8. Ovidiu Temereanca (ovidiut) 24-Nov-1999
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. #include "pch.h"
  13. //
  14. // Includes
  15. //
  16. // None
  17. #define DBG_BLOBS "Blobs"
  18. //
  19. // Strings
  20. //
  21. // None
  22. //
  23. // Constants
  24. //
  25. #define BLOB_SIGNATURE 0x79563442
  26. #define BLOB_GROWDATASIZE_DEFAULT 1024
  27. #define BLOBS_GROWCOUNT_DEFAULT 64
  28. #define BLOBS_SIGNATURE 0x12567841
  29. //
  30. // Macros
  31. //
  32. // None
  33. //
  34. // Types
  35. //
  36. typedef struct {
  37. DWORD BlobSignature;
  38. DWORD DataSize;
  39. DWORD Flags;
  40. } BLOBHDR, *PBLOBHDR;
  41. typedef struct {
  42. DWORD BlobsArraySignature;
  43. DWORD BlobsCount;
  44. } BLOBSARRAYHDR, *PBLOBSARRAYHDR;
  45. //
  46. // Globals
  47. //
  48. // None
  49. //
  50. // Macro expansion list
  51. //
  52. // None
  53. //
  54. // Private function prototypes
  55. //
  56. // None
  57. //
  58. // Macro expansion definition
  59. //
  60. // None
  61. //
  62. // Code
  63. //
  64. #ifdef DEBUG
  65. #define ASSERT_VALID_BLOB(b) MYASSERT (pIsValidBlob (b))
  66. #define ASSERT_VALID_BLOBS_ARRAY(a) MYASSERT (pIsValidBlobsArray (a))
  67. BOOL
  68. pIsValidBlob (
  69. IN POURBLOB Blob
  70. )
  71. /*++
  72. Routine Description:
  73. pIsValidBlob checks if the passed-in blob points to a valid OURBLOB blob structure
  74. Arguments:
  75. Blob - Specifies a pointer to the blob to be checked
  76. Return Value:
  77. TRUE if the check was successful.
  78. FALSE if not.
  79. --*/
  80. {
  81. BOOL b = TRUE;
  82. if (!Blob) {
  83. return FALSE;
  84. }
  85. __try {
  86. b = !Blob->Data && !Blob->End && !Blob->Index && !Blob->AllocSize ||
  87. Blob->Data && Blob->AllocSize && Blob->End <= Blob->AllocSize && Blob->Index <= Blob->AllocSize;
  88. }
  89. __except (TRUE) {
  90. b = FALSE;
  91. }
  92. return b;
  93. }
  94. BOOL
  95. pIsValidBlobsArray (
  96. IN PBLOBS BlobsArray
  97. )
  98. /*++
  99. Routine Description:
  100. pIsValidBlobsArray checks if the passed-in bloba array points to a valid BLOBS array structure
  101. Arguments:
  102. BlobsArray - Specifies a pointer to the blobs array to be checked
  103. Return Value:
  104. TRUE if the check was successful.
  105. FALSE if not.
  106. --*/
  107. {
  108. BOOL b = TRUE;
  109. if (!BlobsArray) {
  110. return FALSE;
  111. }
  112. __try {
  113. b = !BlobsArray->Blobs && !BlobsArray->BlobsCount && !BlobsArray->BlobsAllocated ||
  114. BlobsArray->Signature == BLOBS_SIGNATURE &&
  115. BlobsArray->Blobs &&
  116. BlobsArray->BlobsAllocated &&
  117. BlobsArray->BlobsGrowCount &&
  118. BlobsArray->BlobsCount <= BlobsArray->BlobsAllocated;
  119. }
  120. __except (TRUE) {
  121. b = FALSE;
  122. }
  123. return b;
  124. }
  125. #else
  126. #define ASSERT_VALID_BLOB(b)
  127. #define ASSERT_VALID_BLOBS_ARRAY(a)
  128. #endif
  129. PVOID
  130. pBlobAllocateMemory (
  131. IN DWORD Size
  132. )
  133. /*++
  134. Routine Description:
  135. pBlobAllocateMemory is a private function that allocates space from the process heap
  136. Arguments:
  137. Size - Specifies the size (in bytes) to allocate.
  138. Return Value:
  139. A pointer to the successfully allocated memory or NULL if not enough memory
  140. --*/
  141. {
  142. MYASSERT (Size);
  143. return HeapAlloc (g_hHeap, 0, Size);
  144. }
  145. static
  146. PVOID
  147. pReAllocateMemory (
  148. IN PVOID OldBuffer,
  149. IN DWORD NewSize
  150. )
  151. /*++
  152. Routine Description:
  153. pReAllocateMemory is a private function that re-allocates space from the process heap
  154. Arguments:
  155. OldBuffer - Specifies the buffer to be re-allocated
  156. Size - Specifies the size (in bytes) to allocate.
  157. Return Value:
  158. A pointer to the successfully re-allocated memory or NULL if not enough memory
  159. --*/
  160. {
  161. MYASSERT (OldBuffer);
  162. MYASSERT (NewSize);
  163. return HeapReAlloc (g_hHeap, 0, OldBuffer, NewSize);
  164. }
  165. VOID
  166. pBlobFreeMemory (
  167. IN PVOID Buffer
  168. )
  169. /*++
  170. Routine Description:
  171. pBlobFreeMemory is a private function that frees space allocated from the process heap
  172. Arguments:
  173. Buffer - Specifies a pointer to buffer to free.
  174. Return Value:
  175. none
  176. --*/
  177. {
  178. MYASSERT (Buffer);
  179. HeapFree (g_hHeap, 0, Buffer);
  180. }
  181. POURBLOB
  182. BlobCreate (
  183. VOID
  184. )
  185. {
  186. POURBLOB newBlob;
  187. newBlob = pBlobAllocateMemory (DWSIZEOF (OURBLOB));
  188. if (newBlob) {
  189. ZeroMemory (newBlob, DWSIZEOF (OURBLOB));
  190. }
  191. return newBlob;
  192. }
  193. POURBLOB
  194. BlobDuplicate (
  195. IN POURBLOB SourceBlob
  196. )
  197. /*++
  198. Routine Description:
  199. BlobDuplicate duplicates the data in the source blob, so the resulting blob will
  200. have an identical copy of data
  201. Arguments:
  202. SourceBlob - Specifies the blob source of data
  203. Return Value:
  204. Pointer to the new blob if duplicate was successful; NULL if not enough memory
  205. --*/
  206. {
  207. POURBLOB newBlob;
  208. DWORD dataSize;
  209. newBlob = BlobCreate ();
  210. if (newBlob && SourceBlob->Data) {
  211. dataSize = BlobGetDataSize (SourceBlob);
  212. newBlob->Data = pBlobAllocateMemory (dataSize);
  213. if (!newBlob->Data) {
  214. BlobDestroy (newBlob);
  215. return NULL;
  216. }
  217. newBlob->AllocSize = dataSize;
  218. newBlob->End = dataSize;
  219. CopyMemory (newBlob->Data, SourceBlob->Data, dataSize);
  220. newBlob->Flags = SourceBlob->Flags;
  221. }
  222. return newBlob;
  223. }
  224. VOID
  225. BlobClear (
  226. IN OUT POURBLOB Blob
  227. )
  228. /*++
  229. Routine Description:
  230. BlobClear clears the specified blob (frees its associated data)
  231. Arguments:
  232. Blob - Specifies the blob to clear
  233. Return Value:
  234. none
  235. --*/
  236. {
  237. if (Blob && Blob->Data) {
  238. pBlobFreeMemory (Blob->Data);
  239. ZeroMemory (Blob, DWSIZEOF (OURBLOB));
  240. }
  241. }
  242. VOID
  243. BlobDestroy (
  244. IN OUT POURBLOB Blob
  245. )
  246. /*++
  247. Routine Description:
  248. BlobDestroy destroys the specified blob (frees its associated data and the blob itself)
  249. Arguments:
  250. Blob - Specifies the blob to destroy
  251. Return Value:
  252. none
  253. --*/
  254. {
  255. if (Blob) {
  256. BlobClear (Blob);
  257. pBlobFreeMemory (Blob);
  258. }
  259. }
  260. BOOL
  261. BlobSetIndex (
  262. IN OUT POURBLOB Blob,
  263. IN DWORD Index
  264. )
  265. /*++
  266. Routine Description:
  267. BlobSetIndex sets the current read/write pointer
  268. Arguments:
  269. Blob - Specifies the blob
  270. Index - Specifies the new index value
  271. Return Value:
  272. TRUE if the index move was successful
  273. --*/
  274. {
  275. ASSERT_VALID_BLOB (Blob);
  276. if (Index > Blob->End) {
  277. DEBUGMSG ((DBG_BLOBS, "BlobSetIndex: invalid Index specified (%lu)", Index));
  278. MYASSERT (FALSE); //lint !e506
  279. return FALSE;
  280. }
  281. Blob->Index = Index;
  282. return TRUE;
  283. }
  284. DWORD
  285. BlobGetRecordedDataType (
  286. IN POURBLOB Blob
  287. )
  288. /*++
  289. Routine Description:
  290. BlobGetRecordedDataType returns the data type recorded at current read position
  291. Arguments:
  292. Blob - Specifies the blob
  293. Return Value:
  294. The current data type if the blob records data type and the read position is valid;
  295. BDT_NONE otherwise
  296. --*/
  297. {
  298. PBYTE p;
  299. if (BlobRecordsDataType (Blob)) {
  300. p = BlobGetPointer (Blob);
  301. if (p) {
  302. return *(DWORD*)p;
  303. }
  304. }
  305. return BDT_NONE;
  306. }
  307. BOOL
  308. BlobWriteEx (
  309. IN OUT POURBLOB Blob,
  310. IN DWORD DataType, OPTIONAL
  311. IN BOOL RecordDataSize,
  312. IN DWORD DataSize,
  313. IN PCVOID Data
  314. )
  315. /*++
  316. Routine Description:
  317. BlobWriteEx writes data at the current index position, growing the blob if necessary
  318. and adjusting it's size.
  319. Arguments:
  320. Blob - Specifies the blob
  321. DataType - Specifies the type of data to be stored; can be zero only if the blob
  322. doesn't record data types
  323. RecordDataSize - Specifies TRUE if this size has to be recorded in the blob
  324. DataSize - Specifies the size, in bytes, of the data to be stored
  325. Data - Specifies the data
  326. Return Value:
  327. TRUE if write was successful; FALSE if not enough memory
  328. --*/
  329. {
  330. PBYTE p;
  331. DWORD totalDataSize;
  332. DWORD growTo;
  333. DWORD d;
  334. ASSERT_VALID_BLOB (Blob);
  335. MYASSERT (DataSize);
  336. MYASSERT (DataType || !BlobRecordsDataType (Blob));
  337. if (!DataType && BlobRecordsDataType (Blob)) {
  338. return FALSE;
  339. }
  340. if (!Blob->GrowSize) {
  341. Blob->GrowSize = BLOB_GROWDATASIZE_DEFAULT;
  342. }
  343. totalDataSize = Blob->Index + DataSize;
  344. if (BlobRecordsDataType (Blob)) {
  345. //
  346. // add the size of a DWORD
  347. //
  348. totalDataSize += DWSIZEOF (DWORD);
  349. }
  350. if (BlobRecordsDataSize (Blob) || RecordDataSize) {
  351. //
  352. // add the size of a DWORD
  353. //
  354. totalDataSize += DWSIZEOF (DWORD);
  355. }
  356. if (totalDataSize > Blob->AllocSize) {
  357. d = totalDataSize + Blob->GrowSize - 1;
  358. growTo = d - d % Blob->GrowSize;
  359. } else {
  360. growTo = 0;
  361. }
  362. if (!Blob->Data) {
  363. Blob->Data = (PBYTE) pBlobAllocateMemory (growTo);
  364. if (!Blob->Data) {
  365. DEBUGMSG ((DBG_ERROR, "BlobWriteEx: pBlobAllocateMemory (%lu) failed", growTo));
  366. return FALSE;
  367. }
  368. Blob->AllocSize = growTo;
  369. } else if (growTo) {
  370. p = pReAllocateMemory (Blob->Data, growTo);
  371. if (!p) {
  372. DEBUGMSG ((DBG_ERROR, "BlobWriteEx: pReAllocateMemory (%lu) failed", growTo));
  373. return FALSE;
  374. }
  375. Blob->AllocSize = growTo;
  376. Blob->Data = p;
  377. }
  378. p = BlobGetPointer (Blob);
  379. if (BlobRecordsDataType (Blob)) {
  380. *(PDWORD)p = DataType;
  381. p += DWSIZEOF (DWORD);
  382. Blob->Index += DWSIZEOF (DWORD);
  383. }
  384. if (BlobRecordsDataSize (Blob) || RecordDataSize) {
  385. *(PDWORD)p = DataSize;
  386. p += DWSIZEOF (DWORD);
  387. Blob->Index += DWSIZEOF (DWORD);
  388. }
  389. CopyMemory (p, Data, DataSize);
  390. Blob->Index += DataSize;
  391. //
  392. // adjust EOF
  393. //
  394. if (Blob->Index > Blob->End) {
  395. Blob->End = Blob->Index;
  396. }
  397. return TRUE;
  398. }
  399. PBYTE
  400. BlobReadEx (
  401. IN OUT POURBLOB Blob,
  402. IN DWORD ExpectedDataType, OPTIONAL
  403. IN DWORD ExpectedDataSize, OPTIONAL
  404. IN BOOL RecordedDataSize,
  405. OUT PDWORD ActualDataSize, OPTIONAL
  406. OUT PVOID Data, OPTIONAL
  407. IN PMHANDLE Pool OPTIONAL
  408. )
  409. /*++
  410. Routine Description:
  411. BlobReadEx reads data from the specified blob, at the current index position
  412. Arguments:
  413. Blob - Specifies the blob to read from
  414. ExpectedDataType - Specifies the expected data type; optional
  415. ExpectedDataSize - Specifies the expected data size; optional
  416. RecordedDataSize - Specifies TRUE if the data size was recorded in the blob
  417. ActualDataSize - Receives the actual data size; optional
  418. Data - Receives the actual data; optional; if NULL, a buffer will be allocated
  419. Pool - Specifies the pool to use for memory allocations; optional;
  420. if NULL, the process heap will be used
  421. Return Value:
  422. A pointer to the buffer containing the data; NULL if an error occured
  423. or some data conditions don't match
  424. --*/
  425. {
  426. DWORD initialIndex;
  427. PBYTE readPtr;
  428. DWORD actualDataType;
  429. DWORD actualDataSize = 0;
  430. ASSERT_VALID_BLOB (Blob);
  431. readPtr = BlobGetPointer (Blob);
  432. if (!readPtr) {
  433. return NULL;
  434. }
  435. //
  436. // data size must be available some way
  437. //
  438. MYASSERT (BlobRecordsDataSize (Blob) || RecordedDataSize || ExpectedDataSize);
  439. initialIndex = BlobGetIndex (Blob);
  440. if (BlobRecordsDataType (Blob)) {
  441. if (readPtr + DWSIZEOF (DWORD) > BlobGetEOF (Blob)) {
  442. return NULL;
  443. }
  444. //
  445. // check actual data type
  446. //
  447. actualDataType = *(DWORD*)readPtr;
  448. if (ExpectedDataType && ExpectedDataType != actualDataType) {
  449. DEBUGMSG ((
  450. DBG_ERROR,
  451. "BlobReadEx: Actual data type (%lu) different than expected data type (%lu)",
  452. actualDataType,
  453. ExpectedDataType
  454. ));
  455. return NULL;
  456. }
  457. Blob->Index += DWSIZEOF (DWORD);
  458. readPtr += DWSIZEOF (DWORD);
  459. }
  460. if (BlobRecordsDataSize (Blob) || RecordedDataSize) {
  461. if (readPtr + DWSIZEOF (DWORD) > BlobGetEOF (Blob)) {
  462. BlobSetIndex (Blob, initialIndex);
  463. return NULL;
  464. }
  465. //
  466. // read actual data size
  467. //
  468. actualDataSize = *(DWORD*)readPtr;
  469. if (ExpectedDataSize && ExpectedDataSize != actualDataSize) {
  470. DEBUGMSG ((
  471. DBG_ERROR,
  472. "BlobReadEx: Actual data size (%lu) different than expected data size (%lu)",
  473. actualDataSize,
  474. ExpectedDataSize
  475. ));
  476. BlobSetIndex (Blob, initialIndex);
  477. return NULL;
  478. }
  479. Blob->Index += DWSIZEOF (DWORD);
  480. readPtr += DWSIZEOF (DWORD);
  481. } else {
  482. actualDataSize = ExpectedDataSize;
  483. }
  484. if (!actualDataSize) {
  485. BlobSetIndex (Blob, initialIndex);
  486. return NULL;
  487. }
  488. if (ActualDataSize) {
  489. *ActualDataSize = actualDataSize;
  490. }
  491. //
  492. // don't read over end of file
  493. //
  494. if (readPtr + actualDataSize > BlobGetEOF (Blob)) {
  495. //
  496. // corrupt blob; undo anyway
  497. //
  498. MYASSERT (FALSE); //lint !e506
  499. BlobSetIndex (Blob, initialIndex);
  500. return NULL;
  501. }
  502. if (!Data) {
  503. if (Pool) {
  504. Data = PmGetMemory (Pool, actualDataSize);
  505. } else {
  506. Data = pBlobAllocateMemory (actualDataSize);
  507. }
  508. if (!Data) {
  509. BlobSetIndex (Blob, initialIndex);
  510. return NULL;
  511. }
  512. }
  513. CopyMemory (Data, readPtr, actualDataSize);
  514. Blob->Index += actualDataSize;
  515. return Data;
  516. }
  517. BOOL
  518. BlobWriteDword (
  519. IN OUT POURBLOB Blob,
  520. IN DWORD Data
  521. )
  522. /*++
  523. Routine Description:
  524. BlobWriteDword writes a DWORD at the current writing position in the specified blob
  525. Arguments:
  526. Blob - Specifies the blob to write to
  527. Data - Specifies the DWORD
  528. Return Value:
  529. TRUE if data was successfully stored in the blob
  530. --*/
  531. {
  532. return BlobWriteEx (Blob, BDT_DWORD, FALSE, DWSIZEOF (DWORD), &Data);
  533. }
  534. BOOL
  535. BlobReadDword (
  536. IN OUT POURBLOB Blob,
  537. OUT PDWORD Data
  538. )
  539. /*++
  540. Routine Description:
  541. BlobReadDword reads a DWORD from the current reading position in the specified blob
  542. Arguments:
  543. Blob - Specifies the blob to read from
  544. Data - Receives the DWORD
  545. Return Value:
  546. TRUE if data was successfully read from the blob
  547. --*/
  548. {
  549. return BlobReadEx (Blob, BDT_DWORD, DWSIZEOF (DWORD), FALSE, NULL, Data, NULL) != NULL;
  550. }
  551. BOOL
  552. BlobWriteQword (
  553. IN OUT POURBLOB Blob,
  554. IN DWORDLONG Data
  555. )
  556. /*++
  557. Routine Description:
  558. BlobWriteQword writes a DWORDLONG at the current writing position in the specified blob
  559. Arguments:
  560. Blob - Specifies the blob to write to
  561. Data - Specifies the DWORDLONG
  562. Return Value:
  563. TRUE if data was successfully stored in the blob
  564. --*/
  565. {
  566. return BlobWriteEx (Blob, BDT_QWORD, FALSE, DWSIZEOF (DWORDLONG), &Data);
  567. }
  568. BOOL
  569. BlobReadQword (
  570. IN OUT POURBLOB Blob,
  571. OUT PDWORDLONG Data
  572. )
  573. /*++
  574. Routine Description:
  575. BlobReadQword reads a DWORDLONG from the current reading position in the specified blob
  576. Arguments:
  577. Blob - Specifies the blob to read from
  578. Data - Receives the DWORDLONG
  579. Return Value:
  580. TRUE if data was successfully read from the blob
  581. --*/
  582. {
  583. return BlobReadEx (Blob, BDT_QWORD, DWSIZEOF (DWORDLONG), FALSE, NULL, Data, NULL) != NULL;
  584. }
  585. /*++
  586. Routine Description:
  587. BlobWriteString writes a string at the current writing position in the specified blob;
  588. the string is stored in UNICODE inside the blob if BF_UNICODESTRINGS is set
  589. Arguments:
  590. Blob - Specifies the blob to write to
  591. Data - Specifies the string
  592. Return Value:
  593. TRUE if data was successfully stored in the blob
  594. --*/
  595. BOOL
  596. BlobWriteStringA (
  597. IN OUT POURBLOB Blob,
  598. IN PCSTR Data
  599. )
  600. {
  601. PCWSTR unicodeString;
  602. BOOL b;
  603. if (BlobRecordsUnicodeStrings (Blob)) {
  604. unicodeString = ConvertAtoW (Data);
  605. b = BlobWriteStringW (Blob, unicodeString);
  606. FreeConvertedStr (unicodeString);
  607. return b;
  608. }
  609. return BlobWriteEx (Blob, BDT_SZA, TRUE, SizeOfStringA (Data), Data);
  610. }
  611. BOOL
  612. BlobWriteStringW (
  613. IN OUT POURBLOB Blob,
  614. IN PCWSTR Data
  615. )
  616. {
  617. return BlobWriteEx (Blob, BDT_SZW, TRUE, SizeOfStringW (Data), Data);
  618. }
  619. /*++
  620. Routine Description:
  621. BlobReadString reads a string from the current reading position in the specified blob;
  622. the string may be converted to the ANSI/UNICODE format.
  623. If the blob doesn't store data types, this is assumed to be BDT_SZA for the ANSI version
  624. and BDT_SZW for the UNICODE version of this function
  625. Arguments:
  626. Blob - Specifies the blob to read from
  627. Data - Receives a pointer to the new allocated string
  628. Pool - Specifies the pool to use for allocating memory;
  629. if NULL, the process heap will be used
  630. Return Value:
  631. TRUE if data was successfully read from the blob
  632. --*/
  633. BOOL
  634. BlobReadStringA (
  635. IN OUT POURBLOB Blob,
  636. OUT PCSTR* Data,
  637. IN PMHANDLE Pool OPTIONAL
  638. )
  639. {
  640. PSTR ansiString;
  641. PCWSTR unicodeString;
  642. DWORD dataType;
  643. DWORD index;
  644. DWORD length = 0;
  645. //
  646. // save initial index; in case of failure it will be restored
  647. //
  648. index = BlobGetIndex (Blob);
  649. if (!index) {
  650. return FALSE;
  651. }
  652. ansiString = NULL;
  653. unicodeString = NULL;
  654. if (BlobRecordsDataType (Blob)) {
  655. dataType = BlobGetRecordedDataType (Blob);
  656. if (dataType == BDT_SZA) {
  657. ansiString = BlobReadEx (Blob, BDT_SZA, 0, TRUE, NULL, NULL, Pool);
  658. } else if (dataType == BDT_SZW) {
  659. unicodeString = (PCWSTR)BlobReadEx (Blob, BDT_SZW, 0, TRUE, &length, NULL, Pool);
  660. } else {
  661. DEBUGMSG ((DBG_ERROR, "BlobReadStringA: unexpected data type (%lu)", dataType));
  662. return FALSE;
  663. }
  664. } else {
  665. if (BlobRecordsUnicodeStrings (Blob)) {
  666. unicodeString = (PCWSTR)BlobReadEx (Blob, BDT_SZW, 0, TRUE, &length, NULL, Pool);
  667. } else {
  668. //
  669. // assume an ANSI string is stored there
  670. //
  671. ansiString = BlobReadEx (Blob, BDT_SZA, 0, TRUE, NULL, NULL, Pool);
  672. }
  673. }
  674. if (!ansiString) {
  675. if (!unicodeString) {
  676. return FALSE;
  677. }
  678. if (Pool) {
  679. ansiString = PmGetMemory (Pool, length);
  680. } else {
  681. ansiString = pBlobAllocateMemory (length);
  682. }
  683. if (ansiString) {
  684. DirectUnicodeToDbcsN (ansiString, unicodeString, length);
  685. }
  686. if (Pool) {
  687. PmReleaseMemory (Pool, (PVOID)unicodeString);
  688. } else {
  689. pBlobFreeMemory ((PVOID)unicodeString);
  690. }
  691. if (!ansiString) {
  692. //
  693. // recover prev state
  694. //
  695. BlobSetIndex (Blob, index);
  696. return FALSE;
  697. }
  698. }
  699. *Data = ansiString;
  700. return TRUE;
  701. }
  702. BOOL
  703. BlobReadStringW (
  704. IN OUT POURBLOB Blob,
  705. OUT PCWSTR* Data,
  706. IN PMHANDLE Pool OPTIONAL
  707. )
  708. {
  709. PWSTR unicodeString;
  710. PCSTR ansiString;
  711. DWORD dataType;
  712. DWORD index;
  713. DWORD length;
  714. //
  715. // save initial index; in case of failure it will be restored
  716. //
  717. index = BlobGetIndex (Blob);
  718. if (!index) {
  719. return FALSE;
  720. }
  721. if (BlobRecordsDataType (Blob)) {
  722. dataType = BlobGetRecordedDataType (Blob);
  723. if (dataType == BDT_SZW) {
  724. unicodeString = (PWSTR)BlobReadEx (Blob, BDT_SZW, 0, TRUE, NULL, NULL, Pool);
  725. } else if (dataType == BDT_SZA) {
  726. ansiString = BlobReadEx (Blob, BDT_SZA, 0, TRUE, &length, NULL, Pool);
  727. if (!ansiString) {
  728. return FALSE;
  729. }
  730. if (Pool) {
  731. unicodeString = PmGetMemory (Pool, length * DWSIZEOF (WCHAR));
  732. } else {
  733. unicodeString = pBlobAllocateMemory (length * DWSIZEOF (WCHAR));
  734. }
  735. if (unicodeString) {
  736. DirectDbcsToUnicodeN (unicodeString, ansiString, length);
  737. }
  738. if (Pool) {
  739. PmReleaseMemory (Pool, (PVOID)ansiString);
  740. } else {
  741. pBlobFreeMemory ((PVOID)ansiString);
  742. }
  743. if (!unicodeString) {
  744. //
  745. // recover prev state
  746. //
  747. BlobSetIndex (Blob, index);
  748. return FALSE;
  749. }
  750. } else {
  751. DEBUGMSG ((DBG_ERROR, "BlobReadStringW: unexpected data type (%lu)", dataType));
  752. return FALSE;
  753. }
  754. } else {
  755. //
  756. // assume an UNICODE string is stored there
  757. //
  758. unicodeString = (PWSTR)BlobReadEx (Blob, BDT_SZW, 0, TRUE, NULL, NULL, Pool);
  759. }
  760. if (!unicodeString) {
  761. return FALSE;
  762. }
  763. *Data = unicodeString;
  764. return TRUE;
  765. }
  766. /*++
  767. Routine Description:
  768. BlobWriteMultiSz writes a multisz at the current writing position in the specified blob;
  769. the multisz is stored in UNICODE inside the blob if BF_UNICODESTRINGS is set
  770. Arguments:
  771. Blob - Specifies the blob to write to
  772. Data - Specifies the multisz
  773. Return Value:
  774. TRUE if data was successfully stored in the blob
  775. --*/
  776. BOOL
  777. BlobWriteMultiSzA (
  778. IN OUT POURBLOB Blob,
  779. IN PCSTR Data
  780. )
  781. {
  782. PWSTR unicodeString;
  783. BOOL b;
  784. DWORD stringSize = SizeOfMultiSzA (Data);
  785. if (BlobRecordsUnicodeStrings (Blob)) {
  786. unicodeString = AllocTextW (stringSize);
  787. DirectDbcsToUnicodeN (unicodeString, Data, stringSize);
  788. b = BlobWriteMultiSzW (Blob, unicodeString);
  789. FreeTextW (unicodeString);
  790. return b;
  791. }
  792. return BlobWriteEx (Blob, BDT_MULTISZA, TRUE, stringSize, Data);
  793. }
  794. BOOL
  795. BlobWriteMultiSzW (
  796. IN OUT POURBLOB Blob,
  797. IN PCWSTR Data
  798. )
  799. {
  800. return BlobWriteEx (Blob, BDT_MULTISZW, TRUE, SizeOfMultiSzW (Data), Data);
  801. }
  802. /*++
  803. Routine Description:
  804. BlobReadMultiSz reads a multisz from the current reading position in the specified blob;
  805. the string may be converted to the ANSI/UNICODE format.
  806. If the blob doesn't store data types, this is assumed to be BDT_MULTISZA for the ANSI version
  807. and BDT_MULTISZW for the UNICODE version of this function
  808. Arguments:
  809. Blob - Specifies the blob to read from
  810. Data - Receives a pointer to the new allocated multisz
  811. Pool - Specifies the pool to use for allocating memory;
  812. if NULL, the process heap will be used
  813. Return Value:
  814. TRUE if data was successfully read from the blob
  815. --*/
  816. BOOL
  817. BlobReadMultiSzA (
  818. IN OUT POURBLOB Blob,
  819. OUT PCSTR* Data,
  820. IN PMHANDLE Pool OPTIONAL
  821. )
  822. {
  823. PSTR ansiString;
  824. PCWSTR unicodeString;
  825. DWORD dataType;
  826. DWORD index;
  827. DWORD length = 0;
  828. //
  829. // save initial index; in case of failure it will be restored
  830. //
  831. index = BlobGetIndex (Blob);
  832. if (!index) {
  833. return FALSE;
  834. }
  835. ansiString = NULL;
  836. unicodeString = NULL;
  837. if (BlobRecordsDataType (Blob)) {
  838. dataType = BlobGetRecordedDataType (Blob);
  839. if (dataType == BDT_MULTISZA) {
  840. ansiString = BlobReadEx (Blob, BDT_MULTISZA, 0, TRUE, NULL, NULL, Pool);
  841. } else if (dataType == BDT_MULTISZW) {
  842. unicodeString = (PCWSTR)BlobReadEx (Blob, BDT_MULTISZW, 0, TRUE, &length, NULL, Pool);
  843. } else {
  844. DEBUGMSG ((DBG_ERROR, "BlobReadMultiSzA: unexpected data type (%lu)", dataType));
  845. return FALSE;
  846. }
  847. } else {
  848. if (BlobRecordsUnicodeStrings (Blob)) {
  849. unicodeString = (PCWSTR)BlobReadEx (Blob, BDT_MULTISZW, 0, TRUE, &length, NULL, Pool);
  850. } else {
  851. //
  852. // assume an ANSI string is stored there
  853. //
  854. ansiString = BlobReadEx (Blob, BDT_MULTISZA, 0, TRUE, NULL, NULL, Pool);
  855. }
  856. }
  857. if (!ansiString) {
  858. if (!unicodeString) {
  859. return FALSE;
  860. }
  861. if (Pool) {
  862. ansiString = PmGetMemory (Pool, length);
  863. } else {
  864. ansiString = pBlobAllocateMemory (length);
  865. }
  866. if (ansiString) {
  867. DirectUnicodeToDbcsN (ansiString, unicodeString, length);
  868. }
  869. if (Pool) {
  870. PmReleaseMemory (Pool, (PVOID)unicodeString);
  871. } else {
  872. pBlobFreeMemory ((PVOID)unicodeString);
  873. }
  874. if (!ansiString) {
  875. //
  876. // recover prev state
  877. //
  878. BlobSetIndex (Blob, index);
  879. return FALSE;
  880. }
  881. }
  882. *Data = ansiString;
  883. return TRUE;
  884. }
  885. BOOL
  886. BlobReadMultiSzW (
  887. IN OUT POURBLOB Blob,
  888. OUT PCWSTR* Data,
  889. IN PMHANDLE Pool OPTIONAL
  890. )
  891. {
  892. PWSTR unicodeString;
  893. PCSTR ansiString;
  894. DWORD dataType;
  895. DWORD index;
  896. DWORD length;
  897. //
  898. // save initial index; in case of failure it will be restored
  899. //
  900. index = BlobGetIndex (Blob);
  901. if (!index) {
  902. return FALSE;
  903. }
  904. if (BlobRecordsDataType (Blob)) {
  905. dataType = BlobGetRecordedDataType (Blob);
  906. if (dataType == BDT_MULTISZW) {
  907. unicodeString = (PWSTR)BlobReadEx (Blob, BDT_MULTISZW, 0, TRUE, NULL, NULL, Pool);
  908. } else if (dataType == BDT_MULTISZA) {
  909. ansiString = BlobReadEx (Blob, BDT_MULTISZA, 0, TRUE, &length, NULL, Pool);
  910. if (!ansiString) {
  911. return FALSE;
  912. }
  913. if (Pool) {
  914. unicodeString = PmGetMemory (Pool, length * DWSIZEOF (WCHAR));
  915. } else {
  916. unicodeString = pBlobAllocateMemory (length * DWSIZEOF (WCHAR));
  917. }
  918. if (unicodeString) {
  919. DirectDbcsToUnicodeN (unicodeString, ansiString, length);
  920. }
  921. if (Pool) {
  922. PmReleaseMemory (Pool, (PVOID)ansiString);
  923. } else {
  924. pBlobFreeMemory ((PVOID)ansiString);
  925. }
  926. if (!unicodeString) {
  927. //
  928. // recover prev state
  929. //
  930. BlobSetIndex (Blob, index);
  931. return FALSE;
  932. }
  933. } else {
  934. DEBUGMSG ((DBG_ERROR, "BlobReadMultiSzW: unexpected data type (%lu)", dataType));
  935. return FALSE;
  936. }
  937. } else {
  938. //
  939. // assume an UNICODE string is stored there
  940. //
  941. unicodeString = (PWSTR)BlobReadEx (Blob, BDT_MULTISZW, 0, TRUE, NULL, NULL, Pool);
  942. }
  943. if (!unicodeString) {
  944. return FALSE;
  945. }
  946. *Data = unicodeString;
  947. return TRUE;
  948. }
  949. BOOL
  950. BlobWriteBinaryEx (
  951. IN OUT POURBLOB Blob,
  952. IN PBYTE Data,
  953. IN DWORD Size,
  954. IN BOOL RecordDataSize
  955. )
  956. /*++
  957. Routine Description:
  958. BlobWriteBinary writes a buffer at the current writing position in the specified blob
  959. Arguments:
  960. Blob - Specifies the blob to write to
  961. Data - Specifies the source buffer
  962. Size - Specifies the size of the buffer
  963. RecordDataSize - Specifies TRUE if data size should be recorded, too
  964. Return Value:
  965. TRUE if data was successfully stored in the blob
  966. --*/
  967. {
  968. return BlobWriteEx (Blob, BDT_BINARY, RecordDataSize, Size, Data);
  969. }
  970. BOOL
  971. BlobReadBinary (
  972. IN OUT POURBLOB Blob,
  973. OUT PBYTE* Data,
  974. OUT PDWORD Size,
  975. IN PMHANDLE Pool OPTIONAL
  976. )
  977. /*++
  978. Routine Description:
  979. BlobReadBinary reads a buffer from the current reading position in the specified blob
  980. Arguments:
  981. Blob - Specifies the blob to read from
  982. Data - Receives a pointer to the new allocated buffer
  983. Size - Receives the size of the buffer
  984. Pool - Specifies the pool to use for allocating memory;
  985. if NULL, the process heap will be used
  986. Return Value:
  987. TRUE if data was successfully read from the blob
  988. --*/
  989. {
  990. *Data = BlobReadEx (Blob, BDT_BINARY, 0, TRUE, Size, NULL, Pool);
  991. return *Data != NULL;
  992. }
  993. BOOL
  994. BlobWriteToFile (
  995. IN POURBLOB Blob,
  996. IN HANDLE File
  997. )
  998. /*++
  999. Routine Description:
  1000. BlobWriteToFile writes the specified blob to the given file
  1001. Arguments:
  1002. Blob - Specifies the blob to save
  1003. File - Specifies the handle of the file to write the blob to
  1004. Return Value:
  1005. TRUE if blob was successfully written to the file
  1006. --*/
  1007. {
  1008. BLOBHDR header;
  1009. DWORD d;
  1010. if (!Blob->End) {
  1011. DEBUGMSG ((DBG_BLOBS, "BlobWriteToFile: Did not write empty blob to file"));
  1012. return FALSE;
  1013. }
  1014. //
  1015. // save blob's Flags and End position
  1016. //
  1017. header.BlobSignature = BLOB_SIGNATURE;
  1018. header.DataSize = Blob->End;
  1019. header.Flags = Blob->Flags;
  1020. if (!WriteFile (File, &header, DWSIZEOF (BLOBHDR), &d, NULL) || d != DWSIZEOF (BLOBHDR)) {
  1021. DEBUGMSG ((DBG_ERROR, "BlobWriteToFile: Error writing blob header!"));
  1022. return FALSE;
  1023. }
  1024. if (!WriteFile (File, Blob->Data, Blob->End, &d, NULL) || d != Blob->End) {
  1025. DEBUGMSG ((DBG_ERROR, "BlobWriteToFile: Error writing blob data!"));
  1026. return FALSE;
  1027. }
  1028. return TRUE;
  1029. }
  1030. BOOL
  1031. BlobReadFromFile (
  1032. OUT POURBLOB Blob,
  1033. IN HANDLE File
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. BlobReadFromFile reads data from the given file in the specified blob
  1038. Arguments:
  1039. Blob - Receives the data
  1040. File - Specifies the handle of the file to read from
  1041. Return Value:
  1042. TRUE if blob was successfully read from the file
  1043. --*/
  1044. {
  1045. BLOBHDR header;
  1046. DWORD d;
  1047. //
  1048. // read blob's Flags and End position
  1049. //
  1050. if (!ReadFile (File, &header, DWSIZEOF (BLOBHDR), &d, NULL) || d != DWSIZEOF (BLOBHDR)) {
  1051. DEBUGMSG ((DBG_ERROR, "BlobReadFromFile: Error reading blob header!"));
  1052. return FALSE;
  1053. }
  1054. if (header.BlobSignature != BLOB_SIGNATURE) {
  1055. DEBUGMSG ((DBG_ERROR, "BlobReadFromFile: Not a valid blob signature!"));
  1056. return FALSE;
  1057. }
  1058. Blob->Data = pBlobAllocateMemory (header.DataSize);
  1059. if (!Blob->Data) {
  1060. return FALSE;
  1061. }
  1062. if (!ReadFile (File, Blob->Data, header.DataSize, &d, NULL) || d != header.DataSize) {
  1063. DEBUGMSG ((DBG_ERROR, "BlobReadFromFile: Error reading blob data!"));
  1064. pBlobFreeMemory (Blob->Data);
  1065. Blob->Data = NULL;
  1066. return FALSE;
  1067. }
  1068. Blob->AllocSize = header.DataSize;
  1069. Blob->End = header.DataSize;
  1070. Blob->Flags = header.Flags;
  1071. Blob->Index = 0;
  1072. return TRUE;
  1073. }
  1074. BOOL
  1075. BlobsAdd (
  1076. IN OUT PBLOBS BlobsArray,
  1077. IN POURBLOB Blob
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. BlobsAdd adds the specified Blob to a blobs array
  1082. Arguments:
  1083. BlobsArray - Specifies the array to add to
  1084. Blob - Specifies the blob to add
  1085. Return Value:
  1086. TRUE if the new blob pointer was added successfully
  1087. --*/
  1088. {
  1089. ASSERT_VALID_BLOBS_ARRAY (BlobsArray);
  1090. if (!BlobsArray->BlobsGrowCount) {
  1091. BlobsArray->BlobsGrowCount = BLOBS_GROWCOUNT_DEFAULT;
  1092. }
  1093. if (!BlobsArray->Blobs) {
  1094. BlobsArray->Blobs = (POURBLOB*)pBlobAllocateMemory (
  1095. BlobsArray->BlobsGrowCount * DWSIZEOF (POURBLOB)
  1096. );
  1097. if (!BlobsArray->Blobs) {
  1098. DEBUGMSG ((DBG_ERROR, "BlobsAddE: Initial alloc failed"));
  1099. return FALSE;
  1100. }
  1101. BlobsArray->Signature = BLOBS_SIGNATURE;
  1102. BlobsArray->BlobsAllocated = BlobsArray->BlobsGrowCount;
  1103. BlobsArray->BlobsCount = 0;
  1104. } else if (BlobsArray->BlobsCount == BlobsArray->BlobsAllocated) {
  1105. BlobsArray->BlobsAllocated += BlobsArray->BlobsGrowCount;
  1106. BlobsArray->Blobs = (POURBLOB*)pReAllocateMemory (
  1107. BlobsArray->Blobs,
  1108. BlobsArray->BlobsAllocated * DWSIZEOF (POURBLOB)
  1109. );
  1110. if (!BlobsArray->Blobs) {
  1111. BlobsArray->BlobsAllocated -= BlobsArray->BlobsGrowCount;
  1112. DEBUGMSG ((DBG_ERROR, "BlobsAdd: Realloc failed"));
  1113. return FALSE;
  1114. }
  1115. }
  1116. *(BlobsArray->Blobs + BlobsArray->BlobsCount) = Blob;
  1117. BlobsArray->BlobsCount++;
  1118. ASSERT_VALID_BLOBS_ARRAY (BlobsArray);
  1119. return TRUE;
  1120. }
  1121. VOID
  1122. BlobsFree (
  1123. IN OUT PBLOBS BlobsArray,
  1124. IN BOOL DestroyBlobs
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. BlobsFree destroys the array and optionally destroys all blobs in it
  1129. Arguments:
  1130. BlobsArray - Specifies the array to delete
  1131. DestroyBlobs - Specifies TRUE if the component blobs are to be deleted, too
  1132. Return Value:
  1133. none
  1134. --*/
  1135. {
  1136. BLOB_ENUM e;
  1137. ASSERT_VALID_BLOBS_ARRAY (BlobsArray);
  1138. if (DestroyBlobs) {
  1139. if (EnumFirstBlob (&e, BlobsArray)) {
  1140. do {
  1141. BlobDestroy (e.CurrentBlob);
  1142. } while (EnumNextBlob (&e));
  1143. }
  1144. }
  1145. pBlobFreeMemory (BlobsArray->Blobs);
  1146. ZeroMemory (BlobsArray, DWSIZEOF (BLOBS));
  1147. }
  1148. BOOL
  1149. EnumFirstBlob (
  1150. OUT PBLOB_ENUM BlobEnum,
  1151. IN PBLOBS BlobsArray
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. EnumFirstBlob enumerates the first blob in the given array
  1156. Arguments:
  1157. BlobEnum - Receives enum info
  1158. BlobsArray - Specifies the array to enum from
  1159. Return Value:
  1160. TRUE if a first blob was found; FALSE if array is empty
  1161. --*/
  1162. {
  1163. ASSERT_VALID_BLOBS_ARRAY (BlobsArray);
  1164. BlobEnum->Index = 0;
  1165. BlobEnum->Array = BlobsArray;
  1166. return EnumNextBlob (BlobEnum);
  1167. }
  1168. BOOL
  1169. EnumNextBlob (
  1170. IN OUT PBLOB_ENUM BlobEnum
  1171. )
  1172. /*++
  1173. Routine Description:
  1174. EnumNextBlob enumerates the next blob in the given array
  1175. Arguments:
  1176. BlobEnum - Specifies/receives enum info
  1177. Return Value:
  1178. TRUE if a next blob was found; FALSE if no more blobs
  1179. --*/
  1180. {
  1181. if (BlobEnum->Index >= BlobEnum->Array->BlobsCount) {
  1182. return FALSE;
  1183. }
  1184. BlobEnum->CurrentBlob = *(BlobEnum->Array->Blobs + BlobEnum->Index);
  1185. BlobEnum->Index++;
  1186. return TRUE;
  1187. }
  1188. BOOL
  1189. BlobsWriteToFile (
  1190. IN PBLOBS BlobsArray,
  1191. IN HANDLE File
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. BlobsWriteToFile writes the specified blobs array to the given file
  1196. Arguments:
  1197. BlobsArray - Specifies the blobs array to save
  1198. File - Specifies the handle of the file to write the array to
  1199. Return Value:
  1200. TRUE if array was successfully written to the file
  1201. --*/
  1202. {
  1203. BLOBSARRAYHDR header;
  1204. DWORD d;
  1205. POURBLOB* blob;
  1206. if (!BlobsArray->BlobsCount) {
  1207. DEBUGMSG ((DBG_BLOBS, "BlobsWriteToFile: Did not write empty blobs array to file"));
  1208. return FALSE;
  1209. }
  1210. //
  1211. // save blobs count
  1212. //
  1213. header.BlobsArraySignature = BLOBS_SIGNATURE;
  1214. header.BlobsCount = BlobsArray->BlobsCount;
  1215. if (!WriteFile (File, &header, DWSIZEOF (BLOBSARRAYHDR), &d, NULL) ||
  1216. d != DWSIZEOF (BLOBSARRAYHDR)
  1217. ) {
  1218. DEBUGMSG ((DBG_ERROR, "BlobsWriteToFile: Error writing blobs array header!"));
  1219. return FALSE;
  1220. }
  1221. for (blob = BlobsArray->Blobs; blob < BlobsArray->Blobs + BlobsArray->BlobsCount; blob++) {
  1222. if (!BlobWriteToFile (*blob, File)) {
  1223. DEBUGMSG ((
  1224. DBG_BLOBS,
  1225. "BlobsWriteToFile: Error writing blob # %lu to file",
  1226. blob - BlobsArray->Blobs
  1227. ));
  1228. return FALSE;
  1229. }
  1230. }
  1231. return TRUE;
  1232. }
  1233. BOOL
  1234. BlobsReadFromFile (
  1235. OUT PBLOBS BlobsArray,
  1236. IN HANDLE File
  1237. )
  1238. /*++
  1239. Routine Description:
  1240. BlobsReadFromFile reads data from the given file in the specified blobs array
  1241. Arguments:
  1242. BlobsArray - Receives the data
  1243. File - Specifies the handle of the file to read from
  1244. Return Value:
  1245. TRUE if array was successfully read from the file
  1246. --*/
  1247. {
  1248. BLOBSARRAYHDR header;
  1249. DWORD d;
  1250. UINT u;
  1251. POURBLOB blob;
  1252. //
  1253. // read blobs count
  1254. //
  1255. if (!ReadFile (File, &header, DWSIZEOF (BLOBSARRAYHDR), &d, NULL) ||
  1256. d != DWSIZEOF (BLOBSARRAYHDR)
  1257. ) {
  1258. DEBUGMSG ((DBG_ERROR, "BlobsReadFromFile: Error reading blobs array header!"));
  1259. return FALSE;
  1260. }
  1261. if (header.BlobsArraySignature != BLOBS_SIGNATURE) {
  1262. DEBUGMSG ((DBG_ERROR, "BlobsReadFromFile: Not a valid blobs array signature!"));
  1263. return FALSE;
  1264. }
  1265. BlobsArray->Blobs = (POURBLOB*)pBlobAllocateMemory (header.BlobsCount * DWSIZEOF (POURBLOB*));
  1266. if (!BlobsArray->Blobs) {
  1267. return FALSE;
  1268. }
  1269. ZeroMemory (BlobsArray->Blobs, header.BlobsCount * DWSIZEOF (POURBLOB));
  1270. BlobsArray->Signature = BLOBS_SIGNATURE;
  1271. BlobsArray->BlobsAllocated = header.BlobsCount;
  1272. BlobsArray->BlobsCount = 0;
  1273. BlobsArray->BlobsGrowCount = BLOBS_GROWCOUNT_DEFAULT;
  1274. for (u = 0; u < header.BlobsCount; u++) {
  1275. blob = BlobCreate ();
  1276. if (!blob) {
  1277. return FALSE;
  1278. }
  1279. if (!BlobReadFromFile (blob, File)) {
  1280. DEBUGMSG ((
  1281. DBG_BLOBS,
  1282. "BlobsReadFromFile: Error reading blob # %lu from file",
  1283. u
  1284. ));
  1285. BlobsFree (BlobsArray, TRUE);
  1286. return FALSE;
  1287. }
  1288. if (!BlobsAdd (BlobsArray, blob)) {
  1289. DEBUGMSG ((
  1290. DBG_BLOBS,
  1291. "BlobsReadFromFile: Error adding blob # %lu to array",
  1292. u
  1293. ));
  1294. BlobsFree (BlobsArray, TRUE);
  1295. return FALSE;
  1296. }
  1297. }
  1298. return TRUE;
  1299. }