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.

213 lines
4.5 KiB

  1. /*
  2. * tree.c
  3. *
  4. * Tree building routines.
  5. *
  6. * These routines are originally from the Public Domain source "AR001".
  7. *
  8. * However, they have been modified for use in LZX.
  9. */
  10. #include "encoder.h"
  11. /* Function prototypes */
  12. static void downheap(t_encoder_context *context, short i);
  13. static void make_tree2(t_encoder_context *context, short avail, ushort freqparm[], ushort codeparm[]);
  14. static void make_len(t_encoder_context *context, short root);
  15. static void make_code(t_encoder_context *context, int n, char len[], ushort code[]);
  16. static void count_len(t_encoder_context *context, short i) /* call with i = root */
  17. {
  18. if (i < context->enc_tree_n)
  19. context->enc_tree_len_cnt[(context->enc_depth < 16) ? context->enc_depth : 16]++; /* NOTE: 16 is max len allowed */
  20. else
  21. {
  22. context->enc_depth++;
  23. count_len(context, context->enc_tree_leftright[i*2]);
  24. count_len(context, context->enc_tree_leftright[i*2+1]);
  25. context->enc_depth--;
  26. }
  27. }
  28. static void make_len(t_encoder_context *context, short root)
  29. {
  30. signed short k;
  31. ushort cum;
  32. byte i;
  33. for (i = 0; i <= 16; i++)
  34. context->enc_tree_len_cnt[i] = 0;
  35. count_len(context, root);
  36. cum = 0;
  37. for (i = 16; i > 0; i--)
  38. cum += (ushort) (context->enc_tree_len_cnt[i] << (16 - i));
  39. /* cum should equal 1<<16, which is 0 since cum is a ushort */
  40. while (cum)
  41. {
  42. context->enc_tree_len_cnt[16]--;
  43. for (i = 15; i > 0; i--)
  44. {
  45. if (context->enc_tree_len_cnt[i])
  46. {
  47. context->enc_tree_len_cnt[i]--;
  48. context->enc_tree_len_cnt[i+1] += 2;
  49. break;
  50. }
  51. }
  52. cum--;
  53. }
  54. for (i = 16; i > 0; i--)
  55. {
  56. k = context->enc_tree_len_cnt[i];
  57. while (--k >= 0)
  58. context->enc_len[*context->enc_tree_sortptr++] = (byte) i;
  59. }
  60. }
  61. static void __inline downheap(t_encoder_context *context, short i)
  62. /* priority queue; send i-th entry down heap */
  63. {
  64. short j, k;
  65. k = context->enc_tree_heap[i];
  66. while ((j = (i<<1)) <= context->enc_tree_heapsize)
  67. {
  68. if (j < context->enc_tree_heapsize &&
  69. context->enc_tree_freq[context->enc_tree_heap[j]] > context->enc_tree_freq[context->enc_tree_heap[j + 1]])
  70. j++;
  71. if (context->enc_tree_freq[k] <= context->enc_tree_freq[context->enc_tree_heap[j]])
  72. break;
  73. context->enc_tree_heap[i] = context->enc_tree_heap[j];
  74. i = j;
  75. }
  76. context->enc_tree_heap[i] = k;
  77. }
  78. static void make_code(t_encoder_context *context, int n, char len[], ushort code[])
  79. {
  80. int i;
  81. ushort start[18];
  82. start[1] = 0;
  83. for (i = 1; i <= 16; i++)
  84. start[i + 1] = (start[i] + context->enc_tree_len_cnt[i]) << 1;
  85. for (i = 0; i < n; i++)
  86. {
  87. code[i] = start[len[i]]++;
  88. }
  89. }
  90. void make_tree(
  91. t_encoder_context *context,
  92. int nparm,
  93. ushort *freqparm,
  94. byte *lenparm,
  95. ushort *codeparm,
  96. bool make_codes /* for estimations, we only want the lengths */
  97. )
  98. {
  99. short i, avail;
  100. REDO_TREE:
  101. context->enc_tree_n = nparm;
  102. context->enc_tree_freq = freqparm;
  103. context->enc_len = lenparm;
  104. avail = (short)context->enc_tree_n;
  105. context->enc_depth = 0;
  106. context->enc_tree_heapsize = 0;
  107. context->enc_tree_heap[1] = 0;
  108. for (i = 0; i < nparm; i++)
  109. {
  110. context->enc_len[i] = 0;
  111. if (freqparm[i])
  112. context->enc_tree_heap[++context->enc_tree_heapsize] = i;
  113. }
  114. if (context->enc_tree_heapsize < 2)
  115. {
  116. if (!context->enc_tree_heapsize)
  117. {
  118. codeparm[context->enc_tree_heap[1]] = 0;
  119. return;
  120. }
  121. if (!context->enc_tree_heap[1])
  122. freqparm[1] = 1;
  123. else
  124. freqparm[0] = 1;
  125. goto REDO_TREE;
  126. }
  127. make_tree2(context, avail, freqparm, codeparm);
  128. if (make_codes)
  129. make_code(context, nparm, lenparm, codeparm);
  130. }
  131. static void make_tree2(
  132. t_encoder_context *context,
  133. short avail,
  134. ushort freqparm[],
  135. ushort codeparm[]
  136. )
  137. {
  138. short i, j, k;
  139. for (i = context->enc_tree_heapsize >> 1; i >= 1; i--)
  140. downheap(context, i); /* make priority queue */
  141. context->enc_tree_sortptr = codeparm;
  142. do
  143. { /* while queue has at least two entries */
  144. i = context->enc_tree_heap[1]; /* take out least-freq entry */
  145. if (i < context->enc_tree_n)
  146. *context->enc_tree_sortptr++ = i;
  147. context->enc_tree_heap[1] = context->enc_tree_heap[context->enc_tree_heapsize--];
  148. downheap(context, 1);
  149. j = context->enc_tree_heap[1]; /* next least-freq entry */
  150. if (j < context->enc_tree_n)
  151. *context->enc_tree_sortptr++ = j;
  152. k = avail++; /* generate new node */
  153. freqparm[k] = freqparm[i] + freqparm[j];
  154. context->enc_tree_heap[1] = k;
  155. downheap(context, 1); /* put into queue */
  156. context->enc_tree_leftright[k*2] = i;
  157. context->enc_tree_leftright[k*2+1] = j;
  158. } while (context->enc_tree_heapsize > 1);
  159. context->enc_tree_sortptr = codeparm;
  160. make_len(context, k);
  161. }