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.

1947 lines
43 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. PMHANDLE 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. RealHtAllocExAW (
  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. PMHANDLE pool;
  216. if (!Buckets) {
  217. Buckets = BUCKETS;
  218. }
  219. pool = PmCreateNamedPool (S_HASHTABLE);
  220. MYASSERT (pool);
  221. PmDisableTracking (pool);
  222. hashTable = (PHASHTABLESTRUCT) PmGetAlignedMemory (
  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. PmEmptyPool (table->Pool);
  262. PmDestroyPool (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. (void) CharLowerA (dupStr);
  305. String = dupStr;
  306. }
  307. hashValue = pComputeHashValueA (String, table->Buckets);
  308. item = table->Bucket[hashValue];
  309. while (item) {
  310. if (table->ExternalStrings) {
  311. p1 = (PCSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  312. } else {
  313. p1 = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  314. }
  315. p2 = String;
  316. while (*p1) {
  317. if (*p1 != *p2) {
  318. break;
  319. }
  320. p1++;
  321. p2++;
  322. }
  323. if (*p1 == 0 && *p2 == 0) {
  324. break;
  325. }
  326. *PrevBucketItem = item;
  327. item = item->Next;
  328. }
  329. if (item && ExtraDataBuffer) {
  330. (void) HtGetExtraData (HashTable, (HASHITEM)item, &storedDataPtr);
  331. CopyMemory (
  332. (PBYTE) ExtraDataBuffer,
  333. (PBYTE) storedDataPtr,
  334. table->ExtraDataSize
  335. );
  336. }
  337. FreeTextA (dupStr);
  338. *OutHashValue = hashValue;
  339. return item;
  340. }
  341. PBUCKETITEM
  342. pHtFindStringW (
  343. IN HASHTABLE HashTable,
  344. IN PCWSTR String,
  345. OUT PVOID ExtraDataBuffer, OPTIONAL
  346. IN BOOL AlreadyLowercase,
  347. OUT PUINT OutHashValue,
  348. OUT PBUCKETITEM *PrevBucketItem
  349. )
  350. {
  351. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  352. PWSTR dupStr = NULL;
  353. UINT hashValue;
  354. PBUCKETITEM item;
  355. PCWSTR p1, p2;
  356. PCVOID storedDataPtr;
  357. ASSERT_TABLE_IS_VALID (HashTable);
  358. *PrevBucketItem = NULL;
  359. if (!AlreadyLowercase && !table->CaseSensitive) {
  360. dupStr = DuplicateTextW (String);
  361. (void) CharLowerW (dupStr);
  362. String = dupStr;
  363. }
  364. hashValue = pComputeHashValueW (String, table->Buckets);
  365. item = table->Bucket[hashValue];
  366. while (item) {
  367. if (table->ExternalStrings) {
  368. p1 = (PCWSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  369. } else {
  370. p1 = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  371. }
  372. p2 = String;
  373. while (*p1) {
  374. if (*p1 != *p2) {
  375. break;
  376. }
  377. p1++;
  378. p2++;
  379. }
  380. if (*p1 == 0 && *p2 == 0) {
  381. break;
  382. }
  383. *PrevBucketItem = item;
  384. item = item->Next;
  385. }
  386. if (item && ExtraDataBuffer) {
  387. (void) HtGetExtraData (HashTable, (HASHITEM)item, &storedDataPtr);
  388. CopyMemory (
  389. (PBYTE) ExtraDataBuffer,
  390. (PBYTE) storedDataPtr,
  391. table->ExtraDataSize
  392. );
  393. }
  394. FreeTextW (dupStr);
  395. *OutHashValue = hashValue;
  396. return item;
  397. }
  398. PBUCKETITEM
  399. pHtFindPrefixA (
  400. IN HASHTABLE HashTable,
  401. IN PCSTR String,
  402. IN PCSTR BufferEnd,
  403. OUT PVOID ExtraDataBuffer, OPTIONAL
  404. IN BOOL AlreadyLowercase,
  405. OUT PUINT OutHashValue
  406. )
  407. /*++
  408. Routine Description:
  409. pHtFindPrefix implements a hash table lookup routine that tests each hash
  410. table entry, character-by-character, until a match is found, or until the
  411. hash table maximum is reached. It returns the pointer to the bucket item or
  412. NULL if the item was not found.
  413. Arguments:
  414. HashTable - Specifies the handle to the hash table
  415. String - Specifies the string to find. If this string is
  416. case-insensitive but has already been lowercased, then make
  417. sure to pass TRUE in the AlreadyLowercase argument.
  418. BufferEnd - Specifies the end of the string buffer, which may be longer
  419. than all entries in the hash table, or it may be shorter.
  420. ExtraDataBuffer - A buffer that receives the bytes stored as extra data with
  421. the found item; caller must size this according to the
  422. extra data size specified to HtAllocExAW
  423. AlreadyLowercase - Specifies TRUE if String is in lower-case, FALSE otherwise.
  424. OutHashValue - Receives the hash value. This is non optional for
  425. efficiency. If pHtFindPrefix does not find a match,
  426. this value will be set to zero.
  427. Return Value:
  428. The pointer to the bucket item or NULL if no item was found.
  429. --*/
  430. {
  431. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  432. PSTR dupStr = NULL;
  433. UINT hashValue = 0;
  434. PBUCKETITEM item = NULL;
  435. PCSTR p1, p2;
  436. PCSTR p1End;
  437. PCVOID storedDataPtr;
  438. UINT maxBytes;
  439. UINT currentBytes;
  440. PCSTR shortestEnd;
  441. ASSERT_TABLE_IS_VALID (HashTable);
  442. maxBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  443. maxBytes = min (maxBytes, table->MaximumStringBytes);
  444. if (!maxBytes || table->MinimumStringBytes == (UINT) -1) {
  445. return NULL;
  446. }
  447. if (!AlreadyLowercase && !table->CaseSensitive) {
  448. dupStr = AllocTextA (maxBytes / sizeof (CHAR));
  449. if (!dupStr) {
  450. return NULL;
  451. }
  452. StringCopyByteCountA (dupStr, String, maxBytes + sizeof (CHAR));
  453. CharLowerA (dupStr);
  454. String = dupStr;
  455. }
  456. BufferEnd = (PCSTR) ((PBYTE) String + maxBytes);
  457. shortestEnd = (PCSTR) ((PBYTE) String + table->MinimumStringBytes);
  458. if (shortestEnd == String) {
  459. shortestEnd = _mbsinc (shortestEnd);
  460. }
  461. while (BufferEnd >= shortestEnd) {
  462. currentBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  463. hashValue = pComputePrefixHashValueA (String, currentBytes, table->Buckets);
  464. item = table->Bucket[hashValue];
  465. while (item) {
  466. if ((item->StringSize - sizeof (CHAR)) == currentBytes) {
  467. if (table->ExternalStrings) {
  468. p1 = (PCSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  469. } else {
  470. p1 = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  471. }
  472. p1End = (PCSTR) ((PBYTE) p1 + currentBytes);
  473. p2 = String;
  474. while (p1 < p1End) {
  475. if (*p1 != *p2) {
  476. break;
  477. }
  478. p1++;
  479. p2++;
  480. }
  481. if (p1 == p1End) {
  482. break;
  483. }
  484. }
  485. item = item->Next;
  486. }
  487. if (item) {
  488. break;
  489. }
  490. BufferEnd = _mbsdec2 (String, BufferEnd);
  491. }
  492. if (item && ExtraDataBuffer) {
  493. (void) HtGetExtraData (HashTable, (HASHITEM)item, &storedDataPtr);
  494. CopyMemory (
  495. (PBYTE) ExtraDataBuffer,
  496. (PBYTE) storedDataPtr,
  497. table->ExtraDataSize
  498. );
  499. }
  500. FreeTextA (dupStr);
  501. *OutHashValue = hashValue;
  502. return item;
  503. }
  504. PBUCKETITEM
  505. pHtFindPrefixW (
  506. IN HASHTABLE HashTable,
  507. IN PCWSTR String,
  508. IN PCWSTR BufferEnd,
  509. OUT PVOID ExtraDataBuffer, OPTIONAL
  510. IN BOOL AlreadyLowercase,
  511. OUT PUINT OutHashValue
  512. )
  513. {
  514. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  515. PWSTR dupStr = NULL;
  516. UINT hashValue = 0;
  517. PBUCKETITEM item = NULL;
  518. PCWSTR p1, p2;
  519. PCWSTR p1End;
  520. PCVOID storedDataPtr;
  521. UINT maxBytes;
  522. PCWSTR shortestEnd;
  523. UINT currentBytes;
  524. ASSERT_TABLE_IS_VALID (HashTable);
  525. maxBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  526. maxBytes = min (maxBytes, table->MaximumStringBytes);
  527. if (!maxBytes || table->MinimumStringBytes == (UINT) -1) {
  528. return NULL;
  529. }
  530. if (!AlreadyLowercase && !table->CaseSensitive) {
  531. dupStr = AllocTextW (maxBytes / sizeof (WCHAR));
  532. if (!dupStr) {
  533. return NULL;
  534. }
  535. StringCopyByteCountW (dupStr, String, maxBytes + sizeof (WCHAR));
  536. CharLowerW (dupStr);
  537. String = dupStr;
  538. }
  539. BufferEnd = (PCWSTR) ((PBYTE) String + maxBytes);
  540. shortestEnd = (PCWSTR) ((PBYTE) String + table->MinimumStringBytes);
  541. if (shortestEnd == String) {
  542. shortestEnd++;
  543. }
  544. while (BufferEnd >= shortestEnd) {
  545. currentBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  546. hashValue = pComputePrefixHashValueW (String, currentBytes, table->Buckets);
  547. item = table->Bucket[hashValue];
  548. while (item) {
  549. if ((item->StringSize - sizeof (WCHAR)) == currentBytes) {
  550. if (table->ExternalStrings) {
  551. p1 = (PCWSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  552. } else {
  553. p1 = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  554. }
  555. p1End = (PCWSTR) ((PBYTE) p1 + currentBytes);
  556. p2 = String;
  557. while (p1 < p1End) {
  558. if (*p1 != *p2) {
  559. break;
  560. }
  561. p1++;
  562. p2++;
  563. }
  564. if (p1 == p1End) {
  565. break;
  566. }
  567. }
  568. item = item->Next;
  569. }
  570. if (item) {
  571. break;
  572. }
  573. BufferEnd--;
  574. }
  575. if (item && ExtraDataBuffer) {
  576. (void) HtGetExtraData (HashTable, (HASHITEM)item, &storedDataPtr);
  577. CopyMemory (
  578. (PBYTE) ExtraDataBuffer,
  579. (PBYTE) storedDataPtr,
  580. table->ExtraDataSize
  581. );
  582. }
  583. FreeTextW (dupStr);
  584. *OutHashValue = hashValue;
  585. return item;
  586. }
  587. HASHITEM
  588. HtAddStringExA (
  589. IN HASHTABLE HashTable,
  590. IN PCSTR String,
  591. IN PCVOID ExtraData, OPTIONAL
  592. IN BOOL AlreadyLowercase
  593. )
  594. /*++
  595. Routine Description:
  596. HtAddStringEx adds a string to the hash table, and copies ExtraData to the
  597. new hash table entry. If String is already in the hash table, the ExtraData
  598. is updated.
  599. Arguments:
  600. HashTable - Specifies the handle to the hash table, as returned from
  601. AllocateHashTable.
  602. String - Specifies the string to add to the table
  603. ExtraData - Specifies the source binary data to be copied to the hash
  604. table entry
  605. AlreadyLowercase - Specifies TRUE String is in all lowercase
  606. Return Value:
  607. Returns the pointer to the bucket item allocated or update.
  608. --*/
  609. {
  610. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  611. PBUCKETITEM item;
  612. PBUCKETITEM_EXTERN_STR externItem;
  613. PBUCKETITEM existingItem;
  614. PSTR dupStr = NULL;
  615. HASHITEM rc = NULL;
  616. UINT size;
  617. UINT hashValue;
  618. UINT strSize;
  619. PCVOID storedDataPtr;
  620. PBUCKETITEM dontCare;
  621. ASSERT_TABLE_IS_VALID (HashTable);
  622. if (table->Unicode) {
  623. DEBUGMSG ((DBG_WHOOPS, "Cannot add ANSI string to UNICODE table"));
  624. return 0;
  625. }
  626. if (!AlreadyLowercase && !table->CaseSensitive) {
  627. dupStr = DuplicateTextA (String);
  628. CharLowerA (dupStr);
  629. String = dupStr;
  630. }
  631. existingItem = pHtFindStringA (HashTable, String, NULL, TRUE, &hashValue, &dontCare);
  632. if (existingItem) {
  633. rc = (HASHITEM) existingItem;
  634. } else {
  635. //
  636. // item does not exist, add it now
  637. //
  638. strSize = SizeOfStringA (String);
  639. if (table->ExternalStrings) {
  640. size = sizeof (BUCKETITEM_EXTERN_STR) + table->ExtraDataSize;
  641. externItem = (PBUCKETITEM_EXTERN_STR) PmGetAlignedMemory (table->Pool, size);
  642. MYASSERT (externItem);
  643. externItem->Locked = 0;
  644. externItem->Next = table->Bucket[hashValue];
  645. table->Bucket[hashValue] = (PBUCKETITEM) externItem;
  646. if (table->LastLink) {
  647. table->LastLink->NextLink = (PBUCKETITEM) externItem;
  648. }
  649. externItem->PrevLink = table->LastLink;
  650. table->LastLink = (PBUCKETITEM) externItem;
  651. externItem->NextLink = NULL;
  652. if (!table->FirstLink) {
  653. table->FirstLink = (PBUCKETITEM) externItem;
  654. }
  655. rc = (HASHITEM) externItem;
  656. } else {
  657. size = sizeof (BUCKETITEM) + strSize + table->ExtraDataSize;
  658. item = (PBUCKETITEM) PmGetAlignedMemory (table->Pool, size);
  659. MYASSERT (item);
  660. item->Locked = 0;
  661. item->Next = table->Bucket[hashValue];
  662. table->Bucket[hashValue] = item;
  663. item->StringSize = (WORD) strSize;
  664. CopyMemory ((PBYTE) item + sizeof (BUCKETITEM), String, strSize);
  665. if (table->LastLink) {
  666. table->LastLink->NextLink = item;
  667. }
  668. item->PrevLink = table->LastLink;
  669. table->LastLink = item;
  670. item->NextLink = NULL;
  671. if (!table->FirstLink) {
  672. table->FirstLink = item;
  673. }
  674. rc = (HASHITEM) item;
  675. }
  676. strSize -= sizeof (CHAR);
  677. table->MaximumStringBytes = max (table->MaximumStringBytes, strSize);
  678. table->MinimumStringBytes = min (table->MinimumStringBytes, strSize);
  679. }
  680. MYASSERT (rc);
  681. (void) HtGetExtraData (HashTable, rc, &storedDataPtr);
  682. if (ExtraData) {
  683. CopyMemory (
  684. (PBYTE) storedDataPtr,
  685. (PBYTE) ExtraData,
  686. table->ExtraDataSize
  687. );
  688. } else if (!existingItem) {
  689. ZeroMemory (
  690. (PBYTE) storedDataPtr,
  691. table->ExtraDataSize
  692. );
  693. }
  694. FreeTextA (dupStr);
  695. return rc;
  696. }
  697. HASHITEM
  698. HtAddStringExW (
  699. IN HASHTABLE HashTable,
  700. IN PCWSTR String,
  701. IN PCVOID ExtraData, OPTIONAL
  702. IN BOOL AlreadyLowercase
  703. )
  704. {
  705. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  706. PBUCKETITEM item;
  707. PBUCKETITEM_EXTERN_STR externItem;
  708. PBUCKETITEM existingItem;
  709. PWSTR dupStr = NULL;
  710. HASHITEM rc = NULL;
  711. UINT size;
  712. UINT hashValue;
  713. UINT strSize;
  714. PCVOID storedDataPtr;
  715. PBUCKETITEM dontCare;
  716. ASSERT_TABLE_IS_VALID (HashTable);
  717. if (!table->Unicode) {
  718. DEBUGMSG ((DBG_WHOOPS, "Cannot add ANSI string to UNICODE table"));
  719. return 0;
  720. }
  721. if (!AlreadyLowercase && !table->CaseSensitive) {
  722. dupStr = DuplicateTextW (String);
  723. CharLowerW (dupStr);
  724. String = dupStr;
  725. }
  726. existingItem = pHtFindStringW (HashTable, String, NULL, TRUE, &hashValue, &dontCare);
  727. if (existingItem) {
  728. rc = (HASHITEM) existingItem;
  729. } else {
  730. //
  731. // item does not exist, add it now
  732. //
  733. strSize = SizeOfStringW (String);
  734. if (table->ExternalStrings) {
  735. size = sizeof (BUCKETITEM_EXTERN_STR) + table->ExtraDataSize;
  736. externItem = (PBUCKETITEM_EXTERN_STR) PmGetAlignedMemory (table->Pool, size);
  737. MYASSERT (externItem);
  738. externItem->Locked = 0;
  739. externItem->Next = table->Bucket[hashValue];
  740. table->Bucket[hashValue] = (PBUCKETITEM) externItem;
  741. if (table->LastLink) {
  742. table->LastLink->NextLink = (PBUCKETITEM) externItem;
  743. }
  744. externItem->PrevLink = table->LastLink;
  745. table->LastLink = (PBUCKETITEM) externItem;
  746. externItem->NextLink = NULL;
  747. if (!table->FirstLink) {
  748. table->FirstLink = (PBUCKETITEM) externItem;
  749. }
  750. rc = (HASHITEM) externItem;
  751. } else {
  752. size = sizeof (BUCKETITEM) + strSize + table->ExtraDataSize;
  753. item = (PBUCKETITEM) PmGetAlignedMemory (table->Pool, size);
  754. MYASSERT (item);
  755. item->Locked = 0;
  756. item->Next = table->Bucket[hashValue];
  757. table->Bucket[hashValue] = item;
  758. item->StringSize = (WORD) strSize;
  759. CopyMemory ((PBYTE) item + sizeof (BUCKETITEM), String, strSize);
  760. if (table->LastLink) {
  761. table->LastLink->NextLink = item;
  762. }
  763. item->PrevLink = table->LastLink;
  764. table->LastLink = item;
  765. item->NextLink = NULL;
  766. if (!table->FirstLink) {
  767. table->FirstLink = item;
  768. }
  769. rc = (HASHITEM) item;
  770. }
  771. strSize -= sizeof (WCHAR);
  772. table->MaximumStringBytes = max (table->MaximumStringBytes, strSize);
  773. table->MinimumStringBytes = min (table->MinimumStringBytes, strSize);
  774. }
  775. MYASSERT (rc);
  776. (void) HtGetExtraData (HashTable, rc, &storedDataPtr);
  777. if (ExtraData) {
  778. CopyMemory (
  779. (PBYTE) storedDataPtr,
  780. (PBYTE) ExtraData,
  781. table->ExtraDataSize
  782. );
  783. } else if (!existingItem) {
  784. ZeroMemory (
  785. (PBYTE) storedDataPtr,
  786. table->ExtraDataSize
  787. );
  788. }
  789. FreeTextW (dupStr);
  790. return rc;
  791. }
  792. VOID
  793. pRemoveHashItem (
  794. IN PHASHTABLESTRUCT Table,
  795. IN UINT BucketNum,
  796. IN PBUCKETITEM PrevItem,
  797. IN PBUCKETITEM ItemToDelete
  798. )
  799. {
  800. if (!PrevItem) {
  801. MYASSERT (Table->Bucket[BucketNum] == ItemToDelete);
  802. Table->Bucket[BucketNum] = ItemToDelete->Next;
  803. } else {
  804. PrevItem->Next = ItemToDelete->Next;
  805. }
  806. if (ItemToDelete->PrevLink) {
  807. ItemToDelete->PrevLink->NextLink = ItemToDelete->NextLink;
  808. } else {
  809. Table->FirstLink = ItemToDelete->Next;
  810. }
  811. if (ItemToDelete->NextLink) {
  812. ItemToDelete->NextLink->PrevLink = ItemToDelete->PrevLink;
  813. } else {
  814. Table->LastLink = ItemToDelete->PrevLink;
  815. }
  816. if (ItemToDelete->Locked) {
  817. ItemToDelete->Next = Table->DelayedDelete;
  818. Table->DelayedDelete = ItemToDelete;
  819. } else {
  820. PmReleaseMemory (Table->Pool, ItemToDelete);
  821. }
  822. }
  823. BOOL
  824. HtRemoveItem (
  825. IN HASHTABLE HashTable,
  826. IN HASHITEM Item
  827. )
  828. {
  829. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  830. UINT bucketNumber;
  831. PBUCKETITEM prevItem;
  832. PBUCKETITEM thisItem;
  833. PCSTR ansiStr;
  834. PCWSTR unicodeStr;
  835. if (!Item) {
  836. return FALSE;
  837. }
  838. //
  839. // Find prev bucket item
  840. //
  841. if (table->Unicode) {
  842. unicodeStr = HtGetStringFromItemW (Item);
  843. MYASSERT (unicodeStr);
  844. thisItem = pHtFindStringW (
  845. HashTable,
  846. unicodeStr,
  847. NULL,
  848. TRUE,
  849. &bucketNumber,
  850. &prevItem
  851. );
  852. } else {
  853. ansiStr = HtGetStringFromItemA (Item);
  854. MYASSERT (ansiStr);
  855. thisItem = pHtFindStringA (
  856. HashTable,
  857. ansiStr,
  858. NULL,
  859. TRUE,
  860. &bucketNumber,
  861. &prevItem
  862. );
  863. }
  864. MYASSERT (Item == thisItem);
  865. if (Item != thisItem) {
  866. return FALSE;
  867. }
  868. pRemoveHashItem (table, bucketNumber, prevItem, thisItem);
  869. return TRUE;
  870. }
  871. BOOL
  872. HtRemoveStringA (
  873. IN HASHTABLE HashTable,
  874. IN PCSTR AnsiString
  875. )
  876. {
  877. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  878. UINT bucketNumber;
  879. PBUCKETITEM prevItem;
  880. PBUCKETITEM thisItem;
  881. if (table->Unicode) {
  882. DEBUGMSG ((DBG_WHOOPS, "Cannot delete UNICODE table with ANSI api"));
  883. return FALSE;
  884. }
  885. thisItem = pHtFindStringA (
  886. HashTable,
  887. AnsiString,
  888. NULL,
  889. FALSE,
  890. &bucketNumber,
  891. &prevItem
  892. );
  893. if (!thisItem) {
  894. return FALSE;
  895. }
  896. pRemoveHashItem (table, bucketNumber, prevItem, thisItem);
  897. return TRUE;
  898. }
  899. BOOL
  900. HtRemoveStringW (
  901. IN HASHTABLE HashTable,
  902. IN PCWSTR UnicodeString
  903. )
  904. {
  905. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  906. UINT bucketNumber;
  907. PBUCKETITEM prevItem;
  908. PBUCKETITEM thisItem;
  909. if (!table->Unicode) {
  910. DEBUGMSG ((DBG_WHOOPS, "Cannot delete ANSI table with UNICODE api"));
  911. return FALSE;
  912. }
  913. thisItem = pHtFindStringW (
  914. HashTable,
  915. UnicodeString,
  916. NULL,
  917. FALSE,
  918. &bucketNumber,
  919. &prevItem
  920. );
  921. if (!thisItem) {
  922. return FALSE;
  923. }
  924. pRemoveHashItem (table, bucketNumber, prevItem, thisItem);
  925. return TRUE;
  926. }
  927. /*++
  928. Routine Description:
  929. HtFindStringEx is the external entry point for pHtFindString.
  930. Arguments:
  931. HashTable - Specifies the hash table handle, as returned by
  932. AllocateHashTable.
  933. String - Specifies the string to find
  934. ExtraDataBuffer - Receives the extra data associated with the found item
  935. AlreadyLowercase - Specifies TRUE if the String is in lowercase
  936. Return Value:
  937. A pointer to the bucket item or NULL if the string was not found.
  938. --*/
  939. HASHITEM
  940. HtFindStringExA (
  941. IN HASHTABLE HashTable,
  942. IN PCSTR String,
  943. OUT PVOID ExtraDataBuffer, OPTIONAL
  944. IN BOOL AlreadyLowercase
  945. )
  946. {
  947. UINT dontCare;
  948. PBUCKETITEM dontCare2;
  949. return (HASHITEM) pHtFindStringA (
  950. HashTable,
  951. String,
  952. ExtraDataBuffer,
  953. AlreadyLowercase,
  954. &dontCare,
  955. &dontCare2
  956. );
  957. }
  958. HASHITEM
  959. HtFindStringExW (
  960. IN HASHTABLE HashTable,
  961. IN PCWSTR String,
  962. OUT PVOID ExtraDataBuffer, OPTIONAL
  963. IN BOOL AlreadyLowercase
  964. )
  965. {
  966. UINT dontCare;
  967. PBUCKETITEM dontCare2;
  968. return (HASHITEM) pHtFindStringW (
  969. HashTable,
  970. String,
  971. ExtraDataBuffer,
  972. AlreadyLowercase,
  973. &dontCare,
  974. &dontCare2
  975. );
  976. }
  977. /*++
  978. Routine Description:
  979. HtFindStringEx is the external entry point for pHtFindString.
  980. Arguments:
  981. HashTable - Specifies the hash table handle, as returned by
  982. AllocateHashTable.
  983. String - Specifies the string to find
  984. BufferEnd - Specifies the end of the buffer for String
  985. ExtraDataBuffer - Receives the extra data associated with the found item
  986. AlreadyLowercase - Specifies TRUE if String is in all lowercase
  987. Return Value:
  988. A pointer to the bucket item or NULL if the string was not found.
  989. --*/
  990. HASHITEM
  991. HtFindPrefixExA (
  992. IN HASHTABLE HashTable,
  993. IN PCSTR String,
  994. IN PCSTR BufferEnd,
  995. OUT PVOID ExtraDataBuffer, OPTIONAL
  996. IN BOOL AlreadyLowercase
  997. )
  998. {
  999. UINT dontCare;
  1000. return (HASHITEM) pHtFindPrefixA (
  1001. HashTable,
  1002. String,
  1003. BufferEnd,
  1004. ExtraDataBuffer,
  1005. AlreadyLowercase,
  1006. &dontCare
  1007. );
  1008. }
  1009. HASHITEM
  1010. HtFindPrefixExW (
  1011. IN HASHTABLE HashTable,
  1012. IN PCWSTR String,
  1013. IN PCWSTR BufferEnd,
  1014. OUT PVOID ExtraDataBuffer, OPTIONAL
  1015. IN BOOL AlreadyLowercase
  1016. )
  1017. {
  1018. UINT dontCare;
  1019. return (HASHITEM) pHtFindPrefixW (
  1020. HashTable,
  1021. String,
  1022. BufferEnd,
  1023. ExtraDataBuffer,
  1024. AlreadyLowercase,
  1025. &dontCare
  1026. );
  1027. }
  1028. BOOL
  1029. HtGetExtraData (
  1030. IN HASHTABLE HashTable,
  1031. IN HASHITEM Index,
  1032. OUT PCVOID *ExtraData
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. HtGetExtraData gets the extra data associated with a bucket item.
  1037. The caller must supply the ID as returned from HtFindStringEx or
  1038. HtAddStringEx. This routine is useful when ExtraData is large, and
  1039. the normal find routine would be slow because of the CopyMemory code path.
  1040. Arguments:
  1041. HashTable - Specifies the handle to the hash table
  1042. Index - Specifies the offset as returned from HtFindStringEx or
  1043. HtAddStringEx
  1044. ExtraData - Receives the extra data pointer (it does NOT copy the data to
  1045. the buffer).
  1046. Return Value:
  1047. TRUE if ExtraData was set, FALSE otherwise.
  1048. --*/
  1049. {
  1050. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1051. PBUCKETITEM item;
  1052. PBUCKETITEM_EXTERN_STR externStrItem;
  1053. ASSERT_TABLE_IS_VALID (HashTable);
  1054. if (!Index) {
  1055. return FALSE;
  1056. }
  1057. if (table->ExternalStrings) {
  1058. externStrItem = (PBUCKETITEM_EXTERN_STR) Index;
  1059. *ExtraData = (PCVOID) ((PBYTE) externStrItem + sizeof (PBUCKETITEM_EXTERN_STR));
  1060. } else {
  1061. item = (PBUCKETITEM) Index;
  1062. *ExtraData = (PCVOID) ((PBYTE) item + sizeof (BUCKETITEM) + item->StringSize);
  1063. }
  1064. return TRUE;
  1065. }
  1066. BOOL
  1067. HtCopyStringData (
  1068. IN HASHTABLE HashTable,
  1069. IN HASHITEM Index,
  1070. OUT PVOID ExtraDataBuffer
  1071. )
  1072. /*++
  1073. Routine Description:
  1074. HtCopyStringData gets the extra data associated with a bucket item
  1075. and copies it to the caller's buffer.
  1076. Arguments:
  1077. HashTable - Specifies the handle to the hash table
  1078. Index - Specifies the offset as returned from HtFindStringEx or
  1079. HtAddStringEx
  1080. ExtraDataBuffer - Receives the extra data
  1081. Return Value:
  1082. TRUE if ExtraDataBuffer was copied, FALSE otherwise.
  1083. --*/
  1084. {
  1085. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1086. PCVOID storedDataPtr;
  1087. ASSERT_TABLE_IS_VALID (HashTable);
  1088. if (!HtGetExtraData (HashTable, Index, &storedDataPtr)) {
  1089. return FALSE;
  1090. }
  1091. CopyMemory (
  1092. (PBYTE) ExtraDataBuffer,
  1093. (PBYTE) storedDataPtr,
  1094. table->ExtraDataSize
  1095. );
  1096. return TRUE;
  1097. }
  1098. BOOL
  1099. HtSetStringData (
  1100. IN HASHTABLE HashTable,
  1101. IN HASHITEM Index,
  1102. IN PCVOID ExtraData
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. HtSetStringData copies new extra data to the specified hash table entry.
  1107. Arguments:
  1108. HashTable - Specifies the handle to the hash table
  1109. Index - Specifies the offset as returned from HtFindStringEx or
  1110. HtAddStringEx
  1111. ExtraData - Specifies the extra data
  1112. Return Value:
  1113. TRUE if the item was updated, FALSE otherwise.
  1114. --*/
  1115. {
  1116. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1117. PCVOID storedDataPtr;
  1118. ASSERT_TABLE_IS_VALID (HashTable);
  1119. if (!HtGetExtraData (HashTable, Index, &storedDataPtr)) {
  1120. return FALSE;
  1121. }
  1122. CopyMemory (
  1123. (PBYTE) storedDataPtr,
  1124. (PBYTE) ExtraData,
  1125. table->ExtraDataSize
  1126. );
  1127. return TRUE;
  1128. }
  1129. BOOL
  1130. EnumFirstHashTableStringA (
  1131. OUT PHASHTABLE_ENUMA EnumPtr,
  1132. IN HASHTABLE HashTable
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. EnumFirstHashTableString begins an enumeration of the hash table structure.
  1137. The return order is random. Also, do not modify the hash table while an
  1138. enumeration is active.
  1139. Arguments:
  1140. EnumPtr - Receives the string, extra data and offset for the first item
  1141. in the hash table.
  1142. HashTable - Specifies the handle of the hash table to enumerate.
  1143. Return Value:
  1144. TRUE if an item was enumerated, FALSE otherwise.
  1145. --*/
  1146. {
  1147. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1148. ASSERT_TABLE_IS_VALID (HashTable);
  1149. if (table->Unicode) {
  1150. DEBUGMSG ((DBG_WHOOPS, "Cannot enum UNICODE table with ANSI wrapper"));
  1151. return FALSE;
  1152. }
  1153. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMA));
  1154. EnumPtr->Internal = (HASHTABLE) table;
  1155. return EnumNextHashTableStringA (EnumPtr);
  1156. }
  1157. BOOL
  1158. EnumFirstHashTableStringW (
  1159. OUT PHASHTABLE_ENUMW EnumPtr,
  1160. IN HASHTABLE HashTable
  1161. )
  1162. {
  1163. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1164. ASSERT_TABLE_IS_VALID (HashTable);
  1165. if (!table->Unicode) {
  1166. DEBUGMSG ((DBG_WHOOPS, "Cannot enum ANSI table with UNICODE wrapper"));
  1167. return FALSE;
  1168. }
  1169. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMW));
  1170. EnumPtr->Internal = (HASHTABLE) table;
  1171. return EnumNextHashTableStringW (EnumPtr);
  1172. }
  1173. BOOL
  1174. EnumNextHashTableStringA (
  1175. IN OUT PHASHTABLE_ENUMA EnumPtr
  1176. )
  1177. /*++
  1178. Routine Description:
  1179. EnumNextHashTableString continues an enumeration started by
  1180. EnumFirstHashTableString. Call the routine until it returns FALSE.
  1181. Arguments:
  1182. EnumPtr - Specifies the structure of an active enumeration. Receives
  1183. updated string, extra data and offset members.
  1184. Return Value:
  1185. TRUE if another item was enumerated, FALSE if no items remain.
  1186. --*/
  1187. {
  1188. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1189. PBUCKETITEM item;
  1190. PBUCKETITEM_EXTERN_STR externItem;
  1191. if (!EnumPtr->Internal) {
  1192. return FALSE;
  1193. }
  1194. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1195. if (!EnumPtr->Index) {
  1196. item = table->FirstLink;
  1197. } else {
  1198. item = (PBUCKETITEM) EnumPtr->Index;
  1199. item->Locked -= 1;
  1200. MYASSERT (item->Locked >= 0);
  1201. item = item->NextLink;
  1202. }
  1203. if (item) {
  1204. //
  1205. // Return a valid item
  1206. //
  1207. item->Locked += 1;
  1208. EnumPtr->Index = (HASHITEM) item;
  1209. if (table->ExternalStrings) {
  1210. externItem = (PBUCKETITEM_EXTERN_STR) item;
  1211. EnumPtr->String = (PCSTR) (externItem->String);
  1212. } else {
  1213. EnumPtr->String = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  1214. }
  1215. if (table->ExtraDataSize) {
  1216. MYASSERT (EnumPtr->Index);
  1217. (void) HtGetExtraData (EnumPtr->Internal, EnumPtr->Index, &EnumPtr->ExtraData);
  1218. }
  1219. return TRUE;
  1220. }
  1221. EnumPtr->Internal = 0;
  1222. return FALSE;
  1223. }
  1224. BOOL
  1225. EnumNextHashTableStringW (
  1226. IN OUT PHASHTABLE_ENUMW EnumPtr
  1227. )
  1228. {
  1229. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1230. PBUCKETITEM item;
  1231. PBUCKETITEM_EXTERN_STR externItem;
  1232. if (!EnumPtr->Internal) {
  1233. return FALSE;
  1234. }
  1235. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1236. if (!EnumPtr->Index) {
  1237. item = table->FirstLink;
  1238. } else {
  1239. item = (PBUCKETITEM) EnumPtr->Index;
  1240. item->Locked -= 1;
  1241. MYASSERT (item->Locked >= 0);
  1242. item = item->NextLink;
  1243. }
  1244. if (item) {
  1245. //
  1246. // Return a valid item
  1247. //
  1248. item->Locked += 1;
  1249. EnumPtr->Index = (HASHITEM) item;
  1250. if (table->ExternalStrings) {
  1251. externItem = (PBUCKETITEM_EXTERN_STR) item;
  1252. EnumPtr->String = (PCWSTR) (externItem->String);
  1253. } else {
  1254. EnumPtr->String = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  1255. }
  1256. if (table->ExtraDataSize) {
  1257. MYASSERT (EnumPtr->Index);
  1258. (void) HtGetExtraData (EnumPtr->Internal, EnumPtr->Index, &EnumPtr->ExtraData);
  1259. }
  1260. return TRUE;
  1261. }
  1262. EnumPtr->Internal = 0;
  1263. return FALSE;
  1264. }
  1265. VOID
  1266. AbortHashTableEnumA (
  1267. IN PHASHTABLE_ENUMA EnumPtr
  1268. )
  1269. {
  1270. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1271. PBUCKETITEM item;
  1272. PBUCKETITEM nextItem;
  1273. PBUCKETITEM prevItem;
  1274. if (!EnumPtr->Internal) {
  1275. return;
  1276. }
  1277. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1278. if (EnumPtr->Index) {
  1279. item = (PBUCKETITEM) EnumPtr->Index;
  1280. item->Locked -= 1;
  1281. MYASSERT (item->Locked >= 0);
  1282. }
  1283. //
  1284. // Evaluate delayed delete items; remove those that are no longer locked
  1285. //
  1286. if (table->DelayedDelete) {
  1287. item = table->DelayedDelete;
  1288. prevItem = NULL;
  1289. while (item) {
  1290. nextItem = item->Next;
  1291. if (!item->Locked) {
  1292. PmReleaseMemory (table->Pool, item);
  1293. } else {
  1294. if (prevItem) {
  1295. prevItem->Next = item;
  1296. } else {
  1297. table->DelayedDelete = item;
  1298. }
  1299. prevItem = item;
  1300. }
  1301. item = nextItem;
  1302. }
  1303. if (prevItem) {
  1304. prevItem->Next = NULL;
  1305. } else {
  1306. table->DelayedDelete = NULL;
  1307. }
  1308. }
  1309. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMA));
  1310. }
  1311. VOID
  1312. AbortHashTableEnumW (
  1313. IN PHASHTABLE_ENUMW EnumPtr
  1314. )
  1315. {
  1316. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1317. PBUCKETITEM item;
  1318. PBUCKETITEM prevItem;
  1319. PBUCKETITEM nextItem;
  1320. if (!EnumPtr->Internal) {
  1321. return;
  1322. }
  1323. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1324. if (EnumPtr->Index) {
  1325. item = (PBUCKETITEM) EnumPtr->Index;
  1326. item->Locked -= 1;
  1327. MYASSERT (item->Locked >= 0);
  1328. }
  1329. //
  1330. // Evaluate delayed delete items; remove those that are no longer locked
  1331. //
  1332. if (table->DelayedDelete) {
  1333. item = table->DelayedDelete;
  1334. prevItem = NULL;
  1335. while (item) {
  1336. nextItem = item->Next;
  1337. if (!item->Locked) {
  1338. PmReleaseMemory (table->Pool, item);
  1339. } else {
  1340. if (prevItem) {
  1341. prevItem->Next = item;
  1342. } else {
  1343. table->DelayedDelete = item;
  1344. }
  1345. prevItem = item;
  1346. }
  1347. item = nextItem;
  1348. }
  1349. if (prevItem) {
  1350. prevItem->Next = NULL;
  1351. } else {
  1352. table->DelayedDelete = NULL;
  1353. }
  1354. }
  1355. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMW));
  1356. }
  1357. BOOL
  1358. EnumHashTableWithCallbackA (
  1359. IN HASHTABLE HashTable,
  1360. IN PHASHTABLE_CALLBACK_ROUTINEA Proc,
  1361. IN LPARAM lParam
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. EnumHashTableWithCallback implements a setupapi-style enumerator. The
  1366. callback routine is called for each item in the string table, and if the
  1367. callback routine returns FALSE, the enumeration ends.
  1368. Arguments:
  1369. HashTable - Specifies the handle to the table to enumerate
  1370. Proc - Specifies the callback procedure address
  1371. lParam - Specifies a value to pass to the callback, and is intended only
  1372. for use by the caller.
  1373. Return Value:
  1374. Always TRUE.
  1375. --*/
  1376. {
  1377. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1378. HASHTABLE_ENUMA e;
  1379. ASSERT_TABLE_IS_VALID (HashTable);
  1380. if (EnumFirstHashTableStringA (&e, HashTable)) {
  1381. do {
  1382. if (!Proc (HashTable, e.Index, e.String, (PVOID) e.ExtraData, table->ExtraDataSize, lParam)) {
  1383. AbortHashTableEnumA (&e);
  1384. break;
  1385. }
  1386. } while (EnumNextHashTableStringA (&e));
  1387. }
  1388. return TRUE;
  1389. }
  1390. BOOL
  1391. EnumHashTableWithCallbackW (
  1392. IN HASHTABLE HashTable,
  1393. IN PHASHTABLE_CALLBACK_ROUTINEW Proc,
  1394. IN LPARAM lParam
  1395. )
  1396. {
  1397. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1398. HASHTABLE_ENUMW e;
  1399. ASSERT_TABLE_IS_VALID (HashTable);
  1400. if (EnumFirstHashTableStringW (&e, HashTable)) {
  1401. do {
  1402. if (!Proc (HashTable, e.Index, e.String, (PVOID) e.ExtraData, table->ExtraDataSize, lParam)) {
  1403. AbortHashTableEnumW (&e);
  1404. break;
  1405. }
  1406. } while (EnumNextHashTableStringW (&e));
  1407. }
  1408. return TRUE;
  1409. }
  1410. PCSTR
  1411. HtGetStringFromItemA (
  1412. IN HASHITEM Item
  1413. )
  1414. {
  1415. if (!Item) {
  1416. return NULL;
  1417. }
  1418. return (PCSTR) ((PBYTE) Item + sizeof (BUCKETITEM));
  1419. }
  1420. PCWSTR
  1421. HtGetStringFromItemW (
  1422. IN HASHITEM Item
  1423. )
  1424. {
  1425. if (!Item) {
  1426. return NULL;
  1427. }
  1428. return (PCWSTR) ((PBYTE) Item + sizeof (BUCKETITEM));
  1429. }