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.

2405 lines
60 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Prefix.c
  5. Abstract:
  6. This module implements the prefix table utility. The two structures
  7. used in a prefix table are the PREFIX_TABLE and PREFIX_TABLE_ENTRY.
  8. Each table has one prefix table and multiple prefix table entries
  9. corresponding to each prefix stored in the table.
  10. A prefix table is a list of prefix trees, where each tree contains
  11. the prefixes corresponding to a particular name length (i.e., all
  12. prefixes of length 1 are stored in one tree, prefixes of length 2
  13. are stored in another tree, and so forth). A prefixes name length
  14. is the number of separate names that appear in the string, and not
  15. the number of characters in the string (e.g., Length("\alpha\beta") = 2).
  16. The elements of each tree are ordered lexicalgraphically (case blind)
  17. using a splay tree data structure. If two or more prefixes are identical
  18. except for case then one of the corresponding table entries is actually
  19. in the tree, while the other entries are in a circular linked list joined
  20. with the tree member.
  21. Author:
  22. Gary Kimura [GaryKi] 3-Aug-1989
  23. Environment:
  24. Pure utility routine
  25. Revision History:
  26. 08-Mar-1993 JulieB Moved Upcase Macro to ntrtlp.h.
  27. --*/
  28. #include "ntrtlp.h"
  29. //
  30. // Local procedures and types used only in this package
  31. //
  32. typedef enum _COMPARISON {
  33. IsLessThan,
  34. IsPrefix,
  35. IsEqual,
  36. IsGreaterThan
  37. } COMPARISON;
  38. CLONG
  39. ComputeNameLength(
  40. IN PSTRING Name
  41. );
  42. COMPARISON
  43. CompareNamesCaseSensitive (
  44. IN PSTRING Prefix,
  45. IN PSTRING Name
  46. );
  47. CLONG
  48. ComputeUnicodeNameLength(
  49. IN PUNICODE_STRING Name
  50. );
  51. COMPARISON
  52. CompareUnicodeStrings (
  53. IN PUNICODE_STRING Prefix,
  54. IN PUNICODE_STRING Name,
  55. IN ULONG CaseInsensitiveIndex
  56. );
  57. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  58. #pragma alloc_text(PAGE,ComputeNameLength)
  59. #pragma alloc_text(PAGE,CompareNamesCaseSensitive)
  60. #pragma alloc_text(PAGE,PfxInitialize)
  61. #pragma alloc_text(PAGE,PfxInsertPrefix)
  62. #pragma alloc_text(PAGE,PfxRemovePrefix)
  63. #pragma alloc_text(PAGE,PfxFindPrefix)
  64. #pragma alloc_text(PAGE,ComputeUnicodeNameLength)
  65. #pragma alloc_text(PAGE,CompareUnicodeStrings)
  66. #pragma alloc_text(PAGE,RtlInitializeUnicodePrefix)
  67. #pragma alloc_text(PAGE,RtlInsertUnicodePrefix)
  68. #pragma alloc_text(PAGE,RtlRemoveUnicodePrefix)
  69. #pragma alloc_text(PAGE,RtlFindUnicodePrefix)
  70. #pragma alloc_text(PAGE,RtlNextUnicodePrefix)
  71. #endif
  72. //
  73. // The node type codes for the prefix data structures
  74. //
  75. #define RTL_NTC_PREFIX_TABLE ((CSHORT)0x0200)
  76. #define RTL_NTC_ROOT ((CSHORT)0x0201)
  77. #define RTL_NTC_INTERNAL ((CSHORT)0x0202)
  78. VOID
  79. PfxInitialize (
  80. IN PPREFIX_TABLE PrefixTable
  81. )
  82. /*++
  83. Routine Description:
  84. This routine initializes a prefix table record to the empty state.
  85. Arguments:
  86. PrefixTable - Supplies the prefix table being initialized
  87. Return Value:
  88. None.
  89. --*/
  90. {
  91. RTL_PAGED_CODE();
  92. PrefixTable->NodeTypeCode = RTL_NTC_PREFIX_TABLE;
  93. PrefixTable->NameLength = 0;
  94. PrefixTable->NextPrefixTree = (PPREFIX_TABLE_ENTRY)PrefixTable;
  95. //
  96. // return to our caller
  97. //
  98. return;
  99. }
  100. BOOLEAN
  101. PfxInsertPrefix (
  102. IN PPREFIX_TABLE PrefixTable,
  103. IN PSTRING Prefix,
  104. IN PPREFIX_TABLE_ENTRY PrefixTableEntry
  105. )
  106. /*++
  107. Routine Description:
  108. This routine inserts a new prefix into the specified prefix table
  109. Arguments:
  110. PrefixTable - Supplies the target prefix table
  111. Prefix - Supplies the string to be inserted in the prefix table
  112. PrefixTableEntry - Supplies the entry to use to insert the prefix
  113. Return Value:
  114. BOOLEAN - TRUE if the Prefix is not already in the table, and FALSE
  115. otherwise
  116. --*/
  117. {
  118. ULONG PrefixNameLength;
  119. PPREFIX_TABLE_ENTRY PreviousTree;
  120. PPREFIX_TABLE_ENTRY CurrentTree;
  121. PPREFIX_TABLE_ENTRY NextTree;
  122. PPREFIX_TABLE_ENTRY Node;
  123. COMPARISON Comparison;
  124. RTL_PAGED_CODE();
  125. //
  126. // Determine the name length of the input string
  127. //
  128. PrefixNameLength = ComputeNameLength(Prefix);
  129. //
  130. // Setup parts of the prefix table entry that we will always need
  131. //
  132. PrefixTableEntry->NameLength = (CSHORT)PrefixNameLength;
  133. PrefixTableEntry->Prefix = Prefix;
  134. RtlInitializeSplayLinks(&PrefixTableEntry->Links);
  135. //
  136. // find the corresponding tree, or find where the tree should go
  137. //
  138. PreviousTree = (PPREFIX_TABLE_ENTRY)PrefixTable;
  139. CurrentTree = PreviousTree->NextPrefixTree;
  140. while (CurrentTree->NameLength > (CSHORT)PrefixNameLength) {
  141. PreviousTree = CurrentTree;
  142. CurrentTree = CurrentTree->NextPrefixTree;
  143. }
  144. //
  145. // If the name length of the current tree is not equal to the
  146. // prefix name length then the tree does not exist and we need
  147. // to make a new tree node.
  148. //
  149. if (CurrentTree->NameLength != (CSHORT)PrefixNameLength) {
  150. //
  151. // Insert the new prefix entry to the list between
  152. // previous and current tree
  153. //
  154. PreviousTree->NextPrefixTree = PrefixTableEntry;
  155. PrefixTableEntry->NextPrefixTree = CurrentTree;
  156. //
  157. // And set the node type code
  158. //
  159. PrefixTableEntry->NodeTypeCode = RTL_NTC_ROOT;
  160. //
  161. // And tell our caller everything worked fine
  162. //
  163. return TRUE;
  164. }
  165. //
  166. // The tree does exist so now search the tree for our
  167. // position in it. We only exit the loop if we've inserted
  168. // a new node, and node is left is left pointing to the
  169. // tree position
  170. //
  171. Node = CurrentTree;
  172. while (TRUE) {
  173. //
  174. // Compare the prefix in the tree with the prefix we want
  175. // to insert
  176. //
  177. Comparison = CompareNamesCaseSensitive(Node->Prefix, Prefix);
  178. //
  179. // If we do match case sensitive then we cannot add
  180. // this prefix so we return false. Note this is the
  181. // only condition where we return false
  182. //
  183. if (Comparison == IsEqual) {
  184. return FALSE;
  185. }
  186. //
  187. // If the tree prefix is greater than the new prefix then
  188. // we go down the left subtree
  189. //
  190. if (Comparison == IsGreaterThan) {
  191. //
  192. // We want to go down the left subtree, first check to see
  193. // if we have a left subtree
  194. //
  195. if (RtlLeftChild(&Node->Links) == NULL) {
  196. //
  197. // there isn't a left child so we insert ourselves as the
  198. // new left child
  199. //
  200. PrefixTableEntry->NodeTypeCode = RTL_NTC_INTERNAL;
  201. PrefixTableEntry->NextPrefixTree = NULL;
  202. RtlInsertAsLeftChild(&Node->Links, &PrefixTableEntry->Links);
  203. //
  204. // and exit the while loop
  205. //
  206. break;
  207. } else {
  208. //
  209. // there is a left child so simply go down that path, and
  210. // go back to the top of the loop
  211. //
  212. Node = CONTAINING_RECORD( RtlLeftChild(&Node->Links),
  213. PREFIX_TABLE_ENTRY,
  214. Links );
  215. }
  216. } else {
  217. //
  218. // The tree prefix is either less than or a proper prefix
  219. // of the new string. We treat both cases a less than when
  220. // we do insert. So we want to go down the right subtree,
  221. // first check to see if we have a right subtree
  222. //
  223. if (RtlRightChild(&Node->Links) == NULL) {
  224. //
  225. // These isn't a right child so we insert ourselves as the
  226. // new right child
  227. //
  228. PrefixTableEntry->NodeTypeCode = RTL_NTC_INTERNAL;
  229. PrefixTableEntry->NextPrefixTree = NULL;
  230. RtlInsertAsRightChild(&Node->Links, &PrefixTableEntry->Links);
  231. //
  232. // and exit the while loop
  233. //
  234. break;
  235. } else {
  236. //
  237. // there is a right child so simply go down that path, and
  238. // go back to the top of the loop
  239. //
  240. Node = CONTAINING_RECORD( RtlRightChild(&Node->Links),
  241. PREFIX_TABLE_ENTRY,
  242. Links );
  243. }
  244. }
  245. }
  246. //
  247. // Now that we've inserted the new node we can splay the tree.
  248. // To do this we need to remember how we find this tree in the root
  249. // tree list, set the root to be an internal, splay, the tree, and
  250. // then setup the new root node. Note: we cannot splay the prefix table
  251. // entry because it might be a case match node so we only splay
  252. // the Node variable, which for case match insertions is the
  253. // internal node for the case match and for non-case match insertions
  254. // the Node variable is the parent node.
  255. //
  256. //
  257. // Save a pointer to the next tree, we already have the previous tree
  258. //
  259. NextTree = CurrentTree->NextPrefixTree;
  260. //
  261. // Reset the current root to be an internal node
  262. //
  263. CurrentTree->NodeTypeCode = RTL_NTC_INTERNAL;
  264. CurrentTree->NextPrefixTree = NULL;
  265. //
  266. // Splay the tree and get the root
  267. //
  268. Node = CONTAINING_RECORD(RtlSplay(&Node->Links), PREFIX_TABLE_ENTRY, Links);
  269. //
  270. // Set the new root's node type code and make it part of the
  271. // root tree list
  272. //
  273. Node->NodeTypeCode = RTL_NTC_ROOT;
  274. PreviousTree->NextPrefixTree = Node;
  275. Node->NextPrefixTree = NextTree;
  276. //
  277. // tell our caller everything worked fine
  278. //
  279. return TRUE;
  280. }
  281. VOID
  282. PfxRemovePrefix (
  283. IN PPREFIX_TABLE PrefixTable,
  284. IN PPREFIX_TABLE_ENTRY PrefixTableEntry
  285. )
  286. /*++
  287. Routine Description:
  288. This routine removes the indicated prefix table entry from
  289. the prefix table
  290. Arguments:
  291. PrefixTable - Supplies the prefix table affected
  292. PrefixTableEntry - Supplies the prefix entry to remove
  293. Return Value:
  294. None.
  295. --*/
  296. {
  297. PRTL_SPLAY_LINKS Links;
  298. PPREFIX_TABLE_ENTRY Root;
  299. PPREFIX_TABLE_ENTRY NewRoot;
  300. PPREFIX_TABLE_ENTRY PreviousTree;
  301. RTL_PAGED_CODE();
  302. //
  303. // case on the type of node that we are trying to delete
  304. //
  305. switch (PrefixTableEntry->NodeTypeCode) {
  306. case RTL_NTC_INTERNAL:
  307. case RTL_NTC_ROOT:
  308. //
  309. // The node is internal or root node so we need to delete it from
  310. // the tree, but first find the root of the tree
  311. //
  312. Links = &PrefixTableEntry->Links;
  313. while (!RtlIsRoot(Links)) {
  314. Links = RtlParent(Links);
  315. }
  316. Root = CONTAINING_RECORD( Links, PREFIX_TABLE_ENTRY, Links );
  317. //
  318. // Now delete the node
  319. //
  320. Links = RtlDelete(&PrefixTableEntry->Links);
  321. //
  322. // Now see if the tree is deleted
  323. //
  324. if (Links == NULL) {
  325. //
  326. // The tree is now empty so remove this tree from
  327. // the tree list, by first finding the previous tree that
  328. // references us
  329. //
  330. PreviousTree = Root->NextPrefixTree;
  331. while ( PreviousTree->NextPrefixTree != Root ) {
  332. PreviousTree = PreviousTree->NextPrefixTree;
  333. }
  334. //
  335. // We've located the previous tree so now just have it
  336. // point around the deleted node
  337. //
  338. PreviousTree->NextPrefixTree = Root->NextPrefixTree;
  339. //
  340. // and return the our caller
  341. //
  342. return;
  343. }
  344. //
  345. // The tree is not deleted but see if we changed roots
  346. //
  347. if (&Root->Links != Links) {
  348. //
  349. // Get a pointer to the new root
  350. //
  351. NewRoot = CONTAINING_RECORD(Links, PREFIX_TABLE_ENTRY, Links);
  352. //
  353. // We changed root so we better need to make the new
  354. // root part of the prefix data structure, by
  355. // first finding the previous tree that
  356. // references us
  357. //
  358. PreviousTree = Root->NextPrefixTree;
  359. while ( PreviousTree->NextPrefixTree != Root ) {
  360. PreviousTree = PreviousTree->NextPrefixTree;
  361. }
  362. //
  363. // Set the new root
  364. //
  365. NewRoot->NodeTypeCode = RTL_NTC_ROOT;
  366. PreviousTree->NextPrefixTree = NewRoot;
  367. NewRoot->NextPrefixTree = Root->NextPrefixTree;
  368. //
  369. // Set the old root to be an internal node
  370. //
  371. Root->NodeTypeCode = RTL_NTC_INTERNAL;
  372. Root->NextPrefixTree = NULL;
  373. //
  374. // And return to our caller
  375. //
  376. return;
  377. }
  378. //
  379. // We didn't change roots so everything is fine and we can
  380. // simply return to our caller
  381. //
  382. return;
  383. default:
  384. //
  385. // If we get here then there was an error and the node type
  386. // code is unknown
  387. //
  388. return;
  389. }
  390. }
  391. PPREFIX_TABLE_ENTRY
  392. PfxFindPrefix (
  393. IN PPREFIX_TABLE PrefixTable,
  394. IN PSTRING FullName
  395. )
  396. /*++
  397. Routine Description:
  398. This routine finds if a full name has a prefix in a prefix table.
  399. It returns a pointer to the largest proper prefix found if one exists.
  400. Arguments:
  401. PrefixTable - Supplies the prefix table to search
  402. FullString - Supplies the name to search for
  403. Return Value:
  404. PPREFIX_TABLE_ENTRY - a pointer to the longest prefix found if one
  405. exists, and NULL otherwise
  406. --*/
  407. {
  408. CLONG NameLength;
  409. PPREFIX_TABLE_ENTRY PreviousTree;
  410. PPREFIX_TABLE_ENTRY CurrentTree;
  411. PPREFIX_TABLE_ENTRY NextTree;
  412. PRTL_SPLAY_LINKS Links;
  413. PPREFIX_TABLE_ENTRY Node;
  414. COMPARISON Comparison;
  415. RTL_PAGED_CODE();
  416. //
  417. // Determine the name length of the input string
  418. //
  419. NameLength = ComputeNameLength(FullName);
  420. //
  421. // Locate the first tree that can contain a prefix
  422. //
  423. PreviousTree = (PPREFIX_TABLE_ENTRY)PrefixTable;
  424. CurrentTree = PreviousTree->NextPrefixTree;
  425. while (CurrentTree->NameLength > (CSHORT)NameLength) {
  426. PreviousTree = CurrentTree;
  427. CurrentTree = CurrentTree->NextPrefixTree;
  428. }
  429. //
  430. // Now search for a prefix until we find one or until we exhaust
  431. // the prefix trees
  432. //
  433. while (CurrentTree->NameLength > 0) {
  434. Links = &CurrentTree->Links;
  435. while (Links != NULL) {
  436. Node = CONTAINING_RECORD(Links, PREFIX_TABLE_ENTRY, Links);
  437. //
  438. // Compare the prefix in the tree with the full name
  439. //
  440. Comparison = CompareNamesCaseSensitive(Node->Prefix, FullName);
  441. //
  442. // See if they don't match
  443. //
  444. if (Comparison == IsGreaterThan) {
  445. //
  446. // The prefix is greater than the full name
  447. // so we go down the left child
  448. //
  449. Links = RtlLeftChild(Links);
  450. //
  451. // And continue searching down this tree
  452. //
  453. } else if (Comparison == IsLessThan) {
  454. //
  455. // The prefix is less than the full name
  456. // so we go down the right child
  457. //
  458. Links = RtlRightChild(Links);
  459. //
  460. // And continue searching down this tree
  461. //
  462. } else {
  463. //
  464. // We found it.
  465. //
  466. // Now that we've located the node we can splay the tree.
  467. // To do this we need to remember how we find this tree in the root
  468. // tree list, set the root to be an internal, splay, the tree, and
  469. // then setup the new root node.
  470. //
  471. if (Node->NodeTypeCode == RTL_NTC_INTERNAL) {
  472. //DbgPrint("PrefixTable = %08lx\n", PrefixTable);
  473. //DbgPrint("Node = %08lx\n", Node);
  474. //DbgPrint("CurrentTree = %08lx\n", CurrentTree);
  475. //DbgPrint("PreviousTree = %08lx\n", PreviousTree);
  476. //DbgBreakPoint();
  477. //
  478. // Save a pointer to the next tree, we already have the previous tree
  479. //
  480. NextTree = CurrentTree->NextPrefixTree;
  481. //
  482. // Reset the current root to be an internal node
  483. //
  484. CurrentTree->NodeTypeCode = RTL_NTC_INTERNAL;
  485. CurrentTree->NextPrefixTree = NULL;
  486. //
  487. // Splay the tree and get the root
  488. //
  489. Node = CONTAINING_RECORD(RtlSplay(&Node->Links), PREFIX_TABLE_ENTRY, Links);
  490. //
  491. // Set the new root's node type code and make it part of the
  492. // root tree list
  493. //
  494. Node->NodeTypeCode = RTL_NTC_ROOT;
  495. PreviousTree->NextPrefixTree = Node;
  496. Node->NextPrefixTree = NextTree;
  497. }
  498. return Node;
  499. }
  500. }
  501. //
  502. // This tree is done so now find the next tree
  503. //
  504. PreviousTree = CurrentTree;
  505. CurrentTree = CurrentTree->NextPrefixTree;
  506. }
  507. //
  508. // We sesarched everywhere and didn't find a prefix so tell the
  509. // caller none was found
  510. //
  511. return NULL;
  512. }
  513. CLONG
  514. ComputeNameLength(
  515. IN PSTRING Name
  516. )
  517. /*++
  518. Routine Description:
  519. This routine counts the number of names appearing in the input string.
  520. It does this by simply counting the number of backslashes in the string.
  521. To handle ill-formed names (i.e., names that do not contain a backslash)
  522. this routine really returns the number of backslashes plus 1.
  523. Arguments:
  524. Name - Supplies the input name to examine
  525. Returns Value:
  526. CLONG - the number of names in the input string
  527. --*/
  528. {
  529. ULONG NameLength;
  530. ULONG i;
  531. ULONG Count;
  532. extern const PUSHORT NlsLeadByteInfo; // Lead byte info. for ACP ( nlsxlat.c )
  533. extern BOOLEAN NlsMbCodePageTag;
  534. RTL_PAGED_CODE();
  535. //
  536. // Save the name length, this should make the compiler be able to
  537. // optimize not having to reload the length each time
  538. //
  539. NameLength = Name->Length - 1;
  540. //
  541. // Now loop through the input string counting back slashes
  542. //
  543. if (NlsMbCodePageTag) {
  544. //
  545. // ComputeNameLength() skip DBCS character when counting '\'
  546. //
  547. for (i = 0, Count = 1; i < NameLength; ) {
  548. if (NlsLeadByteInfo[(UCHAR)Name->Buffer[i]]) {
  549. i += 2;
  550. } else {
  551. if (Name->Buffer[i] == '\\') {
  552. Count += 1;
  553. }
  554. i += 1;
  555. }
  556. }
  557. } else {
  558. for (i = 0, Count = 1; i < NameLength; i += 1) {
  559. //
  560. // check for a back slash
  561. //
  562. if (Name->Buffer[i] == '\\') {
  563. Count += 1;
  564. }
  565. }
  566. }
  567. //
  568. // return the number of back slashes we found
  569. //
  570. //DbgPrint("ComputeNameLength(%s) = %x\n", Name->Buffer, Count);
  571. return Count;
  572. }
  573. COMPARISON
  574. CompareNamesCaseSensitive (
  575. IN PSTRING Prefix,
  576. IN PSTRING Name
  577. )
  578. /*++
  579. Routine Description:
  580. This routine takes a prefix string and a full name string and determines
  581. if the prefix string is a proper prefix of the name string (case sensitive)
  582. Arguments:
  583. Prefix - Supplies the input prefix string
  584. Name - Supplies the full name input string
  585. Return Value:
  586. COMPARISON - returns
  587. IsLessThan if Prefix < Name lexicalgraphically,
  588. IsPrefix if Prefix is a proper prefix of Name
  589. IsEqual if Prefix is equal to Name, and
  590. IsGreaterThan if Prefix > Name lexicalgraphically
  591. --*/
  592. {
  593. ULONG PrefixLength;
  594. ULONG NameLength;
  595. ULONG MinLength;
  596. ULONG i;
  597. UCHAR PrefixChar;
  598. UCHAR NameChar;
  599. extern const PUSHORT NlsLeadByteInfo; // Lead byte info. for ACP ( nlsxlat.c )
  600. extern BOOLEAN NlsMbCodePageTag;
  601. RTL_PAGED_CODE();
  602. //DbgPrint("CompareNamesCaseSensitive(\"%s\", \"%s\") = ", Prefix->Buffer, Name->Buffer);
  603. //
  604. // Save the length of the prefix and name string, this should allow
  605. // the compiler to not need to reload the length through a pointer every
  606. // time we need their values
  607. //
  608. PrefixLength = Prefix->Length;
  609. NameLength = Name->Length;
  610. //
  611. // Special case the situation where the prefix string is simply "\" and
  612. // the name starts with an "\"
  613. //
  614. if ((Prefix->Length == 1) && (Prefix->Buffer[0] == '\\') &&
  615. (Name->Length > 1) && (Name->Buffer[0] == '\\')) {
  616. //DbgPrint("IsPrefix\n");
  617. return IsPrefix;
  618. }
  619. //
  620. // Figure out the minimum of the two lengths
  621. //
  622. MinLength = (PrefixLength < NameLength ? PrefixLength : NameLength);
  623. //
  624. // Loop through looking at all of the characters in both strings
  625. // testing for equalilty, less than, and greater than
  626. //
  627. i = (ULONG) RtlCompareMemory( &Prefix->Buffer[0], &Name->Buffer[0], MinLength );
  628. if (i < MinLength) {
  629. UCHAR c;
  630. //
  631. // Get both characters to examine and keep their case
  632. //
  633. PrefixChar = ((c = Prefix->Buffer[i]) == '\\' ? (CHAR)0 : c);
  634. NameChar = ((c = Name->Buffer[i]) == '\\' ? (CHAR)0 : c);
  635. //
  636. // Unfortunately life is not so easy in DBCS land.
  637. //
  638. if (NlsMbCodePageTag) {
  639. //
  640. // CompareNamesCaseSensitive(): check backslash in trailing bytes
  641. //
  642. if (Prefix->Buffer[i] == '\\') {
  643. ULONG j;
  644. extern const PUSHORT NlsLeadByteInfo; // Lead byte info. for ACP ( nlsxlat.c )
  645. for (j = 0; j < i;) {
  646. j += NlsLeadByteInfo[(UCHAR)Prefix->Buffer[j]] ? 2 : 1;
  647. }
  648. if (j != i) {
  649. PrefixChar = '\\';
  650. //DbgPrint("RTL:CompareNamesCaseSensitive encountered a fake backslash!\n");
  651. }
  652. }
  653. if (Name->Buffer[i] == '\\') {
  654. ULONG j;
  655. extern const PUSHORT NlsLeadByteInfo; // Lead byte info. for ACP ( nlsxlat.c )
  656. for (j = 0; j < i;) {
  657. j += NlsLeadByteInfo[(UCHAR)Name->Buffer[j]] ? 2 : 1;
  658. }
  659. if (j != i) {
  660. NameChar = '\\';
  661. //DbgPrint("RTL:CompareNamesCaseSensitive encountered a fake backslash!\n");
  662. }
  663. }
  664. }
  665. //
  666. // Now compare the characters
  667. //
  668. if (PrefixChar < NameChar) {
  669. return IsLessThan;
  670. } else if (PrefixChar > NameChar) {
  671. return IsGreaterThan;
  672. }
  673. }
  674. //
  675. // They match upto the minimum length so now figure out the largest string
  676. // and see if one is a proper prefix of the other
  677. //
  678. if (PrefixLength < NameLength) {
  679. //
  680. // The prefix string is shorter so if it is a proper prefix we
  681. // return prefix otherwise we return less than (e.g., "\a" < "\ab")
  682. //
  683. if (Name->Buffer[PrefixLength] == '\\') {
  684. return IsPrefix;
  685. } else {
  686. return IsLessThan;
  687. }
  688. } else if (PrefixLength > NameLength) {
  689. //
  690. // The Prefix string is longer so we say that the prefix is
  691. // greater than the name (e.g., "\ab" > "\a")
  692. //
  693. return IsGreaterThan;
  694. } else {
  695. //
  696. // They lengths are equal so the strings are equal
  697. //
  698. return IsEqual;
  699. }
  700. }
  701. //
  702. // The node type codes for the prefix data structures
  703. //
  704. #define RTL_NTC_UNICODE_PREFIX_TABLE ((CSHORT)0x0800)
  705. #define RTL_NTC_UNICODE_ROOT ((CSHORT)0x0801)
  706. #define RTL_NTC_UNICODE_INTERNAL ((CSHORT)0x0802)
  707. #define RTL_NTC_UNICODE_CASE_MATCH ((CSHORT)0x0803)
  708. VOID
  709. RtlInitializeUnicodePrefix (
  710. IN PUNICODE_PREFIX_TABLE PrefixTable
  711. )
  712. /*++
  713. Routine Description:
  714. This routine initializes a unicode prefix table record to the empty state.
  715. Arguments:
  716. PrefixTable - Supplies the prefix table being initialized
  717. Return Value:
  718. None.
  719. --*/
  720. {
  721. RTL_PAGED_CODE();
  722. PrefixTable->NodeTypeCode = RTL_NTC_UNICODE_PREFIX_TABLE;
  723. PrefixTable->NameLength = 0;
  724. PrefixTable->NextPrefixTree = (PUNICODE_PREFIX_TABLE_ENTRY)PrefixTable;
  725. PrefixTable->LastNextEntry = NULL;
  726. //
  727. // return to our caller
  728. //
  729. return;
  730. }
  731. BOOLEAN
  732. RtlInsertUnicodePrefix (
  733. IN PUNICODE_PREFIX_TABLE PrefixTable,
  734. IN PUNICODE_STRING Prefix,
  735. IN PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry
  736. )
  737. /*++
  738. Routine Description:
  739. This routine inserts a new unicode prefix into the specified prefix table
  740. Arguments:
  741. PrefixTable - Supplies the target prefix table
  742. Prefix - Supplies the string to be inserted in the prefix table
  743. PrefixTableEntry - Supplies the entry to use to insert the prefix
  744. Return Value:
  745. BOOLEAN - TRUE if the Prefix is not already in the table, and FALSE
  746. otherwise
  747. --*/
  748. {
  749. ULONG PrefixNameLength;
  750. PUNICODE_PREFIX_TABLE_ENTRY PreviousTree;
  751. PUNICODE_PREFIX_TABLE_ENTRY CurrentTree;
  752. PUNICODE_PREFIX_TABLE_ENTRY NextTree;
  753. PUNICODE_PREFIX_TABLE_ENTRY Node;
  754. COMPARISON Comparison;
  755. RTL_PAGED_CODE();
  756. //
  757. // Determine the name length of the input string
  758. //
  759. PrefixNameLength = ComputeUnicodeNameLength(Prefix);
  760. //
  761. // Setup parts of the prefix table entry that we will always need
  762. //
  763. PrefixTableEntry->NameLength = (CSHORT)PrefixNameLength;
  764. PrefixTableEntry->Prefix = Prefix;
  765. RtlInitializeSplayLinks(&PrefixTableEntry->Links);
  766. //
  767. // find the corresponding tree, or find where the tree should go
  768. //
  769. PreviousTree = (PUNICODE_PREFIX_TABLE_ENTRY)PrefixTable;
  770. CurrentTree = PreviousTree->NextPrefixTree;
  771. while (CurrentTree->NameLength > (CSHORT)PrefixNameLength) {
  772. PreviousTree = CurrentTree;
  773. CurrentTree = CurrentTree->NextPrefixTree;
  774. }
  775. //
  776. // If the name length of the current tree is not equal to the
  777. // prefix name length then the tree does not exist and we need
  778. // to make a new tree node.
  779. //
  780. if (CurrentTree->NameLength != (CSHORT)PrefixNameLength) {
  781. //
  782. // Insert the new prefix entry to the list between
  783. // previous and current tree
  784. //
  785. PreviousTree->NextPrefixTree = PrefixTableEntry;
  786. PrefixTableEntry->NextPrefixTree = CurrentTree;
  787. //
  788. // And set the node type code, case match for the root tree node
  789. //
  790. PrefixTableEntry->NodeTypeCode = RTL_NTC_UNICODE_ROOT;
  791. PrefixTableEntry->CaseMatch = PrefixTableEntry;
  792. //
  793. // And tell our caller everything worked fine
  794. //
  795. return TRUE;
  796. }
  797. //
  798. // The tree does exist so now search the tree for our
  799. // position in it. We only exit the loop if we've inserted
  800. // a new node, and node is left is left pointing to the
  801. // tree position
  802. //
  803. Node = CurrentTree;
  804. while (TRUE) {
  805. //
  806. // Compare the prefix in the tree with the prefix we want
  807. // to insert. Do the compare case blind
  808. //
  809. Comparison = CompareUnicodeStrings(Node->Prefix, Prefix, 0);
  810. //
  811. // If they are equal then this node gets added as a case
  812. // match, provided it doesn't case sensitive match anyone
  813. //
  814. if (Comparison == IsEqual) {
  815. PUNICODE_PREFIX_TABLE_ENTRY Next;
  816. //
  817. // Loop through the case match list checking to see if we
  818. // match case sensitive with anyone. Get the first node
  819. //
  820. Next = Node;
  821. //
  822. // And loop checking each node until we're back to where
  823. // we started
  824. //
  825. do {
  826. //
  827. // If we do match case sensitive then we cannot add
  828. // this prefix so we return false. Note this is the
  829. // only condition where we return false
  830. //
  831. if (CompareUnicodeStrings(Next->Prefix, Prefix, MAXULONG) == IsEqual) {
  832. return FALSE;
  833. }
  834. //
  835. // Get the next node in the case match list
  836. //
  837. Next = Next->CaseMatch;
  838. //
  839. // And continue looping until we're back where we started
  840. //
  841. } while ( Next != Node );
  842. //
  843. // We've searched the case match and didn't find an exact match
  844. // so we can insert this node in the case match list
  845. //
  846. PrefixTableEntry->NodeTypeCode = RTL_NTC_UNICODE_CASE_MATCH;
  847. PrefixTableEntry->NextPrefixTree = NULL;
  848. PrefixTableEntry->CaseMatch = Node->CaseMatch;
  849. Node->CaseMatch = PrefixTableEntry;
  850. //
  851. // And exit out of the while loop
  852. //
  853. break;
  854. }
  855. //
  856. // If the tree prefix is greater than the new prefix then
  857. // we go down the left subtree
  858. //
  859. if (Comparison == IsGreaterThan) {
  860. //
  861. // We want to go down the left subtree, first check to see
  862. // if we have a left subtree
  863. //
  864. if (RtlLeftChild(&Node->Links) == NULL) {
  865. //
  866. // there isn't a left child so we insert ourselves as the
  867. // new left child
  868. //
  869. PrefixTableEntry->NodeTypeCode = RTL_NTC_UNICODE_INTERNAL;
  870. PrefixTableEntry->NextPrefixTree = NULL;
  871. PrefixTableEntry->CaseMatch = PrefixTableEntry;
  872. RtlInsertAsLeftChild(&Node->Links, &PrefixTableEntry->Links);
  873. //
  874. // and exit the while loop
  875. //
  876. break;
  877. } else {
  878. //
  879. // there is a left child so simply go down that path, and
  880. // go back to the top of the loop
  881. //
  882. Node = CONTAINING_RECORD( RtlLeftChild(&Node->Links),
  883. UNICODE_PREFIX_TABLE_ENTRY,
  884. Links );
  885. }
  886. } else {
  887. //
  888. // The tree prefix is either less than or a proper prefix
  889. // of the new string. We treat both cases a less than when
  890. // we do insert. So we want to go down the right subtree,
  891. // first check to see if we have a right subtree
  892. //
  893. if (RtlRightChild(&Node->Links) == NULL) {
  894. //
  895. // These isn't a right child so we insert ourselves as the
  896. // new right child
  897. //
  898. PrefixTableEntry->NodeTypeCode = RTL_NTC_UNICODE_INTERNAL;
  899. PrefixTableEntry->NextPrefixTree = NULL;
  900. PrefixTableEntry->CaseMatch = PrefixTableEntry;
  901. RtlInsertAsRightChild(&Node->Links, &PrefixTableEntry->Links);
  902. //
  903. // and exit the while loop
  904. //
  905. break;
  906. } else {
  907. //
  908. // there is a right child so simply go down that path, and
  909. // go back to the top of the loop
  910. //
  911. Node = CONTAINING_RECORD( RtlRightChild(&Node->Links),
  912. UNICODE_PREFIX_TABLE_ENTRY,
  913. Links );
  914. }
  915. }
  916. }
  917. //
  918. // Now that we've inserted the new node we can splay the tree.
  919. // To do this we need to remember how we find this tree in the root
  920. // tree list, set the root to be an internal, splay, the tree, and
  921. // then setup the new root node. Note: we cannot splay the prefix table
  922. // entry because it might be a case match node so we only splay
  923. // the Node variable, which for case match insertions is the
  924. // internal node for the case match and for non-case match insertions
  925. // the Node variable is the parent node.
  926. //
  927. //
  928. // Save a pointer to the next tree, we already have the previous tree
  929. //
  930. NextTree = CurrentTree->NextPrefixTree;
  931. //
  932. // Reset the current root to be an internal node
  933. //
  934. CurrentTree->NodeTypeCode = RTL_NTC_UNICODE_INTERNAL;
  935. CurrentTree->NextPrefixTree = NULL;
  936. //
  937. // Splay the tree and get the root
  938. //
  939. Node = CONTAINING_RECORD(RtlSplay(&Node->Links), UNICODE_PREFIX_TABLE_ENTRY, Links);
  940. //
  941. // Set the new root's node type code and make it part of the
  942. // root tree list
  943. //
  944. Node->NodeTypeCode = RTL_NTC_UNICODE_ROOT;
  945. PreviousTree->NextPrefixTree = Node;
  946. Node->NextPrefixTree = NextTree;
  947. //
  948. // tell our caller everything worked fine
  949. //
  950. return TRUE;
  951. }
  952. VOID
  953. RtlRemoveUnicodePrefix (
  954. IN PUNICODE_PREFIX_TABLE PrefixTable,
  955. IN PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry
  956. )
  957. /*++
  958. Routine Description:
  959. This routine removes the indicated prefix table entry from
  960. the prefix table
  961. Arguments:
  962. PrefixTable - Supplies the prefix table affected
  963. PrefixTableEntry - Supplies the prefix entry to remove
  964. Return Value:
  965. None.
  966. --*/
  967. {
  968. PUNICODE_PREFIX_TABLE_ENTRY PreviousCaseMatch;
  969. PRTL_SPLAY_LINKS Links;
  970. PUNICODE_PREFIX_TABLE_ENTRY Root;
  971. PUNICODE_PREFIX_TABLE_ENTRY NewRoot;
  972. PUNICODE_PREFIX_TABLE_ENTRY PreviousTree;
  973. RTL_PAGED_CODE();
  974. //
  975. // Wipe out the next last entry field of the prefix table
  976. //
  977. PrefixTable->LastNextEntry = NULL;
  978. //
  979. // case on the type of node that we are trying to delete
  980. //
  981. switch (PrefixTableEntry->NodeTypeCode) {
  982. case RTL_NTC_UNICODE_CASE_MATCH:
  983. //
  984. // The prefix entry is a case match record so
  985. // we only need to remove it from the case match list.
  986. // Locate the previous PrefixTableEntry that reference this
  987. // case match record
  988. //
  989. PreviousCaseMatch = PrefixTableEntry->CaseMatch;
  990. while ( PreviousCaseMatch->CaseMatch != PrefixTableEntry ) {
  991. PreviousCaseMatch = PreviousCaseMatch->CaseMatch;
  992. }
  993. //
  994. // Now that we have the previous record just have it point
  995. // around the case match that is being deleted
  996. //
  997. PreviousCaseMatch->CaseMatch = PrefixTableEntry->CaseMatch;
  998. //
  999. // And return to our caller
  1000. //
  1001. return;
  1002. case RTL_NTC_UNICODE_INTERNAL:
  1003. case RTL_NTC_UNICODE_ROOT:
  1004. //
  1005. // The prefix entry is an internal/root node so check to see if it
  1006. // has any case match nodes with it
  1007. //
  1008. if (PrefixTableEntry->CaseMatch != PrefixTableEntry) {
  1009. //
  1010. // There is at least one case match that goes with this
  1011. // node, so we need to make the next case match the
  1012. // new node and remove this node.
  1013. // Locate the previous prefix table entry that references this
  1014. // case match record
  1015. //
  1016. PreviousCaseMatch = PrefixTableEntry->CaseMatch;
  1017. while ( PreviousCaseMatch->CaseMatch != PrefixTableEntry ) {
  1018. PreviousCaseMatch = PreviousCaseMatch->CaseMatch;
  1019. }
  1020. //
  1021. // Now that we have the previous record just have it point
  1022. // around the node being deleted
  1023. //
  1024. PreviousCaseMatch->CaseMatch = PrefixTableEntry->CaseMatch;
  1025. //
  1026. // Now make the previous case match in the new node
  1027. //
  1028. PreviousCaseMatch->NodeTypeCode = PrefixTableEntry->NodeTypeCode;
  1029. PreviousCaseMatch->NextPrefixTree = PrefixTableEntry->NextPrefixTree;
  1030. PreviousCaseMatch->Links = PrefixTableEntry->Links;
  1031. //
  1032. // Now take care of the back pointers to this new internal
  1033. // node in the splay tree, first do the parent's pointer to us.
  1034. //
  1035. if (RtlIsRoot(&PrefixTableEntry->Links)) {
  1036. //
  1037. // This is the root so make this new node the root
  1038. //
  1039. PreviousCaseMatch->Links.Parent = &PreviousCaseMatch->Links;
  1040. //
  1041. // Fix up the root tree list, by first finding the previous
  1042. // pointer to us
  1043. PreviousTree = PrefixTableEntry->NextPrefixTree;
  1044. while ( PreviousTree->NextPrefixTree != PrefixTableEntry ) {
  1045. PreviousTree = PreviousTree->NextPrefixTree;
  1046. }
  1047. //
  1048. // We've located the previous tree so now have the previous
  1049. // tree point to our new root
  1050. //
  1051. PreviousTree->NextPrefixTree = PreviousCaseMatch;
  1052. } else if (RtlIsLeftChild(&PrefixTableEntry->Links)) {
  1053. //
  1054. // The node was the left child so make the new node the
  1055. // left child
  1056. //
  1057. RtlParent(&PrefixTableEntry->Links)->LeftChild = &PreviousCaseMatch->Links;
  1058. } else {
  1059. //
  1060. // The node was the right child so make the new node the
  1061. // right child
  1062. //
  1063. RtlParent(&PrefixTableEntry->Links)->RightChild = &PreviousCaseMatch->Links;
  1064. }
  1065. //
  1066. // Now update the parent pointer for our new children
  1067. //
  1068. if (RtlLeftChild(&PreviousCaseMatch->Links) != NULL) {
  1069. RtlLeftChild(&PreviousCaseMatch->Links)->Parent = &PreviousCaseMatch->Links;
  1070. }
  1071. if (RtlRightChild(&PreviousCaseMatch->Links) != NULL) {
  1072. RtlRightChild(&PreviousCaseMatch->Links)->Parent = &PreviousCaseMatch->Links;
  1073. }
  1074. //
  1075. // And return to our caller
  1076. //
  1077. return;
  1078. }
  1079. //
  1080. // The node is internal or root node and does not have any case match
  1081. // nodes so we need to delete it from the tree, but first find
  1082. // the root of the tree
  1083. //
  1084. Links = &PrefixTableEntry->Links;
  1085. while (!RtlIsRoot(Links)) {
  1086. Links = RtlParent(Links);
  1087. }
  1088. Root = CONTAINING_RECORD( Links, UNICODE_PREFIX_TABLE_ENTRY, Links );
  1089. //
  1090. // Now delete the node
  1091. //
  1092. Links = RtlDelete(&PrefixTableEntry->Links);
  1093. //
  1094. // Now see if the tree is deleted
  1095. //
  1096. if (Links == NULL) {
  1097. //
  1098. // The tree is now empty so remove this tree from
  1099. // the tree list, by first finding the previous tree that
  1100. // references us
  1101. //
  1102. PreviousTree = Root->NextPrefixTree;
  1103. while ( PreviousTree->NextPrefixTree != Root ) {
  1104. PreviousTree = PreviousTree->NextPrefixTree;
  1105. }
  1106. //
  1107. // We've located the previous tree so now just have it
  1108. // point around the deleted node
  1109. //
  1110. PreviousTree->NextPrefixTree = Root->NextPrefixTree;
  1111. //
  1112. // and return the our caller
  1113. //
  1114. return;
  1115. }
  1116. //
  1117. // The tree is not deleted but see if we changed roots
  1118. //
  1119. if (&Root->Links != Links) {
  1120. //
  1121. // Get a pointer to the new root
  1122. //
  1123. NewRoot = CONTAINING_RECORD(Links, UNICODE_PREFIX_TABLE_ENTRY, Links);
  1124. //
  1125. // We changed root so we better need to make the new
  1126. // root part of the prefix data structure, by
  1127. // first finding the previous tree that
  1128. // references us
  1129. //
  1130. PreviousTree = Root->NextPrefixTree;
  1131. while ( PreviousTree->NextPrefixTree != Root ) {
  1132. PreviousTree = PreviousTree->NextPrefixTree;
  1133. }
  1134. //
  1135. // Set the new root
  1136. //
  1137. NewRoot->NodeTypeCode = RTL_NTC_UNICODE_ROOT;
  1138. PreviousTree->NextPrefixTree = NewRoot;
  1139. NewRoot->NextPrefixTree = Root->NextPrefixTree;
  1140. //
  1141. // Set the old root to be an internal node
  1142. //
  1143. Root->NodeTypeCode = RTL_NTC_UNICODE_INTERNAL;
  1144. Root->NextPrefixTree = NULL;
  1145. //
  1146. // And return to our caller
  1147. //
  1148. return;
  1149. }
  1150. //
  1151. // We didn't change roots so everything is fine and we can
  1152. // simply return to our caller
  1153. //
  1154. return;
  1155. default:
  1156. //
  1157. // If we get here then there was an error and the node type
  1158. // code is unknown
  1159. //
  1160. return;
  1161. }
  1162. }
  1163. PUNICODE_PREFIX_TABLE_ENTRY
  1164. RtlFindUnicodePrefix (
  1165. IN PUNICODE_PREFIX_TABLE PrefixTable,
  1166. IN PUNICODE_STRING FullName,
  1167. IN ULONG CaseInsensitiveIndex
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. This routine finds if a full name has a prefix in a prefix table.
  1172. It returns a pointer to the largest proper prefix found if one exists.
  1173. Arguments:
  1174. PrefixTable - Supplies the prefix table to search
  1175. FullString - Supplies the name to search for
  1176. CaseInsensitiveIndex - Indicates the wchar index at which to do a case
  1177. insensitive search. All characters before the index are searched
  1178. case sensitive and all characters at and after the index are searched
  1179. insensitive.
  1180. Return Value:
  1181. PPREFIX_TABLE_ENTRY - a pointer to the longest prefix found if one
  1182. exists, and NULL otherwise
  1183. --*/
  1184. {
  1185. CLONG NameLength;
  1186. PUNICODE_PREFIX_TABLE_ENTRY PreviousTree;
  1187. PUNICODE_PREFIX_TABLE_ENTRY CurrentTree;
  1188. PUNICODE_PREFIX_TABLE_ENTRY NextTree;
  1189. PRTL_SPLAY_LINKS Links;
  1190. PUNICODE_PREFIX_TABLE_ENTRY Node;
  1191. PUNICODE_PREFIX_TABLE_ENTRY Next;
  1192. COMPARISON Comparison;
  1193. RTL_PAGED_CODE();
  1194. //
  1195. // Determine the name length of the input string
  1196. //
  1197. NameLength = ComputeUnicodeNameLength(FullName);
  1198. //
  1199. // Locate the first tree that can contain a prefix
  1200. //
  1201. PreviousTree = (PUNICODE_PREFIX_TABLE_ENTRY)PrefixTable;
  1202. CurrentTree = PreviousTree->NextPrefixTree;
  1203. while (CurrentTree->NameLength > (CSHORT)NameLength) {
  1204. PreviousTree = CurrentTree;
  1205. CurrentTree = CurrentTree->NextPrefixTree;
  1206. }
  1207. //
  1208. // Now search for a prefix until we find one or until we exhaust
  1209. // the prefix trees
  1210. //
  1211. while (CurrentTree->NameLength > 0) {
  1212. Links = &CurrentTree->Links;
  1213. while (Links != NULL) {
  1214. Node = CONTAINING_RECORD(Links, UNICODE_PREFIX_TABLE_ENTRY, Links);
  1215. //
  1216. // Compare the prefix in the tree with the full name, do the
  1217. // compare case blind
  1218. //
  1219. Comparison = CompareUnicodeStrings(Node->Prefix, FullName, 0);
  1220. //
  1221. // See if they don't match
  1222. //
  1223. if (Comparison == IsGreaterThan) {
  1224. //
  1225. // The prefix is greater than the full name
  1226. // so we go down the left child
  1227. //
  1228. Links = RtlLeftChild(Links);
  1229. //
  1230. // And continue searching down this tree
  1231. //
  1232. } else if (Comparison == IsLessThan) {
  1233. //
  1234. // The prefix is less than the full name
  1235. // so we go down the right child
  1236. //
  1237. Links = RtlRightChild(Links);
  1238. //
  1239. // And continue searching down this tree
  1240. //
  1241. } else {
  1242. //
  1243. // We have either a prefix or a match either way
  1244. // we need to check if we should do case sensitive
  1245. // seearches
  1246. //
  1247. if (CaseInsensitiveIndex == 0) {
  1248. //
  1249. // The caller wants case insensitive so we'll
  1250. // return the first one we found
  1251. //
  1252. // Now that we've located the node we can splay the tree.
  1253. // To do this we need to remember how we find this tree in the root
  1254. // tree list, set the root to be an internal, splay, the tree, and
  1255. // then setup the new root node.
  1256. //
  1257. if (Node->NodeTypeCode == RTL_NTC_UNICODE_INTERNAL) {
  1258. //DbgPrint("PrefixTable = %08lx\n", PrefixTable);
  1259. //DbgPrint("Node = %08lx\n", Node);
  1260. //DbgPrint("CurrentTree = %08lx\n", CurrentTree);
  1261. //DbgPrint("PreviousTree = %08lx\n", PreviousTree);
  1262. //DbgBreakPoint();
  1263. //
  1264. // Save a pointer to the next tree, we already have the previous tree
  1265. //
  1266. NextTree = CurrentTree->NextPrefixTree;
  1267. //
  1268. // Reset the current root to be an internal node
  1269. //
  1270. CurrentTree->NodeTypeCode = RTL_NTC_UNICODE_INTERNAL;
  1271. CurrentTree->NextPrefixTree = NULL;
  1272. //
  1273. // Splay the tree and get the root
  1274. //
  1275. Node = CONTAINING_RECORD(RtlSplay(&Node->Links), UNICODE_PREFIX_TABLE_ENTRY, Links);
  1276. //
  1277. // Set the new root's node type code and make it part of the
  1278. // root tree list
  1279. //
  1280. Node->NodeTypeCode = RTL_NTC_UNICODE_ROOT;
  1281. PreviousTree->NextPrefixTree = Node;
  1282. Node->NextPrefixTree = NextTree;
  1283. }
  1284. //
  1285. // Now return the root to our caller
  1286. //
  1287. return Node;
  1288. }
  1289. //
  1290. // The caller wants an exact match so search the case match
  1291. // until we find a complete match. Get the first node
  1292. //
  1293. Next = Node;
  1294. //
  1295. // Loop through the case match list checking to see if we
  1296. // match case sensitive with anyone.
  1297. //
  1298. do {
  1299. //
  1300. // If we do match case sensitive then we found one
  1301. // and we return it to our caller
  1302. //
  1303. Comparison = CompareUnicodeStrings( Next->Prefix,
  1304. FullName,
  1305. CaseInsensitiveIndex );
  1306. if ((Comparison == IsEqual) || (Comparison == IsPrefix)) {
  1307. //
  1308. // We found a good one, so return it to our caller
  1309. //
  1310. return Next;
  1311. }
  1312. //
  1313. // Get the next case match record
  1314. //
  1315. Next = Next->CaseMatch;
  1316. //
  1317. // And continue the loop until we reach the original
  1318. // node again
  1319. //
  1320. } while ( Next != Node );
  1321. //
  1322. // We found a case blind prefix but the caller wants
  1323. // case sensitive and we weren't able to find one of those
  1324. // so we need to go on to the next tree, by breaking out
  1325. // of the inner while-loop
  1326. //
  1327. break;
  1328. }
  1329. }
  1330. //
  1331. // This tree is done so now find the next tree
  1332. //
  1333. PreviousTree = CurrentTree;
  1334. CurrentTree = CurrentTree->NextPrefixTree;
  1335. }
  1336. //
  1337. // We sesarched everywhere and didn't find a prefix so tell the
  1338. // caller none was found
  1339. //
  1340. return NULL;
  1341. }
  1342. PUNICODE_PREFIX_TABLE_ENTRY
  1343. RtlNextUnicodePrefix (
  1344. IN PUNICODE_PREFIX_TABLE PrefixTable,
  1345. IN BOOLEAN Restart
  1346. )
  1347. /*++
  1348. Routine Description:
  1349. This routine returns the next prefix entry stored in the prefix table
  1350. Arguments:
  1351. PrefixTable - Supplies the prefix table to enumerate
  1352. Restart - Indicates if the enumeration should start over
  1353. Return Value:
  1354. PPREFIX_TABLE_ENTRY - A pointer to the next prefix table entry if
  1355. one exists otherwise NULL
  1356. --*/
  1357. {
  1358. PUNICODE_PREFIX_TABLE_ENTRY Node;
  1359. PRTL_SPLAY_LINKS Links;
  1360. RTL_PAGED_CODE();
  1361. //
  1362. // See if we are restarting the sequence
  1363. //
  1364. if (Restart || (PrefixTable->LastNextEntry == NULL)) {
  1365. //
  1366. // we are restarting the sequence so locate the first entry
  1367. // in the first tree
  1368. //
  1369. Node = PrefixTable->NextPrefixTree;
  1370. //
  1371. // Make sure we've pointing at a prefix tree
  1372. //
  1373. if (Node->NodeTypeCode == RTL_NTC_UNICODE_PREFIX_TABLE) {
  1374. //
  1375. // No we aren't so the table must be empty
  1376. //
  1377. return NULL;
  1378. }
  1379. //
  1380. // Find the first node in the tree
  1381. //
  1382. Links = &Node->Links;
  1383. while (RtlLeftChild(Links) != NULL) {
  1384. Links = RtlLeftChild(Links);
  1385. }
  1386. //
  1387. // Set it as our the node we're returning
  1388. //
  1389. Node = CONTAINING_RECORD( Links, UNICODE_PREFIX_TABLE_ENTRY, Links);
  1390. } else if (PrefixTable->LastNextEntry->CaseMatch->NodeTypeCode == RTL_NTC_UNICODE_CASE_MATCH) {
  1391. //
  1392. // The last node has a case match that we should be returning
  1393. // this time around
  1394. //
  1395. Node = PrefixTable->LastNextEntry->CaseMatch;
  1396. } else {
  1397. //
  1398. // Move over the last node returned by the case match link, this
  1399. // will enable us to finish off the last case match node if there
  1400. // was one, and go to the next internal/root node. If this node
  1401. // does not have a case match then we simply circle back to ourselves
  1402. //
  1403. Node = PrefixTable->LastNextEntry->CaseMatch;
  1404. //
  1405. // Find the successor for the last node we returned
  1406. //
  1407. Links = RtlRealSuccessor(&Node->Links);
  1408. //
  1409. // If links is null then we've exhausted this tree and need to
  1410. // the the next tree to use
  1411. //
  1412. if (Links == NULL) {
  1413. Links = &PrefixTable->LastNextEntry->Links;
  1414. while (!RtlIsRoot(Links)) {
  1415. Links = RtlParent(Links);
  1416. }
  1417. Node = CONTAINING_RECORD(Links, UNICODE_PREFIX_TABLE_ENTRY, Links);
  1418. //
  1419. // Now we've found the root see if there is another
  1420. // tree to enumerate
  1421. //
  1422. Node = Node->NextPrefixTree;
  1423. if (Node->NameLength <= 0) {
  1424. //
  1425. // We've run out of tree so tell our caller there
  1426. // are no more
  1427. //
  1428. return NULL;
  1429. }
  1430. //
  1431. // We have another tree to go down
  1432. //
  1433. Links = &Node->Links;
  1434. while (RtlLeftChild(Links) != NULL) {
  1435. Links = RtlLeftChild(Links);
  1436. }
  1437. }
  1438. //
  1439. // Set it as our the node we're returning
  1440. //
  1441. Node = CONTAINING_RECORD( Links, UNICODE_PREFIX_TABLE_ENTRY, Links);
  1442. }
  1443. //
  1444. // Save node as the last next entry
  1445. //
  1446. PrefixTable->LastNextEntry = Node;
  1447. //
  1448. // And return this entry to our caller
  1449. //
  1450. return Node;
  1451. }
  1452. CLONG
  1453. ComputeUnicodeNameLength(
  1454. IN PUNICODE_STRING Name
  1455. )
  1456. /*++
  1457. Routine Description:
  1458. This routine counts the number of names appearing in the input string.
  1459. It does this by simply counting the number of backslashes in the string.
  1460. To handle ill-formed names (i.e., names that do not contain a backslash)
  1461. this routine really returns the number of backslashes plus 1.
  1462. Arguments:
  1463. Name - Supplies the input name to examine
  1464. Returns Value:
  1465. CLONG - the number of names in the input string
  1466. --*/
  1467. {
  1468. WCHAR UnicodeBackSlash = '\\';
  1469. ULONG NameLength;
  1470. ULONG i;
  1471. ULONG Count;
  1472. RTL_PAGED_CODE();
  1473. //
  1474. // Save the name length, this should make the compiler be able to
  1475. // optimize not having to reload the length each time
  1476. //
  1477. NameLength = (ULONG)Name->Length/sizeof (WCHAR);
  1478. if (NameLength == 0) {
  1479. return 1;
  1480. }
  1481. //
  1482. // Now loop through the input string counting back slashes
  1483. //
  1484. for (i = 0, Count = 1; i < NameLength - 1; i += 1) {
  1485. //
  1486. // check for a back slash
  1487. //
  1488. if (Name->Buffer[i] == UnicodeBackSlash) {
  1489. Count += 1;
  1490. }
  1491. }
  1492. //
  1493. // return the number of back slashes we found
  1494. //
  1495. //DbgPrint("ComputeUnicodeNameLength(%Z) = %x\n", Name, Count);
  1496. return Count;
  1497. }
  1498. COMPARISON
  1499. CompareUnicodeStrings (
  1500. IN PUNICODE_STRING Prefix,
  1501. IN PUNICODE_STRING Name,
  1502. IN ULONG CaseInsensitiveIndex
  1503. )
  1504. /*++
  1505. Routine Description:
  1506. This routine takes a prefix string and a full name string and determines
  1507. if the prefix string is a proper prefix of the name string (case sensitive)
  1508. Arguments:
  1509. Prefix - Supplies the input prefix string
  1510. Name - Supplies the full name input string
  1511. CaseInsensitiveIndex - Indicates the wchar index at which to do a case
  1512. insensitive search. All characters before the index are searched
  1513. case sensitive and all characters at and after the index are searched
  1514. Return Value:
  1515. COMPARISON - returns
  1516. IsLessThan if Prefix < Name lexicalgraphically,
  1517. IsPrefix if Prefix is a proper prefix of Name
  1518. IsEqual if Prefix is equal to Name, and
  1519. IsGreaterThan if Prefix > Name lexicalgraphically
  1520. --*/
  1521. {
  1522. WCHAR UnicodeBackSlash = '\\';
  1523. ULONG PrefixLength;
  1524. ULONG NameLength;
  1525. ULONG MinLength;
  1526. ULONG i;
  1527. WCHAR PrefixChar;
  1528. WCHAR NameChar;
  1529. RTL_PAGED_CODE();
  1530. //DbgPrint("CompareUnicodeStrings(\"%Z\", \"%Z\") = ", Prefix, Name);
  1531. //
  1532. // Save the length of the prefix and name string, this should allow
  1533. // the compiler to not need to reload the length through a pointer every
  1534. // time we need their values
  1535. //
  1536. PrefixLength = (ULONG)Prefix->Length/2;
  1537. NameLength = (ULONG)Name->Length/2;
  1538. //
  1539. // Special case the situation where the prefix string is simply "\" and
  1540. // the name starts with an "\"
  1541. //
  1542. if ((PrefixLength == 1) && (Prefix->Buffer[0] == UnicodeBackSlash) &&
  1543. (NameLength > 1) && (Name->Buffer[0] == UnicodeBackSlash)) {
  1544. //DbgPrint("IsPrefix\n");
  1545. return IsPrefix;
  1546. }
  1547. //
  1548. // Figure out the minimum of the two lengths
  1549. //
  1550. MinLength = (PrefixLength < NameLength ? PrefixLength : NameLength);
  1551. //
  1552. // Loop through looking at all of the characters in both strings
  1553. // testing for equalilty. First to the CaseSensitive part, then the
  1554. // CaseInsensitive part.
  1555. //
  1556. if (CaseInsensitiveIndex > MinLength) {
  1557. CaseInsensitiveIndex = MinLength;
  1558. }
  1559. //
  1560. // CaseSensitive compare
  1561. //
  1562. for (i = 0; i < CaseInsensitiveIndex; i += 1) {
  1563. PrefixChar = Prefix->Buffer[i];
  1564. NameChar = Name->Buffer[i];
  1565. if (PrefixChar != NameChar) {
  1566. break;
  1567. }
  1568. }
  1569. //
  1570. // If we didn't break out of the above loop, do the
  1571. // CaseInsensitive compare.
  1572. //
  1573. if (i == CaseInsensitiveIndex) {
  1574. WCHAR *s1 = &Prefix->Buffer[i];
  1575. WCHAR *s2 = &Name->Buffer[i];
  1576. for (; i < MinLength; i += 1) {
  1577. PrefixChar = *s1++;
  1578. NameChar = *s2++;
  1579. if (PrefixChar != NameChar) {
  1580. PrefixChar = NLS_UPCASE(PrefixChar);
  1581. NameChar = NLS_UPCASE(NameChar);
  1582. if (PrefixChar != NameChar) {
  1583. break;
  1584. }
  1585. }
  1586. }
  1587. }
  1588. //
  1589. // If we broke out of the above loop because of a mismatch, determine
  1590. // the result of the comparison.
  1591. //
  1592. if (i < MinLength) {
  1593. //
  1594. // We also need to treat "\" as less than all other characters, so
  1595. // if the char is a "\" we'll drop it down to a value of zero.
  1596. //
  1597. if (PrefixChar == UnicodeBackSlash) {
  1598. return IsLessThan;
  1599. }
  1600. if (NameChar == UnicodeBackSlash) {
  1601. return IsGreaterThan;
  1602. }
  1603. //
  1604. // Now compare the characters
  1605. //
  1606. if (PrefixChar < NameChar) {
  1607. return IsLessThan;
  1608. } else if (PrefixChar > NameChar) {
  1609. return IsGreaterThan;
  1610. }
  1611. }
  1612. //
  1613. // They match upto the minimum length so now figure out the largest string
  1614. // and see if one is a proper prefix of the other
  1615. //
  1616. if (PrefixLength < NameLength) {
  1617. //
  1618. // The prefix string is shorter so if it is a proper prefix we
  1619. // return prefix otherwise we return less than (e.g., "\a" < "\ab")
  1620. //
  1621. if (Name->Buffer[PrefixLength] == UnicodeBackSlash) {
  1622. //DbgPrint("IsPrefix\n");
  1623. return IsPrefix;
  1624. } else {
  1625. //DbgPrint("IsLessThan\n");
  1626. return IsLessThan;
  1627. }
  1628. } else if (PrefixLength > NameLength) {
  1629. //
  1630. // The Prefix string is longer so we say that the prefix is
  1631. // greater than the name (e.g., "\ab" > "\a")
  1632. //
  1633. //DbgPrint("IsGreaterThan\n");
  1634. return IsGreaterThan;
  1635. } else {
  1636. //
  1637. // They lengths are equal so the strings are equal
  1638. //
  1639. //DbgPrint("IsEqual\n");
  1640. return IsEqual;
  1641. }
  1642. }