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.

432 lines
14 KiB

  1. /*
  2. * deflate.c
  3. *
  4. * Main compression entrypoint for all three encoders
  5. */
  6. #include <string.h>
  7. #include <stdio.h>
  8. #include <crtdbg.h>
  9. #include "deflate.h"
  10. #include "fasttbl.h"
  11. #include "defgzip.h"
  12. typedef struct config_s
  13. {
  14. int good_length; /* reduce lazy search above this match length */
  15. int max_lazy; /* do not perform lazy search above this match length */
  16. int nice_length; /* quit search above this match length */
  17. int max_chain;
  18. } compression_config;
  19. static const compression_config configuration_table[11] = {
  20. /* good lazy nice chain */
  21. /* 0 */ {0, 0, 0, 0 }, /* store only */
  22. /* 1 */ {4, 4, 8, 4 }, /* maximum speed, no lazy matches */
  23. /* 2 */ {4, 5, 16, 8 },
  24. /* 3 */ {4, 6, 32, 32 },
  25. /* 4 */ {4, 4, 16, 16 }, /* lazy matches */
  26. /* 5 */ {8, 16, 32, 32 },
  27. /* 6 */ {8, 16, 128, 128 },
  28. /* 7 */ {8, 32, 128, 256 },
  29. /* 8 */ {32, 128, 258, 1024 },
  30. /* 9 */ {32, 258, 258, 4096 },
  31. /* 10 */ {32, 258, 258, 4096 } /* maximum compression */
  32. };
  33. //
  34. // Destroy the std encoder, optimal encoder, and fast encoder, but leave the
  35. // compressor context around
  36. //
  37. VOID DestroyIndividualCompressors(PVOID void_context)
  38. {
  39. t_encoder_context *context = (t_encoder_context *) void_context;
  40. if (context->std_encoder != NULL)
  41. {
  42. LocalFree((PVOID) context->std_encoder);
  43. context->std_encoder = NULL;
  44. }
  45. if (context->optimal_encoder != NULL)
  46. {
  47. LocalFree((PVOID) context->optimal_encoder);
  48. context->optimal_encoder = NULL;
  49. }
  50. if (context->fast_encoder != NULL)
  51. {
  52. LocalFree((PVOID) context->fast_encoder);
  53. context->fast_encoder = NULL;
  54. }
  55. }
  56. //
  57. // Mark the final block in the compressed data
  58. //
  59. // There must be one final block with bfinal=1 indicating that it is the last one. In the case of
  60. // the fast encoder we just need to output the end of block code, since the fast encoder just outputs
  61. // one very long block.
  62. //
  63. // In the case of the standard and optimal encoders we have already finished outputting blocks,
  64. // so we output a new block (a static/fixed block) with bfinal=1, consisting merely of the
  65. // end of block code.
  66. //
  67. static void markFinalBlock(t_encoder_context *context)
  68. {
  69. if (context->fast_encoder != NULL)
  70. {
  71. // The fast encoder outputs one long block, so it just needs to terminate this block
  72. outputBits(
  73. context,
  74. g_FastEncoderLiteralTreeLength[END_OF_BLOCK_CODE],
  75. g_FastEncoderLiteralTreeCode[END_OF_BLOCK_CODE]
  76. );
  77. }
  78. else
  79. {
  80. // To finish, output a static block consisting of a single end of block code
  81. // Combined these three outputBits() calls (commented out) into one call
  82. // The total number of bits output in one shot must be <= 16, but we're ok
  83. // since the the length of END_OF_BLOCK_CODE is 7 for a static (fixed) block
  84. #if 0
  85. outputBits(context, 1, 1); // bfinal = 1
  86. outputBits(context, 2, BLOCKTYPE_FIXED);
  87. outputBits(context, g_StaticLiteralTreeLength[END_OF_BLOCK_CODE], g_StaticLiteralTreeCode[END_OF_BLOCK_CODE]);
  88. #endif
  89. // note: g_StaticLiteralTreeCode[END_OF_BLOCK_CODE] == 0x0000
  90. outputBits(
  91. context,
  92. (7 + 3), // StaticLiteralTreeLength[END_OF_BLOCK_CODE]=7, + 1 bfinal bit + 2 blocktype bits
  93. ((0x0000) << 3) | (BLOCKTYPE_FIXED << 1) | 1
  94. );
  95. }
  96. // flush bits from bit buffer to output buffer
  97. flushOutputBitBuffer(context);
  98. if (context->using_gzip)
  99. WriteGzipFooter(context);
  100. }
  101. //
  102. // Returns a pointer to the start of the window of the currently active compressor
  103. //
  104. // Used for memcpy'ing window data when we reach the end of the window
  105. //
  106. static BYTE *GetEncoderWindow(t_encoder_context *context)
  107. {
  108. _ASSERT(context->std_encoder != NULL || context->optimal_encoder != NULL || context->fast_encoder != NULL);
  109. if (context->std_encoder != NULL)
  110. return context->std_encoder->window;
  111. else if (context->optimal_encoder != NULL)
  112. return context->optimal_encoder->window;
  113. else
  114. return context->fast_encoder->window;
  115. }
  116. //
  117. // This function does the actual work of resetting the compression state.
  118. // However, it does not free the std/fast/optimal encoder memory (something
  119. // that the external ResetCompression() API currently does).
  120. //
  121. void InternalResetCompression(t_encoder_context *context)
  122. {
  123. context->no_more_input = FALSE;
  124. context->marked_final_block = FALSE;
  125. context->state = STATE_NORMAL;
  126. context->outputting_block_num_literals = 0;
  127. if (context->using_gzip)
  128. EncoderInitGzipVariables(context);
  129. InitBitBuffer(context);
  130. }
  131. //
  132. // The compress API
  133. //
  134. HRESULT WINAPI Compress(
  135. PVOID void_context,
  136. CONST BYTE * input_buffer,
  137. LONG input_buffer_size,
  138. PBYTE output_buffer,
  139. LONG output_buffer_size,
  140. PLONG input_used,
  141. PLONG output_used,
  142. INT compression_level
  143. )
  144. {
  145. int lazy_match_threshold;
  146. int search_depth;
  147. int good_length;
  148. int nice_length;
  149. t_encoder_context * context = (t_encoder_context *) void_context;
  150. t_std_encoder * std_encoder;
  151. t_optimal_encoder * optimal_encoder;
  152. t_fast_encoder * fast_encoder;
  153. HRESULT result = S_OK; // default to success
  154. *input_used = 0;
  155. *output_used = 0;
  156. // validate compression level
  157. if (compression_level < 0 || compression_level > 10)
  158. {
  159. result = E_INVALIDARG;
  160. goto exit;
  161. }
  162. context->output_curpos = output_buffer;
  163. context->output_endpos = output_buffer + output_buffer_size;
  164. context->output_near_end_threshold = output_buffer + output_buffer_size - 16;
  165. //
  166. // Have we allocated the particular compressor we want yet?
  167. //
  168. if (context->std_encoder == NULL && context->optimal_encoder == NULL && context->fast_encoder == NULL)
  169. {
  170. // No
  171. if (compression_level <= 3) // fast encoder
  172. {
  173. if (FastEncoderInit(context) == FALSE)
  174. {
  175. result = E_OUTOFMEMORY;
  176. goto exit;
  177. }
  178. }
  179. else if (compression_level == 10) // optimal encoder
  180. {
  181. if (OptimalEncoderInit(context) == FALSE)
  182. {
  183. result = E_OUTOFMEMORY;
  184. goto exit;
  185. }
  186. }
  187. else
  188. {
  189. if (StdEncoderInit(context) == FALSE)
  190. {
  191. result = E_OUTOFMEMORY;
  192. goto exit;
  193. }
  194. }
  195. }
  196. std_encoder = context->std_encoder;
  197. optimal_encoder = context->optimal_encoder;
  198. fast_encoder = context->fast_encoder;
  199. _ASSERT(std_encoder != NULL || optimal_encoder != NULL || fast_encoder != NULL);
  200. // set search depth
  201. if (fast_encoder != NULL)
  202. {
  203. search_depth = configuration_table[compression_level].max_chain;
  204. good_length = configuration_table[compression_level].good_length;
  205. nice_length = configuration_table[compression_level].nice_length;
  206. lazy_match_threshold = configuration_table[compression_level].max_lazy;
  207. }
  208. else if (std_encoder != NULL)
  209. {
  210. search_depth = configuration_table[compression_level].max_chain;
  211. good_length = configuration_table[compression_level].good_length;
  212. nice_length = configuration_table[compression_level].nice_length;
  213. lazy_match_threshold = configuration_table[compression_level].max_lazy;
  214. }
  215. // the output buffer must be large enough to contain an entire tree
  216. if (output_buffer_size < MAX_TREE_DATA_SIZE)
  217. {
  218. result = E_INVALIDARG;
  219. goto exit;
  220. }
  221. if (context->using_gzip && context->gzip_fOutputGzipHeader == FALSE)
  222. {
  223. // Write the GZIP header
  224. WriteGzipHeader(context, compression_level);
  225. context->gzip_fOutputGzipHeader = TRUE;
  226. }
  227. //
  228. // Check if previously we were in the middle of outputting a block
  229. //
  230. if (context->state != STATE_NORMAL)
  231. {
  232. // The fast encoder is a special case; it doesn't use OutputBlock()
  233. if (fast_encoder != NULL)
  234. goto start_encoding;
  235. // yes we were, so continue outputting it
  236. OutputBlock(context);
  237. //
  238. // Check if we're still outputting a block (it may be a long block that
  239. // has filled up the output buffer again)
  240. //
  241. // If we're coming close to the end of the buffer, and may not have enough space to
  242. // output a full tree structure, stop now.
  243. //
  244. if (context->state != STATE_NORMAL ||
  245. context->output_endpos - context->output_curpos < MAX_TREE_DATA_SIZE)
  246. {
  247. *output_used = (long) (context->output_curpos - output_buffer);
  248. goto set_output_used_then_exit; // success
  249. }
  250. //
  251. // We finished outputting the previous block, so time to compress some more input
  252. //
  253. }
  254. #ifdef _DEBUG
  255. // Fast encoder doesn't use outputBlock, so it doesn't have the tree limitation
  256. if (fast_encoder == NULL)
  257. _ASSERTE(context->output_endpos - context->output_curpos >= MAX_TREE_DATA_SIZE);
  258. #endif
  259. //
  260. // input_buffer_size == 0 means "this is the final block"
  261. //
  262. // Of course, the client may still need to call Compress() many more times if the output
  263. // buffer is small and there is a big block waiting to be sent.
  264. //
  265. // We may even have some pending input data in our buffer waiting to be compressed.
  266. //
  267. if ((input_buffer_size == 0 || context->no_more_input) && context->bufpos >= context->bufpos_end)
  268. {
  269. // if we're ever passed zero bytes of input, it means that there will never be any
  270. // more input
  271. context->no_more_input = TRUE;
  272. // output existing block
  273. // this never happens for the fast encoder, since we don't record blocks
  274. if (context->outputting_block_num_literals != 0)
  275. {
  276. FlushRecordingBuffer(context);
  277. OutputBlock(context);
  278. //
  279. // Still outputting a block?
  280. //
  281. if (context->state != STATE_NORMAL)
  282. goto set_output_used_then_exit; // success
  283. }
  284. // for the fast encoder only, we won't have output our fast encoder preamble if the
  285. // file size == 0, so output it now if we haven't already.
  286. if (fast_encoder != NULL)
  287. {
  288. if (fast_encoder->fOutputBlockHeader == FALSE)
  289. {
  290. fast_encoder->fOutputBlockHeader = TRUE;
  291. FastEncoderOutputPreamble(context);
  292. }
  293. }
  294. // if we've already marked the final block, don't do it again
  295. if (context->marked_final_block)
  296. {
  297. result = S_FALSE;
  298. goto set_output_used_then_exit; // should be zero output used
  299. }
  300. // ensure there is enough space to output the final block (max 8 bytes)
  301. if (context->output_curpos + 8 >= context->output_endpos)
  302. goto set_output_used_then_exit; // not enough space - do it next time
  303. // output the final block (of length zero - we just want the bfinal=1 marker)
  304. markFinalBlock(context);
  305. context->marked_final_block = TRUE;
  306. result = S_FALSE;
  307. goto set_output_used_then_exit;
  308. }
  309. // while there is more input data (passed in as parameters) or existing data in
  310. // the window to compress
  311. start_encoding:
  312. while ((input_buffer_size > 0) || (context->bufpos < context->bufpos_end))
  313. {
  314. long amount_to_compress;
  315. long window_space_available;
  316. _ASSERT(context->bufpos >= context->window_size && context->bufpos < (2*context->window_size));
  317. #ifdef _DEBUG
  318. // Fast encoder doesn't use outputBlock, so it doesn't have the tree limitation
  319. if (fast_encoder == NULL)
  320. _ASSERTE(context->output_endpos - context->output_curpos >= MAX_TREE_DATA_SIZE);
  321. #endif
  322. // read more input data into the window if there is space available
  323. window_space_available = (2*context->window_size) - context->bufpos_end;
  324. amount_to_compress = (input_buffer_size < window_space_available) ? input_buffer_size : window_space_available;
  325. if (amount_to_compress > 0)
  326. {
  327. *input_used += amount_to_compress;
  328. // copy data into history window
  329. if (context->using_gzip)
  330. {
  331. // In addition to copying data into the history window, GZIP wants a crc32 of the input data.
  332. // We will do both of these things at the same time for the purposes of data locality,
  333. // performance etc.
  334. GzipCRCmemcpy(context, GetEncoderWindow(context) + context->bufpos_end, input_buffer, amount_to_compress);
  335. }
  336. else
  337. {
  338. // Copy data into history window
  339. memcpy(GetEncoderWindow(context) + context->bufpos_end, input_buffer, amount_to_compress);
  340. }
  341. input_buffer += amount_to_compress;
  342. input_buffer_size -= amount_to_compress;
  343. // last input location
  344. context->bufpos_end += amount_to_compress;
  345. }
  346. if (optimal_encoder != NULL)
  347. OptimalEncoderDeflate(context);
  348. else if (std_encoder != NULL)
  349. StdEncoderDeflate(context, search_depth, lazy_match_threshold, good_length, nice_length);
  350. else if (fast_encoder != NULL)
  351. FastEncoderDeflate(context, search_depth, lazy_match_threshold, good_length, nice_length);
  352. // either we reached the end of the buffer, or we had to output a block and ran out
  353. // of output space midway
  354. _ASSERT(context->bufpos == context->bufpos_end || context->state != STATE_NORMAL);
  355. // if we ran out of output space, break now
  356. if (context->state != STATE_NORMAL)
  357. break;
  358. // another check for running out of output space
  359. if (fast_encoder == NULL && context->output_endpos - context->output_curpos >= MAX_TREE_DATA_SIZE)
  360. break;
  361. } /* end ... while (input_buffer_size > 0) */
  362. set_output_used_then_exit:
  363. *output_used = (long) (context->output_curpos - output_buffer);
  364. exit:
  365. _ASSERT(*output_used < output_buffer_size); // make sure we didn't overflow the output buffer
  366. _ASSERT(context->bufpos >= context->window_size && context->bufpos <= 2*context->window_size); // make sure bufpos is sane
  367. return result;
  368. }