Leaked source code of windows server 2003
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.

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