Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
6.7 KiB

  1. /*
  2. ** lzcommon.c - Routines common to LZ compression / expansion.
  3. **
  4. ** Author: DavidDi
  5. */
  6. // Headers
  7. ///////////
  8. #include "lz_common.h"
  9. #include "lz_buffers.h"
  10. #include "lzcommon.h"
  11. /*
  12. ** bool LZInitTree(void);
  13. **
  14. ** Initializes trees used in LZ compression.
  15. **
  16. ** Arguments: none
  17. **
  18. ** Returns: true/false
  19. **
  20. ** Globals: RightChild[] and Parent[] arrays reset to NIL to begin
  21. ** encoding.
  22. */
  23. BOOL LZInitTree(PLZINFO pLZI)
  24. {
  25. INT i;
  26. /*
  27. ** For i = 0 to RING_BUF_LEN - 1, rightChild[i] and leftChild[i] will be the
  28. ** right and left children of node i. These nodes need not be initialized.
  29. ** Also, parent[i] is the parent of node i. These are initialized to
  30. ** NIL (= N), which stands for 'not used.'
  31. ** For i = 0 to 255, rightChild[RING_BUF_LEN + i + 1] is the root of the tree
  32. ** for strings that begin with character i. These are initialized to NIL.
  33. ** n.b., there are 256 trees.
  34. */
  35. if (!pLZI->rightChild) {
  36. if (!(pLZI->rightChild = (INT*)LocalAlloc(LPTR, (RING_BUF_LEN + 257) * sizeof(INT)))) {
  37. return(FALSE);
  38. }
  39. }
  40. if (!pLZI->leftChild) {
  41. if (!(pLZI->leftChild = (INT*)LocalAlloc(LPTR, (RING_BUF_LEN + 1) * sizeof(INT)))) {
  42. return(FALSE);
  43. }
  44. }
  45. if (!pLZI->parent) {
  46. if (!(pLZI->parent = (INT*)LocalAlloc(LPTR, (RING_BUF_LEN + 1) * sizeof(INT)))) {
  47. return(FALSE);
  48. }
  49. }
  50. for (i = RING_BUF_LEN + 1; i <= RING_BUF_LEN + 256; i++)
  51. pLZI->rightChild[i] = NIL;
  52. for (i = 0; i < RING_BUF_LEN; i++)
  53. pLZI->parent[i] = NIL;
  54. return(TRUE);
  55. }
  56. VOID
  57. LZFreeTree(PLZINFO pLZI)
  58. {
  59. // Sanity check
  60. if (!pLZI) {
  61. return;
  62. }
  63. if (pLZI->rightChild) {
  64. LocalFree((HLOCAL)pLZI->rightChild);
  65. pLZI->rightChild = NULL;
  66. }
  67. if (pLZI->leftChild) {
  68. LocalFree((HLOCAL)pLZI->leftChild);
  69. pLZI->leftChild = NULL;
  70. }
  71. if (pLZI->parent) {
  72. LocalFree((HLOCAL)pLZI->parent);
  73. pLZI->parent = NULL;
  74. }
  75. }
  76. /*
  77. ** void LZInsertNode(int nodeToInsert, BOOL bDoArithmeticInsert);
  78. **
  79. ** Inserts a new tree into the forest. Inserts string of length
  80. ** cbMaxMatchLen, rgbyteRingBuf[r..r + cbMaxMatchLen - 1], into one of the trees
  81. ** (rgbyteRingBuf[r]'th tree).
  82. **
  83. ** Arguments: nodeToInsert - start of string in ring buffer to insert
  84. ** (also, associated tree root)
  85. ** bDoArithmeticInsert - flag for performing regular LZ node
  86. ** insertion or arithmetic encoding node
  87. ** insertion
  88. **
  89. ** Returns: void
  90. **
  91. ** Globals: cbCurMatch - set to length of longest match
  92. ** iCurMatch - set to start index of longest matching string in
  93. ** ring buffer
  94. **
  95. ** N.b., if cbCurMatch == cbMaxMatchLen, we remove the old node in favor of
  96. ** the new one, since the old node will be deleted sooner.
  97. */
  98. VOID LZInsertNode(INT nodeToInsert, BOOL bDoArithmeticInsert, PLZINFO pLZI)
  99. {
  100. INT i, p, cmp, temp;
  101. BYTE FAR *key;
  102. // Sanity check
  103. if (!pLZI) {
  104. return;
  105. }
  106. cmp = 1;
  107. key = pLZI->rgbyteRingBuf + nodeToInsert;
  108. p = RING_BUF_LEN + 1 + key[0];
  109. pLZI->rightChild[nodeToInsert] = pLZI->leftChild[nodeToInsert] = NIL;
  110. pLZI->cbCurMatch = 0;
  111. FOREVER
  112. {
  113. if (cmp >= 0)
  114. {
  115. if (pLZI->rightChild[p] != NIL)
  116. p = pLZI->rightChild[p];
  117. else
  118. {
  119. pLZI->rightChild[p] = nodeToInsert;
  120. pLZI->parent[nodeToInsert] = p;
  121. return;
  122. }
  123. }
  124. else
  125. {
  126. if (pLZI->leftChild[p] != NIL)
  127. p = pLZI->leftChild[p];
  128. else
  129. {
  130. pLZI->leftChild[p] = nodeToInsert;
  131. pLZI->parent[nodeToInsert] = p;
  132. return;
  133. }
  134. }
  135. for (i = 1; i < pLZI->cbMaxMatchLen; i++)
  136. if ((cmp = key[i] - pLZI->rgbyteRingBuf[p + i]) != 0)
  137. break;
  138. if (bDoArithmeticInsert == TRUE)
  139. {
  140. // Do node insertion for arithmetic encoding.
  141. if (i > MAX_LITERAL_LEN)
  142. {
  143. if (i > pLZI->cbCurMatch)
  144. {
  145. pLZI->iCurMatch = (nodeToInsert - p) & (RING_BUF_LEN - 1);
  146. if ((pLZI->cbCurMatch = i) >= pLZI->cbMaxMatchLen)
  147. break;
  148. }
  149. else if (i == pLZI->cbCurMatch)
  150. {
  151. if ((temp = (nodeToInsert - p) & (RING_BUF_LEN - 1)) < pLZI->iCurMatch)
  152. pLZI->iCurMatch = temp;
  153. }
  154. }
  155. }
  156. else
  157. {
  158. // Do node insertion for LZ.
  159. if (i > pLZI->cbCurMatch)
  160. {
  161. pLZI->iCurMatch = p;
  162. if ((pLZI->cbCurMatch = i) >= pLZI->cbMaxMatchLen)
  163. break;
  164. }
  165. }
  166. }
  167. pLZI->parent[nodeToInsert] = pLZI->parent[p];
  168. pLZI->leftChild[nodeToInsert] = pLZI->leftChild[p];
  169. pLZI->rightChild[nodeToInsert] = pLZI->rightChild[p];
  170. pLZI->parent[pLZI->leftChild[p]] = nodeToInsert;
  171. pLZI->parent[pLZI->rightChild[p]] = nodeToInsert;
  172. if (pLZI->rightChild[pLZI->parent[p]] == p)
  173. pLZI->rightChild[pLZI->parent[p]] = nodeToInsert;
  174. else
  175. pLZI->leftChild[pLZI->parent[p]] = nodeToInsert;
  176. // Remove p.
  177. pLZI->parent[p] = NIL;
  178. return;
  179. }
  180. /*
  181. ** void LZDeleteNode(int nodeToDelete);
  182. **
  183. ** Delete a tree from the forest.
  184. **
  185. ** Arguments: nodeToDelete - tree to delete from forest
  186. **
  187. ** Returns: void
  188. **
  189. ** Globals: Parent[], RightChild[], and LeftChild[] updated to reflect the
  190. ** deletion of nodeToDelete.
  191. */
  192. VOID LZDeleteNode(INT nodeToDelete, PLZINFO pLZI)
  193. {
  194. INT q;
  195. // Sanity check
  196. if (!pLZI) {
  197. return;
  198. }
  199. if (pLZI->parent[nodeToDelete] == NIL)
  200. // Tree nodeToDelete is not in the forest.
  201. return;
  202. if (pLZI->rightChild[nodeToDelete] == NIL)
  203. q = pLZI->leftChild[nodeToDelete];
  204. else if (pLZI->leftChild[nodeToDelete] == NIL)
  205. q = pLZI->rightChild[nodeToDelete];
  206. else
  207. {
  208. q = pLZI->leftChild[nodeToDelete];
  209. if (pLZI->rightChild[q] != NIL)
  210. {
  211. do
  212. {
  213. q = pLZI->rightChild[q];
  214. } while (pLZI->rightChild[q] != NIL);
  215. pLZI->rightChild[pLZI->parent[q]] = pLZI->leftChild[q];
  216. pLZI->parent[pLZI->leftChild[q]] = pLZI->parent[q];
  217. pLZI->leftChild[q] = pLZI->leftChild[nodeToDelete];
  218. pLZI->parent[pLZI->leftChild[nodeToDelete]] = q;
  219. }
  220. pLZI->rightChild[q] = pLZI->rightChild[nodeToDelete];
  221. pLZI->parent[pLZI->rightChild[nodeToDelete]] = q;
  222. }
  223. pLZI->parent[q] = pLZI->parent[nodeToDelete];
  224. if (pLZI->rightChild[pLZI->parent[nodeToDelete]] == nodeToDelete)
  225. pLZI->rightChild[pLZI->parent[nodeToDelete]] = q;
  226. else
  227. pLZI->leftChild[pLZI->parent[nodeToDelete]] = q;
  228. // Remove nodeToDelete.
  229. pLZI->parent[nodeToDelete] = NIL;
  230. return;
  231. }