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.

239 lines
6.7 KiB

  1. /*
  2. * block.c
  3. *
  4. * LZX block outputting
  5. */
  6. #include "encoder.h"
  7. /*
  8. * Internal function definitions
  9. */
  10. static void do_block_output(
  11. t_encoder_context *context,
  12. long literal_to_end_at,
  13. long distance_to_end_at
  14. );
  15. static void do_block_output(
  16. t_encoder_context *context,
  17. long literal_to_end_at,
  18. long distance_to_end_at
  19. )
  20. {
  21. ulong bytes_compressed;
  22. lzx_block_type block_type;
  23. ulong estimated_block_size;
  24. /*
  25. * Calculate frequencies for all tree elements.
  26. *
  27. * How many uncompressed bytes does this account for?
  28. */
  29. bytes_compressed = get_block_stats(
  30. context,
  31. 0,
  32. 0,
  33. literal_to_end_at
  34. );
  35. /*
  36. * Determine whether we wish to output a verbatim block or an
  37. * aligned offset block
  38. */
  39. block_type = get_aligned_stats(context, distance_to_end_at);
  40. /*
  41. * Create trees from the frequency data
  42. */
  43. create_trees(context, true); /* we want to generate the codes too */
  44. /*
  45. * Determine whether the block should be output as uncompressed
  46. */
  47. estimated_block_size = estimate_compressed_block_size(context);
  48. if (estimated_block_size >= bytes_compressed)
  49. {
  50. if (context->enc_bufpos_at_last_block >= context->enc_earliest_window_data_remaining)
  51. block_type = BLOCKTYPE_UNCOMPRESSED;
  52. }
  53. output_bits(context, 3, (byte) block_type);
  54. /* output 24 bit number, number of bytes compressed here */
  55. output_bits(context, 8, (bytes_compressed >> 16) & 255);
  56. output_bits(context, 8, ((bytes_compressed >> 8) & 255));
  57. output_bits(context, 8, (bytes_compressed & 255));
  58. if (block_type == BLOCKTYPE_VERBATIM)
  59. {
  60. encode_trees(context);
  61. encode_verbatim_block(context, literal_to_end_at);
  62. get_final_repeated_offset_states(context, distance_to_end_at);
  63. }
  64. else if (block_type == BLOCKTYPE_ALIGNED)
  65. {
  66. encode_aligned_tree(context);
  67. encode_trees(context);
  68. encode_aligned_block(context, literal_to_end_at);
  69. get_final_repeated_offset_states(context, distance_to_end_at);
  70. }
  71. else if (block_type == BLOCKTYPE_UNCOMPRESSED)
  72. {
  73. get_final_repeated_offset_states(context, distance_to_end_at);
  74. encode_uncompressed_block(context, context->enc_bufpos_at_last_block, bytes_compressed);
  75. }
  76. context->enc_bufpos_at_last_block += bytes_compressed;
  77. }
  78. /*
  79. * Returns the number of distances which correspond
  80. * to this number of literals
  81. */
  82. ulong get_distances_from_literals(t_encoder_context *context, ulong literals)
  83. {
  84. ulong d = 0;
  85. ulong i;
  86. for (i = 0; i < (literals >> 3); i++)
  87. d += context->enc_ones[ context->enc_ItemType[i] ];
  88. /*
  89. * Handle remaining 0...7
  90. */
  91. for (i = (literals & (~7)); i < literals; i++)
  92. {
  93. if (IsMatch(i))
  94. d++;
  95. }
  96. return d;
  97. }
  98. /*
  99. * Output a block
  100. *
  101. * If trees_only is true, then only the tree statistics are updated.
  102. */
  103. void output_block(t_encoder_context *context)
  104. {
  105. ulong where_to_split;
  106. ulong distances;
  107. //
  108. // We have now output a block.
  109. //
  110. // We set this here in case someone calls LCIFlushOutput, so that
  111. // we don't try to redo the first chunk of bytes in the file
  112. // (since we've been forced to output them)
  113. //
  114. context->enc_first_block = 0;
  115. split_block(
  116. context,
  117. 0,
  118. context->enc_literals,
  119. context->enc_distances,
  120. &where_to_split,
  121. &distances /* distances @ literal == where_to_split */
  122. );
  123. do_block_output(context, where_to_split, distances);
  124. if (where_to_split == context->enc_literals)
  125. {
  126. /*
  127. * If we've output ALL of our literals, then clear the itemtype array
  128. */
  129. memset(context->enc_ItemType, 0, MAX_LITERAL_ITEMS/8);
  130. context->enc_literals = 0;
  131. context->enc_distances = 0;
  132. }
  133. else
  134. {
  135. /*
  136. * If we didn't output all of our literals, then move the literals
  137. * and distances we didn't use, to the beginning of the list
  138. */
  139. memcpy(
  140. &context->enc_ItemType[0],
  141. &context->enc_ItemType[where_to_split/8],
  142. &context->enc_ItemType[1+(context->enc_literals/8)] - &context->enc_ItemType[where_to_split/8]
  143. );
  144. memset(
  145. &context->enc_ItemType[1+(context->enc_literals-where_to_split)/8],
  146. 0,
  147. &context->enc_ItemType[MAX_LITERAL_ITEMS/8] - &context->enc_ItemType[1+(context->enc_literals-where_to_split)/8]
  148. );
  149. memcpy(
  150. &context->enc_LitData[0],
  151. &context->enc_LitData[where_to_split],
  152. sizeof( context->enc_LitData[0] ) * ( context->enc_literals-where_to_split )
  153. );
  154. #ifdef EXTRALONGMATCHES
  155. memcpy(
  156. &context->enc_ExtraLength[0],
  157. &context->enc_ExtraLength[where_to_split],
  158. sizeof( context->enc_ExtraLength[0] ) * ( context->enc_literals-where_to_split )
  159. );
  160. #endif
  161. memcpy(
  162. &context->enc_DistData[0],
  163. &context->enc_DistData[distances],
  164. sizeof(ulong)*(context->enc_distances-distances)
  165. );
  166. context->enc_literals -= where_to_split;
  167. context->enc_distances -= distances;
  168. }
  169. fix_tree_cost_estimates(context);
  170. }
  171. void flush_output_bit_buffer(t_encoder_context *context)
  172. {
  173. byte temp;
  174. if (context->enc_bitcount < 32)
  175. {
  176. temp = context->enc_bitcount-16;
  177. output_bits(context, temp, 0);
  178. }
  179. }
  180. /*
  181. * Estimate how much it would take to output the compressed
  182. * data left in the buffer
  183. */
  184. long estimate_buffer_contents(t_encoder_context *context)
  185. {
  186. long estimated_block_size;
  187. /*
  188. * Use frequency data sitting around from last tree creation
  189. */
  190. create_trees(context, false); /* don't generate codes */
  191. estimated_block_size = estimate_compressed_block_size(context);
  192. /* so the optimal parser doesn't get confused */
  193. fix_tree_cost_estimates(context);
  194. return estimated_block_size;
  195. }