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.

2060 lines
45 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. hash.c
  5. Abstract:
  6. Replacement routines for the string table functions in setupapi.dll.
  7. This routines are much more easy to work with.
  8. Author:
  9. Jim Schmidt (jimschm) 22-Dec-1998
  10. Revision History:
  11. jimschm 23-Nov-1999 Removed setup api compatibility, fixed enum
  12. to be insertion order
  13. ovidiut 14-Oct-1999 New coding conventions + Win64 compliance.
  14. marcw 2-Sep-1999 Moved over from Win9xUpg project.
  15. --*/
  16. #include "pch.h"
  17. //
  18. // Includes
  19. //
  20. // None
  21. #define DBG_HASH "HashTable"
  22. //
  23. // Strings
  24. //
  25. #define S_HASHTABLE "HashTable"
  26. //
  27. // Constants
  28. //
  29. #define BUCKETS 1009
  30. #define HASHTABLE_SIGNATURE 0x122398ff
  31. //
  32. // Macros
  33. //
  34. #ifdef DEBUG
  35. #define ASSERT_TABLE_IS_VALID(table) MYASSERT(pTableIsValid(table))
  36. #else
  37. #define ASSERT_TABLE_IS_VALID(table)
  38. #endif
  39. //
  40. // Types
  41. //
  42. typedef struct _tagBUCKETITEM {
  43. struct _tagBUCKETITEM *Next;
  44. struct _tagBUCKETITEM *NextLink, *PrevLink;
  45. INT Locked;
  46. WORD StringSize;
  47. // string follows StringSize
  48. // optional data follows string
  49. } BUCKETITEM, *PBUCKETITEM;
  50. typedef struct {
  51. struct _tagBUCKETITEM *Next;
  52. struct _tagBUCKETITEM *NextLink, *PrevLink;
  53. INT Locked;
  54. PVOID String;
  55. // optional data follows struct
  56. } BUCKETITEM_EXTERN_STR, *PBUCKETITEM_EXTERN_STR;
  57. typedef struct {
  58. DWORD Signature;
  59. BOOL Unicode;
  60. BOOL ExternalStrings;
  61. BOOL CaseSensitive;
  62. POOLHANDLE Pool;
  63. PBUCKETITEM *Bucket;
  64. PBUCKETITEM FirstLink;
  65. PBUCKETITEM LastLink;
  66. PBUCKETITEM DelayedDelete;
  67. UINT ExtraDataSize;
  68. UINT MinimumStringBytes;
  69. UINT MaximumStringBytes;
  70. UINT Buckets;
  71. } HASHTABLESTRUCT, *PHASHTABLESTRUCT;
  72. //
  73. // Globals
  74. //
  75. // None
  76. //
  77. // Macro expansion list
  78. //
  79. // None
  80. //
  81. // Private function prototypes
  82. //
  83. // None
  84. //
  85. // Macro expansion definition
  86. //
  87. // None
  88. //
  89. // Code
  90. //
  91. #ifdef DEBUG
  92. BOOL
  93. pTableIsValid (
  94. IN HASHTABLE Table
  95. )
  96. {
  97. BOOL b = TRUE;
  98. if (!Table) {
  99. return FALSE;
  100. }
  101. __try {
  102. if (((PHASHTABLESTRUCT) Table)->Signature != HASHTABLE_SIGNATURE) {
  103. b = FALSE;
  104. }
  105. }
  106. __except (TRUE) {
  107. b = FALSE;
  108. }
  109. return b;
  110. }
  111. #endif
  112. /*++
  113. Routine Description:
  114. pComputeHashValue adds all the character values of the string, shifting to
  115. maintain order.
  116. Arguments:
  117. String - Specifies the string to compute the hash value for
  118. Return Value:
  119. The hash value, within the range of 0 to BUCKETS - 1.
  120. --*/
  121. UINT
  122. pComputeHashValueA (
  123. IN PCSTR String,
  124. IN UINT Buckets
  125. )
  126. {
  127. UINT hashValue = 0;
  128. while (*String) {
  129. hashValue = _rotl (hashValue, 2);
  130. hashValue += (UINT) *String;
  131. String++;
  132. }
  133. hashValue %= Buckets;
  134. return hashValue;
  135. }
  136. UINT
  137. pComputeHashValueW (
  138. IN PCWSTR String,
  139. IN UINT Buckets
  140. )
  141. {
  142. UINT hashValue = 0;
  143. while (*String) {
  144. hashValue = _rotl (hashValue, 2);
  145. hashValue += (UINT) *String;
  146. String++;
  147. }
  148. hashValue %= Buckets;
  149. return hashValue;
  150. }
  151. UINT
  152. pComputePrefixHashValueA (
  153. IN PCSTR String,
  154. IN UINT Size,
  155. IN UINT Buckets
  156. )
  157. {
  158. UINT hashValue = 0;
  159. PCSTR end;
  160. end = (PCSTR) ((PBYTE) String + Size);
  161. while (String < end) {
  162. hashValue = _rotl (hashValue, 2);
  163. hashValue += (UINT) *String;
  164. String++;
  165. }
  166. hashValue %= Buckets;
  167. return hashValue;
  168. }
  169. UINT
  170. pComputePrefixHashValueW (
  171. IN PCWSTR String,
  172. IN UINT Size,
  173. IN UINT Buckets
  174. )
  175. {
  176. UINT hashValue = 0;
  177. PCWSTR end;
  178. end = (PCWSTR) ((PBYTE) String + Size);
  179. while (String < end) {
  180. hashValue = _rotl (hashValue, 2);
  181. hashValue += (UINT) *String;
  182. String++;
  183. }
  184. hashValue %= Buckets;
  185. return hashValue;
  186. }
  187. HASHTABLE
  188. HtAllocExAW (
  189. IN BOOL CaseSensitive,
  190. IN BOOL Unicode,
  191. IN BOOL ExternalStrings,
  192. IN UINT ExtraDataSize,
  193. IN UINT Buckets
  194. )
  195. /*++
  196. Routine Description:
  197. AllocateHashTableEx creates a hash table. If ExtraDataSize is non-zero,
  198. each hash table entry gets an allocation of ExtraDataSize added to it.
  199. Arguments:
  200. CaseSensitive - Specifies TRUE if the hash table is case-sensitive, FALSE
  201. if all strings should be stored and compared in lower-case
  202. only
  203. Unicode - Specifies TRUE to allocate a UNICODE hash table, or FALSE to
  204. allocate an ANSI table. None of the routines in this file do any
  205. sort of UNICODE/ANSI converstion.
  206. ExternalStrings - Specifies TRUE if the strings belong to memory maintained
  207. by the caller
  208. ExtraDataSize - Specifies the size of binary data associated with the
  209. table item, or 0 for none.
  210. Return Value:
  211. A handle to the string table.
  212. --*/
  213. {
  214. PHASHTABLESTRUCT hashTable;
  215. POOLHANDLE pool;
  216. if (!Buckets) {
  217. Buckets = BUCKETS;
  218. }
  219. pool = PoolMemInitNamedPool (S_HASHTABLE);
  220. MYASSERT (pool);
  221. PoolMemDisableTracking (pool);
  222. hashTable = (PHASHTABLESTRUCT) PoolMemGetAlignedMemory (
  223. pool,
  224. sizeof (HASHTABLESTRUCT) + (sizeof (PBUCKETITEM) * Buckets)
  225. );
  226. MYASSERT (hashTable);
  227. hashTable->Signature = HASHTABLE_SIGNATURE;
  228. hashTable->CaseSensitive = CaseSensitive;
  229. hashTable->Unicode = Unicode;
  230. hashTable->ExternalStrings = ExternalStrings;
  231. hashTable->Pool = pool;
  232. hashTable->Bucket = (PBUCKETITEM *) ((PBYTE) hashTable + sizeof (HASHTABLESTRUCT));
  233. hashTable->FirstLink = NULL;
  234. hashTable->LastLink = NULL;
  235. hashTable->ExtraDataSize = ExtraDataSize;
  236. hashTable->MinimumStringBytes = (UINT) -1;
  237. hashTable->MaximumStringBytes = 0;
  238. hashTable->Buckets = Buckets;
  239. //
  240. // Zero out all of the bucket structures.
  241. //
  242. ZeroMemory (hashTable->Bucket, sizeof (PBUCKETITEM) * Buckets);
  243. return (HASHTABLE) hashTable;
  244. }
  245. VOID
  246. HtFree (
  247. IN HASHTABLE HashTable
  248. )
  249. /*++
  250. Routine Description:
  251. HtFree releases all resources associated with a string table.
  252. Arguments:
  253. None.
  254. Return Value:
  255. None.
  256. --*/
  257. {
  258. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  259. if (table) {
  260. ASSERT_TABLE_IS_VALID (HashTable);
  261. PoolMemEmptyPool (table->Pool);
  262. PoolMemDestroyPool (table->Pool);
  263. }
  264. }
  265. PBUCKETITEM
  266. pHtFindStringA (
  267. IN HASHTABLE HashTable,
  268. IN PCSTR String,
  269. OUT PVOID ExtraDataBuffer, OPTIONAL
  270. IN BOOL AlreadyLowercase,
  271. OUT PUINT OutHashValue,
  272. OUT PBUCKETITEM *PrevBucketItem
  273. )
  274. /*++
  275. Routine Description:
  276. pHtFindString implements the hash table lookup routine. It returns the
  277. pointer to the bucket item or NULL if the item was not found.
  278. Arguments:
  279. HashTable - Specifies the handle to the hash table
  280. String - Specifies the string to find. If this string is
  281. case-insensitive but has already been lowercased, then make
  282. sure to pass TRUE in the AlreadyLowercase argument.
  283. ExtraDataBuffer - A buffer that receives the bytes stored as extra data with
  284. the found item; caller must size this according to the
  285. extra data size specified to HtAllocExAW
  286. AlreadyLowercase - Specifies TRUE if String is already lower case
  287. OutHashValue - Receives the hash value. This is non optional for
  288. efficiency.
  289. PrevBucketItem - Receives the previous bucket item
  290. Return Value:
  291. The pointer to the bucket item or NULL if no item was found.
  292. --*/
  293. {
  294. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  295. PSTR dupStr = NULL;
  296. UINT hashValue;
  297. PBUCKETITEM item;
  298. PCSTR p1, p2;
  299. PCVOID storedDataPtr;
  300. ASSERT_TABLE_IS_VALID (HashTable);
  301. *PrevBucketItem = NULL;
  302. if (!AlreadyLowercase && !table->CaseSensitive) {
  303. dupStr = DuplicateTextA (String);
  304. if (!dupStr) {
  305. MYASSERT (FALSE);
  306. return NULL;
  307. }
  308. (void) CharLowerA (dupStr);
  309. String = dupStr;
  310. }
  311. hashValue = pComputeHashValueA (String, table->Buckets);
  312. item = table->Bucket[hashValue];
  313. while (item) {
  314. if (table->ExternalStrings) {
  315. p1 = (PCSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  316. } else {
  317. p1 = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  318. }
  319. p2 = String;
  320. while (*p1) {
  321. if (*p1 != *p2) {
  322. break;
  323. }
  324. p1++;
  325. p2++;
  326. }
  327. if (*p1 == 0 && *p2 == 0) {
  328. break;
  329. }
  330. *PrevBucketItem = item;
  331. item = item->Next;
  332. }
  333. if (item && ExtraDataBuffer) {
  334. (void) HtGetExtraData (HashTable, (HASHITEM)item, &storedDataPtr);
  335. CopyMemory (
  336. (PBYTE) ExtraDataBuffer,
  337. (PBYTE) storedDataPtr,
  338. table->ExtraDataSize
  339. );
  340. }
  341. FreeTextA (dupStr);
  342. *OutHashValue = hashValue;
  343. return item;
  344. }
  345. PBUCKETITEM
  346. pHtFindStringW (
  347. IN HASHTABLE HashTable,
  348. IN PCWSTR String,
  349. OUT PVOID ExtraDataBuffer, OPTIONAL
  350. IN BOOL AlreadyLowercase,
  351. OUT PUINT OutHashValue,
  352. OUT PBUCKETITEM *PrevBucketItem
  353. )
  354. {
  355. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  356. PWSTR dupStr = NULL;
  357. UINT hashValue;
  358. PBUCKETITEM item;
  359. PCWSTR p1, p2;
  360. PCVOID storedDataPtr;
  361. ASSERT_TABLE_IS_VALID (HashTable);
  362. *PrevBucketItem = NULL;
  363. if (!AlreadyLowercase && !table->CaseSensitive) {
  364. dupStr = DuplicateTextW (String);
  365. if (!dupStr) {
  366. MYASSERT (FALSE);
  367. return NULL;
  368. }
  369. (void) _wcslwr (dupStr);
  370. String = dupStr;
  371. }
  372. hashValue = pComputeHashValueW (String, table->Buckets);
  373. item = table->Bucket[hashValue];
  374. while (item) {
  375. if (table->ExternalStrings) {
  376. p1 = (PCWSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  377. } else {
  378. p1 = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  379. }
  380. p2 = String;
  381. while (*p1) {
  382. if (*p1 != *p2) {
  383. break;
  384. }
  385. p1++;
  386. p2++;
  387. }
  388. if (*p1 == 0 && *p2 == 0) {
  389. break;
  390. }
  391. *PrevBucketItem = item;
  392. item = item->Next;
  393. }
  394. if (item && ExtraDataBuffer) {
  395. (void) HtGetExtraData (HashTable, (HASHITEM)item, &storedDataPtr);
  396. CopyMemory (
  397. (PBYTE) ExtraDataBuffer,
  398. (PBYTE) storedDataPtr,
  399. table->ExtraDataSize
  400. );
  401. }
  402. FreeTextW (dupStr);
  403. *OutHashValue = hashValue;
  404. return item;
  405. }
  406. PBUCKETITEM
  407. pHtFindPrefixA (
  408. IN HASHTABLE HashTable,
  409. IN PCSTR String,
  410. IN PCSTR BufferEnd,
  411. OUT PVOID ExtraDataBuffer, OPTIONAL
  412. IN BOOL AlreadyLowercase,
  413. OUT PUINT OutHashValue
  414. )
  415. /*++
  416. Routine Description:
  417. pHtFindPrefix implements a hash table lookup routine that tests each hash
  418. table entry, character-by-character, until a match is found, or until the
  419. hash table maximum is reached. It returns the pointer to the bucket item or
  420. NULL if the item was not found.
  421. Arguments:
  422. HashTable - Specifies the handle to the hash table
  423. String - Specifies the string to find. If this string is
  424. case-insensitive but has already been lowercased, then make
  425. sure to pass TRUE in the AlreadyLowercase argument.
  426. BufferEnd - Specifies the end of the string buffer, which may be longer
  427. than all entries in the hash table, or it may be shorter.
  428. ExtraDataBuffer - A buffer that receives the bytes stored as extra data with
  429. the found item; caller must size this according to the
  430. extra data size specified to HtAllocExAW
  431. AlreadyLowercase - Specifies TRUE if String is in lower-case, FALSE otherwise.
  432. OutHashValue - Receives the hash value. This is non optional for
  433. efficiency. If pHtFindPrefix does not find a match,
  434. this value will be set to zero.
  435. Return Value:
  436. The pointer to the bucket item or NULL if no item was found.
  437. --*/
  438. {
  439. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  440. PSTR dupStr = NULL;
  441. UINT hashValue = 0;
  442. PBUCKETITEM item = NULL;
  443. PCSTR p1, p2;
  444. PCSTR p1End;
  445. PCVOID storedDataPtr;
  446. UINT maxBytes;
  447. UINT currentBytes;
  448. PCSTR shortestEnd;
  449. ASSERT_TABLE_IS_VALID (HashTable);
  450. maxBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  451. maxBytes = min (maxBytes, table->MaximumStringBytes);
  452. if (!maxBytes || table->MinimumStringBytes == (UINT) -1) {
  453. return NULL;
  454. }
  455. if (!AlreadyLowercase && !table->CaseSensitive) {
  456. dupStr = AllocTextA (maxBytes / sizeof (CHAR));
  457. if (!dupStr) {
  458. MYASSERT (FALSE);
  459. return NULL;
  460. }
  461. StringCopyByteCountA (dupStr, String, maxBytes + sizeof (CHAR));
  462. CharLowerA (dupStr);
  463. String = dupStr;
  464. }
  465. BufferEnd = (PCSTR) ((PBYTE) String + maxBytes);
  466. shortestEnd = (PCSTR) ((PBYTE) String + table->MinimumStringBytes);
  467. if (shortestEnd == String) {
  468. shortestEnd = _mbsinc (shortestEnd);
  469. }
  470. while (BufferEnd >= shortestEnd) {
  471. currentBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  472. hashValue = pComputePrefixHashValueA (String, currentBytes, table->Buckets);
  473. item = table->Bucket[hashValue];
  474. while (item) {
  475. if ((item->StringSize - sizeof (CHAR)) == currentBytes) {
  476. if (table->ExternalStrings) {
  477. p1 = (PCSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  478. } else {
  479. p1 = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  480. }
  481. p1End = (PCSTR) ((PBYTE) p1 + currentBytes);
  482. p2 = String;
  483. while (p1 < p1End) {
  484. if (*p1 != *p2) {
  485. break;
  486. }
  487. p1++;
  488. p2++;
  489. }
  490. if (p1 == p1End) {
  491. break;
  492. }
  493. }
  494. item = item->Next;
  495. }
  496. if (item) {
  497. break;
  498. }
  499. BufferEnd = _mbsdec2 (String, BufferEnd);
  500. }
  501. if (item && ExtraDataBuffer) {
  502. (void) HtGetExtraData (HashTable, (HASHITEM)item, &storedDataPtr);
  503. CopyMemory (
  504. (PBYTE) ExtraDataBuffer,
  505. (PBYTE) storedDataPtr,
  506. table->ExtraDataSize
  507. );
  508. }
  509. FreeTextA (dupStr);
  510. *OutHashValue = hashValue;
  511. return item;
  512. }
  513. PBUCKETITEM
  514. pHtFindPrefixW (
  515. IN HASHTABLE HashTable,
  516. IN PCWSTR String,
  517. IN PCWSTR BufferEnd,
  518. OUT PVOID ExtraDataBuffer, OPTIONAL
  519. IN BOOL AlreadyLowercase,
  520. OUT PUINT OutHashValue
  521. )
  522. {
  523. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  524. PWSTR dupStr = NULL;
  525. UINT hashValue = 0;
  526. PBUCKETITEM item = NULL;
  527. PCWSTR p1, p2;
  528. PCWSTR p1End;
  529. PCVOID storedDataPtr;
  530. UINT maxBytes;
  531. PCWSTR shortestEnd;
  532. UINT currentBytes;
  533. ASSERT_TABLE_IS_VALID (HashTable);
  534. maxBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  535. maxBytes = min (maxBytes, table->MaximumStringBytes);
  536. if (!maxBytes || table->MinimumStringBytes == (UINT) -1) {
  537. return NULL;
  538. }
  539. if (!AlreadyLowercase && !table->CaseSensitive) {
  540. dupStr = AllocTextW (maxBytes / sizeof (WCHAR));
  541. if (!dupStr) {
  542. MYASSERT (FALSE);
  543. return NULL;
  544. }
  545. StringCopyByteCountW (dupStr, String, maxBytes + sizeof (WCHAR));
  546. _wcslwr (dupStr);
  547. String = dupStr;
  548. }
  549. BufferEnd = (PCWSTR) ((PBYTE) String + maxBytes);
  550. shortestEnd = (PCWSTR) ((PBYTE) String + table->MinimumStringBytes);
  551. if (shortestEnd == String) {
  552. shortestEnd++;
  553. }
  554. while (BufferEnd >= shortestEnd) {
  555. currentBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  556. hashValue = pComputePrefixHashValueW (String, currentBytes, table->Buckets);
  557. item = table->Bucket[hashValue];
  558. while (item) {
  559. if ((item->StringSize - sizeof (WCHAR)) == currentBytes) {
  560. if (table->ExternalStrings) {
  561. p1 = (PCWSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  562. } else {
  563. p1 = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  564. }
  565. p1End = (PCWSTR) ((PBYTE) p1 + currentBytes);
  566. p2 = String;
  567. while (p1 < p1End) {
  568. if (*p1 != *p2) {
  569. break;
  570. }
  571. p1++;
  572. p2++;
  573. }
  574. if (p1 == p1End) {
  575. break;
  576. }
  577. }
  578. item = item->Next;
  579. }
  580. if (item) {
  581. break;
  582. }
  583. BufferEnd--;
  584. }
  585. if (item && ExtraDataBuffer) {
  586. (void) HtGetExtraData (HashTable, (HASHITEM)item, &storedDataPtr);
  587. CopyMemory (
  588. (PBYTE) ExtraDataBuffer,
  589. (PBYTE) storedDataPtr,
  590. table->ExtraDataSize
  591. );
  592. }
  593. FreeTextW (dupStr);
  594. *OutHashValue = hashValue;
  595. return item;
  596. }
  597. HASHITEM
  598. HtAddStringExA (
  599. IN HASHTABLE HashTable,
  600. IN PCSTR String,
  601. IN PCVOID ExtraData, OPTIONAL
  602. IN BOOL AlreadyLowercase
  603. )
  604. /*++
  605. Routine Description:
  606. HtAddStringEx adds a string to the hash table, and copies ExtraData to the
  607. new hash table entry. If String is already in the hash table, the ExtraData
  608. is updated.
  609. Arguments:
  610. HashTable - Specifies the handle to the hash table, as returned from
  611. AllocateHashTable.
  612. String - Specifies the string to add to the table
  613. ExtraData - Specifies the source binary data to be copied to the hash
  614. table entry
  615. AlreadyLowercase - Specifies TRUE String is in all lowercase
  616. Return Value:
  617. Returns the pointer to the bucket item allocated or update.
  618. --*/
  619. {
  620. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  621. PBUCKETITEM item;
  622. PBUCKETITEM_EXTERN_STR externItem;
  623. PBUCKETITEM existingItem;
  624. PSTR dupStr = NULL;
  625. HASHITEM rc = NULL;
  626. UINT size;
  627. UINT hashValue;
  628. UINT strSize;
  629. PCVOID storedDataPtr;
  630. PBUCKETITEM dontCare;
  631. ASSERT_TABLE_IS_VALID (HashTable);
  632. if (table->Unicode) {
  633. DEBUGMSG ((DBG_WHOOPS, "Cannot add ANSI string to UNICODE table"));
  634. return 0;
  635. }
  636. if (!AlreadyLowercase && !table->CaseSensitive) {
  637. dupStr = DuplicateTextA (String);
  638. if (!dupStr) {
  639. MYASSERT (FALSE);
  640. return 0;
  641. }
  642. CharLowerA (dupStr);
  643. String = dupStr;
  644. }
  645. existingItem = pHtFindStringA (HashTable, String, NULL, TRUE, &hashValue, &dontCare);
  646. if (existingItem) {
  647. rc = (HASHITEM) existingItem;
  648. } else {
  649. //
  650. // item does not exist, add it now
  651. //
  652. strSize = SizeOfStringA (String);
  653. if (table->ExternalStrings) {
  654. size = sizeof (BUCKETITEM_EXTERN_STR) + table->ExtraDataSize;
  655. externItem = (PBUCKETITEM_EXTERN_STR) PoolMemGetAlignedMemory (table->Pool, size);
  656. MYASSERT (externItem);
  657. externItem->Locked = 0;
  658. externItem->Next = table->Bucket[hashValue];
  659. table->Bucket[hashValue] = (PBUCKETITEM) externItem;
  660. if (table->LastLink) {
  661. table->LastLink->NextLink = (PBUCKETITEM) externItem;
  662. }
  663. externItem->PrevLink = table->LastLink;
  664. table->LastLink = (PBUCKETITEM) externItem;
  665. externItem->NextLink = NULL;
  666. if (!table->FirstLink) {
  667. table->FirstLink = (PBUCKETITEM) externItem;
  668. }
  669. rc = (HASHITEM) externItem;
  670. } else {
  671. size = sizeof (BUCKETITEM) + strSize + table->ExtraDataSize;
  672. item = (PBUCKETITEM) PoolMemGetAlignedMemory (table->Pool, size);
  673. MYASSERT (item);
  674. item->Locked = 0;
  675. item->Next = table->Bucket[hashValue];
  676. table->Bucket[hashValue] = item;
  677. item->StringSize = (WORD) strSize;
  678. CopyMemory ((PBYTE) item + sizeof (BUCKETITEM), String, strSize);
  679. if (table->LastLink) {
  680. table->LastLink->NextLink = item;
  681. }
  682. item->PrevLink = table->LastLink;
  683. table->LastLink = item;
  684. item->NextLink = NULL;
  685. if (!table->FirstLink) {
  686. table->FirstLink = item;
  687. }
  688. rc = (HASHITEM) item;
  689. }
  690. strSize -= sizeof (CHAR);
  691. table->MaximumStringBytes = max (table->MaximumStringBytes, strSize);
  692. table->MinimumStringBytes = min (table->MinimumStringBytes, strSize);
  693. }
  694. MYASSERT (rc);
  695. (void) HtGetExtraData (HashTable, rc, &storedDataPtr);
  696. if (ExtraData) {
  697. CopyMemory (
  698. (PBYTE) storedDataPtr,
  699. (PBYTE) ExtraData,
  700. table->ExtraDataSize
  701. );
  702. } else if (!existingItem) {
  703. ZeroMemory (
  704. (PBYTE) storedDataPtr,
  705. table->ExtraDataSize
  706. );
  707. }
  708. FreeTextA (dupStr);
  709. return rc;
  710. }
  711. HASHITEM
  712. HtAddStringExW (
  713. IN HASHTABLE HashTable,
  714. IN PCWSTR String,
  715. IN PCVOID ExtraData, OPTIONAL
  716. IN BOOL AlreadyLowercase
  717. )
  718. {
  719. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  720. PBUCKETITEM item;
  721. PBUCKETITEM_EXTERN_STR externItem;
  722. PBUCKETITEM existingItem;
  723. PWSTR dupStr = NULL;
  724. HASHITEM rc = NULL;
  725. UINT size;
  726. UINT hashValue;
  727. UINT strSize;
  728. PCVOID storedDataPtr;
  729. PBUCKETITEM dontCare;
  730. ASSERT_TABLE_IS_VALID (HashTable);
  731. if (!table->Unicode) {
  732. DEBUGMSG ((DBG_WHOOPS, "Cannot add UNICODE string to ANSI table"));
  733. return 0;
  734. }
  735. if (!AlreadyLowercase && !table->CaseSensitive) {
  736. dupStr = DuplicateTextW (String);
  737. if (!dupStr) {
  738. MYASSERT (FALSE);
  739. return 0;
  740. }
  741. _wcslwr (dupStr);
  742. String = dupStr;
  743. }
  744. existingItem = pHtFindStringW (HashTable, String, NULL, TRUE, &hashValue, &dontCare);
  745. if (existingItem) {
  746. rc = (HASHITEM) existingItem;
  747. } else {
  748. //
  749. // item does not exist, add it now
  750. //
  751. strSize = SizeOfStringW (String);
  752. if (table->ExternalStrings) {
  753. size = sizeof (BUCKETITEM_EXTERN_STR) + table->ExtraDataSize;
  754. externItem = (PBUCKETITEM_EXTERN_STR) PoolMemGetAlignedMemory (table->Pool, size);
  755. MYASSERT (externItem);
  756. externItem->Locked = 0;
  757. externItem->Next = table->Bucket[hashValue];
  758. table->Bucket[hashValue] = (PBUCKETITEM) externItem;
  759. if (table->LastLink) {
  760. table->LastLink->NextLink = (PBUCKETITEM) externItem;
  761. }
  762. externItem->PrevLink = table->LastLink;
  763. table->LastLink = (PBUCKETITEM) externItem;
  764. externItem->NextLink = NULL;
  765. if (!table->FirstLink) {
  766. table->FirstLink = (PBUCKETITEM) externItem;
  767. }
  768. rc = (HASHITEM) externItem;
  769. } else {
  770. size = sizeof (BUCKETITEM) + strSize + table->ExtraDataSize;
  771. item = (PBUCKETITEM) PoolMemGetAlignedMemory (table->Pool, size);
  772. MYASSERT (item);
  773. item->Locked = 0;
  774. item->Next = table->Bucket[hashValue];
  775. table->Bucket[hashValue] = item;
  776. item->StringSize = (WORD) strSize;
  777. CopyMemory ((PBYTE) item + sizeof (BUCKETITEM), String, strSize);
  778. if (table->LastLink) {
  779. table->LastLink->NextLink = item;
  780. }
  781. item->PrevLink = table->LastLink;
  782. table->LastLink = item;
  783. item->NextLink = NULL;
  784. if (!table->FirstLink) {
  785. table->FirstLink = item;
  786. }
  787. rc = (HASHITEM) item;
  788. }
  789. strSize -= sizeof (WCHAR);
  790. table->MaximumStringBytes = max (table->MaximumStringBytes, strSize);
  791. table->MinimumStringBytes = min (table->MinimumStringBytes, strSize);
  792. }
  793. MYASSERT (rc);
  794. (void) HtGetExtraData (HashTable, rc, &storedDataPtr);
  795. if (ExtraData) {
  796. CopyMemory (
  797. (PBYTE) storedDataPtr,
  798. (PBYTE) ExtraData,
  799. table->ExtraDataSize
  800. );
  801. } else if (!existingItem) {
  802. ZeroMemory (
  803. (PBYTE) storedDataPtr,
  804. table->ExtraDataSize
  805. );
  806. }
  807. FreeTextW (dupStr);
  808. return rc;
  809. }
  810. VOID
  811. pRemoveHashItem (
  812. IN PHASHTABLESTRUCT Table,
  813. IN UINT BucketNum,
  814. IN PBUCKETITEM PrevItem,
  815. IN PBUCKETITEM ItemToDelete
  816. )
  817. {
  818. if (!PrevItem) {
  819. MYASSERT (Table->Bucket[BucketNum] == ItemToDelete);
  820. Table->Bucket[BucketNum] = ItemToDelete->Next;
  821. } else {
  822. PrevItem->Next = ItemToDelete->Next;
  823. }
  824. if (ItemToDelete->PrevLink) {
  825. ItemToDelete->PrevLink->NextLink = ItemToDelete->NextLink;
  826. } else {
  827. Table->FirstLink = ItemToDelete->Next;
  828. }
  829. if (ItemToDelete->NextLink) {
  830. ItemToDelete->NextLink->PrevLink = ItemToDelete->PrevLink;
  831. } else {
  832. Table->LastLink = ItemToDelete->PrevLink;
  833. }
  834. if (ItemToDelete->Locked) {
  835. ItemToDelete->Next = Table->DelayedDelete;
  836. Table->DelayedDelete = ItemToDelete;
  837. } else {
  838. PoolMemReleaseMemory (Table->Pool, ItemToDelete);
  839. }
  840. }
  841. BOOL
  842. HtRemoveItem (
  843. IN HASHTABLE HashTable,
  844. IN HASHITEM Item
  845. )
  846. {
  847. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  848. UINT bucketNumber;
  849. PBUCKETITEM prevItem;
  850. PBUCKETITEM thisItem;
  851. PCSTR ansiStr;
  852. PCWSTR unicodeStr;
  853. if (!Item) {
  854. return FALSE;
  855. }
  856. //
  857. // Find prev bucket item
  858. //
  859. if (table->Unicode) {
  860. unicodeStr = HtGetStringFromItemW (Item);
  861. MYASSERT (unicodeStr);
  862. thisItem = pHtFindStringW (
  863. HashTable,
  864. unicodeStr,
  865. NULL,
  866. TRUE,
  867. &bucketNumber,
  868. &prevItem
  869. );
  870. } else {
  871. ansiStr = HtGetStringFromItemA (Item);
  872. MYASSERT (ansiStr);
  873. thisItem = pHtFindStringA (
  874. HashTable,
  875. ansiStr,
  876. NULL,
  877. TRUE,
  878. &bucketNumber,
  879. &prevItem
  880. );
  881. }
  882. MYASSERT (Item == thisItem);
  883. if (Item != thisItem) {
  884. return FALSE;
  885. }
  886. pRemoveHashItem (table, bucketNumber, prevItem, thisItem);
  887. return TRUE;
  888. }
  889. BOOL
  890. HtRemoveStringA (
  891. IN HASHTABLE HashTable,
  892. IN PCSTR AnsiString
  893. )
  894. {
  895. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  896. UINT bucketNumber;
  897. PBUCKETITEM prevItem;
  898. PBUCKETITEM thisItem;
  899. if (table->Unicode) {
  900. DEBUGMSG ((DBG_WHOOPS, "Cannot delete UNICODE table with ANSI api"));
  901. return FALSE;
  902. }
  903. thisItem = pHtFindStringA (
  904. HashTable,
  905. AnsiString,
  906. NULL,
  907. FALSE,
  908. &bucketNumber,
  909. &prevItem
  910. );
  911. if (!thisItem) {
  912. return FALSE;
  913. }
  914. pRemoveHashItem (table, bucketNumber, prevItem, thisItem);
  915. return TRUE;
  916. }
  917. BOOL
  918. HtRemoveStringW (
  919. IN HASHTABLE HashTable,
  920. IN PCWSTR UnicodeString
  921. )
  922. {
  923. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  924. UINT bucketNumber;
  925. PBUCKETITEM prevItem;
  926. PBUCKETITEM thisItem;
  927. if (!table->Unicode) {
  928. DEBUGMSG ((DBG_WHOOPS, "Cannot delete ANSI table with UNICODE api"));
  929. return FALSE;
  930. }
  931. thisItem = pHtFindStringW (
  932. HashTable,
  933. UnicodeString,
  934. NULL,
  935. FALSE,
  936. &bucketNumber,
  937. &prevItem
  938. );
  939. if (!thisItem) {
  940. return FALSE;
  941. }
  942. pRemoveHashItem (table, bucketNumber, prevItem, thisItem);
  943. return TRUE;
  944. }
  945. /*++
  946. Routine Description:
  947. HtFindStringEx is the external entry point for pHtFindString.
  948. Arguments:
  949. HashTable - Specifies the hash table handle, as returned by
  950. AllocateHashTable.
  951. String - Specifies the string to find
  952. ExtraDataBuffer - Receives the extra data associated with the found item
  953. AlreadyLowercase - Specifies TRUE if the String is in lowercase
  954. Return Value:
  955. A pointer to the bucket item or NULL if the string was not found.
  956. --*/
  957. HASHITEM
  958. HtFindStringExA (
  959. IN HASHTABLE HashTable,
  960. IN PCSTR String,
  961. OUT PVOID ExtraDataBuffer, OPTIONAL
  962. IN BOOL AlreadyLowercase
  963. )
  964. {
  965. UINT dontCare;
  966. PBUCKETITEM dontCare2;
  967. return (HASHITEM) pHtFindStringA (
  968. HashTable,
  969. String,
  970. ExtraDataBuffer,
  971. AlreadyLowercase,
  972. &dontCare,
  973. &dontCare2
  974. );
  975. }
  976. HASHITEM
  977. HtFindStringExW (
  978. IN HASHTABLE HashTable,
  979. IN PCWSTR String,
  980. OUT PVOID ExtraDataBuffer, OPTIONAL
  981. IN BOOL AlreadyLowercase
  982. )
  983. {
  984. UINT dontCare;
  985. PBUCKETITEM dontCare2;
  986. return (HASHITEM) pHtFindStringW (
  987. HashTable,
  988. String,
  989. ExtraDataBuffer,
  990. AlreadyLowercase,
  991. &dontCare,
  992. &dontCare2
  993. );
  994. }
  995. /*++
  996. Routine Description:
  997. HtFindStringEx is the external entry point for pHtFindString.
  998. Arguments:
  999. HashTable - Specifies the hash table handle, as returned by
  1000. AllocateHashTable.
  1001. String - Specifies the string to find
  1002. BufferEnd - Specifies the end of the buffer for String
  1003. ExtraDataBuffer - Receives the extra data associated with the found item
  1004. AlreadyLowercase - Specifies TRUE if String is in all lowercase
  1005. Return Value:
  1006. A pointer to the bucket item or NULL if the string was not found.
  1007. --*/
  1008. HASHITEM
  1009. HtFindPrefixExA (
  1010. IN HASHTABLE HashTable,
  1011. IN PCSTR String,
  1012. IN PCSTR BufferEnd,
  1013. OUT PVOID ExtraDataBuffer, OPTIONAL
  1014. IN BOOL AlreadyLowercase
  1015. )
  1016. {
  1017. UINT dontCare;
  1018. return (HASHITEM) pHtFindPrefixA (
  1019. HashTable,
  1020. String,
  1021. BufferEnd,
  1022. ExtraDataBuffer,
  1023. AlreadyLowercase,
  1024. &dontCare
  1025. );
  1026. }
  1027. HASHITEM
  1028. HtFindPrefixExW (
  1029. IN HASHTABLE HashTable,
  1030. IN PCWSTR String,
  1031. IN PCWSTR BufferEnd,
  1032. OUT PVOID ExtraDataBuffer, OPTIONAL
  1033. IN BOOL AlreadyLowercase
  1034. )
  1035. {
  1036. UINT dontCare;
  1037. return (HASHITEM) pHtFindPrefixW (
  1038. HashTable,
  1039. String,
  1040. BufferEnd,
  1041. ExtraDataBuffer,
  1042. AlreadyLowercase,
  1043. &dontCare
  1044. );
  1045. }
  1046. BOOL
  1047. HtGetExtraData (
  1048. IN HASHTABLE HashTable,
  1049. IN HASHITEM Index,
  1050. OUT PCVOID *ExtraData
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. HtGetExtraData gets the extra data associated with a bucket item.
  1055. The caller must supply the ID as returned from HtFindStringEx or
  1056. HtAddStringEx. This routine is useful when ExtraData is large, and
  1057. the normal find routine would be slow because of the CopyMemory code path.
  1058. Arguments:
  1059. HashTable - Specifies the handle to the hash table
  1060. Index - Specifies the offset as returned from HtFindStringEx or
  1061. HtAddStringEx
  1062. ExtraData - Receives the extra data pointer (it does NOT copy the data to
  1063. the buffer).
  1064. Return Value:
  1065. TRUE if ExtraData was set, FALSE otherwise.
  1066. --*/
  1067. {
  1068. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1069. PBUCKETITEM item;
  1070. PBUCKETITEM_EXTERN_STR externStrItem;
  1071. ASSERT_TABLE_IS_VALID (HashTable);
  1072. if (!Index) {
  1073. return FALSE;
  1074. }
  1075. if (table->ExternalStrings) {
  1076. externStrItem = (PBUCKETITEM_EXTERN_STR) Index;
  1077. *ExtraData = (PCVOID) ((PBYTE) externStrItem + sizeof (PBUCKETITEM_EXTERN_STR));
  1078. } else {
  1079. item = (PBUCKETITEM) Index;
  1080. *ExtraData = (PCVOID) ((PBYTE) item + sizeof (BUCKETITEM) + item->StringSize);
  1081. }
  1082. return TRUE;
  1083. }
  1084. BOOL
  1085. HtCopyStringData (
  1086. IN HASHTABLE HashTable,
  1087. IN HASHITEM Index,
  1088. OUT PVOID ExtraDataBuffer
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. HtCopyStringData gets the extra data associated with a bucket item
  1093. and copies it to the caller's buffer.
  1094. Arguments:
  1095. HashTable - Specifies the handle to the hash table
  1096. Index - Specifies the offset as returned from HtFindStringEx or
  1097. HtAddStringEx
  1098. ExtraDataBuffer - Receives the extra data
  1099. Return Value:
  1100. TRUE if ExtraDataBuffer was copied, FALSE otherwise.
  1101. --*/
  1102. {
  1103. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1104. PCVOID storedDataPtr;
  1105. ASSERT_TABLE_IS_VALID (HashTable);
  1106. if (!HtGetExtraData (HashTable, Index, &storedDataPtr)) {
  1107. return FALSE;
  1108. }
  1109. CopyMemory (
  1110. (PBYTE) ExtraDataBuffer,
  1111. (PBYTE) storedDataPtr,
  1112. table->ExtraDataSize
  1113. );
  1114. return TRUE;
  1115. }
  1116. BOOL
  1117. HtSetStringData (
  1118. IN HASHTABLE HashTable,
  1119. IN HASHITEM Index,
  1120. IN PCVOID ExtraData
  1121. )
  1122. /*++
  1123. Routine Description:
  1124. HtSetStringData copies new extra data to the specified hash table entry.
  1125. Arguments:
  1126. HashTable - Specifies the handle to the hash table
  1127. Index - Specifies the offset as returned from HtFindStringEx or
  1128. HtAddStringEx
  1129. ExtraData - Specifies the extra data
  1130. Return Value:
  1131. TRUE if the item was updated, FALSE otherwise.
  1132. --*/
  1133. {
  1134. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1135. PCVOID storedDataPtr;
  1136. ASSERT_TABLE_IS_VALID (HashTable);
  1137. if (!HtGetExtraData (HashTable, Index, &storedDataPtr)) {
  1138. return FALSE;
  1139. }
  1140. CopyMemory (
  1141. (PBYTE) storedDataPtr,
  1142. (PBYTE) ExtraData,
  1143. table->ExtraDataSize
  1144. );
  1145. return TRUE;
  1146. }
  1147. BOOL
  1148. EnumFirstHashTableStringA (
  1149. OUT PHASHTABLE_ENUMA EnumPtr,
  1150. IN HASHTABLE HashTable
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. EnumFirstHashTableString begins an enumeration of the hash table structure.
  1155. The return order is random. Also, do not modify the hash table while an
  1156. enumeration is active.
  1157. Arguments:
  1158. EnumPtr - Receives the string, extra data and offset for the first item
  1159. in the hash table.
  1160. HashTable - Specifies the handle of the hash table to enumerate.
  1161. Return Value:
  1162. TRUE if an item was enumerated, FALSE otherwise.
  1163. --*/
  1164. {
  1165. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1166. ASSERT_TABLE_IS_VALID (HashTable);
  1167. if (table->Unicode) {
  1168. DEBUGMSG ((DBG_WHOOPS, "Cannot enum UNICODE table with ANSI wrapper"));
  1169. return FALSE;
  1170. }
  1171. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMA));
  1172. EnumPtr->Internal = (HASHTABLE) table;
  1173. return EnumNextHashTableStringA (EnumPtr);
  1174. }
  1175. BOOL
  1176. EnumFirstHashTableStringW (
  1177. OUT PHASHTABLE_ENUMW EnumPtr,
  1178. IN HASHTABLE HashTable
  1179. )
  1180. {
  1181. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1182. ASSERT_TABLE_IS_VALID (HashTable);
  1183. if (!table->Unicode) {
  1184. DEBUGMSG ((DBG_WHOOPS, "Cannot enum ANSI table with UNICODE wrapper"));
  1185. return FALSE;
  1186. }
  1187. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMW));
  1188. EnumPtr->Internal = (HASHTABLE) table;
  1189. return EnumNextHashTableStringW (EnumPtr);
  1190. }
  1191. BOOL
  1192. EnumNextHashTableStringA (
  1193. IN OUT PHASHTABLE_ENUMA EnumPtr
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. EnumNextHashTableString continues an enumeration started by
  1198. EnumFirstHashTableString. Call the routine until it returns FALSE.
  1199. Arguments:
  1200. EnumPtr - Specifies the structure of an active enumeration. Receives
  1201. updated string, extra data and offset members.
  1202. Return Value:
  1203. TRUE if another item was enumerated, FALSE if no items remain.
  1204. --*/
  1205. {
  1206. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1207. PBUCKETITEM item;
  1208. PBUCKETITEM_EXTERN_STR externItem;
  1209. if (!EnumPtr->Internal) {
  1210. return FALSE;
  1211. }
  1212. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1213. if (!EnumPtr->Index) {
  1214. item = table->FirstLink;
  1215. } else {
  1216. item = (PBUCKETITEM) EnumPtr->Index;
  1217. item->Locked -= 1;
  1218. MYASSERT (item->Locked >= 0);
  1219. item = item->NextLink;
  1220. }
  1221. if (item) {
  1222. //
  1223. // Return a valid item
  1224. //
  1225. item->Locked += 1;
  1226. EnumPtr->Index = (HASHITEM) item;
  1227. if (table->ExternalStrings) {
  1228. externItem = (PBUCKETITEM_EXTERN_STR) item;
  1229. EnumPtr->String = (PCSTR) (externItem->String);
  1230. } else {
  1231. EnumPtr->String = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  1232. }
  1233. if (table->ExtraDataSize) {
  1234. MYASSERT (EnumPtr->Index);
  1235. (void) HtGetExtraData (EnumPtr->Internal, EnumPtr->Index, &EnumPtr->ExtraData);
  1236. }
  1237. return TRUE;
  1238. }
  1239. EnumPtr->Internal = 0;
  1240. return FALSE;
  1241. }
  1242. BOOL
  1243. EnumNextHashTableStringW (
  1244. IN OUT PHASHTABLE_ENUMW EnumPtr
  1245. )
  1246. {
  1247. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1248. PBUCKETITEM item;
  1249. PBUCKETITEM_EXTERN_STR externItem;
  1250. if (!EnumPtr->Internal) {
  1251. return FALSE;
  1252. }
  1253. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1254. if (!EnumPtr->Index) {
  1255. item = table->FirstLink;
  1256. } else {
  1257. item = (PBUCKETITEM) EnumPtr->Index;
  1258. item->Locked -= 1;
  1259. MYASSERT (item->Locked >= 0);
  1260. item = item->NextLink;
  1261. }
  1262. if (item) {
  1263. //
  1264. // Return a valid item
  1265. //
  1266. item->Locked += 1;
  1267. EnumPtr->Index = (HASHITEM) item;
  1268. if (table->ExternalStrings) {
  1269. externItem = (PBUCKETITEM_EXTERN_STR) item;
  1270. EnumPtr->String = (PCWSTR) (externItem->String);
  1271. } else {
  1272. EnumPtr->String = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  1273. }
  1274. if (table->ExtraDataSize) {
  1275. MYASSERT (EnumPtr->Index);
  1276. (void) HtGetExtraData (EnumPtr->Internal, EnumPtr->Index, &EnumPtr->ExtraData);
  1277. }
  1278. return TRUE;
  1279. }
  1280. EnumPtr->Internal = 0;
  1281. return FALSE;
  1282. }
  1283. VOID
  1284. AbortHashTableEnumA (
  1285. IN PHASHTABLE_ENUMA EnumPtr
  1286. )
  1287. {
  1288. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1289. PBUCKETITEM item;
  1290. PBUCKETITEM nextItem;
  1291. PBUCKETITEM prevItem;
  1292. if (!EnumPtr->Internal) {
  1293. return;
  1294. }
  1295. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1296. if (EnumPtr->Index) {
  1297. item = (PBUCKETITEM) EnumPtr->Index;
  1298. item->Locked -= 1;
  1299. MYASSERT (item->Locked >= 0);
  1300. }
  1301. //
  1302. // Evaluate delayed delete items; remove those that are no longer locked
  1303. //
  1304. if (table->DelayedDelete) {
  1305. item = table->DelayedDelete;
  1306. prevItem = NULL;
  1307. while (item) {
  1308. nextItem = item->Next;
  1309. if (!item->Locked) {
  1310. PoolMemReleaseMemory (table->Pool, item);
  1311. } else {
  1312. if (prevItem) {
  1313. prevItem->Next = item;
  1314. } else {
  1315. table->DelayedDelete = item;
  1316. }
  1317. prevItem = item;
  1318. }
  1319. item = nextItem;
  1320. }
  1321. if (prevItem) {
  1322. prevItem->Next = NULL;
  1323. } else {
  1324. table->DelayedDelete = NULL;
  1325. }
  1326. }
  1327. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMA));
  1328. }
  1329. VOID
  1330. AbortHashTableEnumW (
  1331. IN PHASHTABLE_ENUMW EnumPtr
  1332. )
  1333. {
  1334. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1335. PBUCKETITEM item;
  1336. PBUCKETITEM prevItem;
  1337. PBUCKETITEM nextItem;
  1338. if (!EnumPtr->Internal) {
  1339. return;
  1340. }
  1341. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1342. if (EnumPtr->Index) {
  1343. item = (PBUCKETITEM) EnumPtr->Index;
  1344. item->Locked -= 1;
  1345. MYASSERT (item->Locked >= 0);
  1346. }
  1347. //
  1348. // Evaluate delayed delete items; remove those that are no longer locked
  1349. //
  1350. if (table->DelayedDelete) {
  1351. item = table->DelayedDelete;
  1352. prevItem = NULL;
  1353. while (item) {
  1354. nextItem = item->Next;
  1355. if (!item->Locked) {
  1356. PoolMemReleaseMemory (table->Pool, item);
  1357. } else {
  1358. if (prevItem) {
  1359. prevItem->Next = item;
  1360. } else {
  1361. table->DelayedDelete = item;
  1362. }
  1363. prevItem = item;
  1364. }
  1365. item = nextItem;
  1366. }
  1367. if (prevItem) {
  1368. prevItem->Next = NULL;
  1369. } else {
  1370. table->DelayedDelete = NULL;
  1371. }
  1372. }
  1373. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMW));
  1374. }
  1375. BOOL
  1376. EnumHashTableWithCallbackA (
  1377. IN HASHTABLE HashTable,
  1378. IN PHASHTABLE_CALLBACK_ROUTINEA Proc,
  1379. IN LPARAM lParam
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. EnumHashTableWithCallback implements a setupapi-style enumerator. The
  1384. callback routine is called for each item in the string table, and if the
  1385. callback routine returns FALSE, the enumeration ends.
  1386. Arguments:
  1387. HashTable - Specifies the handle to the table to enumerate
  1388. Proc - Specifies the callback procedure address
  1389. lParam - Specifies a value to pass to the callback, and is intended only
  1390. for use by the caller.
  1391. Return Value:
  1392. Always TRUE.
  1393. --*/
  1394. {
  1395. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1396. HASHTABLE_ENUMA e;
  1397. ASSERT_TABLE_IS_VALID (HashTable);
  1398. if (EnumFirstHashTableStringA (&e, HashTable)) {
  1399. do {
  1400. if (!Proc (HashTable, e.Index, e.String, (PVOID) e.ExtraData, table->ExtraDataSize, lParam)) {
  1401. AbortHashTableEnumA (&e);
  1402. break;
  1403. }
  1404. } while (EnumNextHashTableStringA (&e));
  1405. }
  1406. return TRUE;
  1407. }
  1408. BOOL
  1409. EnumHashTableWithCallbackW (
  1410. IN HASHTABLE HashTable,
  1411. IN PHASHTABLE_CALLBACK_ROUTINEW Proc,
  1412. IN LPARAM lParam
  1413. )
  1414. {
  1415. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1416. HASHTABLE_ENUMW e;
  1417. ASSERT_TABLE_IS_VALID (HashTable);
  1418. if (EnumFirstHashTableStringW (&e, HashTable)) {
  1419. do {
  1420. if (!Proc (HashTable, e.Index, e.String, (PVOID) e.ExtraData, table->ExtraDataSize, lParam)) {
  1421. AbortHashTableEnumW (&e);
  1422. break;
  1423. }
  1424. } while (EnumNextHashTableStringW (&e));
  1425. }
  1426. return TRUE;
  1427. }
  1428. PCSTR
  1429. HtGetStringFromItemA (
  1430. IN HASHITEM Item
  1431. )
  1432. {
  1433. if (!Item) {
  1434. return NULL;
  1435. }
  1436. return (PCSTR) ((PBYTE) Item + sizeof (BUCKETITEM));
  1437. }
  1438. PCWSTR
  1439. HtGetStringFromItemW (
  1440. IN HASHITEM Item
  1441. )
  1442. {
  1443. if (!Item) {
  1444. return NULL;
  1445. }
  1446. return (PCWSTR) ((PBYTE) Item + sizeof (BUCKETITEM));
  1447. }
  1448. BOOL
  1449. HtIsEmpty (
  1450. IN HASHTABLE HashTable
  1451. )
  1452. {
  1453. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1454. return (table->FirstLink == NULL);
  1455. }
  1456. BOOL
  1457. HtWriteToFile (
  1458. IN HASHTABLE HashTable,
  1459. IN HANDLE OutputFile,
  1460. IN HASHTABLEOUTPUTFLAGS Flags
  1461. )
  1462. {
  1463. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1464. BOOL result = FALSE;
  1465. DWORD bytesWritten;
  1466. PBUCKETITEM item;
  1467. PCWSTR unicodeStr;
  1468. PCSTR ansiStr;
  1469. DWORD dontCare;
  1470. ASSERT_TABLE_IS_VALID (HashTable);
  1471. __try {
  1472. if (Flags & WRITE_UNICODE_HEADER) {
  1473. if (table->Unicode) {
  1474. if ((!WriteFile (OutputFile, "\xff\xfe", 2, &bytesWritten, NULL)) ||
  1475. (bytesWritten != 2)
  1476. ) {
  1477. DEBUGMSG ((DBG_ERROR, "Error writing hash table to output file"));
  1478. __leave;
  1479. }
  1480. }
  1481. }
  1482. if (Flags & REVERSE_ORDER) {
  1483. item = table->LastLink;
  1484. } else {
  1485. item = table->FirstLink;
  1486. }
  1487. while (item) {
  1488. if (table->Unicode) {
  1489. unicodeStr = HtGetStringFromItemW (item);
  1490. if (!WriteFile (OutputFile, unicodeStr, ByteCountW (unicodeStr), &dontCare, NULL)) {
  1491. __leave;
  1492. }
  1493. if (!WriteFile (OutputFile, L"\r\n", 4, &dontCare, NULL)) {
  1494. __leave;
  1495. }
  1496. } else {
  1497. ansiStr = HtGetStringFromItemA (item);
  1498. if (!WriteFile (OutputFile, ansiStr, ByteCountA (ansiStr), &dontCare, NULL)) {
  1499. __leave;
  1500. }
  1501. if (!WriteFile (OutputFile, "\r\n", 2, &dontCare, NULL)) {
  1502. __leave;
  1503. }
  1504. }
  1505. if (Flags & REVERSE_ORDER) {
  1506. item = item->PrevLink;
  1507. } else {
  1508. item = item->NextLink;
  1509. }
  1510. }
  1511. result = TRUE;
  1512. }
  1513. __finally {
  1514. }
  1515. return result;
  1516. }