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.

2954 lines
63 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. bintree.c
  5. Abstract:
  6. Routines that manage the binary trees in the memdb database
  7. Author:
  8. Matthew Vanderzee (mvander) 13-Aug-1999
  9. --*/
  10. #include "pch.h"
  11. // PORTBUG: Make sure to pick up latest fixes in win9xupg project
  12. //
  13. // Includes
  14. //
  15. #include "memdbp.h"
  16. #include "bintree.h"
  17. //
  18. // Strings
  19. //
  20. // None
  21. //
  22. // Constants
  23. //
  24. #define NODESTRUCT_SIZE_MAIN (4*sizeof(UINT) + sizeof(WORD))
  25. #define BINTREE_SIZE_MAIN sizeof(UINT)
  26. #define LISTELEM_SIZE_MAIN (3*sizeof(UINT))
  27. #ifdef DEBUG
  28. #define NODESTRUCT_HEADER_SIZE (sizeof(DWORD)+sizeof(BOOL))
  29. #define NODESTRUCT_SIZE ((WORD)(NODESTRUCT_SIZE_MAIN + (g_UseDebugStructs ? NODESTRUCT_HEADER_SIZE : 0)))
  30. #define BINTREE_HEADER_SIZE (sizeof(DWORD)+2*sizeof(INT)+sizeof(BOOL))
  31. #define BINTREE_SIZE ((WORD)(BINTREE_SIZE_MAIN + (g_UseDebugStructs ? BINTREE_HEADER_SIZE : 0)))
  32. #define LISTELEM_HEADER_SIZE sizeof(DWORD)
  33. #define LISTELEM_SIZE ((WORD)(LISTELEM_SIZE_MAIN + (g_UseDebugStructs ? LISTELEM_HEADER_SIZE : 0)))
  34. #else
  35. #define NODESTRUCT_SIZE ((WORD)NODESTRUCT_SIZE_MAIN)
  36. #define BINTREE_SIZE ((WORD)BINTREE_SIZE_MAIN)
  37. #define LISTELEM_SIZE ((WORD)LISTELEM_SIZE_MAIN)
  38. #endif
  39. //
  40. // Macros
  41. //
  42. #define MAX(a,b) (a>b ? a : b)
  43. #define ABS(x) (x<0 ? -x : x)
  44. #ifdef DEBUG
  45. //
  46. // if BINTREECHECKTREEBALANCE is true, every addition or deletion
  47. // or rotation checks to make sure tree is balanced and
  48. // correct. this of course take a lot of time.
  49. //
  50. #define BINTREECHECKTREEBALANCE FALSE
  51. #define INITTREENODES(tree) { if (g_UseDebugStructs) { tree->NodeAlloc=0; } }
  52. #define INCTREENODES(tree) { if (g_UseDebugStructs) { tree->NodeAlloc++; } }
  53. #define DECTREENODES(tree) { if (g_UseDebugStructs) { tree->NodeAlloc--; } }
  54. #define TESTTREENODES(tree) { if (g_UseDebugStructs) { MYASSERT(tree->NodeAlloc==0); } }
  55. #define INITTREEELEMS(tree) { if (g_UseDebugStructs) { tree->ElemAlloc=0; } }
  56. #define INCTREEELEMS(tree) { if (g_UseDebugStructs) { tree->ElemAlloc++; } }
  57. #define DECTREEELEMS(tree) { if (g_UseDebugStructs) { tree->ElemAlloc--; } }
  58. #define TESTTREEELEMS(tree) { if (g_UseDebugStructs) { MYASSERT(tree->ElemAlloc==0); } }
  59. #else
  60. #define BINTREECHECKTREEBALANCE
  61. #define INITTREENODES(tree)
  62. #define INCTREENODES(tree)
  63. #define DECTREENODES(tree)
  64. #define TESTTREENODES(tree)
  65. #define INITTREEELEMS(tree)
  66. #define INCTREEELEMS(tree)
  67. #define DECTREEELEMS(tree)
  68. #define TESTTREEELEMS(tree)
  69. #endif
  70. #if defined(DEBUG)
  71. #if BINTREECHECKTREEBALANCE
  72. #define TESTNODETREE(node) MYASSERT(pBinTreeCheckBalance(node));
  73. #define TESTTREE(tree) MYASSERT(pBinTreeCheck(tree));
  74. #else
  75. #define TESTNODETREE(node)
  76. #define TESTTREE(tree)
  77. #endif
  78. #else
  79. #define TESTNODETREE(node)
  80. #define TESTTREE(tree)
  81. #endif
  82. //
  83. // Types
  84. //
  85. typedef struct {
  86. #ifdef DEBUG
  87. DWORD Signature;
  88. BOOL Deleted;
  89. #endif
  90. union {
  91. struct { //for normal nodes
  92. UINT Data; //offset of data structure
  93. UINT Left; //offset of left child
  94. UINT Right; //offset of right child
  95. UINT Parent; //offset of parent
  96. };//lint !e657
  97. struct { //for the InsertionOrdered list header node (tree->Root points to this)
  98. UINT Root; //offset of actual root of tree
  99. UINT Head; //head of insertion ordered list
  100. UINT Tail; //tail of insertion ordered list
  101. };//lint !e657
  102. UINT NextDeleted; //offset of next deleted node
  103. };
  104. struct {
  105. WORD InsertionOrdered : 1; //flag, 1 if insertion-ordered (only really needed
  106. //by enumeration methods, because to save space
  107. //there is no tree pointer in the NODESTRUCT, but
  108. //we need a way for enumeration methods to know if
  109. //node->Data is the offset of the data or the
  110. //offset of a LISTELEM (which it is when we are in
  111. //insertion-ordered mode)).
  112. WORD InsertionHead : 1; //flag, 1 if this node is the head of insertion
  113. //ordered tree.
  114. WORD LeftDepth : 7; //depths of subtrees. these can be 7 bits because
  115. WORD RightDepth : 7; //if depth got up to near 128, the approximate
  116. //number of nodes would be 1e35.
  117. };//lint !e657
  118. } NODESTRUCT, *PNODESTRUCT;
  119. //
  120. // normally, the BINTREE structure simply has the offset
  121. // of the root node of the tree in its Root member. but
  122. // when we are in insertion-ordered mode, we have an extra
  123. // node whose offset is stored in the BINTREE->Root. this
  124. // Header Node points to the head of the insertion-ordered
  125. // linked list, the tail of the list, and the actual root
  126. // of the binary tree.
  127. //
  128. typedef struct {
  129. #ifdef DEBUG
  130. DWORD Signature;
  131. INT NodeAlloc; // counter for number of nodes allocated
  132. INT ElemAlloc; // counter for number of elems allocated
  133. BOOL Deleted; // flag which is TRUE if tree is deleted
  134. #endif
  135. union {
  136. UINT Root; // offset of top level NODESTRUCT
  137. UINT NextDeleted; // offset of next deleted tree
  138. };
  139. } BINTREE, *PBINTREE;
  140. //
  141. // if we are in insertion-ordered mode, that means every
  142. // enumeration will be in the order that we added the
  143. // data. to do this, we use a linked list with the binary
  144. // tree. the data member of the NODESTRUCT holds the
  145. // offset of the LISTELEM structure, and the data member
  146. // of the LISTELEM structure holds the offset of the data.
  147. // To enumerate, we just walk the linked list in order.
  148. //
  149. typedef struct {
  150. #ifdef DEBUG
  151. DWORD Signature;
  152. #endif
  153. union {
  154. struct {
  155. UINT Next; // offset of next element in list
  156. UINT Data; // offset of data structure this element is for
  157. UINT Node; // offset of NODESTRUCT this listelem corresponds to
  158. };//lint !e657
  159. UINT NextDeleted;
  160. };
  161. } LISTELEM, *PLISTELEM;
  162. //
  163. // Globals
  164. //
  165. //
  166. // Macro expansion list
  167. //
  168. // None
  169. //
  170. // Private function prototypes
  171. //
  172. PNODESTRUCT
  173. pBinTreeFindNode (
  174. IN PBINTREE Tree,
  175. IN PCWSTR String
  176. );
  177. PNODESTRUCT
  178. pBinTreeEnumFirst (
  179. IN PBINTREE Tree
  180. );
  181. PNODESTRUCT
  182. pBinTreeEnumNext (
  183. IN OUT PNODESTRUCT CurrentNode
  184. );
  185. PNODESTRUCT
  186. pBinTreeAllocNode (
  187. OUT PUINT Offset
  188. );
  189. PBINTREE
  190. pBinTreeAllocTree (
  191. OUT PUINT Offset
  192. );
  193. PLISTELEM
  194. pBinTreeAllocListElem (
  195. OUT PUINT Offset
  196. );
  197. VOID
  198. pBinTreeFreeNode (
  199. PNODESTRUCT Node
  200. );
  201. VOID
  202. pBinTreeFreeTree (
  203. PBINTREE Tree
  204. );
  205. VOID
  206. pBinTreeFreeListElem (
  207. PLISTELEM Elem
  208. );
  209. VOID
  210. pBinTreeDestroy (
  211. PNODESTRUCT Node,
  212. PBINTREE Tree
  213. );
  214. //
  215. // This starts at node and moves up tree balancing.
  216. // The function stops moving up when it finds a node
  217. // which has no change in depth values and/or no balancing
  218. // to be done. Otherwise, it goes all the way to top.
  219. // Carry TreeOffset through for rotate functions
  220. //
  221. VOID
  222. pBinTreeBalanceUpward (
  223. IN PNODESTRUCT Node,
  224. IN UINT TreeOffset
  225. );
  226. //
  227. // After pBinTreeNodeBalance, parent of node could have incorrect
  228. // depth values and might need rebalancing.
  229. // Carry TreeOffset through for rotate functions.
  230. // Assumes children of 'node' are balanced.
  231. // Returns true if node rebalanced or if depth values changed.
  232. //
  233. BOOL
  234. pBinTreeNodeBalance (
  235. IN PNODESTRUCT Node,
  236. IN UINT TreeOffset
  237. );
  238. //
  239. // After using the following rotate functions, the parents of node
  240. // could have incorrect depth values, and could need rebalancing.
  241. // We do not have double-rotate functions because that is taken
  242. // care of inside these. Need TreeOffset just in case node is top node
  243. //
  244. VOID
  245. pBinTreeRotateRight (
  246. IN PNODESTRUCT Node,
  247. IN UINT TreeOffset
  248. );
  249. VOID
  250. pBinTreeRotateLeft (
  251. IN PNODESTRUCT Node,
  252. IN UINT TreeOffset
  253. );
  254. #ifdef DEBUG
  255. INT
  256. pBinTreeCheckBalance (
  257. IN PNODESTRUCT Node
  258. );
  259. INT
  260. pBinTreeCheck (
  261. IN PBINTREE Tree
  262. );
  263. #endif
  264. //
  265. // Macro expansion definition
  266. //
  267. // None
  268. //
  269. // Code
  270. //
  271. //
  272. // If we are in debug mode, these conversions
  273. // are implemented as functions, so we can
  274. // check for errors. If we are not in debug
  275. // mode, the conversions are simple macros.
  276. //
  277. #ifdef DEBUG
  278. UINT
  279. GetNodeOffset (
  280. IN PNODESTRUCT Node
  281. )
  282. {
  283. if (!Node) {
  284. return INVALID_OFFSET;
  285. }
  286. if (!g_UseDebugStructs) {
  287. return PTR_TO_OFFSET(Node) + NODESTRUCT_HEADER_SIZE;
  288. }
  289. MYASSERT (Node->Signature == NODESTRUCT_SIGNATURE);
  290. return PTR_TO_OFFSET(Node);
  291. }
  292. UINT
  293. GetTreeOffset (
  294. PBINTREE Tree
  295. )
  296. {
  297. if (!Tree) {
  298. return INVALID_OFFSET;
  299. }
  300. if (!g_UseDebugStructs) {
  301. return PTR_TO_OFFSET(Tree) + BINTREE_HEADER_SIZE;
  302. }
  303. MYASSERT (Tree->Signature == BINTREE_SIGNATURE);
  304. return PTR_TO_OFFSET(Tree);
  305. }
  306. UINT
  307. GetListElemOffset (
  308. PLISTELEM Elem
  309. )
  310. {
  311. if (!Elem) {
  312. return INVALID_OFFSET;
  313. }
  314. if (!g_UseDebugStructs) {
  315. return PTR_TO_OFFSET(Elem) + LISTELEM_HEADER_SIZE;
  316. }
  317. MYASSERT (Elem->Signature == LISTELEM_SIGNATURE);
  318. return PTR_TO_OFFSET(Elem);
  319. }
  320. PNODESTRUCT
  321. GetNodeStruct (
  322. UINT Offset
  323. )
  324. {
  325. PNODESTRUCT node;
  326. if (Offset == INVALID_OFFSET) {
  327. return NULL;
  328. }
  329. if (!g_UseDebugStructs) {
  330. return (PNODESTRUCT) OFFSET_TO_PTR(Offset - NODESTRUCT_HEADER_SIZE);
  331. }
  332. node = (PNODESTRUCT) OFFSET_TO_PTR(Offset);
  333. MYASSERT (node->Signature == NODESTRUCT_SIGNATURE);
  334. return node;
  335. }
  336. PBINTREE
  337. GetBinTree (
  338. UINT Offset
  339. )
  340. {
  341. PBINTREE tree;
  342. if (Offset == INVALID_OFFSET) {
  343. return NULL;
  344. }
  345. if (!g_UseDebugStructs) {
  346. return (PBINTREE) OFFSET_TO_PTR(Offset - BINTREE_HEADER_SIZE);
  347. }
  348. tree = (PBINTREE) OFFSET_TO_PTR(Offset);
  349. MYASSERT (tree->Signature == BINTREE_SIGNATURE);
  350. return tree;
  351. }
  352. PLISTELEM
  353. GetListElem (
  354. UINT Offset
  355. )
  356. {
  357. PLISTELEM elem;
  358. if (Offset == INVALID_OFFSET) {
  359. return NULL;
  360. }
  361. if (!g_UseDebugStructs) {
  362. return (PLISTELEM) OFFSET_TO_PTR(Offset - LISTELEM_HEADER_SIZE);
  363. }
  364. elem = (PLISTELEM) OFFSET_TO_PTR(Offset);
  365. MYASSERT (elem->Signature == LISTELEM_SIGNATURE);
  366. return elem;
  367. }
  368. #else
  369. #define GetNodeOffset(Node) ((Node) ? \
  370. PTR_TO_OFFSET(Node) : \
  371. INVALID_OFFSET)
  372. #define GetTreeOffset(Tree) ((Tree) ? \
  373. PTR_TO_OFFSET(Tree) : \
  374. INVALID_OFFSET)
  375. #define GetListElemOffset(Elem) ((Elem) ? \
  376. PTR_TO_OFFSET(Elem) : \
  377. INVALID_OFFSET)
  378. #define GetNodeStruct(Offset) (((Offset) == INVALID_OFFSET) ? \
  379. NULL : \
  380. (PNODESTRUCT) OFFSET_TO_PTR(Offset))
  381. #define GetBinTree(Offset) (((Offset) == INVALID_OFFSET) ? \
  382. NULL : \
  383. (PBINTREE) OFFSET_TO_PTR(Offset))
  384. #define GetListElem(Offset) (((Offset) == INVALID_OFFSET) ? \
  385. NULL : \
  386. (PLISTELEM)OFFSET_TO_PTR(Offset))
  387. #endif
  388. //
  389. // GetNodeData - takes a node and gets the data
  390. // structure offset
  391. //
  392. // GetNodeDataStr - takes a node and gets the
  393. // pascal-style string in the data structure offset
  394. //
  395. #define GetNodeData(Node) ((Node)->InsertionOrdered ? \
  396. GetListElem((Node)->Data)->Data : \
  397. (Node)->Data)
  398. #define GetNodeDataStr(Node) (GetDataStr(GetNodeData(Node)))
  399. PNODESTRUCT
  400. GetTreeRoot (
  401. IN PBINTREE Tree
  402. )
  403. {
  404. PNODESTRUCT cur;
  405. if (!Tree || Tree->Root == INVALID_OFFSET) {
  406. return NULL;
  407. }
  408. cur = GetNodeStruct (Tree->Root);
  409. if (cur->InsertionHead) {
  410. return GetNodeStruct (cur->Root);
  411. } else {
  412. return cur;
  413. }
  414. }
  415. VOID
  416. pSetTreeRoot (
  417. IN PBINTREE Tree,
  418. IN UINT Offset
  419. )
  420. {
  421. PNODESTRUCT cur;
  422. if (!Tree) {
  423. return;
  424. }
  425. cur = GetNodeStruct(Tree->Root);
  426. if (cur && cur->InsertionHead) {
  427. cur->Root = Offset;
  428. } else {
  429. Tree->Root = Offset;
  430. }
  431. }
  432. #define IsTreeInsertionOrdered(Tree) ((Tree) ? \
  433. ((Tree)->Root==INVALID_OFFSET ? \
  434. FALSE : \
  435. GetNodeStruct((Tree)->Root)->InsertionHead) : \
  436. FALSE)
  437. UINT
  438. BinTreeNew (
  439. VOID
  440. )
  441. /*++
  442. Routine Description:
  443. BinTreeNew creates a new binary tree data structure. This is done when a new
  444. node is created via a set operation of some sort. Additional items are added
  445. to the binary tree via BinTreeAddNode.
  446. Arguments:
  447. None.
  448. Return Value:
  449. The offset to the new tree.
  450. Comments:
  451. This function assumes that it cannot fail, because if a low-level memory
  452. routine fails, the process will die.
  453. The database heap might be moved by the allocation request, and could
  454. invalidate pointers. The caller must use care not to use pointers until
  455. after this routine returns, or it must re-convert offsets into new pointers.
  456. --*/
  457. {
  458. UINT treeOffset;
  459. PBINTREE tree;
  460. tree = pBinTreeAllocTree (&treeOffset);
  461. if (!tree) {
  462. return INVALID_OFFSET;
  463. }
  464. tree->Root = INVALID_OFFSET;
  465. INITTREENODES(tree);
  466. INITTREEELEMS(tree);
  467. return treeOffset;
  468. }
  469. BOOL
  470. BinTreeAddNode (
  471. IN UINT TreeOffset,
  472. IN UINT Data
  473. )
  474. /*++
  475. Routine Description:
  476. BinTreeAddNode adds a new item to an existing binary tree.
  477. Arguments:
  478. TreeOffset - Indicates the root of the binary tree, as returned by
  479. BinTreeNew.
  480. Data - Specifies the offset of the data structure containing the
  481. node to insert. The string address is computed from Data via
  482. GetDataStr.
  483. Return Value:
  484. TRUE if the insertion operation succeeded, FALSE if the item is already in
  485. the tree.
  486. --*/
  487. {
  488. UINT nodeOffset;
  489. UINT elemOffset;
  490. UINT parentOffset;
  491. PNODESTRUCT node;
  492. PNODESTRUCT cur;
  493. PNODESTRUCT parent;
  494. PBINTREE tree;
  495. PLISTELEM elem;
  496. INT cmp;
  497. PCWSTR dataStr;
  498. if (TreeOffset == INVALID_OFFSET) {
  499. return FALSE;
  500. }
  501. //
  502. // Keep track of initial database pointer. If it changes, we need
  503. // to readjust our pointers.
  504. //
  505. tree = GetBinTree (TreeOffset);
  506. if (!GetTreeRoot (tree)) {
  507. //
  508. // No root case -- add this item as the root
  509. //
  510. node = pBinTreeAllocNode (&nodeOffset);
  511. if (!node) {
  512. return FALSE;
  513. }
  514. PTR_WAS_INVALIDATED(tree);
  515. tree = GetBinTree (TreeOffset);
  516. INCTREENODES (tree);
  517. pSetTreeRoot (tree, nodeOffset);
  518. node->Parent = INVALID_OFFSET;
  519. parentOffset = INVALID_OFFSET;
  520. parent = NULL;
  521. } else {
  522. //
  523. // Existing root case -- try to find the item, then if it does
  524. // not exist, add it.
  525. //
  526. cur = GetTreeRoot (tree);
  527. dataStr = GetDataStr (Data);
  528. do {
  529. cmp = StringPasICompare (dataStr, GetNodeDataStr (cur));
  530. if (!cmp) {
  531. //
  532. // Node is already in tree
  533. //
  534. return FALSE;
  535. }
  536. //
  537. // Go to left or right node, depending on search result
  538. //
  539. parentOffset = GetNodeOffset (cur);
  540. if (cmp < 0) {
  541. cur = GetNodeStruct(cur->Left);
  542. } else {
  543. cur = GetNodeStruct(cur->Right);
  544. }
  545. } while (cur);
  546. //
  547. // Node is not in the tree. Add it now.
  548. //
  549. node = pBinTreeAllocNode(&nodeOffset);
  550. if (!node) {
  551. return FALSE;
  552. }
  553. PTR_WAS_INVALIDATED(cur);
  554. PTR_WAS_INVALIDATED(tree);
  555. tree = GetBinTree (TreeOffset);
  556. INCTREENODES (tree);
  557. node->Parent = parentOffset;
  558. parent = GetNodeStruct (parentOffset);
  559. if (cmp < 0) {
  560. parent->Left = nodeOffset;
  561. } else {
  562. parent->Right = nodeOffset;
  563. }
  564. }
  565. //
  566. // Verify the code above restored the tree pointer if
  567. // an allocation occurred.
  568. //
  569. MYASSERT (tree == GetBinTree (TreeOffset));
  570. //
  571. // Initialize the new node
  572. //
  573. node->Left = INVALID_OFFSET;
  574. node->Right = INVALID_OFFSET;
  575. node->LeftDepth = 0;
  576. node->RightDepth = 0;
  577. node->InsertionHead = 0;
  578. if (!IsTreeInsertionOrdered (tree)) {
  579. //
  580. // We are in sorted-order mode
  581. //
  582. node->Data = Data;
  583. node->InsertionOrdered = 0;
  584. } else {
  585. //
  586. // We are in insertion-ordered mode
  587. //
  588. elem = pBinTreeAllocListElem (&elemOffset);
  589. if (!elem) {
  590. return FALSE;
  591. }
  592. PTR_WAS_INVALIDATED(parent);
  593. PTR_WAS_INVALIDATED(tree);
  594. PTR_WAS_INVALIDATED(node);
  595. parent = GetNodeStruct (parentOffset);
  596. tree = GetBinTree (TreeOffset);
  597. node = GetNodeStruct (nodeOffset);
  598. INCTREEELEMS(tree);
  599. node->InsertionOrdered = 1;
  600. node->Data = elemOffset; // NODESTRUCT.Data is offset of list element
  601. elem->Data = Data; // LISTELEM holds offset of data
  602. elem->Node = nodeOffset; // LISTELEM points back to nodestruct
  603. elem->Next = INVALID_OFFSET; // elem will be put at end of list
  604. //now use node to point to list header
  605. node = GetNodeStruct (tree->Root);
  606. MYASSERT (node->InsertionHead);
  607. if (node->Head == INVALID_OFFSET) { // if this is true, the list is empty
  608. node->Head = elemOffset; // put elemOffset at beginning of the list
  609. } else { // otherwise, put the new element at end of list
  610. MYASSERT (node->Tail != INVALID_OFFSET);
  611. GetListElem (node->Tail)->Next = elemOffset;
  612. }
  613. node->Tail = elemOffset; // new element is tail of list
  614. }
  615. pBinTreeBalanceUpward (parent, TreeOffset);
  616. TESTTREE (GetBinTree (TreeOffset));
  617. return TRUE;
  618. }
  619. UINT
  620. BinTreeDeleteNode (
  621. IN UINT TreeOffset,
  622. IN PCWSTR Str,
  623. OUT PBOOL LastNode OPTIONAL
  624. )
  625. /*++
  626. Routine Description:
  627. BinTreeDeleteNode removes a string from a binary tree.
  628. Arguments:
  629. TreeOffset - Specifies the binary tree to remove the string from
  630. Str - Specifies the string to remove
  631. LastNode - Receives TRUE if the binary tree became empty as a result of
  632. the delete, FALSE otherwise
  633. Return Value:
  634. The data offset of the string that was deleted
  635. --*/
  636. {
  637. PNODESTRUCT deleteNode;
  638. PNODESTRUCT parent;
  639. PNODESTRUCT replace;
  640. UINT data;
  641. UINT replaceOffset;
  642. UINT deleteNodeOffset;
  643. PNODESTRUCT startBalance;
  644. PNODESTRUCT startBalance2 = NULL;
  645. PBINTREE tree;
  646. UINT elemOffset;
  647. PLISTELEM elem;
  648. PLISTELEM cur;
  649. PNODESTRUCT header;
  650. //
  651. // after we delete a node, we have to start from somewhere and
  652. // move up the tree, fixing the balance of nodes. startBalance
  653. // is a pointer to the nodestruct to start at. in more complicated
  654. // deletions, like when the deleted node has two children, and the
  655. // replacement node is way down the tree, there are two places to
  656. // start rebalancing from.
  657. //
  658. if (TreeOffset == INVALID_OFFSET) {
  659. return INVALID_OFFSET;
  660. }
  661. tree = GetBinTree (TreeOffset);
  662. deleteNode = pBinTreeFindNode (tree, Str);
  663. if (deleteNode == NULL) {
  664. return INVALID_OFFSET;
  665. }
  666. if (LastNode) {
  667. *LastNode = FALSE;
  668. }
  669. deleteNodeOffset = GetNodeOffset (deleteNode);
  670. parent = GetNodeStruct (deleteNode->Parent);
  671. data = GetNodeData (deleteNode);
  672. if (deleteNode->Right == INVALID_OFFSET && deleteNode->Left == INVALID_OFFSET) {
  673. //
  674. // deleteNode has no children
  675. //
  676. if (parent == NULL) {
  677. if (LastNode) {
  678. *LastNode = TRUE;
  679. }
  680. pSetTreeRoot(tree, INVALID_OFFSET);
  681. } else {
  682. if (parent->Left == deleteNodeOffset) {
  683. parent->Left=INVALID_OFFSET;
  684. } else {
  685. parent->Right=INVALID_OFFSET;
  686. }
  687. }
  688. startBalance = parent;
  689. } else {
  690. //
  691. // deleteNode has one or two children
  692. //
  693. if (deleteNode->Right == INVALID_OFFSET || deleteNode->Left == INVALID_OFFSET) {
  694. //
  695. // deleteNode has one child
  696. //
  697. if (deleteNode->Right == INVALID_OFFSET) {
  698. replace = GetNodeStruct (deleteNode->Left);
  699. } else {
  700. replace = GetNodeStruct (deleteNode->Right);
  701. }
  702. replaceOffset = GetNodeOffset (replace);
  703. //
  704. // deleteNode->Parent has new child, so check balance
  705. //
  706. startBalance = parent;
  707. } else {
  708. //
  709. // deleteNode has two children: find replacement on deeper side
  710. //
  711. if (deleteNode->LeftDepth > deleteNode->RightDepth) {
  712. //
  713. // find replacement node on left
  714. //
  715. replace = GetNodeStruct (deleteNode->Left);
  716. if (replace->Right == INVALID_OFFSET) {
  717. //
  718. // node's left child has no right child, so replace is node->Left
  719. //
  720. replace->Right = deleteNode->Right; //hook up node's right child to replace
  721. GetNodeStruct (replace->Right)->Parent = deleteNode->Left;
  722. replaceOffset = GetNodeOffset (replace);
  723. } else {
  724. //
  725. // deleteNode's left child has right child, so find the rightmost child
  726. //
  727. do {
  728. //
  729. // move right as far as possible
  730. //
  731. replace = GetNodeStruct (replace->Right);
  732. } while (replace->Right != INVALID_OFFSET);
  733. //
  734. // child of replace->Parent changed, so balance
  735. //
  736. startBalance2 = GetNodeStruct (replace->Parent);
  737. //
  738. // replace's parent's right child is replace's left
  739. //
  740. startBalance2->Right = replace->Left;
  741. if (replace->Left != INVALID_OFFSET) {
  742. //
  743. // hook up left children to replace->Parent
  744. //
  745. GetNodeStruct(replace->Left)->Parent = replace->Parent;
  746. }
  747. replaceOffset = GetNodeOffset (replace);
  748. //
  749. // hook up children of deleteNode to replace
  750. //
  751. replace->Left = deleteNode->Left;
  752. GetNodeStruct (replace->Left)->Parent = replaceOffset;
  753. replace->Right = deleteNode->Right;
  754. GetNodeStruct (replace->Right)->Parent = replaceOffset;
  755. }
  756. } else {
  757. //
  758. // find replacement node on right
  759. //
  760. replace = GetNodeStruct (deleteNode->Right);
  761. if (replace->Left == INVALID_OFFSET) {
  762. //
  763. // deleteNode's right child has no left child, so replace is deleteNode->Right
  764. //
  765. replace->Left = deleteNode->Left; // hook up node's left child to replace
  766. GetNodeStruct (replace->Left)->Parent = deleteNode->Right;
  767. replaceOffset = GetNodeOffset (replace);
  768. } else {
  769. //
  770. // deleteNode's right child has left child, so find the leftmost child
  771. //
  772. do {
  773. replace = GetNodeStruct (replace->Left);
  774. } while (replace->Left != INVALID_OFFSET);
  775. //
  776. // child of replace->Parent changed, so balance
  777. //
  778. startBalance2 = GetNodeStruct (replace->Parent);
  779. //
  780. // replace's parent's left child is replace's right
  781. //
  782. startBalance2->Left = replace->Right;
  783. if (replace->Right != INVALID_OFFSET) {
  784. //
  785. // hook up right children to replace->Parent
  786. //
  787. GetNodeStruct (replace->Right)->Parent = replace->Parent;
  788. }
  789. replaceOffset = GetNodeOffset (replace);
  790. //
  791. // hook up children of deleteNode to replace
  792. //
  793. replace->Right = deleteNode->Right;
  794. GetNodeStruct (replace->Right)->Parent = replaceOffset;
  795. replace->Left = deleteNode->Left;
  796. GetNodeStruct (replace->Left)->Parent = replaceOffset;
  797. }
  798. }
  799. //
  800. // in all cases of deleted node having two children,
  801. // the place to start (second) balancing is the node
  802. // that replaces the deleted node, because it will
  803. // always have at least one new child.
  804. //
  805. startBalance = replace;
  806. }
  807. //
  808. // this is offset
  809. //
  810. replace->Parent = deleteNode->Parent;
  811. if (parent == NULL) {
  812. //
  813. // deleting top-level node
  814. //
  815. pSetTreeRoot (tree, replaceOffset);
  816. } else {
  817. if (parent->Left == deleteNodeOffset) {
  818. parent->Left = replaceOffset;
  819. } else {
  820. parent->Right = replaceOffset;
  821. }
  822. }
  823. }
  824. if (startBalance2) {
  825. //
  826. // startBalance2 is lower one
  827. //
  828. pBinTreeBalanceUpward (startBalance2, TreeOffset);
  829. }
  830. pBinTreeBalanceUpward (startBalance, TreeOffset);
  831. if (deleteNode->InsertionOrdered) {
  832. //
  833. // We are in insertion-ordered mode
  834. //
  835. //
  836. // get offset of LISTELEM for this NODESTRUCT
  837. //
  838. elemOffset = deleteNode->Data;
  839. elem = GetListElem (elemOffset);
  840. header = GetNodeStruct (tree->Root); //get the header of list
  841. if (header->Head == elemOffset) {
  842. //
  843. // if elem was first in list
  844. //
  845. header->Head = elem->Next;
  846. if (elem->Next == INVALID_OFFSET) { // if elem was last in list
  847. header->Tail = INVALID_OFFSET;
  848. }
  849. } else {
  850. //
  851. // elem was not first in list
  852. //
  853. cur = GetListElem (header->Head);
  854. while (cur->Next != elemOffset) {
  855. MYASSERT (cur->Next != INVALID_OFFSET);
  856. cur = GetListElem (cur->Next);
  857. }
  858. //
  859. // now cur is the element before elem, so pull elem out of list
  860. //
  861. cur->Next = elem->Next;
  862. if (elem->Next == INVALID_OFFSET) { // if elem was last in list
  863. header->Tail = GetListElemOffset(cur); // set end pointer to new last element
  864. }
  865. }
  866. pBinTreeFreeListElem (elem);
  867. DECTREEELEMS(tree);
  868. }
  869. pBinTreeFreeNode (deleteNode);
  870. DECTREENODES(tree);
  871. TESTTREE(tree);
  872. return data;
  873. }
  874. PNODESTRUCT
  875. pBinTreeFindNode (
  876. IN PBINTREE Tree,
  877. IN PCWSTR Str
  878. )
  879. {
  880. PNODESTRUCT cur;
  881. INT cmp;
  882. if (!Tree) {
  883. return NULL;
  884. }
  885. cur = GetTreeRoot (Tree);
  886. while (cur) {
  887. cmp = StringPasICompare (Str, GetNodeDataStr (cur));
  888. if (!cmp) {
  889. break;
  890. }
  891. if (cmp < 0) {
  892. cur = GetNodeStruct (cur->Left);
  893. } else {
  894. cur = GetNodeStruct (cur->Right);
  895. }
  896. }
  897. return cur;
  898. }
  899. UINT
  900. BinTreeFindNode (
  901. IN UINT TreeOffset,
  902. IN PCWSTR Str
  903. )
  904. /*++
  905. Routine Description:
  906. BinTreeFindNode searches a binary tree for a string and returns the offset
  907. to the item data.
  908. Arguments:
  909. TreeOffset - Specifies the binary tree to search
  910. Str - Specifies the string to find
  911. Return Value:
  912. The offset to the node data, or INVALID_OFFSET if string is not found.
  913. --*/
  914. {
  915. PNODESTRUCT node;
  916. PBINTREE tree;
  917. tree = GetBinTree (TreeOffset);
  918. node = pBinTreeFindNode (tree, Str);
  919. if (!node) {
  920. return INVALID_OFFSET;
  921. }
  922. return GetNodeData(node);
  923. }
  924. VOID
  925. pBinTreeDestroy (
  926. IN PNODESTRUCT Node, OPTIONAL
  927. IN PBINTREE Tree OPTIONAL
  928. )
  929. /*++
  930. Routine Description:
  931. pBinTreeDestroy destroys a binary tree. This routine is recursive.
  932. Arguments:
  933. Node - Specifies the node to deallocate. All child nodes are also
  934. deallocated.
  935. Tree - Specifies the tree that Node belongs to
  936. Return Value:
  937. None.
  938. --*/
  939. {
  940. if (!Node || !Tree) {
  941. return;
  942. }
  943. pBinTreeDestroy (GetNodeStruct (Node->Left), Tree);
  944. pBinTreeDestroy (GetNodeStruct (Node->Right), Tree);
  945. if (Node->InsertionOrdered) {
  946. pBinTreeFreeListElem (GetListElem (Node->Data));
  947. DECTREEELEMS(Tree);
  948. }
  949. pBinTreeFreeNode (Node);
  950. DECTREENODES(Tree);
  951. }
  952. VOID
  953. BinTreeDestroy (
  954. IN UINT TreeOffset
  955. )
  956. /*++
  957. Routine Description:
  958. BinTreeDestroy deallocates all nodes in a binary tree.
  959. Arguments:
  960. TreeOffset - Specifies the binary tree to free
  961. Return Value:
  962. None.
  963. --*/
  964. {
  965. PBINTREE tree;
  966. PNODESTRUCT root;
  967. PNODESTRUCT header;
  968. if (TreeOffset==INVALID_OFFSET) {
  969. return;
  970. }
  971. tree = GetBinTree (TreeOffset);
  972. root = GetNodeStruct (tree->Root);
  973. if (root && root->InsertionHead) {
  974. header = root;
  975. root = GetNodeStruct (root->Root);
  976. } else {
  977. header = NULL;
  978. }
  979. pBinTreeDestroy (root, tree);
  980. if (header) {
  981. pBinTreeFreeNode(header);
  982. DECTREENODES(tree);
  983. }
  984. TESTTREENODES(tree);
  985. TESTTREEELEMS(tree);
  986. pBinTreeFreeTree(tree);
  987. }
  988. PNODESTRUCT
  989. pBinTreeEnumFirst (
  990. IN PBINTREE Tree
  991. )
  992. /*++
  993. Routine Description:
  994. pBinTreeEnumFirst returns the first node in the specified tree.
  995. Arguments:
  996. Tree - Specifies the tree to begin enumerating
  997. Return Value:
  998. A pointer to the first node struct, or NULL if no items exist in Tree, or
  999. if Tree is NULL.
  1000. --*/
  1001. {
  1002. PNODESTRUCT cur;
  1003. cur = GetTreeRoot (Tree);
  1004. if (cur) {
  1005. while (cur->Left != INVALID_OFFSET) {
  1006. cur = GetNodeStruct (cur->Left);
  1007. }
  1008. }
  1009. return cur;
  1010. }
  1011. PNODESTRUCT
  1012. pBinTreeEnumNext (
  1013. IN PNODESTRUCT CurrentNode
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. pBinTreeEnumNext continues an enumeration of a binary tree. It walks the
  1018. tree in sorted order.
  1019. Arguments:
  1020. CurrentNode - Specifies the previous node returned by pBinTreeEnumFirst or
  1021. pBinTreeEnumNext.
  1022. Return Value:
  1023. Returns the next node in the tree, or NULL if no more items are left to
  1024. enumerate.
  1025. --*/
  1026. {
  1027. PNODESTRUCT cur;
  1028. PNODESTRUCT parent;
  1029. if (!CurrentNode) {
  1030. return NULL;
  1031. }
  1032. cur = CurrentNode;
  1033. if (cur->Right != INVALID_OFFSET) {
  1034. cur = GetNodeStruct (cur->Right);
  1035. while (cur->Left != INVALID_OFFSET) {
  1036. cur = GetNodeStruct (cur->Left);
  1037. }
  1038. return cur;
  1039. }
  1040. //
  1041. // otherwise, cur has no right child, so we have to
  1042. // move upwards until we find a parent to the right
  1043. // (or we reach top of tree, meaning we are done)
  1044. //
  1045. for (;;) {
  1046. parent = GetNodeStruct (cur->Parent);
  1047. //
  1048. // if has no parent or parent is to right
  1049. //
  1050. if (!parent || parent->Left == GetNodeOffset (cur)) {
  1051. break;
  1052. }
  1053. cur = parent;
  1054. }
  1055. return parent;
  1056. }
  1057. PLISTELEM
  1058. pBinTreeInsertionEnumFirst (
  1059. PBINTREE Tree
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. pBinTreeInsertionEnumFirst begins an enumeration of the nodes inside an
  1064. insertion-ordered tree. If the tree is not insertion ordered, no items are
  1065. enumerated. If insertion order was enabled after items had been previously
  1066. added, this enumeration will not return those initial items.
  1067. Arguments:
  1068. Tree - Specifies the tree to begin enumeration of
  1069. Return Value:
  1070. A pointer to the linked list element, or NULL if no insertion-ordered nodes
  1071. exist in Tree, or NULL if Tree is NULL.
  1072. --*/
  1073. {
  1074. PNODESTRUCT header;
  1075. if (!Tree) {
  1076. return NULL;
  1077. }
  1078. header = GetNodeStruct (Tree->Root);
  1079. return header ? GetListElem (header->Head) : NULL;
  1080. }
  1081. PLISTELEM
  1082. pBinTreeInsertionEnumNext (
  1083. IN PLISTELEM Elem
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. pBinTreeInsertionEnumNext continues an enumeration of the insertion-ordered
  1088. nodes in a binary tree.
  1089. Arguments:
  1090. Elem - Specifies the previously enumerated list element
  1091. Return Value:
  1092. A pointer to the next element, or NULL if no more elements exist, or if
  1093. Elem is NULL.
  1094. --*/
  1095. {
  1096. if (!Elem) {
  1097. return NULL;
  1098. }
  1099. return GetListElem (Elem->Next);
  1100. }
  1101. UINT
  1102. BinTreeEnumFirst (
  1103. IN UINT TreeOffset,
  1104. OUT PUINT Enum
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. BinTreeEnumFirst begins an enumeration of the data offsets stored in a
  1109. binary tree. The enumeration is sorted order or insertion order, depending
  1110. on the insertion order setting within the tree.
  1111. Arguments:
  1112. TreeOffset - Specifies the binary tree to begin enumeration of.
  1113. Enum - Receives the offset to the binary tree node.
  1114. Return Value:
  1115. The offset to the data associated with the first node, or INVALID_OFFSET if
  1116. the tree is empty.
  1117. --*/
  1118. {
  1119. PBINTREE tree;
  1120. PNODESTRUCT node;
  1121. PLISTELEM elem;
  1122. MYASSERT (Enum);
  1123. if (TreeOffset == INVALID_OFFSET) {
  1124. return INVALID_OFFSET;
  1125. }
  1126. tree = GetBinTree (TreeOffset);
  1127. if (IsTreeInsertionOrdered (tree)) {
  1128. //
  1129. // tree is insertion-ordered, so get first element in
  1130. // linked list. enumerator is NODESTRUCT for this elem
  1131. //
  1132. elem = pBinTreeInsertionEnumFirst (tree);
  1133. if (!elem) {
  1134. if (Enum) {
  1135. *Enum = INVALID_OFFSET;
  1136. }
  1137. return INVALID_OFFSET;
  1138. } else {
  1139. if (Enum) {
  1140. *Enum = elem->Node;
  1141. }
  1142. return elem->Data;
  1143. }
  1144. } else {
  1145. //
  1146. // tree is not insertion-ordered, so get leftmost node.
  1147. // enumerator is the offset of this node.
  1148. //
  1149. node = pBinTreeEnumFirst (tree);
  1150. if (Enum) {
  1151. *Enum = GetNodeOffset (node);
  1152. }
  1153. return !node ? INVALID_OFFSET : node->Data;
  1154. }
  1155. }
  1156. UINT
  1157. BinTreeEnumNext (
  1158. IN OUT PUINT Enum
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. BinTreeEnumNext continues an enumeration started by BinTreeEnumFirst.
  1163. Arguments:
  1164. Enum - Specifies the previous node offset, receivies the enumerated node
  1165. offset.
  1166. Return Value:
  1167. The offset to the data associated with the next node, or INVALID_OFFSET if
  1168. no more nodes exist in the tree.
  1169. --*/
  1170. {
  1171. PNODESTRUCT node;
  1172. PLISTELEM elem;
  1173. MYASSERT (Enum);
  1174. if (*Enum == INVALID_OFFSET) {
  1175. return INVALID_OFFSET;
  1176. }
  1177. node = GetNodeStruct (*Enum);
  1178. if (node->InsertionOrdered) {
  1179. //
  1180. // tree is insertion-ordered,
  1181. // so get next node in list.
  1182. //
  1183. elem = pBinTreeInsertionEnumNext (GetListElem (node->Data));
  1184. if (!elem) {
  1185. *Enum = INVALID_OFFSET;
  1186. return INVALID_OFFSET;
  1187. } else {
  1188. *Enum = elem->Node;
  1189. return elem->Data;
  1190. }
  1191. } else {
  1192. //
  1193. // tree is not insertion-ordered,
  1194. // so get next node in tree.
  1195. //
  1196. node = pBinTreeEnumNext (node);
  1197. *Enum = GetNodeOffset (node);
  1198. return !node ? INVALID_OFFSET : node->Data;
  1199. }
  1200. }
  1201. PNODESTRUCT
  1202. pBinTreeAllocNode (
  1203. OUT PUINT Offset
  1204. )
  1205. /*++
  1206. Routine Description:
  1207. pBinTreeAllocNode allocates a node in the current global database, and
  1208. returns the offset and pointer to that node.
  1209. Allocations can alter the location of the database, and subsequently
  1210. invalidate the caller's pointers into the database.
  1211. Arguments:
  1212. Offset - Receivies the offset to the newly created node.
  1213. Return Value:
  1214. A pointer to the newly created node.
  1215. --*/
  1216. {
  1217. PNODESTRUCT node;
  1218. UINT tempOffset;
  1219. MYASSERT (g_CurrentDatabase);
  1220. if (g_CurrentDatabase->FirstBinTreeNodeDeleted == INVALID_OFFSET) {
  1221. tempOffset = DatabaseAllocBlock (NODESTRUCT_SIZE);
  1222. if (tempOffset == INVALID_OFFSET) {
  1223. return NULL;
  1224. }
  1225. *Offset = tempOffset;
  1226. #ifdef DEBUG
  1227. if (g_UseDebugStructs) {
  1228. node = (PNODESTRUCT) OFFSET_TO_PTR(*Offset);
  1229. node->Signature = NODESTRUCT_SIGNATURE;
  1230. } else {
  1231. node = (PNODESTRUCT) OFFSET_TO_PTR(*Offset - NODESTRUCT_HEADER_SIZE);
  1232. }
  1233. #else
  1234. node = (PNODESTRUCT) OFFSET_TO_PTR(*Offset);
  1235. #endif
  1236. } else {
  1237. *Offset = g_CurrentDatabase->FirstBinTreeNodeDeleted;
  1238. node = GetNodeStruct(*Offset);
  1239. g_CurrentDatabase->FirstBinTreeNodeDeleted = node->NextDeleted;
  1240. }
  1241. #ifdef DEBUG
  1242. if (g_UseDebugStructs) {
  1243. node->Deleted = FALSE;
  1244. }
  1245. #endif
  1246. return node;
  1247. }
  1248. VOID
  1249. pBinTreeFreeNode (
  1250. IN PNODESTRUCT Node
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. pBinTreeFreeNode puts an allocated node on the deleted list. It does not
  1255. adjust any other linkage.
  1256. Arguments:
  1257. Node - Specifies the node to put on the deleted list.
  1258. Return Value:
  1259. None.
  1260. --*/
  1261. {
  1262. MYASSERT(Node);
  1263. #ifdef DEBUG
  1264. if (g_UseDebugStructs) {
  1265. MYASSERT(Node->Signature == NODESTRUCT_SIGNATURE);
  1266. Node->Deleted = TRUE;
  1267. }
  1268. #endif
  1269. MYASSERT(g_CurrentDatabase);
  1270. Node->NextDeleted = g_CurrentDatabase->FirstBinTreeNodeDeleted;
  1271. g_CurrentDatabase->FirstBinTreeNodeDeleted = GetNodeOffset(Node);
  1272. }
  1273. PBINTREE
  1274. pBinTreeAllocTree (
  1275. OUT PUINT Offset
  1276. )
  1277. /*++
  1278. Routine Description:
  1279. pBinTreeAllocTree creates a binary tree data structure. If a structure
  1280. is available in the detele list, then it is used. Otherwise, the
  1281. database grows.
  1282. Allocations can alter the location of the database, and subsequently
  1283. invalidate the caller's pointers into the database.
  1284. Arguments:
  1285. Offset - Receivies the offset to the binary tree.
  1286. Return Value:
  1287. A pointer to the new binary tree structure.
  1288. --*/
  1289. {
  1290. PBINTREE tree;
  1291. UINT tempOffset;
  1292. MYASSERT(g_CurrentDatabase);
  1293. if (g_CurrentDatabase->FirstBinTreeDeleted == INVALID_OFFSET) {
  1294. tempOffset = DatabaseAllocBlock (BINTREE_SIZE);
  1295. if (tempOffset == INVALID_OFFSET) {
  1296. return NULL;
  1297. }
  1298. *Offset = tempOffset;
  1299. #ifdef DEBUG
  1300. if (g_UseDebugStructs) {
  1301. tree = (PBINTREE) OFFSET_TO_PTR(*Offset);
  1302. tree->Signature = BINTREE_SIGNATURE;
  1303. } else {
  1304. tree = (PBINTREE) OFFSET_TO_PTR(*Offset - BINTREE_HEADER_SIZE);
  1305. }
  1306. #else
  1307. tree = (PBINTREE)OFFSET_TO_PTR(*Offset);
  1308. #endif
  1309. } else {
  1310. *Offset = g_CurrentDatabase->FirstBinTreeDeleted;
  1311. tree = GetBinTree (*Offset);
  1312. g_CurrentDatabase->FirstBinTreeDeleted = tree->NextDeleted;
  1313. }
  1314. #ifdef DEBUG
  1315. if (g_UseDebugStructs) {
  1316. tree->Deleted = FALSE;
  1317. }
  1318. #endif
  1319. return tree;
  1320. }
  1321. VOID
  1322. pBinTreeFreeTree (
  1323. IN PBINTREE Tree
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. pBinTreeFreeTree frees a binary tree structure. It does not free the nodes
  1328. within the structure.
  1329. Arguments:
  1330. Tree - Specifies the binary tree structure to put on the deleted list.
  1331. Return Value:
  1332. None.
  1333. --*/
  1334. {
  1335. MYASSERT (Tree);
  1336. MYASSERT (g_CurrentDatabase);
  1337. #ifdef DEBUG
  1338. if (g_UseDebugStructs) {
  1339. Tree->Deleted = TRUE;
  1340. MYASSERT (Tree->Signature == BINTREE_SIGNATURE);
  1341. }
  1342. #endif
  1343. Tree->NextDeleted = g_CurrentDatabase->FirstBinTreeDeleted;
  1344. g_CurrentDatabase->FirstBinTreeDeleted = GetTreeOffset (Tree);
  1345. }
  1346. PLISTELEM
  1347. pBinTreeAllocListElem (
  1348. OUT PUINT Offset
  1349. )
  1350. /*++
  1351. Routine Description:
  1352. pBinTreeAllocListElem allocates a list element. If an element is available
  1353. in the deleted list, it is used. Otherwise, a new element is allocated
  1354. from the database.
  1355. Allocations can alter the location of the database, and subsequently
  1356. invalidate the caller's pointers into the database.
  1357. Arguments:
  1358. Offset - Receives the offset of the newly allocated element
  1359. Return Value:
  1360. A pointer to the allocated list element
  1361. --*/
  1362. {
  1363. PLISTELEM elem;
  1364. UINT tempOffset;
  1365. MYASSERT (g_CurrentDatabase);
  1366. if (g_CurrentDatabase->FirstBinTreeListElemDeleted == INVALID_OFFSET) {
  1367. tempOffset = DatabaseAllocBlock (LISTELEM_SIZE);
  1368. if (tempOffset == INVALID_OFFSET) {
  1369. return NULL;
  1370. }
  1371. *Offset = tempOffset;
  1372. #ifdef DEBUG
  1373. if (g_UseDebugStructs) {
  1374. elem = (PLISTELEM) OFFSET_TO_PTR(*Offset);
  1375. elem->Signature = LISTELEM_SIGNATURE;
  1376. } else {
  1377. elem = (PLISTELEM) OFFSET_TO_PTR(*Offset - LISTELEM_HEADER_SIZE);
  1378. }
  1379. #else
  1380. elem = (PLISTELEM) OFFSET_TO_PTR(*Offset);
  1381. #endif
  1382. } else {
  1383. *Offset = g_CurrentDatabase->FirstBinTreeListElemDeleted;
  1384. elem = GetListElem (*Offset);
  1385. g_CurrentDatabase->FirstBinTreeListElemDeleted = elem->NextDeleted;
  1386. }
  1387. return elem;
  1388. }
  1389. VOID
  1390. pBinTreeFreeListElem (
  1391. IN PLISTELEM Elem
  1392. )
  1393. /*++
  1394. Routine Description:
  1395. pBinTreeFreeListElem puts an allocated list element on the deleted element
  1396. list, so it will be reused in a future allocation.
  1397. Arguments:
  1398. Elem - Specifies the element to put on the deleted list.
  1399. Return Value:
  1400. None.
  1401. --*/
  1402. {
  1403. MYASSERT(Elem);
  1404. MYASSERT(g_CurrentDatabase);
  1405. #ifdef DEBUG
  1406. if (g_UseDebugStructs) {
  1407. MYASSERT(Elem->Signature == LISTELEM_SIGNATURE);
  1408. }
  1409. #endif
  1410. Elem->NextDeleted = g_CurrentDatabase->FirstBinTreeListElemDeleted;
  1411. g_CurrentDatabase->FirstBinTreeListElemDeleted = GetListElemOffset(Elem);
  1412. }
  1413. VOID
  1414. pBinTreeBalanceUpward (
  1415. IN PNODESTRUCT Node,
  1416. IN UINT TreeOffset
  1417. )
  1418. /*++
  1419. Routine Description:
  1420. pBinTreeBalanceUpward makes sure that the specified node is balanced. If it
  1421. is not balanced, the nodes are rotated as necessary, and balancing
  1422. continues up the tree.
  1423. Arguments:
  1424. Node - Specifies the node to balance
  1425. TreeOffset - Specifies the offset of the binary tree containing Node
  1426. Return Value:
  1427. None.
  1428. --*/
  1429. {
  1430. PNODESTRUCT cur;
  1431. PNODESTRUCT next;
  1432. cur = Node;
  1433. //
  1434. // Move up tree. stop if:
  1435. // a) hit top of tree
  1436. // b) pBinTreeNodeBalance returns FALSE (nothing changed)
  1437. //
  1438. while (cur) {
  1439. //
  1440. // need to grab cur's parent before balancing
  1441. // cur because cur might change place in tree
  1442. //
  1443. next = GetNodeStruct (cur->Parent);
  1444. if (!pBinTreeNodeBalance (cur, TreeOffset)) {
  1445. return;
  1446. }
  1447. cur = next;
  1448. }
  1449. }
  1450. BOOL
  1451. pBinTreeNodeBalance (
  1452. IN PNODESTRUCT Node,
  1453. IN UINT TreeOffset
  1454. )
  1455. /*++
  1456. Routine Description:
  1457. pBinTreeNodeBalance checks the balance of the specified node, and if
  1458. necessary, performs a rotation to balance the node. If a rotation was
  1459. performed, the parent might become imbalanced.
  1460. Arguments:
  1461. Node - Specifies the node to balance
  1462. TreeOffset - Specifies the offset to the binary tree that contains Node
  1463. Return Value:
  1464. TRUE if a rotation was performed, FALSE if Node is already balanced
  1465. --*/
  1466. {
  1467. UINT left;
  1468. UINT right;
  1469. PNODESTRUCT leftNode;
  1470. PNODESTRUCT rightNode;
  1471. if (!Node) {
  1472. return FALSE;
  1473. }
  1474. leftNode = GetNodeStruct (Node->Left);
  1475. rightNode = GetNodeStruct (Node->Right);
  1476. if (!rightNode) {
  1477. right = 0;
  1478. } else {
  1479. right = MAX (rightNode->RightDepth, rightNode->LeftDepth) + 1;
  1480. }
  1481. if (!leftNode) {
  1482. left = 0;
  1483. } else {
  1484. left = MAX (leftNode->RightDepth, leftNode->LeftDepth) + 1;
  1485. }
  1486. if (right == Node->RightDepth && left == Node->LeftDepth) {
  1487. //
  1488. // if node values have not changed, node is balanced
  1489. //
  1490. TESTNODETREE(Node);
  1491. return FALSE;
  1492. }
  1493. MYASSERT (right < 126);
  1494. MYASSERT (left < 126);
  1495. Node->RightDepth = (WORD) right;
  1496. Node->LeftDepth = (WORD) left;
  1497. if (Node->RightDepth > (Node->LeftDepth + 1)) {
  1498. //
  1499. // right heavy
  1500. //
  1501. pBinTreeRotateLeft (Node, TreeOffset);
  1502. } else if (Node->LeftDepth > (Node->RightDepth + 1)) {
  1503. //
  1504. // left heavy
  1505. //
  1506. pBinTreeRotateRight (Node, TreeOffset);
  1507. }
  1508. return TRUE;
  1509. }
  1510. VOID
  1511. pBinTreeRotateLeft (
  1512. IN PNODESTRUCT Node,
  1513. IN UINT TreeOffset
  1514. )
  1515. /*++
  1516. Routine Description:
  1517. pBinTreeRotateLeft performs a left rotation on Node, moving one node
  1518. from the right side to the left side, in order to balance the node.
  1519. Arguments:
  1520. Node - Specifies the node to rotate left
  1521. TreeOffset - Specifies the offset of the binary tree containing Node
  1522. Return Value:
  1523. None.
  1524. --*/
  1525. {
  1526. PNODESTRUCT newRoot;
  1527. PNODESTRUCT parent;
  1528. PNODESTRUCT right;
  1529. UINT nodeOffset;
  1530. UINT newRootOffset;
  1531. if (!Node) {
  1532. return;
  1533. }
  1534. MYASSERT (Node->Right != INVALID_OFFSET);
  1535. nodeOffset = GetNodeOffset (Node);
  1536. parent = GetNodeStruct (Node->Parent);
  1537. right = GetNodeStruct (Node->Right);
  1538. //
  1539. // make sure right side is heavier on outside
  1540. //
  1541. if (right->LeftDepth > right->RightDepth) {
  1542. pBinTreeRotateRight (right, TreeOffset);
  1543. PTR_WAS_INVALIDATED(right);
  1544. }
  1545. newRootOffset = Node->Right;
  1546. newRoot = GetNodeStruct (newRootOffset);
  1547. Node->Right = newRoot->Left;
  1548. if (newRoot->Left != INVALID_OFFSET) {
  1549. GetNodeStruct (newRoot->Left)->Parent = nodeOffset;
  1550. }
  1551. newRoot->Parent = Node->Parent;
  1552. if (Node->Parent == INVALID_OFFSET) {
  1553. pSetTreeRoot (GetBinTree (TreeOffset), newRootOffset);
  1554. } else {
  1555. if (parent->Left == nodeOffset) {
  1556. parent->Left = newRootOffset;
  1557. } else {
  1558. parent->Right = newRootOffset;
  1559. }
  1560. }
  1561. newRoot->Left = nodeOffset;
  1562. Node->Parent = newRootOffset;
  1563. pBinTreeNodeBalance (Node, TreeOffset);
  1564. pBinTreeNodeBalance (newRoot, TreeOffset);
  1565. }
  1566. VOID
  1567. pBinTreeRotateRight (
  1568. IN PNODESTRUCT Node,
  1569. IN UINT TreeOffset
  1570. )
  1571. /*++
  1572. Routine Description:
  1573. pBinTreeRotateRight performs a right rotation on Node, moving one node from
  1574. the left side to the right side, in order to balance the node.
  1575. Arguments:
  1576. Node - Specifies the node to rotate left
  1577. TreeOffset - Specifies the offset of the binary tree containing Node
  1578. Return Value:
  1579. None.
  1580. --*/
  1581. {
  1582. PNODESTRUCT newRoot;
  1583. PNODESTRUCT parent;
  1584. PNODESTRUCT left;
  1585. UINT nodeOffset;
  1586. UINT newRootOffset;
  1587. if (!Node) {
  1588. return;
  1589. }
  1590. MYASSERT (Node->Left != INVALID_OFFSET);
  1591. nodeOffset = GetNodeOffset (Node);
  1592. parent = GetNodeStruct (Node->Parent);
  1593. left = GetNodeStruct (Node->Left);
  1594. //
  1595. // make sure left side is heavier on outside
  1596. //
  1597. if (left->RightDepth > left->LeftDepth) {
  1598. pBinTreeRotateLeft (left, TreeOffset);
  1599. PTR_WAS_INVALIDATED (left);
  1600. }
  1601. newRootOffset = Node->Left;
  1602. newRoot = GetNodeStruct (newRootOffset);
  1603. Node->Left = newRoot->Right;
  1604. if (newRoot->Right != INVALID_OFFSET) {
  1605. GetNodeStruct (newRoot->Right)->Parent = nodeOffset;
  1606. }
  1607. newRoot->Parent = Node->Parent;
  1608. if (Node->Parent == INVALID_OFFSET) {
  1609. pSetTreeRoot (GetBinTree (TreeOffset), newRootOffset);
  1610. } else {
  1611. if (parent->Left == nodeOffset) {
  1612. parent->Left = newRootOffset;
  1613. } else {
  1614. parent->Right = newRootOffset;
  1615. }
  1616. }
  1617. newRoot->Right = nodeOffset;
  1618. Node->Parent = newRootOffset;
  1619. pBinTreeNodeBalance (Node, TreeOffset);
  1620. pBinTreeNodeBalance (newRoot, TreeOffset);
  1621. }
  1622. BOOL
  1623. BinTreeSetInsertionOrdered (
  1624. IN UINT TreeOffset
  1625. )
  1626. /*++
  1627. Routine Description:
  1628. BinTreeSetInsertionOrdered transforms a binary tree into an
  1629. insertion-ordered link list.
  1630. Arguments:
  1631. TreeOffset - Specifies the binary tree to make insertion-ordered
  1632. Return Value:
  1633. TRUE if the tree was changed, FALSE if TreeOffset is not valid.
  1634. --*/
  1635. {
  1636. PBINTREE tree;
  1637. PNODESTRUCT node;
  1638. PNODESTRUCT root;
  1639. PNODESTRUCT header;
  1640. PLISTELEM elem;
  1641. PLISTELEM prevElem;
  1642. UINT headerOffset;
  1643. UINT offset;
  1644. UINT nodeOffset;
  1645. PBYTE buf;
  1646. MYASSERT (g_CurrentDatabase);
  1647. if (TreeOffset == INVALID_OFFSET) {
  1648. return FALSE;
  1649. }
  1650. //
  1651. // This is to test if allocations move buffer
  1652. //
  1653. buf = g_CurrentDatabase->Buf;
  1654. tree = GetBinTree (TreeOffset);
  1655. root = GetNodeStruct (tree->Root);
  1656. if (root && root->InsertionHead) {
  1657. return TRUE;
  1658. }
  1659. header = pBinTreeAllocNode (&headerOffset);
  1660. if (!header) {
  1661. return FALSE;
  1662. }
  1663. if (buf != g_CurrentDatabase->Buf) {
  1664. PTR_WAS_INVALIDATED(tree);
  1665. PTR_WAS_INVALIDATED(root);
  1666. tree = GetBinTree (TreeOffset);
  1667. root = GetNodeStruct (tree->Root);
  1668. buf = g_CurrentDatabase->Buf;
  1669. }
  1670. INCTREENODES(tree);
  1671. header->InsertionOrdered = TRUE;
  1672. header->InsertionHead = TRUE;
  1673. header->Data = tree->Root;
  1674. header->Head = INVALID_OFFSET;
  1675. header->Tail = INVALID_OFFSET;
  1676. header->Parent = INVALID_OFFSET;
  1677. tree->Root = headerOffset;
  1678. if (root) {
  1679. //
  1680. // There is at least one node in tree, so create LISTELEMs
  1681. //
  1682. node = pBinTreeEnumFirst (tree);
  1683. do {
  1684. nodeOffset = GetNodeOffset (node);
  1685. elem = pBinTreeAllocListElem (&offset);
  1686. if (!elem) {
  1687. return FALSE;
  1688. }
  1689. if (buf != g_CurrentDatabase->Buf) {
  1690. PTR_WAS_INVALIDATED(tree);
  1691. PTR_WAS_INVALIDATED(root);
  1692. PTR_WAS_INVALIDATED(header);
  1693. PTR_WAS_INVALIDATED(node);
  1694. tree = GetBinTree (TreeOffset);
  1695. header = GetNodeStruct (headerOffset);
  1696. node = GetNodeStruct (nodeOffset);
  1697. buf = g_CurrentDatabase->Buf;
  1698. }
  1699. INCTREEELEMS(tree);
  1700. //
  1701. // Update header element pointers
  1702. //
  1703. if (header->Head == INVALID_OFFSET) {
  1704. header->Head = offset;
  1705. }
  1706. if (header->Tail != INVALID_OFFSET) {
  1707. prevElem = GetListElem (header->Tail);
  1708. prevElem->Next = offset;
  1709. }
  1710. header->Tail = offset;
  1711. //
  1712. // Set new LISTELEM members, and corresponding node members
  1713. //
  1714. elem->Data = node->Data;
  1715. elem->Node = nodeOffset;
  1716. elem->Next = INVALID_OFFSET;
  1717. node->Data = offset;
  1718. node->InsertionOrdered = 1;
  1719. node = pBinTreeEnumNext (node);
  1720. } while (node);
  1721. }
  1722. return TRUE;
  1723. }
  1724. UINT
  1725. pBinTreeSize (
  1726. IN PNODESTRUCT Node
  1727. )
  1728. /*++
  1729. Routine Description:
  1730. pBinTreeSize computes the number of nodes indicated by Node and all of its
  1731. children.
  1732. Arguments:
  1733. Node - Specifies the node to find the size of.
  1734. Return Value:
  1735. The number of nodes represented by Node and its children.
  1736. --*/
  1737. {
  1738. if (!Node) {
  1739. return 0;
  1740. }
  1741. return (pBinTreeSize (GetNodeStruct (Node->Left)) ? 1 : 0) +
  1742. (pBinTreeSize (GetNodeStruct (Node->Right)) ? 1 : 0) + 1;
  1743. }
  1744. UINT
  1745. BinTreeSize (
  1746. IN UINT TreeOffset
  1747. )
  1748. /*++
  1749. Routine Description:
  1750. BinTreeSize returns the total number of nodes in the specified binary tree
  1751. Arguments:
  1752. TreeOffset - Specifies the offset to the binary tree
  1753. Return Value:
  1754. The number of nodes in the binary tree
  1755. --*/
  1756. {
  1757. PBINTREE tree;
  1758. if (TreeOffset == INVALID_OFFSET) {
  1759. return 0;
  1760. }
  1761. tree = GetBinTree (TreeOffset);
  1762. return pBinTreeSize (GetTreeRoot (tree));
  1763. }
  1764. #ifdef DEBUG
  1765. INT
  1766. pBinTreeMaxDepth (
  1767. IN PNODESTRUCT Node
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. pBinTreeMaxDepth returns the number of nodes in the longest path. This
  1772. function is used to find out how deep the tree is.
  1773. This routine is recursive.
  1774. Arguments:
  1775. Node - Specifies the node to compute the depth of.
  1776. Return Value:
  1777. The number of nodes in the deepest path.
  1778. --*/
  1779. {
  1780. INT leftDepth, rightDepth;
  1781. if (Node == NULL) {
  1782. return 0;
  1783. }
  1784. leftDepth = pBinTreeMaxDepth (GetNodeStruct (Node->Left));
  1785. rightDepth = pBinTreeMaxDepth (GetNodeStruct (Node->Right));
  1786. return MAX (leftDepth, rightDepth) + 1;
  1787. }
  1788. INT
  1789. BinTreeMaxDepth (
  1790. UINT TreeOffset
  1791. )
  1792. /*++
  1793. Routine Description:
  1794. BinTreeMaxDepth returns the total depth of the specified tree
  1795. Arguments:
  1796. TreeOffset - Specifies the tree to compute the depth of
  1797. Return Value:
  1798. The depth of the tree (in levels)
  1799. --*/
  1800. {
  1801. PBINTREE tree;
  1802. if (TreeOffset == INVALID_OFFSET) {
  1803. return 0;
  1804. }
  1805. tree = GetBinTree (TreeOffset);
  1806. return pBinTreeMaxDepth (GetTreeRoot (tree));
  1807. }
  1808. BOOL
  1809. pBinTreeCheckBalanceOfNode (
  1810. IN PNODESTRUCT Node,
  1811. OUT PINT Depth
  1812. )
  1813. /*++
  1814. Routine Description:
  1815. pBinTreeCheckBalanceOfNode verifies Node is balanced, and all of its
  1816. children are also balanced.
  1817. This function is recursive.
  1818. Arguments:
  1819. Node - Specifies the node to check
  1820. Depth - Receives the depth of the node
  1821. Return Value:
  1822. TRUE if the node is balanced, FALSE otherwise
  1823. --*/
  1824. {
  1825. INT lDepth = 0;
  1826. INT rDepth = 0;
  1827. BOOL flag = TRUE;
  1828. if (!Node) {
  1829. if (Depth) {
  1830. *Depth = 0;
  1831. }
  1832. return TRUE;
  1833. }
  1834. flag = flag && pBinTreeCheckBalanceOfNode (GetNodeStruct (Node->Left), &lDepth);
  1835. MYASSERT (flag);
  1836. flag = flag && pBinTreeCheckBalanceOfNode (GetNodeStruct (Node->Right), &rDepth);
  1837. MYASSERT (flag);
  1838. flag = flag && ((INT) Node->LeftDepth == lDepth);
  1839. MYASSERT (flag);
  1840. flag = flag && ((INT) Node->RightDepth == rDepth);
  1841. MYASSERT (flag);
  1842. if (Depth != NULL) {
  1843. *Depth = MAX (lDepth, rDepth) + 1;
  1844. }
  1845. flag = flag && (ABS ((lDepth - rDepth)) <= 1);
  1846. MYASSERT (flag);
  1847. return flag;
  1848. }
  1849. BOOL
  1850. pBinTreeCheckBalance (
  1851. IN PNODESTRUCT Node
  1852. )
  1853. /*++
  1854. Routine Description:
  1855. pBinTreeCheckBalance checks the balance of Node
  1856. Arguments:
  1857. Node - Specifies the node to check the balance of
  1858. Return Value:
  1859. TRUE if Node is balanced, FALSE otherwise.
  1860. --*/
  1861. {
  1862. return pBinTreeCheckBalanceOfNode (Node, NULL);
  1863. }
  1864. BOOL
  1865. pBinTreeCheck (
  1866. IN PBINTREE Tree
  1867. )
  1868. /*++
  1869. Routine Description:
  1870. pBinTreeCheck checks if the binary tree is sorted and linked properly. It
  1871. enumerates the binary tree structure and compares the strings for proper
  1872. order. If the tree is sorted properly, then the balance is checked.
  1873. Arguments:
  1874. Tree - Specifies the tree to check
  1875. Return Value:
  1876. TRUE if the binary tree is correct, FALSE otherwise.
  1877. --*/
  1878. {
  1879. BOOL flag;
  1880. PNODESTRUCT cur;
  1881. PNODESTRUCT prev;
  1882. prev = pBinTreeEnumFirst (Tree);
  1883. if (Tree) {
  1884. cur = pBinTreeEnumNext (prev);
  1885. while (cur) {
  1886. flag = (StringPasICompare (GetNodeDataStr(prev), GetNodeDataStr(cur)) < 0);
  1887. MYASSERT(flag);
  1888. if (!flag) {
  1889. return FALSE;
  1890. }
  1891. prev = cur;
  1892. cur = pBinTreeEnumNext (prev);
  1893. }
  1894. }
  1895. return pBinTreeCheckBalance (GetTreeRoot (Tree));
  1896. }
  1897. BOOL
  1898. BinTreeCheck (
  1899. UINT TreeOffset
  1900. )
  1901. /*++
  1902. Routine Description:
  1903. BinTreeCheck makes sure the specified binary tree is sorted and balanced
  1904. properly
  1905. Arguments:
  1906. TreeOffset - Specifies the offset of the tree to check
  1907. Return Value:
  1908. TRUE if the tree is sorted properly, FALSE otherwise.
  1909. --*/
  1910. {
  1911. PBINTREE tree;
  1912. tree = GetBinTree (TreeOffset);
  1913. return pBinTreeCheck (tree);
  1914. }
  1915. #include <stdio.h>
  1916. #include <math.h>
  1917. void indent (
  1918. IN UINT size)
  1919. {
  1920. UINT i;
  1921. for (i = 0; i < size; i++)
  1922. wprintf (L" ");
  1923. }
  1924. INT turn (
  1925. IN UINT num,
  1926. IN UINT sel,
  1927. IN UINT width
  1928. )
  1929. {
  1930. UINT temp = num;
  1931. MYASSERT (width > sel);
  1932. if ((temp >> (width-sel-1)) & 1)
  1933. return 1;
  1934. else
  1935. return -1;
  1936. }
  1937. #define SCREENWIDTH 64
  1938. void BinTreePrint(UINT TreeOffset)
  1939. {
  1940. PNODESTRUCT cur;
  1941. UINT i,j;
  1942. UINT level=0;
  1943. UINT numnodes,spacing;
  1944. BOOL printed;
  1945. PBINTREE tree;
  1946. PWSTR str;
  1947. UINT strsize,stringlen;
  1948. tree = GetBinTree(TreeOffset);
  1949. if (!GetTreeRoot(tree)) return;
  1950. while (level<31)
  1951. {
  1952. printed=FALSE;
  1953. if (level == 0) {
  1954. numnodes = 1;
  1955. } else {
  1956. numnodes = (UINT)pow ((double)2, (double)level);
  1957. }
  1958. spacing=SCREENWIDTH / numnodes;
  1959. for (i=0;i<numnodes;i++)
  1960. {
  1961. cur = GetTreeRoot(tree);
  1962. j=0;
  1963. while (j<level && cur!=NULL)
  1964. {
  1965. if (turn(i,j,level)<0)
  1966. cur = GetNodeStruct(cur->Left);
  1967. else
  1968. cur = GetNodeStruct(cur->Right);
  1969. j++;
  1970. }
  1971. if (cur==NULL) {
  1972. indent(spacing);
  1973. } else {
  1974. str=GetNodeDataStr(cur);
  1975. strsize=StringPasCharCount(str);
  1976. StringPasConvertFrom(str);
  1977. printed=TRUE;
  1978. if (cur->LeftDepth==0 && cur->RightDepth==0) {
  1979. stringlen=strsize+1;
  1980. indent((spacing-stringlen)/2);
  1981. wprintf(L"%s ",str);
  1982. } else {
  1983. stringlen=strsize+2;
  1984. indent((spacing-stringlen)/2);
  1985. wprintf(L"%s%1d%1d",str,cur->LeftDepth,cur->RightDepth);
  1986. }
  1987. indent(spacing-((spacing-stringlen)/2)-stringlen);
  1988. StringPasConvertTo(str);
  1989. }
  1990. }
  1991. wprintf(L"\n");
  1992. if (!printed)
  1993. break;
  1994. level++;
  1995. }
  1996. }
  1997. UINT BinTreeGetSizeOfStruct(DWORD Signature)
  1998. {
  1999. switch (Signature)
  2000. {
  2001. case NODESTRUCT_SIGNATURE:
  2002. return NODESTRUCT_SIZE;
  2003. case BINTREE_SIGNATURE:
  2004. return BINTREE_SIZE;
  2005. case LISTELEM_SIGNATURE:
  2006. return LISTELEM_SIZE;
  2007. default:
  2008. return 0;
  2009. }
  2010. }
  2011. BOOL pBinTreeFindTreeInDatabase(UINT TreeOffset)
  2012. {
  2013. PBINTREE Tree;
  2014. if (!g_UseDebugStructs) {
  2015. return TRUE;
  2016. }
  2017. if (TreeOffset==INVALID_OFFSET)
  2018. return FALSE;
  2019. Tree=GetBinTree(TreeOffset);
  2020. if (Tree->Deleted) {
  2021. return TRUE;
  2022. }
  2023. if (!GetTreeRoot(Tree)) {
  2024. DEBUGMSG ((
  2025. DBG_ERROR,
  2026. "MemDbCheckDatabase: Binary tree at offset 0x%08lX is Empty!",
  2027. TreeOffset
  2028. ));
  2029. return FALSE;
  2030. }
  2031. return BinTreeFindStructInDatabase(NODESTRUCT_SIGNATURE, GetNodeOffset(GetTreeRoot(Tree)));
  2032. }
  2033. BOOL pBinTreeFindNodeInDatabase(UINT NodeOffset)
  2034. {
  2035. UINT Index;
  2036. PNODESTRUCT Node;
  2037. if (!g_UseDebugStructs) {
  2038. return TRUE;
  2039. }
  2040. if (NodeOffset == INVALID_OFFSET)
  2041. return FALSE;
  2042. Node=GetNodeStruct(NodeOffset);
  2043. if (Node->Deleted || Node->InsertionHead) {
  2044. return TRUE;
  2045. }
  2046. Index = GetNodeData(Node);
  2047. if (Index==INVALID_OFFSET) {
  2048. DEBUGMSG ((
  2049. DBG_ERROR,
  2050. "MemDbCheckDatabase: Data of Node at offset 0x%8lX is Invalid!",
  2051. NodeOffset
  2052. ));
  2053. return FALSE;
  2054. }
  2055. return FindKeyStructInDatabase(KeyIndexToOffset(Index));
  2056. }
  2057. BOOL BinTreeFindStructInDatabase(DWORD Sig, UINT Offset)
  2058. {
  2059. switch (Sig)
  2060. {
  2061. case NODESTRUCT_SIGNATURE:
  2062. return (pBinTreeFindNodeInDatabase(Offset));
  2063. case BINTREE_SIGNATURE:
  2064. return (pBinTreeFindTreeInDatabase(Offset));
  2065. case LISTELEM_SIGNATURE:
  2066. return TRUE;
  2067. default:
  2068. DEBUGMSG ((
  2069. DBG_ERROR,
  2070. "MemDbCheckDatabase: Invalid BinTree Struct!"
  2071. ));
  2072. printf("Invalid BinTree struct!\n");
  2073. }
  2074. return FALSE;
  2075. }
  2076. #endif