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.

1596 lines
34 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. WORD StringSize;
  46. // string follows StringSize
  47. // optional data follows string
  48. } BUCKETITEM, *PBUCKETITEM;
  49. typedef struct {
  50. struct _tagBUCKETITEM *Next;
  51. struct _tagBUCKETITEM *NextLink, *PrevLink;
  52. PVOID String;
  53. // optional data follows struct
  54. } BUCKETITEM_EXTERN_STR, *PBUCKETITEM_EXTERN_STR;
  55. typedef struct {
  56. DWORD Signature;
  57. BOOL Unicode;
  58. BOOL ExternalStrings;
  59. PMHANDLE Pool;
  60. PBUCKETITEM *Bucket;
  61. PBUCKETITEM FirstLink;
  62. PBUCKETITEM LastLink;
  63. UINT ExtraDataSize;
  64. UINT MinimumStringBytes;
  65. UINT MaximumStringBytes;
  66. UINT Buckets;
  67. } HASHTABLESTRUCT, *PHASHTABLESTRUCT;
  68. //
  69. // Globals
  70. //
  71. // None
  72. //
  73. // Macro expansion list
  74. //
  75. // None
  76. //
  77. // Private function prototypes
  78. //
  79. // None
  80. //
  81. // Macro expansion definition
  82. //
  83. // None
  84. //
  85. // Code
  86. //
  87. #ifdef DEBUG
  88. BOOL
  89. pTableIsValid (
  90. IN HASHTABLE Table
  91. )
  92. {
  93. BOOL b = TRUE;
  94. if (!Table) {
  95. return FALSE;
  96. }
  97. __try {
  98. if (((PHASHTABLESTRUCT) Table)->Signature != HASHTABLE_SIGNATURE) {
  99. b = FALSE;
  100. }
  101. }
  102. __except (TRUE) {
  103. b = FALSE;
  104. }
  105. return b;
  106. }
  107. #endif
  108. /*++
  109. Routine Description:
  110. pComputeHashValue adds all the character values of the string, shifting to
  111. maintain order.
  112. Arguments:
  113. String - Specifies the string to compute the hash value for
  114. Return Value:
  115. The hash value, within the range of 0 to BUCKETS - 1.
  116. --*/
  117. UINT
  118. pComputeHashValueA (
  119. IN PCSTR String,
  120. IN UINT Buckets
  121. )
  122. {
  123. UINT hashValue = 0;
  124. while (*String) {
  125. hashValue = _rotl (hashValue, 2);
  126. hashValue += (UINT) *String;
  127. String++;
  128. }
  129. hashValue %= Buckets;
  130. return hashValue;
  131. }
  132. UINT
  133. pComputeHashValueW (
  134. IN PCWSTR String,
  135. IN UINT Buckets
  136. )
  137. {
  138. UINT hashValue = 0;
  139. while (*String) {
  140. hashValue = _rotl (hashValue, 2);
  141. hashValue += (UINT) *String;
  142. String++;
  143. }
  144. hashValue %= Buckets;
  145. return hashValue;
  146. }
  147. UINT
  148. pComputePrefixHashValueA (
  149. IN PCSTR String,
  150. IN UINT Size,
  151. IN UINT Buckets
  152. )
  153. {
  154. UINT hashValue = 0;
  155. PCSTR end;
  156. end = (PCSTR) ((PBYTE) String + Size);
  157. while (String < end) {
  158. hashValue = _rotl (hashValue, 2);
  159. hashValue += (UINT) *String;
  160. String++;
  161. }
  162. hashValue %= Buckets;
  163. return hashValue;
  164. }
  165. UINT
  166. pComputePrefixHashValueW (
  167. IN PCWSTR String,
  168. IN UINT Size,
  169. IN UINT Buckets
  170. )
  171. {
  172. UINT hashValue = 0;
  173. PCWSTR end;
  174. end = (PCWSTR) ((PBYTE) String + Size);
  175. while (String < end) {
  176. hashValue = _rotl (hashValue, 2);
  177. hashValue += (UINT) *String;
  178. String++;
  179. }
  180. hashValue %= Buckets;
  181. return hashValue;
  182. }
  183. HASHTABLE
  184. HtAllocExAW (
  185. IN BOOL Unicode,
  186. IN BOOL ExternalStrings,
  187. IN UINT ExtraDataSize,
  188. IN UINT Buckets
  189. )
  190. /*++
  191. Routine Description:
  192. AllocateHashTableEx creates a hash table. If ExtraDataSize is non-zero,
  193. each hash table entry gets an allocation of ExtraDataSize added to it.
  194. Arguments:
  195. Unicode - Specifies TRUE to allocate a UNICODE hash table, or FALSE to
  196. allocate an ANSI table. None of the routines in this file do any
  197. sort of UNICODE/ANSI converstion.
  198. ExternalStrings - Specifies TRUE if the strings belong to memory maintained
  199. by the caller
  200. ExtraDataSize - Specifies the size of binary data associated with the
  201. table item, or 0 for none.
  202. Return Value:
  203. A handle to the string table.
  204. --*/
  205. {
  206. PHASHTABLESTRUCT hashTable;
  207. PMHANDLE pool;
  208. if (!Buckets) {
  209. Buckets = BUCKETS;
  210. }
  211. pool = PmCreateNamedPool (S_HASHTABLE);
  212. MYASSERT (pool);
  213. hashTable = (PHASHTABLESTRUCT) PmGetAlignedMemory (
  214. pool,
  215. sizeof (HASHTABLESTRUCT) + (sizeof (PBUCKETITEM) * Buckets)
  216. );
  217. MYASSERT (hashTable);
  218. hashTable->Signature = HASHTABLE_SIGNATURE;
  219. hashTable->Unicode = Unicode;
  220. hashTable->ExternalStrings = ExternalStrings;
  221. hashTable->Pool = pool;
  222. hashTable->Bucket = (PBUCKETITEM *) ((PBYTE) hashTable + sizeof (HASHTABLESTRUCT));
  223. hashTable->FirstLink = NULL;
  224. hashTable->LastLink = NULL;
  225. hashTable->ExtraDataSize = ExtraDataSize;
  226. hashTable->MinimumStringBytes = (UINT) -1;
  227. hashTable->MaximumStringBytes = 0;
  228. hashTable->Buckets = Buckets;
  229. //
  230. // Zero out all of the bucket structures.
  231. //
  232. ZeroMemory (hashTable->Bucket, sizeof (PBUCKETITEM) * Buckets);
  233. return (HASHTABLE) hashTable;
  234. }
  235. VOID
  236. HtFree (
  237. IN HASHTABLE HashTable
  238. )
  239. /*++
  240. Routine Description:
  241. HtFree releases all resources associated with a string table.
  242. Arguments:
  243. None.
  244. Return Value:
  245. None.
  246. --*/
  247. {
  248. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  249. if (table) {
  250. ASSERT_TABLE_IS_VALID (HashTable);
  251. PmDestroyPool (table->Pool);
  252. }
  253. }
  254. PBUCKETITEM
  255. pHtFindStringA (
  256. IN HASHTABLE HashTable,
  257. IN PCSTR String,
  258. OUT PVOID ExtraData, OPTIONAL
  259. IN BOOL CaseSensitive,
  260. OUT PUINT OutHashValue
  261. )
  262. /*++
  263. Routine Description:
  264. pHtFindString implements the hash table lookup routine. It returns the
  265. pointer to the bucket item or NULL if the item was not found.
  266. Arguments:
  267. HashTable - Specifies the handle to the hash table
  268. String - Specifies the string to find. If this string is
  269. case-insensitive but has already been lowercased, then make
  270. sure to pass TRUE in the CaseSensitive argument.
  271. ExtraData - Specifies the bytes to be copied to the hash table entry.
  272. CaseSensitive - Specifies TRUE if the hash table is case-sensitive, FALSE
  273. otherwise.
  274. OutHashValue - Receives the hash value. This is non optional for
  275. efficiency.
  276. Return Value:
  277. The pointer to the bucket item or NULL if no item was found.
  278. --*/
  279. {
  280. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  281. PSTR dupStr = NULL;
  282. UINT hashValue;
  283. PBUCKETITEM item;
  284. PCSTR p1, p2;
  285. PCVOID storedDataPtr;
  286. ASSERT_TABLE_IS_VALID (HashTable);
  287. if (!CaseSensitive) {
  288. dupStr = DuplicateTextA (String);
  289. (void) _mbslwr (dupStr);
  290. String = dupStr;
  291. }
  292. hashValue = pComputeHashValueA (String, table->Buckets);
  293. item = table->Bucket[hashValue];
  294. while (item) {
  295. if (table->ExternalStrings) {
  296. p1 = (PCSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  297. } else {
  298. p1 = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  299. }
  300. p2 = String;
  301. while (*p1) {
  302. if (*p1 != *p2) {
  303. break;
  304. }
  305. p1++;
  306. p2++;
  307. }
  308. if (*p1 == 0 && *p2 == 0) {
  309. break;
  310. }
  311. item = item->Next;
  312. }
  313. if (item && ExtraData) {
  314. (void) HtGetStringData (HashTable, (HASHITEM)item, &storedDataPtr);
  315. CopyMemory (
  316. (PBYTE) ExtraData,
  317. (PBYTE) storedDataPtr,
  318. table->ExtraDataSize
  319. );
  320. }
  321. FreeTextA (dupStr);
  322. *OutHashValue = hashValue;
  323. return item;
  324. }
  325. PBUCKETITEM
  326. pHtFindStringW (
  327. IN HASHTABLE HashTable,
  328. IN PCWSTR String,
  329. OUT PVOID ExtraData, OPTIONAL
  330. IN BOOL CaseSensitive,
  331. OUT PUINT OutHashValue
  332. )
  333. {
  334. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  335. PWSTR dupStr = NULL;
  336. UINT hashValue;
  337. PBUCKETITEM item;
  338. PCWSTR p1, p2;
  339. PCVOID storedDataPtr;
  340. ASSERT_TABLE_IS_VALID (HashTable);
  341. if (!CaseSensitive) {
  342. dupStr = DuplicateTextW (String);
  343. (void) _wcslwr (dupStr);
  344. String = dupStr;
  345. }
  346. hashValue = pComputeHashValueW (String, table->Buckets);
  347. item = table->Bucket[hashValue];
  348. while (item) {
  349. if (table->ExternalStrings) {
  350. p1 = (PCWSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  351. } else {
  352. p1 = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  353. }
  354. p2 = String;
  355. while (*p1) {
  356. if (*p1 != *p2) {
  357. break;
  358. }
  359. p1++;
  360. p2++;
  361. }
  362. if (*p1 == 0 && *p2 == 0) {
  363. break;
  364. }
  365. item = item->Next;
  366. }
  367. if (item && ExtraData) {
  368. (void) HtGetStringData (HashTable, (HASHITEM)item, &storedDataPtr);
  369. CopyMemory (
  370. (PBYTE) ExtraData,
  371. (PBYTE) storedDataPtr,
  372. table->ExtraDataSize
  373. );
  374. }
  375. FreeTextW (dupStr);
  376. *OutHashValue = hashValue;
  377. return item;
  378. }
  379. PBUCKETITEM
  380. pHtFindPrefixA (
  381. IN HASHTABLE HashTable,
  382. IN PCSTR String,
  383. IN PCSTR BufferEnd,
  384. OUT PVOID ExtraData, OPTIONAL
  385. IN BOOL CaseSensitive,
  386. OUT PUINT OutHashValue
  387. )
  388. /*++
  389. Routine Description:
  390. pHtFindPrefix implements a hash table lookup routine that tests each hash
  391. table entry, character-by-character, until a match is found, or until the
  392. hash table maximum is reached. It returns the pointer to the bucket item or
  393. NULL if the item was not found.
  394. Arguments:
  395. HashTable - Specifies the handle to the hash table
  396. String - Specifies the string to find. If this string is
  397. case-insensitive but has already been lowercased, then make
  398. sure to pass TRUE in the CaseSensitive argument.
  399. BufferEnd - Specifies the end of the string buffer, which may be longer
  400. than all entries in the hash table, or it may be shorter.
  401. ExtraData - Specifies the bytes to be copied to the hash table entry.
  402. CaseSensitive - Specifies TRUE if the hash table is case-sensitive, FALSE
  403. otherwise.
  404. OutHashValue - Receives the hash value. This is non optional for
  405. efficiency. If pHtFindPrefix does not find a match,
  406. this value will be set to zero.
  407. Return Value:
  408. The pointer to the bucket item or NULL if no item was found.
  409. --*/
  410. {
  411. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  412. PSTR dupStr = NULL;
  413. UINT hashValue = 0;
  414. PBUCKETITEM item = NULL;
  415. PCSTR p1, p2;
  416. PCSTR p1End;
  417. PCVOID storedDataPtr;
  418. UINT maxBytes;
  419. UINT currentBytes;
  420. PCSTR shortestEnd;
  421. ASSERT_TABLE_IS_VALID (HashTable);
  422. maxBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  423. maxBytes = min (maxBytes, table->MaximumStringBytes);
  424. if (!maxBytes || table->MinimumStringBytes == (UINT) -1) {
  425. return NULL;
  426. }
  427. if (!CaseSensitive) {
  428. dupStr = AllocTextA (maxBytes / sizeof (CHAR));
  429. if (dupStr) {
  430. StringCopyByteCountA (dupStr, String, maxBytes + sizeof (CHAR));
  431. _mbslwr (dupStr);
  432. String = dupStr;
  433. }
  434. }
  435. BufferEnd = (PCSTR) ((PBYTE) String + maxBytes);
  436. shortestEnd = (PCSTR) ((PBYTE) String + table->MinimumStringBytes);
  437. if (shortestEnd == String) {
  438. shortestEnd = _mbsinc (shortestEnd);
  439. }
  440. while (BufferEnd >= shortestEnd) {
  441. currentBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  442. hashValue = pComputePrefixHashValueA (String, currentBytes, table->Buckets);
  443. item = table->Bucket[hashValue];
  444. while (item) {
  445. if ((item->StringSize - sizeof (CHAR)) == currentBytes) {
  446. if (table->ExternalStrings) {
  447. p1 = (PCSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  448. } else {
  449. p1 = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  450. }
  451. p1End = (PCSTR) ((PBYTE) p1 + currentBytes);
  452. p2 = String;
  453. while (p1 < p1End) {
  454. if (*p1 != *p2) {
  455. break;
  456. }
  457. p1++;
  458. p2++;
  459. }
  460. if (p1 == p1End) {
  461. break;
  462. }
  463. }
  464. item = item->Next;
  465. }
  466. if (item) {
  467. break;
  468. }
  469. BufferEnd = _mbsdec2 (String, BufferEnd);
  470. }
  471. if (item && ExtraData) {
  472. (void) HtGetStringData (HashTable, (HASHITEM)item, &storedDataPtr);
  473. CopyMemory (
  474. (PBYTE) ExtraData,
  475. (PBYTE) storedDataPtr,
  476. table->ExtraDataSize
  477. );
  478. }
  479. FreeTextA (dupStr);
  480. *OutHashValue = hashValue;
  481. return item;
  482. }
  483. PBUCKETITEM
  484. pHtFindPrefixW (
  485. IN HASHTABLE HashTable,
  486. IN PCWSTR String,
  487. IN PCWSTR BufferEnd,
  488. OUT PVOID ExtraData, OPTIONAL
  489. IN BOOL CaseSensitive,
  490. OUT PUINT OutHashValue
  491. )
  492. {
  493. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  494. PWSTR dupStr = NULL;
  495. UINT hashValue = 0;
  496. PBUCKETITEM item = NULL;
  497. PCWSTR p1, p2;
  498. PCWSTR p1End;
  499. PCVOID storedDataPtr;
  500. UINT maxBytes;
  501. PCWSTR shortestEnd;
  502. UINT currentBytes;
  503. ASSERT_TABLE_IS_VALID (HashTable);
  504. maxBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  505. maxBytes = min (maxBytes, table->MaximumStringBytes);
  506. if (!maxBytes || table->MinimumStringBytes == (UINT) -1) {
  507. return NULL;
  508. }
  509. if (!CaseSensitive) {
  510. dupStr = AllocTextW (maxBytes / sizeof (WCHAR));
  511. if (dupStr) {
  512. StringCopyByteCountW (dupStr, String, maxBytes + sizeof (WCHAR));
  513. _wcslwr (dupStr);
  514. String = dupStr;
  515. }
  516. }
  517. BufferEnd = (PCWSTR) ((PBYTE) String + maxBytes);
  518. shortestEnd = (PCWSTR) ((PBYTE) String + table->MinimumStringBytes);
  519. if (shortestEnd == String) {
  520. shortestEnd++;
  521. }
  522. while (BufferEnd >= shortestEnd) {
  523. currentBytes = (UINT)((PBYTE) BufferEnd - (PBYTE) String);
  524. hashValue = pComputePrefixHashValueW (String, currentBytes, table->Buckets);
  525. item = table->Bucket[hashValue];
  526. while (item) {
  527. if ((item->StringSize - sizeof (WCHAR)) == currentBytes) {
  528. if (table->ExternalStrings) {
  529. p1 = (PCWSTR) ((PBUCKETITEM_EXTERN_STR) item)->String;
  530. } else {
  531. p1 = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  532. }
  533. p1End = (PCWSTR) ((PBYTE) p1 + currentBytes);
  534. p2 = String;
  535. while (p1 < p1End) {
  536. if (*p1 != *p2) {
  537. break;
  538. }
  539. p1++;
  540. p2++;
  541. }
  542. if (p1 == p1End) {
  543. break;
  544. }
  545. }
  546. item = item->Next;
  547. }
  548. if (item) {
  549. break;
  550. }
  551. BufferEnd--;
  552. }
  553. if (item && ExtraData) {
  554. (void) HtGetStringData (HashTable, (HASHITEM)item, &storedDataPtr);
  555. CopyMemory (
  556. (PBYTE) ExtraData,
  557. (PBYTE) storedDataPtr,
  558. table->ExtraDataSize
  559. );
  560. }
  561. FreeTextW (dupStr);
  562. *OutHashValue = hashValue;
  563. return item;
  564. }
  565. HASHITEM
  566. HtAddStringExA (
  567. IN HASHTABLE HashTable,
  568. IN PCSTR String,
  569. IN PCVOID ExtraData, OPTIONAL
  570. IN BOOL CaseSensitive
  571. )
  572. /*++
  573. Routine Description:
  574. HtAddStringEx adds a string to the hash table, and copies ExtraData to the
  575. new hash table entry. If String is already in the hash table, the ExtraData
  576. is updated.
  577. Arguments:
  578. HashTable - Specifies the handle to the hash table, as returned from
  579. AllocateHashTable.
  580. String - Specifies the string to add to the table
  581. ExtraData - Specifies the source binary data to be copied to the hash
  582. table entry
  583. CaseSensitive - Specifies TRUE if the string compares are case-sensitive,
  584. or FALSE if they are case-insensitive.
  585. Return Value:
  586. Returns the pointer to the bucket item allocated or update.
  587. --*/
  588. {
  589. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  590. PBUCKETITEM item;
  591. PBUCKETITEM_EXTERN_STR externItem;
  592. PBUCKETITEM existingItem;
  593. PSTR dupStr = NULL;
  594. HASHITEM rc = NULL;
  595. UINT size;
  596. UINT hashValue;
  597. UINT strSize;
  598. PCVOID storedDataPtr;
  599. ASSERT_TABLE_IS_VALID (HashTable);
  600. if (table->Unicode) {
  601. DEBUGMSG ((DBG_WHOOPS, "Cannot add ANSI string to UNICODE table"));
  602. return 0;
  603. }
  604. if (!CaseSensitive) {
  605. dupStr = DuplicateTextA (String);
  606. _mbslwr (dupStr);
  607. String = dupStr;
  608. }
  609. existingItem = pHtFindStringA (HashTable, String, NULL, TRUE, &hashValue);
  610. if (existingItem) {
  611. rc = (HASHITEM) existingItem;
  612. } else {
  613. //
  614. // item does not exist, add it now
  615. //
  616. strSize = SizeOfStringA (String);
  617. if (table->ExternalStrings) {
  618. size = sizeof (BUCKETITEM_EXTERN_STR) + table->ExtraDataSize;
  619. externItem = (PBUCKETITEM_EXTERN_STR) PmGetAlignedMemory (table->Pool, size);
  620. MYASSERT (externItem);
  621. externItem->Next = table->Bucket[hashValue];
  622. table->Bucket[hashValue] = (PBUCKETITEM) externItem;
  623. if (table->LastLink) {
  624. table->LastLink->NextLink = (PBUCKETITEM) externItem;
  625. }
  626. externItem->PrevLink = table->LastLink;
  627. table->LastLink = (PBUCKETITEM) externItem;
  628. externItem->NextLink = NULL;
  629. if (!table->FirstLink) {
  630. table->FirstLink = (PBUCKETITEM) externItem;
  631. }
  632. rc = (HASHITEM) externItem;
  633. } else {
  634. size = sizeof (BUCKETITEM) + strSize + table->ExtraDataSize;
  635. item = (PBUCKETITEM) PmGetAlignedMemory (table->Pool, size);
  636. MYASSERT (item);
  637. item->Next = table->Bucket[hashValue];
  638. table->Bucket[hashValue] = item;
  639. item->StringSize = (WORD) strSize;
  640. CopyMemory ((PBYTE) item + sizeof (BUCKETITEM), String, strSize);
  641. if (table->LastLink) {
  642. table->LastLink->NextLink = item;
  643. }
  644. item->PrevLink = table->LastLink;
  645. table->LastLink = item;
  646. item->NextLink = NULL;
  647. if (!table->FirstLink) {
  648. table->FirstLink = item;
  649. }
  650. rc = (HASHITEM) item;
  651. }
  652. strSize -= sizeof (CHAR);
  653. table->MaximumStringBytes = max (table->MaximumStringBytes, strSize);
  654. table->MinimumStringBytes = min (table->MinimumStringBytes, strSize);
  655. }
  656. MYASSERT (rc);
  657. (void) HtGetStringData (HashTable, rc, &storedDataPtr);
  658. if (ExtraData) {
  659. CopyMemory (
  660. (PBYTE) storedDataPtr,
  661. (PBYTE) ExtraData,
  662. table->ExtraDataSize
  663. );
  664. } else if (!existingItem) {
  665. ZeroMemory (
  666. (PBYTE) storedDataPtr,
  667. table->ExtraDataSize
  668. );
  669. }
  670. FreeTextA (dupStr);
  671. return rc;
  672. }
  673. HASHITEM
  674. HtAddStringExW (
  675. IN HASHTABLE HashTable,
  676. IN PCWSTR String,
  677. IN PCVOID ExtraData, OPTIONAL
  678. IN BOOL CaseSensitive
  679. )
  680. {
  681. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  682. PBUCKETITEM item;
  683. PBUCKETITEM_EXTERN_STR externItem;
  684. PBUCKETITEM existingItem;
  685. PWSTR dupStr = NULL;
  686. HASHITEM rc = NULL;
  687. UINT size;
  688. UINT hashValue;
  689. UINT strSize;
  690. PCVOID storedDataPtr;
  691. ASSERT_TABLE_IS_VALID (HashTable);
  692. if (!table->Unicode) {
  693. DEBUGMSG ((DBG_WHOOPS, "Cannot add ANSI string to UNICODE table"));
  694. return 0;
  695. }
  696. if (!CaseSensitive) {
  697. dupStr = DuplicateTextW (String);
  698. _wcslwr (dupStr);
  699. String = dupStr;
  700. }
  701. existingItem = pHtFindStringW (HashTable, String, NULL, TRUE, &hashValue);
  702. if (existingItem) {
  703. rc = (HASHITEM) existingItem;
  704. } else {
  705. //
  706. // item does not exist, add it now
  707. //
  708. strSize = SizeOfStringW (String);
  709. if (table->ExternalStrings) {
  710. size = sizeof (BUCKETITEM_EXTERN_STR) + table->ExtraDataSize;
  711. externItem = (PBUCKETITEM_EXTERN_STR) PmGetAlignedMemory (table->Pool, size);
  712. MYASSERT (externItem);
  713. externItem->Next = table->Bucket[hashValue];
  714. table->Bucket[hashValue] = (PBUCKETITEM) externItem;
  715. if (table->LastLink) {
  716. table->LastLink->NextLink = (PBUCKETITEM) externItem;
  717. }
  718. externItem->PrevLink = table->LastLink;
  719. table->LastLink = (PBUCKETITEM) externItem;
  720. externItem->NextLink = NULL;
  721. if (!table->FirstLink) {
  722. table->FirstLink = (PBUCKETITEM) externItem;
  723. }
  724. rc = (HASHITEM) externItem;
  725. } else {
  726. size = sizeof (BUCKETITEM) + strSize + table->ExtraDataSize;
  727. item = (PBUCKETITEM) PmGetAlignedMemory (table->Pool, size);
  728. MYASSERT (item);
  729. item->Next = table->Bucket[hashValue];
  730. table->Bucket[hashValue] = item;
  731. item->StringSize = (WORD) strSize;
  732. CopyMemory ((PBYTE) item + sizeof (BUCKETITEM), String, strSize);
  733. if (table->LastLink) {
  734. table->LastLink->NextLink = item;
  735. }
  736. item->PrevLink = table->LastLink;
  737. table->LastLink = item;
  738. item->NextLink = NULL;
  739. if (!table->FirstLink) {
  740. table->FirstLink = item;
  741. }
  742. rc = (HASHITEM) item;
  743. }
  744. strSize -= sizeof (WCHAR);
  745. table->MaximumStringBytes = max (table->MaximumStringBytes, strSize);
  746. table->MinimumStringBytes = min (table->MinimumStringBytes, strSize);
  747. }
  748. MYASSERT (rc);
  749. (void) HtGetStringData (HashTable, rc, &storedDataPtr);
  750. if (ExtraData) {
  751. CopyMemory (
  752. (PBYTE) storedDataPtr,
  753. (PBYTE) ExtraData,
  754. table->ExtraDataSize
  755. );
  756. } else if (!existingItem) {
  757. ZeroMemory (
  758. (PBYTE) storedDataPtr,
  759. table->ExtraDataSize
  760. );
  761. }
  762. FreeTextW (dupStr);
  763. return rc;
  764. }
  765. /*++
  766. Routine Description:
  767. HtFindStringEx is the external entry point for pHtFindString.
  768. Arguments:
  769. HashTable - Specifies the hash table handle, as returned by
  770. AllocateHashTable.
  771. String - Specifies the string to find
  772. ExtraData - Receives the extra data associated with the found item
  773. CaseSensitive - Specifies TRUE if the find should be case-sensitive, FALSE
  774. if it should be case-insensitive.
  775. Return Value:
  776. A pointer to the bucket item or NULL if the string was not found.
  777. --*/
  778. HASHITEM
  779. HtFindStringExA (
  780. IN HASHTABLE HashTable,
  781. IN PCSTR String,
  782. OUT PVOID ExtraData, OPTIONAL
  783. IN BOOL CaseSensitive
  784. )
  785. {
  786. UINT dontCare;
  787. return (HASHITEM) pHtFindStringA (HashTable, String, ExtraData, CaseSensitive, &dontCare);
  788. }
  789. HASHITEM
  790. HtFindStringExW (
  791. IN HASHTABLE HashTable,
  792. IN PCWSTR String,
  793. OUT PVOID ExtraData, OPTIONAL
  794. IN BOOL CaseSensitive
  795. )
  796. {
  797. UINT dontCare;
  798. return (HASHITEM) pHtFindStringW (HashTable, String, ExtraData, CaseSensitive, &dontCare);
  799. }
  800. /*++
  801. Routine Description:
  802. HtFindStringEx is the external entry point for pHtFindString.
  803. Arguments:
  804. HashTable - Specifies the hash table handle, as returned by
  805. AllocateHashTable.
  806. String - Specifies the string to find
  807. BufferEnd - Specifies the end of the buffer for String
  808. ExtraData - Receives the extra data associated with the found item
  809. CaseSensitive - Specifies TRUE if the find should be case-sensitive, FALSE
  810. if it should be case-insensitive.
  811. Return Value:
  812. A pointer to the bucket item or NULL if the string was not found.
  813. --*/
  814. HASHITEM
  815. HtFindPrefixExA (
  816. IN HASHTABLE HashTable,
  817. IN PCSTR String,
  818. IN PCSTR BufferEnd,
  819. OUT PVOID ExtraData, OPTIONAL
  820. IN BOOL CaseSensitive
  821. )
  822. {
  823. UINT dontCare;
  824. return (HASHITEM) pHtFindPrefixA (
  825. HashTable,
  826. String,
  827. BufferEnd,
  828. ExtraData,
  829. CaseSensitive,
  830. &dontCare
  831. );
  832. }
  833. HASHITEM
  834. HtFindPrefixExW (
  835. IN HASHTABLE HashTable,
  836. IN PCWSTR String,
  837. IN PCWSTR BufferEnd,
  838. OUT PVOID ExtraData, OPTIONAL
  839. IN BOOL CaseSensitive
  840. )
  841. {
  842. UINT dontCare;
  843. return (HASHITEM) pHtFindPrefixW (
  844. HashTable,
  845. String,
  846. BufferEnd,
  847. ExtraData,
  848. CaseSensitive,
  849. &dontCare
  850. );
  851. }
  852. BOOL
  853. HtGetStringData (
  854. IN HASHTABLE HashTable,
  855. IN HASHITEM Index,
  856. OUT PCVOID *ExtraData
  857. )
  858. /*++
  859. Routine Description:
  860. HtGetStringData gets the extra data associated with a bucket item.
  861. The caller must supply the ID as returned from HtFindStringEx or
  862. HtAddStringEx. This routine is useful when ExtraData is large, and
  863. the normal find routine would be slow because of the CopyMemory code path.
  864. Arguments:
  865. HashTable - Specifies the handle to the hash table
  866. Index - Specifies the offset as returned from HtFindStringEx or
  867. HtAddStringEx
  868. ExtraData - Receives the extra data pointer (it does NOT copy the data to
  869. the buffer).
  870. Return Value:
  871. TRUE if ExtraData was set, FALSE otherwise.
  872. --*/
  873. {
  874. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  875. PBUCKETITEM item;
  876. PBUCKETITEM_EXTERN_STR externStrItem;
  877. ASSERT_TABLE_IS_VALID (HashTable);
  878. if (!Index) {
  879. return FALSE;
  880. }
  881. if (table->ExternalStrings) {
  882. externStrItem = (PBUCKETITEM_EXTERN_STR) Index;
  883. *ExtraData = (PCVOID) ((PBYTE) externStrItem + sizeof (PBUCKETITEM_EXTERN_STR));
  884. } else {
  885. item = (PBUCKETITEM) Index;
  886. *ExtraData = (PCVOID) ((PBYTE) item + sizeof (BUCKETITEM) + item->StringSize);
  887. }
  888. return TRUE;
  889. }
  890. BOOL
  891. HtCopyStringData (
  892. IN HASHTABLE HashTable,
  893. IN HASHITEM Index,
  894. OUT PVOID ExtraData
  895. )
  896. /*++
  897. Routine Description:
  898. HtCopyStringData gets the extra data associated with a bucket item
  899. and copies it to the caller's buffer.
  900. Arguments:
  901. HashTable - Specifies the handle to the hash table
  902. Index - Specifies the offset as returned from HtFindStringEx or
  903. HtAddStringEx
  904. ExtraData - Receives the extra data
  905. Return Value:
  906. TRUE if ExtraData was copied, FALSE otherwise.
  907. --*/
  908. {
  909. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  910. PCVOID storedDataPtr;
  911. ASSERT_TABLE_IS_VALID (HashTable);
  912. if (!HtGetStringData (HashTable, Index, &storedDataPtr)) {
  913. return FALSE;
  914. }
  915. CopyMemory (
  916. (PBYTE) ExtraData,
  917. (PBYTE) storedDataPtr,
  918. table->ExtraDataSize
  919. );
  920. return TRUE;
  921. }
  922. BOOL
  923. HtSetStringData (
  924. IN HASHTABLE HashTable,
  925. IN HASHITEM Index,
  926. IN PCVOID ExtraData
  927. )
  928. /*++
  929. Routine Description:
  930. HtSetStringData copies new extra data to the specified hash table entry.
  931. Arguments:
  932. HashTable - Specifies the handle to the hash table
  933. Index - Specifies the offset as returned from HtFindStringEx or
  934. HtAddStringEx
  935. ExtraData - Specifies the extra data
  936. Return Value:
  937. TRUE if the item was updated, FALSE otherwise.
  938. --*/
  939. {
  940. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  941. PCVOID storedDataPtr;
  942. ASSERT_TABLE_IS_VALID (HashTable);
  943. if (!HtGetStringData (HashTable, Index, &storedDataPtr)) {
  944. return FALSE;
  945. }
  946. CopyMemory (
  947. (PBYTE) storedDataPtr,
  948. (PBYTE) ExtraData,
  949. table->ExtraDataSize
  950. );
  951. return TRUE;
  952. }
  953. BOOL
  954. EnumFirstHashTableStringA (
  955. OUT PHASHTABLE_ENUMA EnumPtr,
  956. IN HASHTABLE HashTable
  957. )
  958. /*++
  959. Routine Description:
  960. EnumFirstHashTableString begins an enumeration of the hash table structure.
  961. The return order is random. Also, do not modify the hash table while an
  962. enumeration is active.
  963. Arguments:
  964. EnumPtr - Receives the string, extra data and offset for the first item
  965. in the hash table.
  966. HashTable - Specifies the handle of the hash table to enumerate.
  967. Return Value:
  968. TRUE if an item was enumerated, FALSE otherwise.
  969. --*/
  970. {
  971. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  972. ASSERT_TABLE_IS_VALID (HashTable);
  973. if (table->Unicode) {
  974. DEBUGMSG ((DBG_WHOOPS, "Cannot enum UNICODE table with ANSI wrapper"));
  975. return FALSE;
  976. }
  977. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMA));
  978. EnumPtr->Internal = (HASHTABLE) table;
  979. return EnumNextHashTableStringA (EnumPtr);
  980. }
  981. BOOL
  982. EnumFirstHashTableStringW (
  983. OUT PHASHTABLE_ENUMW EnumPtr,
  984. IN HASHTABLE HashTable
  985. )
  986. {
  987. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  988. ASSERT_TABLE_IS_VALID (HashTable);
  989. if (!table->Unicode) {
  990. DEBUGMSG ((DBG_WHOOPS, "Cannot enum ANSI table with UNICODE wrapper"));
  991. return FALSE;
  992. }
  993. ZeroMemory (EnumPtr, sizeof (HASHTABLE_ENUMW));
  994. EnumPtr->Internal = (HASHTABLE) table;
  995. return EnumNextHashTableStringW (EnumPtr);
  996. }
  997. BOOL
  998. EnumNextHashTableStringA (
  999. IN OUT PHASHTABLE_ENUMA EnumPtr
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. EnumNextHashTableString continues an enumeration started by
  1004. EnumFirstHashTableString. Call the routine until it returns FALSE.
  1005. Arguments:
  1006. EnumPtr - Specifies the structure of an active enumeration. Receives
  1007. updated string, extra data and offset members.
  1008. Return Value:
  1009. TRUE if another item was enumerated, FALSE if no items remain.
  1010. --*/
  1011. {
  1012. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1013. PBUCKETITEM item;
  1014. PBUCKETITEM_EXTERN_STR externItem;
  1015. if (!EnumPtr->Internal) {
  1016. return FALSE;
  1017. }
  1018. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1019. if (!EnumPtr->Index) {
  1020. item = table->FirstLink;
  1021. } else {
  1022. item = (PBUCKETITEM) EnumPtr->Index;
  1023. item = item->NextLink;
  1024. }
  1025. if (item) {
  1026. //
  1027. // Return a valid item
  1028. //
  1029. EnumPtr->Index = (HASHITEM) item;
  1030. if (table->ExternalStrings) {
  1031. externItem = (PBUCKETITEM_EXTERN_STR) item;
  1032. EnumPtr->String = (PCSTR) (externItem->String);
  1033. } else {
  1034. EnumPtr->String = (PCSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  1035. }
  1036. if (table->ExtraDataSize) {
  1037. MYASSERT (EnumPtr->Index);
  1038. (void) HtGetStringData (EnumPtr->Internal, EnumPtr->Index, &EnumPtr->ExtraData);
  1039. }
  1040. return TRUE;
  1041. }
  1042. EnumPtr->Internal = 0;
  1043. return FALSE;
  1044. }
  1045. BOOL
  1046. EnumNextHashTableStringW (
  1047. IN OUT PHASHTABLE_ENUMW EnumPtr
  1048. )
  1049. {
  1050. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) EnumPtr->Internal;
  1051. PBUCKETITEM item;
  1052. PBUCKETITEM_EXTERN_STR externItem;
  1053. if (!EnumPtr->Internal) {
  1054. return FALSE;
  1055. }
  1056. ASSERT_TABLE_IS_VALID (EnumPtr->Internal);
  1057. if (!EnumPtr->Index) {
  1058. item = table->FirstLink;
  1059. } else {
  1060. item = (PBUCKETITEM) EnumPtr->Index;
  1061. item = item->NextLink;
  1062. }
  1063. if (item) {
  1064. //
  1065. // Return a valid item
  1066. //
  1067. EnumPtr->Index = (HASHITEM) item;
  1068. if (table->ExternalStrings) {
  1069. externItem = (PBUCKETITEM_EXTERN_STR) item;
  1070. EnumPtr->String = (PCWSTR) (externItem->String);
  1071. } else {
  1072. EnumPtr->String = (PCWSTR) ((PBYTE) item + sizeof (BUCKETITEM));
  1073. }
  1074. if (table->ExtraDataSize) {
  1075. MYASSERT (EnumPtr->Index);
  1076. (void) HtGetStringData (EnumPtr->Internal, EnumPtr->Index, &EnumPtr->ExtraData);
  1077. }
  1078. return TRUE;
  1079. }
  1080. EnumPtr->Internal = 0;
  1081. return FALSE;
  1082. }
  1083. BOOL
  1084. EnumHashTableWithCallbackA (
  1085. IN HASHTABLE HashTable,
  1086. IN PHASHTABLE_CALLBACK_ROUTINEA Proc,
  1087. IN LPARAM lParam
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. EnumHashTableWithCallback implements a setupapi-style enumerator. The
  1092. callback routine is called for each item in the string table, and if the
  1093. callback routine returns FALSE, the enumeration ends.
  1094. Arguments:
  1095. HashTable - Specifies the handle to the table to enumerate
  1096. Proc - Specifies the callback procedure address
  1097. lParam - Specifies a value to pass to the callback, and is intended only
  1098. for use by the caller.
  1099. Return Value:
  1100. Always TRUE.
  1101. --*/
  1102. {
  1103. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1104. HASHTABLE_ENUMA e;
  1105. ASSERT_TABLE_IS_VALID (HashTable);
  1106. if (EnumFirstHashTableStringA (&e, HashTable)) {
  1107. do {
  1108. if (!Proc (HashTable, e.Index, e.String, (PVOID) e.ExtraData, table->ExtraDataSize, lParam)) {
  1109. break;
  1110. }
  1111. } while (EnumNextHashTableStringA (&e));
  1112. }
  1113. return TRUE;
  1114. }
  1115. BOOL
  1116. EnumHashTableWithCallbackW (
  1117. IN HASHTABLE HashTable,
  1118. IN PHASHTABLE_CALLBACK_ROUTINEW Proc,
  1119. IN LPARAM lParam
  1120. )
  1121. {
  1122. PHASHTABLESTRUCT table = (PHASHTABLESTRUCT) HashTable;
  1123. HASHTABLE_ENUMW e;
  1124. ASSERT_TABLE_IS_VALID (HashTable);
  1125. if (EnumFirstHashTableStringW (&e, HashTable)) {
  1126. do {
  1127. if (!Proc (HashTable, e.Index, e.String, (PVOID) e.ExtraData, table->ExtraDataSize, lParam)) {
  1128. break;
  1129. }
  1130. } while (EnumNextHashTableStringW (&e));
  1131. }
  1132. return TRUE;
  1133. }
  1134. PCSTR
  1135. HtGetStringFromItemA (
  1136. IN HASHITEM Item
  1137. )
  1138. {
  1139. if (!Item) {
  1140. return NULL;
  1141. }
  1142. return (PCSTR) ((PBYTE) Item + sizeof (BUCKETITEM));
  1143. }
  1144. PCWSTR
  1145. HtGetStringFromItemW (
  1146. IN HASHITEM Item
  1147. )
  1148. {
  1149. if (!Item) {
  1150. return NULL;
  1151. }
  1152. return (PCWSTR) ((PBYTE) Item + sizeof (BUCKETITEM));
  1153. }