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.

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