fstenc.c
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 20k
Category:

Windows Develop

Development Platform:

Visual C++

  1. /*
  2.  * fstenc.c
  3.  *
  4.  * Fast encoder
  5.  *
  6.  * This is a one pass encoder which uses predefined trees.  However, since these are not the same
  7.  * trees defined for a fixed block (we use better trees than that), we output a dynamic block header.
  8.  */
  9. #include <string.h>
  10. #include <stdio.h>
  11. #include <crtdbg.h>
  12. #include "deflate.h"
  13. #include "fasttbl.h"
  14. //
  15. // For debugging purposes:
  16. //
  17. // Verifies that all of the hash pointers in the hash table are correct, and that everything
  18. // in the same hash chain has the same hash value
  19. //
  20. #ifdef FULL_DEBUG
  21. #define VERIFY_HASHES(bufpos) FastEncoderVerifyHashes(context, bufpos)
  22. #else
  23. #define VERIFY_HASHES(bufpos) ;
  24. #endif
  25. //
  26. // Update hash variable "h" with character c
  27. //
  28. #define UPDATE_HASH(h,c) 
  29. h = ((h) << FAST_ENCODER_HASH_SHIFT) ^ (c);
  30. //
  31. // Insert a string into the hash chain at location bufpos
  32. //
  33. #define INSERT_STRING(search,bufpos) 
  34. UPDATE_HASH(hash, window[bufpos+2]); 
  35. _ASSERT((unsigned int) FAST_ENCODER_RECALCULATE_HASH(bufpos) == (unsigned int) (hash & FAST_ENCODER_HASH_MASK)); 
  36.     search = lookup[hash & FAST_ENCODER_HASH_MASK]; 
  37. lookup[hash & FAST_ENCODER_HASH_MASK] = (t_search_node) (bufpos); 
  38. prev[bufpos & FAST_ENCODER_WINDOW_MASK] = (t_search_node) (search); 
  39. }
  40. //
  41. // Output bits function which uses local variables for the bit buffer
  42. //
  43. #define LOCAL_OUTPUT_BITS(n, x) 
  44. bitbuf |= ((x) << bitcount); 
  45. bitcount += (n); 
  46. if (bitcount >= 16) 
  47.     { 
  48. *output_curpos++ = (BYTE) bitbuf; 
  49. *output_curpos++ = (BYTE) (bitbuf >> 8); 
  50. bitcount -= 16; 
  51. bitbuf >>= 16; 
  52. }
  53. //
  54. // Output unmatched symbol c
  55. //
  56. #define OUTPUT_CHAR(c) 
  57.     LOCAL_OUTPUT_BITS(g_FastEncoderLiteralCodeInfo[c] & 31, g_FastEncoderLiteralCodeInfo[c] >> 5);
  58. //
  59. // Output a match with length match_len (>= MIN_MATCH) and displacement match_pos
  60. //
  61. // Optimisation: unlike the other encoders, here we have an array of codes for each match
  62. // length (not just each match length slot), complete with all the extra bits filled in, in
  63. // a single array element.  
  64. //
  65. // There are many advantages to doing this:
  66. //
  67. // 1. A single array lookup on g_FastEncoderLiteralCodeInfo, instead of separate array lookups
  68. //    on g_LengthLookup (to get the length slot), g_FastEncoderLiteralTreeLength, 
  69. //    g_FastEncoderLiteralTreeCode, g_ExtraLengthBits, and g_BitMask
  70. //
  71. // 2. The array is an array of ULONGs, so no access penalty, unlike for accessing those USHORT
  72. //    code arrays in the other encoders (although they could be made into ULONGs with some
  73. //    modifications to the source).
  74. //
  75. // Note, if we could guarantee that code_len <= 16 always, then we could skip an if statement here.
  76. //
  77. // A completely different optimisation is used for the distance codes since, obviously, a table for 
  78. // all 8192 distances combining their extra bits is not feasible.  The distance codeinfo table is 
  79. // made up of code[], len[] and # extra_bits for this code.
  80. //
  81. // The advantages are similar to the above; a ULONG array instead of a USHORT and BYTE array, better
  82. // cache locality, fewer memory operations.
  83. //
  84. #define OUTPUT_MATCH(match_len, match_pos) 
  85.     int extra_bits; 
  86.     int code_len; 
  87.     ULONG code_info; 
  88. _ASSERT(match_len >= MIN_MATCH && match_len <= MAX_MATCH); 
  89.     code_info = g_FastEncoderLiteralCodeInfo[(NUM_CHARS+1-MIN_MATCH)+match_len]; 
  90.     code_len = code_info & 31; 
  91.     _ASSERT(code_len != 0); 
  92.     if (code_len <= 16) 
  93.     { 
  94.         LOCAL_OUTPUT_BITS(code_len, code_info >> 5); 
  95.     } 
  96.     else 
  97.     { 
  98.         LOCAL_OUTPUT_BITS(16, (code_info >> 5) & 65535); 
  99.         LOCAL_OUTPUT_BITS(code_len-16, code_info >> (5+16)); 
  100.     } 
  101.     code_info = g_FastEncoderDistanceCodeInfo[POS_SLOT(match_pos)]; 
  102.     LOCAL_OUTPUT_BITS(code_info & 15, code_info >> 8); 
  103.     extra_bits = (code_info >> 4) & 15; 
  104.     if (extra_bits != 0) LOCAL_OUTPUT_BITS(extra_bits, (match_pos) & g_BitMask[extra_bits]); 
  105. }
  106. //
  107. // This commented out code is the old way of doing things, which is what the other encoders use
  108. //
  109. #if 0
  110. #define OUTPUT_MATCH(match_len, match_pos) 
  111. int pos_slot = POS_SLOT(match_pos); 
  112. int len_slot = g_LengthLookup[match_len - MIN_MATCH]; 
  113.     int extra_bits; 
  114. _ASSERT(match_len >= MIN_MATCH && match_len <= MAX_MATCH); 
  115.     _ASSERT(g_FastEncoderLiteralTreeLength[(NUM_CHARS+1)+len_slot] != 0); 
  116.     _ASSERT(g_FastEncoderDistanceTreeLength[pos_slot] != 0); 
  117.     LOCAL_OUTPUT_BITS(g_FastEncoderLiteralTreeLength[(NUM_CHARS+1)+len_slot], g_FastEncoderLiteralTreeCode[(NUM_CHARS+1)+len_slot]); 
  118.     extra_bits = g_ExtraLengthBits[len_slot]; 
  119.     if (extra_bits != 0) LOCAL_OUTPUT_BITS(extra_bits, (match_len-MIN_MATCH) & g_BitMask[extra_bits]); 
  120.     LOCAL_OUTPUT_BITS(g_FastEncoderDistanceTreeLength[pos_slot], g_FastEncoderDistanceTreeCode[pos_slot]); 
  121.     extra_bits = g_ExtraDistanceBits[pos_slot]; 
  122.     if (extra_bits != 0) LOCAL_OUTPUT_BITS(extra_bits, (match_pos) & g_BitMask[extra_bits]); 
  123. }
  124. #endif
  125. //
  126. // Local function prototypes
  127. //
  128. static void FastEncoderMoveWindows(t_encoder_context *context);
  129. static int FastEncoderFindMatch(
  130.     const BYTE *    window,
  131.     const USHORT *  prev,
  132.     long            bufpos, 
  133.     long            search, 
  134.     t_match_pos *   match_pos, 
  135.     int             cutoff,
  136.     int             nice_length
  137. );
  138. //
  139. // Output the block type and tree structure for our hard-coded trees.
  140. //
  141. // Functionally equivalent to:
  142. //
  143. // outputBits(context, 1, 1); // "final" block flag
  144. // outputBits(context, 2, BLOCKTYPE_DYNAMIC);
  145. // outputTreeStructure(context, g_FastEncoderLiteralTreeLength, g_FastEncoderDistanceTreeLength);
  146. //
  147. // However, all of the above has smartly been cached in global data, so we just memcpy().
  148. //
  149. void FastEncoderOutputPreamble(t_encoder_context *context)
  150. {
  151. #if 0
  152.     // slow way:
  153.     outputBits(context, 1+2, 1 | (BLOCKTYPE_DYNAMIC << 1));
  154.     outputTreeStructure(context, g_FastEncoderLiteralTreeLength, g_FastEncoderDistanceTreeLength);
  155. #endif
  156.     // make sure tree has been init
  157.     _ASSERT(g_FastEncoderTreeLength > 0);
  158.     // make sure we have enough space to output tree
  159.     _ASSERT(context->output_curpos + g_FastEncoderTreeLength < context->output_endpos);
  160.     // fast way:
  161.     memcpy(context->output_curpos, g_FastEncoderTreeStructureData, g_FastEncoderTreeLength);
  162.     context->output_curpos += g_FastEncoderTreeLength;
  163.     // need to get final states of bitbuf and bitcount after outputting all that stuff
  164.     context->bitbuf = g_FastEncoderPostTreeBitbuf;
  165.     context->bitcount = g_FastEncoderPostTreeBitcount;
  166. }
  167. //
  168. // Fast encoder deflate function
  169. //
  170. void FastEncoderDeflate(
  171. t_encoder_context * context, 
  172.     int                 search_depth, // # hash links to traverse
  173. int lazy_match_threshold, // don't search @ X+1 if match length @ X is > lazy
  174.     int                 good_length, // divide traversal depth by 4 if match length > good
  175.     int                 nice_length // in match finder, if we find >= nice_length match, quit immediately
  176. )
  177. {
  178. long bufpos;
  179. unsigned int hash;
  180.     unsigned long   bitbuf;
  181.     int             bitcount;
  182.     BYTE *          output_curpos;
  183.     t_fast_encoder *encoder = context->fast_encoder;
  184. byte * window = encoder->window; // make local copies of context variables
  185. t_search_node * prev = encoder->prev;
  186. t_search_node * lookup = encoder->lookup;
  187.     //
  188.     // If this is the first time in here (since last reset) then we need to output our dynamic
  189.     // block header
  190.     //
  191.     if (encoder->fOutputBlockHeader == FALSE)
  192.     {
  193.         encoder->fOutputBlockHeader = TRUE;
  194.         //
  195.         // Watch out!  Calls to outputBits() and outputTreeStructure() use the bit buffer 
  196.         // variables stored in the context, not our local cached variables.
  197.         //
  198.         FastEncoderOutputPreamble(context);
  199.     }
  200.     //
  201.     // Copy bitbuf vars into local variables since we're now using OUTPUT_BITS macro.
  202.     // Do not call anything that uses the context structure's bit buffer variables!
  203.     //
  204.     output_curpos   = context->output_curpos;
  205.     bitbuf          = context->bitbuf;
  206.     bitcount        = context->bitcount;
  207.     // copy bufpos into local variable
  208.     bufpos = context->bufpos;
  209. VERIFY_HASHES(bufpos); // debug mode: verify that the hash table is correct
  210.     // initialise the value of the hash
  211.     // no problem if locations bufpos, bufpos+1 are invalid (not enough data), since we will 
  212.     // never insert using that hash value
  213. hash = 0;
  214. UPDATE_HASH(hash, window[bufpos]);
  215. UPDATE_HASH(hash, window[bufpos+1]);
  216.     // while we haven't come to the end of the input, and we still aren't close to the end
  217.     // of the output
  218. while (bufpos < context->bufpos_end && output_curpos < context->output_near_end_threshold)
  219. {
  220. int match_len;
  221. t_match_pos match_pos;
  222. t_match_pos search;
  223.      VERIFY_HASHES(bufpos); // debugger: verify that hash table is correct
  224. if (context->bufpos_end - bufpos <= 3)
  225. {
  226. // The hash value becomes corrupt when we get within 3 characters of the end of the
  227.             // input buffer, since the hash value is based on 3 characters.  We just stop
  228.             // inserting into the hash table at this point, and allow no matches.
  229. match_len = 0;
  230. }
  231. else
  232. {
  233.             // insert string into hash table and return most recent location of same hash value
  234. INSERT_STRING(search,bufpos);
  235.             // did we find a recent location of this hash value?
  236. if (search != 0)
  237. {
  238.      // yes, now find a match at what we'll call position X
  239. match_len = FastEncoderFindMatch(window, prev, bufpos, search, &match_pos, search_depth, nice_length);
  240. // truncate match if we're too close to the end of the input buffer
  241. if (bufpos + match_len > context->bufpos_end)
  242. match_len = context->bufpos_end - bufpos;
  243. }
  244. else
  245. {
  246.                 // no most recent location found
  247. match_len = 0;
  248. }
  249. }
  250. if (match_len < MIN_MATCH)
  251. {
  252.             // didn't find a match, so output unmatched char
  253. OUTPUT_CHAR(window[bufpos]);
  254.      bufpos++;
  255. }
  256. else
  257. {
  258.      // bufpos now points to X+1
  259.      bufpos++;
  260. // is this match so good (long) that we should take it automatically without
  261. // checking X+1 ?
  262. if (match_len <= lazy_match_threshold)
  263. {
  264. int next_match_len;
  265. t_match_pos next_match_pos;
  266. // sets search
  267. INSERT_STRING(search,bufpos);
  268. // no, so check for a better match at X+1
  269. if (search != 0)
  270. {
  271. next_match_len = FastEncoderFindMatch(
  272. window,
  273.                         prev,
  274. bufpos, 
  275. search,
  276. &next_match_pos,
  277. match_len < good_length ? search_depth : (search_depth >> 2),
  278.                         nice_length
  279. );
  280. // truncate match if we're too close to the end of the buffer
  281. // note: next_match_len could now be < MIN_MATCH
  282. if (bufpos + next_match_len > context->bufpos_end)
  283. next_match_len = context->bufpos_end - bufpos;
  284. }
  285. else
  286. {
  287. next_match_len = 0;
  288. }
  289. // right now X and X+1 are both inserted into the search tree
  290. if (next_match_len > match_len)
  291. {
  292. // since next_match_len > match_len, it can't be < MIN_MATCH here
  293. // match at X+1 is better, so output unmatched char at X
  294. OUTPUT_CHAR(window[bufpos-1]);
  295. // now output match at location X+1
  296. OUTPUT_MATCH(next_match_len, next_match_pos);
  297. // insert remainder of second match into search tree
  298. // 
  299. // example: (*=inserted already)
  300. //
  301. // X      X+1               X+2      X+3     X+4
  302. // *      *
  303. //        nextmatchlen=3
  304. //        bufpos
  305. //
  306. // If next_match_len == 3, we want to perform 2
  307. // insertions (at X+2 and X+3).  However, first we must 
  308. // inc bufpos.
  309. //
  310. bufpos++; // now points to X+2
  311. match_len = next_match_len;
  312. goto insert;
  313. }
  314. else
  315. {
  316. // match at X is better, so take it
  317. OUTPUT_MATCH(match_len, match_pos);
  318. //
  319. // Insert remainder of first match into search tree, minus the first
  320. // two locations, which were inserted by the FindMatch() calls.
  321. // 
  322. // For example, if match_len == 3, then we've inserted at X and X+1
  323. // already (and bufpos is now pointing at X+1), and now we need to insert 
  324. // only at X+2.
  325. //
  326. match_len--;
  327. bufpos++; // now bufpos points to X+2
  328. goto insert;
  329. }
  330. }
  331. else /* match_length >= good_match */
  332. {
  333. // in assertion: bufpos points to X+1, location X inserted already
  334. // first match is so good that we're not even going to check at X+1
  335. OUTPUT_MATCH(match_len, match_pos);
  336. // insert remainder of match at X into search tree
  337. insert:
  338. if (context->bufpos_end - bufpos <= match_len)
  339. {
  340. bufpos += (match_len-1);
  341. }
  342. else
  343. {
  344.     while (--match_len > 0)
  345.      {
  346.      t_match_pos ignore;
  347.      INSERT_STRING(ignore,bufpos);
  348.      bufpos++;
  349.     }
  350. }
  351. }
  352. }
  353. } /* end ... while (bufpos < bufpos_end) */
  354.     // store local variables back in context
  355. context->bufpos = bufpos;
  356.     context->bitbuf = bitbuf;
  357.     context->bitcount = bitcount;
  358.     context->output_curpos = output_curpos;
  359. VERIFY_HASHES(bufpos); // debugger: verify that hash table is correct
  360.     if (bufpos == context->bufpos_end)
  361.         context->state = STATE_NORMAL;
  362.     else
  363.         context->state = STATE_OUTPUTTING_BLOCK;
  364.     // slide the window if bufpos has reached 2*window size
  365.     if (context->bufpos == 2*FAST_ENCODER_WINDOW_SIZE)
  366.         FastEncoderMoveWindows(context);
  367. }
  368. static void FastEncoderMoveWindows(t_encoder_context *context)
  369. {
  370. t_search_node *lookup = context->fast_encoder->lookup;
  371. t_search_node *prev = context->fast_encoder->prev;
  372. BYTE *window = context->fast_encoder->window;
  373. int i;
  374.     _ASSERT(context->bufpos == 2*FAST_ENCODER_WINDOW_SIZE);
  375.     // verify that the hash table is correct
  376. VERIFY_HASHES(2*FAST_ENCODER_WINDOW_SIZE);
  377. memcpy(&window[0], &window[context->bufpos - FAST_ENCODER_WINDOW_SIZE], FAST_ENCODER_WINDOW_SIZE);
  378.     // move all the hash pointers back
  379.     // BUGBUG We are incurring a performance penalty since lookup[] is a USHORT array.  Would be
  380.     // nice to subtract from two locations at a time.
  381. for (i = 0; i < FAST_ENCODER_HASH_TABLE_SIZE; i++)
  382. {
  383. long val = ((long) lookup[i]) - FAST_ENCODER_WINDOW_SIZE;
  384. if (val <= 0) // too far away now? then set to zero
  385. lookup[i] = (t_search_node) 0;
  386. else
  387. lookup[i] = (t_search_node) val;
  388. }
  389.     // prev[]'s are absolute pointers, not relative pointers, so we have to move them back too
  390.     // making prev[]'s into relative pointers poses problems of its own
  391. for (i = 0; i < FAST_ENCODER_WINDOW_SIZE; i++)
  392. {
  393. long val = ((long) prev[i]) - FAST_ENCODER_WINDOW_SIZE;
  394. if (val <= 0)
  395. prev[i] = (t_search_node) 0;
  396. else
  397. prev[i] = (t_search_node) val;
  398. }
  399. #ifdef FULL_DEBUG
  400.     // For debugging, wipe the window clean, so that if there is a bug in our hashing,
  401.     // the hash pointers will now point to locations which are not valid for the hash value
  402.     // (and will be caught by our ASSERTs).
  403. memset(&window[FAST_ENCODER_WINDOW_SIZE], 0, FAST_ENCODER_WINDOW_SIZE);
  404. #endif
  405. VERIFY_HASHES(2*FAST_ENCODER_WINDOW_SIZE); // debug: verify hash table is correct
  406. context->bufpos = FAST_ENCODER_WINDOW_SIZE;
  407. context->bufpos_end = context->bufpos;
  408. }
  409. //
  410. // Find match
  411. //
  412. // Returns match length found.  A match length < MIN_MATCH means no match was found.
  413. //
  414. static int FastEncoderFindMatch(
  415.     const BYTE *    window, // window array
  416.     const USHORT *  prev,   // prev ptr array
  417.     long            bufpos, // current buffer position
  418.     long            search, // where to start searching
  419.     t_match_pos *   match_pos, // return match position here
  420.     int             cutoff, // # links to traverse
  421.     int             nice_length // stop immediately if we find a match >= nice_length
  422. )
  423. {
  424.     // make local copies of context variables
  425. long earliest;
  426. int best_match = 0; // best match length found so far
  427. t_match_pos l_match_pos; // absolute match position of best match found
  428.     BYTE            want_char;
  429. _ASSERT(bufpos >= 0 && bufpos < 2*FAST_ENCODER_WINDOW_SIZE);
  430. _ASSERT(search < bufpos);
  431. _ASSERT(FAST_ENCODER_RECALCULATE_HASH(search) == FAST_ENCODER_RECALCULATE_HASH(bufpos));
  432.     // the earliest we can look
  433. earliest = bufpos - FAST_ENCODER_WINDOW_SIZE;
  434.     _ASSERT(earliest >= 0);
  435.     // store window[bufpos + best_match]
  436.     want_char = window[bufpos];
  437. while (search > earliest)
  438. {
  439.         // make sure all our hash links are valid
  440. _ASSERT(FAST_ENCODER_RECALCULATE_HASH(search) == FAST_ENCODER_RECALCULATE_HASH(bufpos));
  441.         // Start by checking the character that would allow us to increase the match
  442.         // length by one.  This improves performance quite a bit.
  443. if (window[search + best_match] == want_char)
  444. {
  445. int j;
  446.             // Now make sure that all the other characters are correct
  447. for (j = 0; j < MAX_MATCH; j++)
  448. {
  449. if (window[bufpos+j] != window[search+j])
  450. break;
  451. }
  452. if (j > best_match)
  453. {
  454. best_match = j;
  455. l_match_pos = search; // absolute position
  456. if (j > nice_length)
  457. break;
  458.                 want_char = window[bufpos+j];
  459. }
  460. }
  461. if (--cutoff == 0)
  462. break;
  463.         // make sure we're always going backwards
  464.         _ASSERT(prev[search & FAST_ENCODER_WINDOW_MASK] < search);
  465. search = (long) prev[search & FAST_ENCODER_WINDOW_MASK];
  466. }
  467.     // doesn't necessarily mean we found a match; best_match could be > 0 and < MIN_MATCH
  468. *match_pos = bufpos - l_match_pos - 1; // convert absolute to relative position
  469.     // don't allow match length 3's which are too far away to be worthwhile
  470. if (best_match == 3 && *match_pos >= FAST_ENCODER_MATCH3_DIST_THRESHOLD)
  471. return 0;
  472. _ASSERT(best_match < MIN_MATCH || *match_pos < FAST_ENCODER_WINDOW_SIZE);
  473. return best_match;
  474. }
  475. void FastEncoderReset(t_encoder_context *context)
  476. {
  477. _ASSERT(context->fast_encoder != NULL);
  478.     // zero hash table
  479. memset(context->fast_encoder->lookup, 0, sizeof(context->fast_encoder->lookup));
  480.     context->window_size = FAST_ENCODER_WINDOW_SIZE;
  481. context->bufpos = FAST_ENCODER_WINDOW_SIZE;
  482.     context->bufpos_end = context->bufpos;
  483.     context->fast_encoder->fOutputBlockHeader = FALSE;
  484. }
  485. BOOL FastEncoderInit(t_encoder_context *context)
  486. {
  487. context->fast_encoder = (t_fast_encoder *) LocalAlloc(LMEM_FIXED, sizeof(t_fast_encoder));
  488.     if (context->fast_encoder == NULL)
  489.         return FALSE;
  490. FastEncoderReset(context);
  491. return TRUE;
  492. }
  493. //
  494. // Pregenerate the structure of the dynamic tree header which is output for
  495. // the fast encoder.  Also record the final states of bitcount and bitbuf
  496. // after outputting.
  497. //
  498. void FastEncoderGenerateDynamicTreeEncoding(void)
  499. {
  500.     t_encoder_context context;
  501.     // Create a fake context with output pointers into our global data
  502.     memset(&context, 0, sizeof(context));
  503.     context.output_curpos = g_FastEncoderTreeStructureData;
  504.     context.output_endpos = g_FastEncoderTreeStructureData + sizeof(g_FastEncoderTreeStructureData);
  505.     context.output_near_end_threshold = context.output_endpos - 16;
  506.     InitBitBuffer(&context);
  507.     outputBits(&context, 1, 1); // "final" block flag
  508.     outputBits(&context, 2, BLOCKTYPE_DYNAMIC);
  509.    
  510.     outputTreeStructure(
  511.         &context,
  512.     g_FastEncoderLiteralTreeLength, 
  513.     g_FastEncoderDistanceTreeLength
  514.     );
  515.     g_FastEncoderTreeLength = (int) (context.output_curpos - (BYTE *) g_FastEncoderTreeStructureData);
  516.     g_FastEncoderPostTreeBitbuf = context.bitbuf;
  517.     g_FastEncoderPostTreeBitcount = context.bitcount;
  518. }