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.

1135 lines
32 KiB

  1. /*
  2. * optenc.c
  3. *
  4. * Encoder for optimal parser
  5. *
  6. *
  7. * Future Improvements:
  8. *
  9. * When two estimations are equal, for example, "should I output a
  10. * character or a match?" there should be some way of deciding
  11. * which to take. Right now we force it to output a match, but
  12. * for text files, outputting a character results in a small
  13. * savings. Even when comparing two matches, we might want to
  14. * force it to take one type of match over another.
  15. */
  16. #include "encoder.h"
  17. #define copymem(src,dst,size) memcpy(dst,src,size)
  18. static bool redo_first_block(t_encoder_context *context, long *bufpos_ptr);
  19. static void block_end(t_encoder_context *context, long BufPos);
  20. /*
  21. * encode a match of length <len> (where <len> >=2), and position <pos>
  22. */
  23. #define OUT_MATCH(len,pos) \
  24. {\
  25. context->enc_ItemType[(context->enc_literals >> 3)] |= (1 << (context->enc_literals & 7)); \
  26. context->enc_LitData [context->enc_literals++] = (byte) (len-2); \
  27. context->enc_DistData[context->enc_distances++] = pos; \
  28. }
  29. /* encode a character */
  30. #define OUT_CHAR(ch) \
  31. context->enc_LitData [context->enc_literals++] = ch;
  32. #define TREE_CREATE_CHECK() \
  33. if (context->enc_literals >= context->enc_next_tree_create) \
  34. { \
  35. update_tree_estimates(context);\
  36. context->enc_next_tree_create += TREE_CREATE_INTERVAL; \
  37. }
  38. /*
  39. * Returns an estimation of how many bits it would take to output
  40. * a given character
  41. */
  42. #define CHAR_EST(c) (numbits_t) (context->enc_main_tree_len[(c)])
  43. /*
  44. * Returns an estimation of how many bits it would take to output
  45. * a given match.
  46. *
  47. * <ml> is the match length, where ml >= 2
  48. * <mp> is the match position
  49. *
  50. * The result is stored in <result>
  51. */
  52. #define MATCH_EST(ml,mp,result) \
  53. { \
  54. byte mp_slot; \
  55. mp_slot = (byte) MP_SLOT(mp); \
  56. if (ml < (NUM_PRIMARY_LENGTHS+2)) \
  57. { \
  58. result = (numbits_t) \
  59. (context->enc_main_tree_len[(NUM_CHARS-2)+(mp_slot<<NL_SHIFT)+ml] + \
  60. enc_extra_bits[mp_slot]); \
  61. } \
  62. else \
  63. { \
  64. result = (numbits_t) \
  65. (context->enc_main_tree_len[(NUM_CHARS+NUM_PRIMARY_LENGTHS)+(mp_slot<<NL_SHIFT)] + \
  66. context->enc_secondary_tree_len[ml-(NUM_PRIMARY_LENGTHS+2)] + \
  67. enc_extra_bits[mp_slot]); \
  68. } \
  69. }
  70. #ifdef _DEBUG
  71. static void VERIFY_MATCH(
  72. t_encoder_context *context,
  73. long bufpos,
  74. int largest_match_len
  75. )
  76. {
  77. int i, j;
  78. ulong match_pos;
  79. /*
  80. * Ensure match does not cross boundary
  81. */
  82. _ASSERTE(
  83. largest_match_len <=
  84. (CHUNK_SIZE-1) - (bufpos & (CHUNK_SIZE-1))
  85. );
  86. for (i = MIN_MATCH; i <= largest_match_len; i++)
  87. {
  88. match_pos = context->enc_matchpos_table[i];
  89. if (match_pos < NUM_REPEATED_OFFSETS)
  90. match_pos = context->enc_last_matchpos_offset[match_pos];
  91. else
  92. match_pos -= (NUM_REPEATED_OFFSETS-1);
  93. _ASSERTE (match_pos <= context->enc_window_size-4);
  94. for (j = 0; j < i; j++)
  95. {
  96. _ASSERTE (
  97. context->enc_MemWindow[bufpos+j] ==
  98. context->enc_MemWindow[bufpos-match_pos+j]
  99. );
  100. }
  101. }
  102. }
  103. #else
  104. # define VERIFY_MATCH(a,b,c) ;
  105. #endif
  106. void flush_all_pending_blocks(t_encoder_context *context)
  107. {
  108. /*
  109. * Force all blocks to be output
  110. */
  111. while (context->enc_literals > 0)
  112. output_block(context);
  113. /*
  114. * Flush compressed data out to the caller
  115. */
  116. perform_flush_output_callback(context);
  117. }
  118. void encoder_start(t_encoder_context *context)
  119. {
  120. long BytesRead, RealBufPos;
  121. /*
  122. * RealBufPos is our position in the window,
  123. * and equals [0...window_size + second_partition_size - 1]
  124. */
  125. RealBufPos = (long) (context->enc_BufPos - (context->enc_RealMemWindow - context->enc_MemWindow));
  126. BytesRead = comp_read_input(context, RealBufPos, CHUNK_SIZE);
  127. if (BytesRead > 0)
  128. opt_encode_top(context, BytesRead);
  129. }
  130. static void update_tree_estimates(t_encoder_context *context)
  131. {
  132. if (context->enc_literals)
  133. {
  134. /*
  135. * Get stats on literals from 0...context->enc_literals
  136. */
  137. if (context->enc_need_to_recalc_stats)
  138. {
  139. /*
  140. * Cumulative total was destroyed, so need to
  141. * recalculate
  142. */
  143. get_block_stats(
  144. context,
  145. 0,
  146. 0,
  147. context->enc_literals
  148. );
  149. context->enc_need_to_recalc_stats = false;
  150. }
  151. else
  152. {
  153. /*
  154. * Add stats from last_literals...context->enc_literals
  155. * to cumulative total
  156. */
  157. update_cumulative_block_stats(
  158. context,
  159. context->enc_last_literals,
  160. context->enc_last_distances,
  161. context->enc_literals
  162. );
  163. }
  164. create_trees(context, false); /* don't generate codes */
  165. fix_tree_cost_estimates(context);
  166. /*
  167. * For cumulative total
  168. */
  169. context->enc_last_literals = context->enc_literals;
  170. context->enc_last_distances = context->enc_distances;
  171. }
  172. }
  173. void opt_encode_top(t_encoder_context *context, long BytesRead)
  174. {
  175. ulong BufPos;
  176. ulong RealBufPos;
  177. ulong BufPosEnd;
  178. ulong MatchPos;
  179. ulong i;
  180. ulong end_pos;
  181. int EncMatchLength; /* must be a signed number */
  182. /*
  183. * Current position in encoding window
  184. */
  185. BufPos = context->enc_BufPos;
  186. /*
  187. * Stop encoding when we reach here
  188. */
  189. BufPosEnd = context->enc_BufPos + BytesRead;
  190. /*
  191. * If this is our first time in here (since a new group), then
  192. * when we reach this many literals, update our tree cost
  193. * estimates.
  194. *
  195. * Also, output the file size we're using for translation
  196. * (0 means no translation at all, which will speed things up
  197. * for the decoder).
  198. */
  199. if (context->enc_first_time_this_group)
  200. {
  201. context->enc_first_time_this_group = false;
  202. /*
  203. * Recreate trees when we reach this many literals
  204. */
  205. context->enc_next_tree_create = 10000;
  206. if (context->enc_file_size_for_translation)
  207. {
  208. output_bits(context, 1, 1); /* translation */
  209. output_bits(context, 16, context->enc_file_size_for_translation >> 16);
  210. output_bits(context, 16, context->enc_file_size_for_translation & 65535);
  211. }
  212. else
  213. {
  214. output_bits(context, 1, 0); /* no translation */
  215. }
  216. }
  217. else
  218. {
  219. /*
  220. * If this is our second or later time in here, then add in the
  221. * strings we removed last time.
  222. *
  223. * We have to be careful here, though, because end_pos is
  224. * equal to our current BufPos - window_size, not
  225. * BufPos - i - window_size; we don't have that much history
  226. * around.
  227. */
  228. for (i = BREAK_LENGTH; i > 0; i--)
  229. quick_insert_bsearch_findmatch(
  230. context,
  231. BufPos - (long) i,
  232. BufPos - context->enc_window_size+4
  233. );
  234. }
  235. while (1)
  236. {
  237. top_of_main_loop:
  238. /*
  239. * While we haven't reached the end of the data
  240. */
  241. while (BufPos < BufPosEnd)
  242. {
  243. /*
  244. * Search for matches of all different possible lengths, at BufPos
  245. */
  246. EncMatchLength = binary_search_findmatch(context, BufPos);
  247. if (EncMatchLength < MIN_MATCH)
  248. {
  249. output_literal:
  250. /*
  251. * No match longer than 1 character exists in the history
  252. * window, so output the character at BufPos as a symbol.
  253. */
  254. OUT_CHAR(context->enc_MemWindow[BufPos]);
  255. BufPos++;
  256. /*
  257. * Check for exceeding literal buffer
  258. */
  259. if (context->enc_literals >= (MAX_LITERAL_ITEMS-8))
  260. block_end(context, BufPos);
  261. continue;
  262. }
  263. /*
  264. * Found a match.
  265. *
  266. * Make sure it cannot exceed the end of the buffer.
  267. */
  268. if ((ulong) EncMatchLength + BufPos > BufPosEnd)
  269. {
  270. EncMatchLength = BufPosEnd - BufPos;
  271. /*
  272. * Oops, not enough for even a small match, so we
  273. * have to output a literal
  274. */
  275. if (EncMatchLength < MIN_MATCH)
  276. goto output_literal;
  277. }
  278. VERIFY_MATCH(context, BufPos, EncMatchLength);
  279. if (EncMatchLength < FAST_DECISION_THRESHOLD)
  280. {
  281. /*
  282. * A match has been found that is between MIN_MATCH and
  283. * FAST_DECISION_THRESHOLD bytes in length. The following
  284. * algorithm is the optimal encoder that will determine the
  285. * most efficient order of matches and unmatched characters
  286. * over a span area defined by LOOK.
  287. *
  288. * The code is essentially a shortest path determination
  289. * algorithm. A stream of data can be encoded in a vast number
  290. * of different ways depending on the match lengths and offsets
  291. * chosen. The key to good compression ratios is to chose the
  292. * least expensive path.
  293. */
  294. ulong span;
  295. ulong epos, bpos, NextPrevPos, MatchPos;
  296. decision_node *decision_node_ptr;
  297. long iterations;
  298. /*
  299. * Points to the end of the area covered by this match; the span
  300. * will continually be extended whenever we find more matches
  301. * later on. It will stop being extended when we reach a spot
  302. * where there are no matches, which is when we decide which
  303. * path to take to output the matches.
  304. */
  305. span = BufPos + EncMatchLength;
  306. /*
  307. * The furthest position into which we will do our lookahead parsing
  308. */
  309. epos = BufPos + LOOK;
  310. /*
  311. * Temporary BufPos variable
  312. */
  313. bpos = BufPos;
  314. /*
  315. * Calculate the path to the next character if we output
  316. * an unmatched symbol.
  317. */
  318. /* bits required to get here */
  319. context->enc_decision_node[1].numbits = CHAR_EST(context->enc_MemWindow[BufPos]);
  320. /* where we came from */
  321. context->enc_decision_node[1].path = BufPos;
  322. /*
  323. * For the match found, estimate the cost of encoding the match
  324. * for each possible match length, shortest offset combination.
  325. *
  326. * The cost, path and offset is stored at BufPos + Length.
  327. */
  328. for (i = MIN_MATCH; i <= (ulong) EncMatchLength; i++)
  329. {
  330. /*
  331. * Get estimation of match cost given match length = i,
  332. * match position = context->enc_matchpos_table[i], and store
  333. * the result in context->enc_numbits[i]
  334. */
  335. MATCH_EST(i, context->enc_matchpos_table[i], context->enc_decision_node[i].numbits);
  336. /*
  337. * Where we came from
  338. */
  339. context->enc_decision_node[i].path = BufPos;
  340. /*
  341. * Associated match position with this path
  342. */
  343. context->enc_decision_node[i].link = context->enc_matchpos_table[i];
  344. }
  345. /*
  346. * Set bit counter to zero at the start
  347. */
  348. context->enc_decision_node[0].numbits = 0;
  349. /*
  350. * Initialise relative match position tables
  351. *
  352. * Really context->enc_repeated_offset_table[BufPos-bpos][x], but here
  353. * BufPos == bpos
  354. */
  355. context->enc_decision_node[0].repeated_offset[0] = context->enc_last_matchpos_offset[0];
  356. context->enc_decision_node[0].repeated_offset[1] = context->enc_last_matchpos_offset[1];
  357. context->enc_decision_node[0].repeated_offset[2] = context->enc_last_matchpos_offset[2];
  358. decision_node_ptr = &context->enc_decision_node[-(long) bpos];
  359. #define rpt_offset_ptr(where,which_offset) decision_node_ptr[(where)].repeated_offset[(which_offset)]
  360. while (1)
  361. {
  362. numbits_t est, cum_numbits;
  363. BufPos++;
  364. /*
  365. * Set the proper repeated offset locations depending on the
  366. * shortest path to the location prior to searching for a
  367. * match.
  368. */
  369. /*
  370. * If this is a match (i.e. path skips over more
  371. * than one character).
  372. */
  373. if (decision_node_ptr[BufPos].path != (ulong) (BufPos-1))
  374. {
  375. ulong LastPos = decision_node_ptr[BufPos].path;
  376. /*
  377. * link_ptr[BufPos] is the match position for this
  378. * location
  379. */
  380. if (decision_node_ptr[BufPos].link >= NUM_REPEATED_OFFSETS)
  381. {
  382. context->enc_last_matchpos_offset[0] = decision_node_ptr[BufPos].link-(NUM_REPEATED_OFFSETS-1);
  383. context->enc_last_matchpos_offset[1] = rpt_offset_ptr(LastPos,0);
  384. context->enc_last_matchpos_offset[2] = rpt_offset_ptr(LastPos,1);
  385. }
  386. else if (decision_node_ptr[BufPos].link == 0)
  387. {
  388. context->enc_last_matchpos_offset[0] = rpt_offset_ptr(LastPos,0);
  389. context->enc_last_matchpos_offset[1] = rpt_offset_ptr(LastPos,1);
  390. context->enc_last_matchpos_offset[2] = rpt_offset_ptr(LastPos,2);
  391. }
  392. else if (decision_node_ptr[BufPos].link == 1)
  393. {
  394. context->enc_last_matchpos_offset[0] = rpt_offset_ptr(LastPos,1);
  395. context->enc_last_matchpos_offset[1] = rpt_offset_ptr(LastPos,0);
  396. context->enc_last_matchpos_offset[2] = rpt_offset_ptr(LastPos,2);
  397. }
  398. else /* == 2 */
  399. {
  400. context->enc_last_matchpos_offset[0] = rpt_offset_ptr(LastPos,2);
  401. context->enc_last_matchpos_offset[1] = rpt_offset_ptr(LastPos,1);
  402. context->enc_last_matchpos_offset[2] = rpt_offset_ptr(LastPos,0);
  403. }
  404. }
  405. rpt_offset_ptr(BufPos,0) = context->enc_last_matchpos_offset[0];
  406. rpt_offset_ptr(BufPos,1) = context->enc_last_matchpos_offset[1];
  407. rpt_offset_ptr(BufPos,2) = context->enc_last_matchpos_offset[2];
  408. /*
  409. * The following is one of the two possible break points from
  410. * the inner encoding loop. This break will exit the loop if
  411. * a point is reached that no match can incorporate; i.e. a
  412. * character that does not match back to anything is a point
  413. * where all possible paths will converge and the longest one
  414. * can be chosen.
  415. */
  416. if (span == BufPos)
  417. break;
  418. /*
  419. * Search for matches at BufPos
  420. */
  421. EncMatchLength = binary_search_findmatch(context, BufPos);
  422. /*
  423. * Make sure that the match does not exceed the stop point
  424. */
  425. if ((ulong) EncMatchLength + BufPos > BufPosEnd)
  426. {
  427. EncMatchLength = BufPosEnd - BufPos;
  428. if (EncMatchLength < MIN_MATCH)
  429. EncMatchLength = 0;
  430. }
  431. VERIFY_MATCH(context, BufPos, EncMatchLength);
  432. /*
  433. * If the match is very long or it exceeds epos (either
  434. * surpassing the LOOK area, or exceeding past the end of the
  435. * input buffer), then break the loop and output the path.
  436. */
  437. if (EncMatchLength > FAST_DECISION_THRESHOLD ||
  438. BufPos + (ulong) EncMatchLength >= epos)
  439. {
  440. MatchPos = context->enc_matchpos_table[EncMatchLength];
  441. decision_node_ptr[BufPos+EncMatchLength].link = MatchPos;
  442. decision_node_ptr[BufPos+EncMatchLength].path = BufPos;
  443. /*
  444. * Quickly insert data into the search tree without
  445. * returning match positions/lengths
  446. */
  447. #ifndef INSERT_NEAR_LONG_MATCHES
  448. if (MatchPos == 3 && EncMatchLength > 16)
  449. {
  450. /*
  451. * If we found a match 1 character away and it's
  452. * length 16 or more, it's probably a string of
  453. * zeroes, so don't insert that into the search
  454. * engine, since doing so can slow things down
  455. * significantly!
  456. */
  457. quick_insert_bsearch_findmatch(
  458. context,
  459. BufPos + 1,
  460. BufPos - context->enc_window_size + (1 + 4) /* bp+1 -(ws-4) */
  461. );
  462. }
  463. else
  464. {
  465. #endif
  466. for (i = 1; i < (ulong) EncMatchLength; i++)
  467. quick_insert_bsearch_findmatch(
  468. context,
  469. BufPos + i,
  470. BufPos + i - context->enc_window_size + 4
  471. );
  472. }
  473. BufPos += EncMatchLength;
  474. /*
  475. * Update the relative match positions
  476. */
  477. if (MatchPos >= NUM_REPEATED_OFFSETS)
  478. {
  479. context->enc_last_matchpos_offset[2] = context->enc_last_matchpos_offset[1];
  480. context->enc_last_matchpos_offset[1] = context->enc_last_matchpos_offset[0];
  481. context->enc_last_matchpos_offset[0] = MatchPos-(NUM_REPEATED_OFFSETS-1);
  482. }
  483. else if (MatchPos)
  484. {
  485. ulong t = context->enc_last_matchpos_offset[0];
  486. context->enc_last_matchpos_offset[0] = context->enc_last_matchpos_offset[MatchPos];
  487. context->enc_last_matchpos_offset[MatchPos] = t;
  488. }
  489. break;
  490. }
  491. /*
  492. * The following code will extend the area spanned by the
  493. * set of matches if the current match surpasses the end of
  494. * the span. A match of length two that is far is not
  495. * accepted, since it would normally be encoded as characters,
  496. * thus allowing the paths to converge.
  497. */
  498. if (EncMatchLength > 2 ||
  499. (EncMatchLength == 2 && context->enc_matchpos_table[2] < BREAK_MAX_LENGTH_TWO_OFFSET))
  500. {
  501. if (span < (ulong) (BufPos + EncMatchLength))
  502. {
  503. long end;
  504. long i;
  505. end = (((BufPos+EncMatchLength-bpos) < (LOOK-1)) ? (BufPos+EncMatchLength-bpos) : (LOOK-1));
  506. /*
  507. * These new positions are undefined for now, since we haven't
  508. * gone there yet, so put in the costliest value
  509. */
  510. for (i = span-bpos+1; i <= end; i++)
  511. context->enc_decision_node[i].numbits = (numbits_t) -1;
  512. span = BufPos + EncMatchLength;
  513. }
  514. }
  515. /*
  516. * The following code will iterate through all combinations
  517. * of match lengths for the current match. It will estimate
  518. * the cost of the path from the beginning of LOOK to
  519. * BufPos and to every locations spanned by the current
  520. * match. If the path through BufPos with the found matches
  521. * is estimated to take fewer number of bits to encode than
  522. * the previously found match, then the path to the location
  523. * is altered.
  524. *
  525. * The code relies on accurate estimation of the cost of
  526. * encoding a character or a match. Furthermore, it requires
  527. * a search engine that will store the smallest match offset
  528. * of each possible match length.
  529. *
  530. * A match of length one is simply treated as an unmatched
  531. * character.
  532. */
  533. /*
  534. * Get the estimated number of bits required to encode the
  535. * path leading up to BufPos.
  536. */
  537. cum_numbits = decision_node_ptr[BufPos].numbits;
  538. /*
  539. * Calculate the estimated cost of outputting the path through
  540. * BufPos and outputting the next character as an unmatched byte
  541. */
  542. est = cum_numbits + CHAR_EST(context->enc_MemWindow[BufPos]);
  543. /*
  544. * Check if it is more efficient to encode the next character
  545. * as an unmatched character rather than the previously found
  546. * match. If so, then update the cheapest path to BufPos + 1.
  547. *
  548. * What happens if est == numbits[BufPos-bpos+1]; i.e. it
  549. * works out as well to output a character as to output a
  550. * match? It's a tough call; however, we will push the
  551. * encoder to use matches where possible.
  552. */
  553. if (est < decision_node_ptr[BufPos+1].numbits)
  554. {
  555. decision_node_ptr[BufPos+1].numbits = est;
  556. decision_node_ptr[BufPos+1].path = BufPos;
  557. }
  558. /*
  559. * Now, iterate through the remaining match lengths and
  560. * compare the new path to the existing. Change the path
  561. * if it is found to be more cost effective to go through
  562. * BufPos.
  563. */
  564. for (i = MIN_MATCH; i <= (ulong) EncMatchLength; i++)
  565. {
  566. MATCH_EST(i, context->enc_matchpos_table[i], est);
  567. est += cum_numbits;
  568. /*
  569. * If est == numbits[BufPos+i] we want to leave things
  570. * alone, since this will tend to force the matches
  571. * to be smaller in size, which is beneficial for most
  572. * data.
  573. */
  574. if (est < decision_node_ptr[BufPos+i].numbits)
  575. {
  576. decision_node_ptr[BufPos+i].numbits = est;
  577. decision_node_ptr[BufPos+i].path = BufPos;
  578. decision_node_ptr[BufPos+i].link = context->enc_matchpos_table[i];
  579. }
  580. }
  581. } /* continue to loop through span of matches */
  582. /*
  583. * Here BufPos == span, ie. a non-matchable character found. The
  584. * following code will output the path properly.
  585. */
  586. /*
  587. * Unfortunately the path is stored in reverse; how to get from
  588. * where we are now, to get back to where it all started.
  589. *
  590. * Traverse the path back to the original starting position
  591. * of the LOOK span. Invert the path pointers in order to be
  592. * able to traverse back to the current position from the start.
  593. */
  594. /*
  595. * Count the number of iterations we did, so when we go forwards
  596. * we'll do the same amount
  597. */
  598. iterations = 0;
  599. NextPrevPos = decision_node_ptr[BufPos].path;
  600. do
  601. {
  602. ulong PrevPos;
  603. PrevPos = NextPrevPos;
  604. NextPrevPos = decision_node_ptr[PrevPos].path;
  605. decision_node_ptr[PrevPos].path = BufPos;
  606. BufPos = PrevPos;
  607. iterations++;
  608. } while (BufPos != bpos);
  609. if (context->enc_literals + iterations >= (MAX_LITERAL_ITEMS-8) ||
  610. context->enc_distances + iterations >= (MAX_DIST_ITEMS-8))
  611. {
  612. block_end(context, BufPos);
  613. }
  614. /*
  615. * Traverse from the beginning of the LOOK span to the end of
  616. * the span along the stored path, outputting matches and
  617. * characters appropriately.
  618. */
  619. do
  620. {
  621. if (decision_node_ptr[BufPos].path > BufPos+1)
  622. {
  623. /*
  624. * Path skips over more than 1 character; therefore it's a match
  625. */
  626. OUT_MATCH(
  627. decision_node_ptr[BufPos].path - BufPos,
  628. decision_node_ptr[ decision_node_ptr[BufPos].path ].link
  629. );
  630. BufPos = decision_node_ptr[BufPos].path;
  631. }
  632. else
  633. {
  634. /*
  635. * Path goes to the next character; therefore it's a symbol
  636. */
  637. OUT_CHAR(context->enc_MemWindow[BufPos]);
  638. BufPos++;
  639. }
  640. } while (--iterations != 0);
  641. TREE_CREATE_CHECK();
  642. /*
  643. * If we're filling up, and are close to outputting a block,
  644. * and it's the first block, then recompress the first N
  645. * literals using our accumulated stats.
  646. */
  647. if (context->enc_first_block &&
  648. (context->enc_literals >= (MAX_LITERAL_ITEMS-512)
  649. || context->enc_distances >= (MAX_DIST_ITEMS-512)))
  650. {
  651. if (redo_first_block(context, &BufPos))
  652. goto top_of_main_loop;
  653. /*
  654. * Unable to redo, so output the block
  655. */
  656. block_end(context, BufPos);
  657. }
  658. }
  659. else /* EncMatchLength >= FAST_DECISION_THRESHOLD */
  660. {
  661. /*
  662. * This code reflects a speed optimization that will always take
  663. * a match of length >= FAST_DECISION_THRESHOLD characters.
  664. */
  665. /*
  666. * The position associated with the match we found
  667. */
  668. MatchPos = context->enc_matchpos_table[EncMatchLength];
  669. /*
  670. * Quickly insert match substrings into search tree
  671. * (don't look for new matches; just insert the strings)
  672. */
  673. #ifndef INSERT_NEAR_LONG_MATCHES
  674. if (MatchPos == 3 && EncMatchLength > 16)
  675. {
  676. quick_insert_bsearch_findmatch(
  677. context,
  678. BufPos + 1,
  679. BufPos - context->enc_window_size + 5 /* bp+1 -(ws-4) */
  680. );
  681. }
  682. else
  683. #endif
  684. {
  685. for (i = 1; i < (ulong) EncMatchLength; i++)
  686. quick_insert_bsearch_findmatch(
  687. context,
  688. BufPos + i,
  689. BufPos + i - context->enc_window_size + 4
  690. );
  691. }
  692. /*
  693. * Advance our position in the window
  694. */
  695. BufPos += EncMatchLength;
  696. /*
  697. * Output the match
  698. */
  699. OUT_MATCH(EncMatchLength, MatchPos);
  700. if (MatchPos >= NUM_REPEATED_OFFSETS)
  701. {
  702. context->enc_last_matchpos_offset[2] = context->enc_last_matchpos_offset[1];
  703. context->enc_last_matchpos_offset[1] = context->enc_last_matchpos_offset[0];
  704. context->enc_last_matchpos_offset[0] = MatchPos-(NUM_REPEATED_OFFSETS-1);
  705. }
  706. else if (MatchPos)
  707. {
  708. ulong t = context->enc_last_matchpos_offset[0];
  709. context->enc_last_matchpos_offset[0] = context->enc_last_matchpos_offset[MatchPos];
  710. context->enc_last_matchpos_offset[MatchPos] = t;
  711. }
  712. /*
  713. * Check to see if we're close to overflowing our output arrays, and
  714. * output a block if this is the case
  715. */
  716. if (context->enc_literals >= (MAX_LITERAL_ITEMS-8) ||
  717. context->enc_distances >= (MAX_DIST_ITEMS-8))
  718. block_end(context, BufPos);
  719. } /* EncMatchLength >= FAST_DECISION_THRESHOLD */
  720. } /* end while ... BufPos <= BufPosEnd */
  721. /*
  722. * Value of BufPos corresponding to earliest window data
  723. */
  724. context->enc_earliest_window_data_remaining = BufPos - context->enc_window_size;
  725. /*
  726. * We didn't read 32K, so we know for sure that
  727. * this was our last block of data.
  728. */
  729. if (BytesRead < CHUNK_SIZE)
  730. {
  731. /*
  732. * If we have never output a block, and we haven't
  733. * recalculated the stats already, then recalculate
  734. * the stats and recompress.
  735. */
  736. if (context->enc_first_block)
  737. {
  738. if (redo_first_block(context, &BufPos))
  739. goto top_of_main_loop;
  740. }
  741. break;
  742. }
  743. /*
  744. * Remove the last BREAK_LENGTH nodes from the binary search tree,
  745. * since we have been inserting strings which contain undefined
  746. * data at the end.
  747. */
  748. end_pos = BufPos - (context->enc_window_size-4-BREAK_LENGTH);
  749. for (i = 1; (i <= BREAK_LENGTH); i++)
  750. binary_search_remove_node(context, BufPos-i, end_pos);
  751. /*
  752. * If we're still in the first window_size + second partition size
  753. * bytes in the file then we don't need to copymem() yet.
  754. *
  755. * RealBufPos is the real position in the file.
  756. */
  757. RealBufPos = (long)(BufPos - (context->enc_RealMemWindow - context->enc_MemWindow));
  758. if (RealBufPos < context->enc_window_size + context->enc_encoder_second_partition_size)
  759. break;
  760. /*
  761. * We're about to trash a whole bunch of history with our copymem,
  762. * so we'd better redo the first block now if we are ever going to.
  763. */
  764. if (context->enc_first_block)
  765. {
  766. if (redo_first_block(context, &BufPos))
  767. goto top_of_main_loop;
  768. }
  769. /*
  770. * We're about to remove a large number of symbols from the window.
  771. * Test to see whether, if we were to output a block now, our compressed
  772. * output size would be larger than our uncompressed data. If so, then
  773. * we will output an uncompressed block.
  774. *
  775. * The reason we have to do this check here, is that data in the
  776. * window is about to be destroyed. We can't simply put this check in
  777. * the block outputting code, since there is no guarantee that the
  778. * memory window contents corresponding to everything in that block,
  779. * are still around - all we'd have would be a set of literals and
  780. * distances, when we need all the uncompressed literals to output
  781. * an uncompressed block.
  782. */
  783. /*
  784. * What value of bufpos corresponds to the oldest data we have in the
  785. * buffer?
  786. *
  787. * After the memory copy, that will be the current buffer position,
  788. * minus window_size.
  789. */
  790. /*
  791. * The end of the data buffer is reached, more data needs to be read
  792. * and the existing data must be shifted into the history window.
  793. *
  794. * MSVC 4.x generates code which does REP MOVSD so no need to
  795. * write this in assembly.
  796. */
  797. copymem(
  798. &context->enc_RealMemWindow[context->enc_encoder_second_partition_size],
  799. &context->enc_RealMemWindow[0],
  800. context->enc_window_size
  801. );
  802. copymem(
  803. &context->enc_RealLeft[context->enc_encoder_second_partition_size],
  804. &context->enc_RealLeft[0],
  805. sizeof(ulong)*context->enc_window_size
  806. );
  807. copymem(
  808. &context->enc_RealRight[context->enc_encoder_second_partition_size],
  809. &context->enc_RealRight[0],
  810. sizeof(ulong)*context->enc_window_size
  811. );
  812. context->enc_earliest_window_data_remaining = BufPos - context->enc_window_size;
  813. /*
  814. * The following bit of code is CRUCIAL yet unorthodox in function
  815. * and serves as a speed and syntax optimization and makes the code
  816. * easier to understand once grasped.
  817. *
  818. * The three main buffers, context->enc_MemWindow, context->enc_Left and context->enc_Right,
  819. * are referensed by BufPos and SearchPos relative to the current
  820. * compression window locations. When the encoder reaches the end
  821. * of its block of input memory, the data in the input buffer is
  822. * shifted into the compression history window and the new input
  823. * stream is loaded. Typically the BufPos pointer would be reduced
  824. * to signify the replaced data. However, this code reduces the
  825. * base pointers to reflect the shift of data, and leaves the BufPos
  826. * pointer in its current state. Therefore, the BufPos pointer is
  827. * an absolute pointer reflecting the position in the input stream,
  828. * and NOT the position in the buffer. The base pointers will point
  829. * to invalid memory locations with addresses smaller than the
  830. * actual array base pointers. However, when the two pointers are
  831. * added together, &(context->enc_MemWindow+BufPos), it will point to the
  832. * correct and valid position in the buffer.
  833. */
  834. context->enc_MemWindow -= context->enc_encoder_second_partition_size;
  835. context->enc_Left -= context->enc_encoder_second_partition_size;
  836. context->enc_Right -= context->enc_encoder_second_partition_size;
  837. break;
  838. }
  839. /*
  840. * Store BufPos in global variable
  841. */
  842. context->enc_BufPos = BufPos;
  843. }
  844. static void block_end(t_encoder_context *context, long BufPos)
  845. {
  846. context->enc_first_block = false;
  847. context->enc_need_to_recalc_stats = true;
  848. output_block(context);
  849. if (context->enc_literals < TREE_CREATE_INTERVAL)
  850. {
  851. context->enc_next_tree_create = TREE_CREATE_INTERVAL;
  852. }
  853. else
  854. {
  855. context->enc_next_tree_create = context->enc_literals + TREE_CREATE_INTERVAL; /* recreate right away */
  856. }
  857. context->enc_bufpos_last_output_block = BufPos;
  858. }
  859. static bool redo_first_block(t_encoder_context *context, long *bufpos_ptr)
  860. {
  861. long start_at;
  862. long earliest_can_start_at;
  863. long pos_in_file;
  864. long history_needed;
  865. long history_avail;
  866. long BufPos;
  867. long split_at_literal;
  868. context->enc_first_block = false;
  869. BufPos = *bufpos_ptr;
  870. /*
  871. * For the first context->enc_window size bytes in the file, we don't
  872. * need to have context->enc_window size bytes around.
  873. *
  874. * For anything after that, though, we do need to have window_size
  875. * previous bytes to look into.
  876. */
  877. /*
  878. * How many bytes are we into the file?
  879. */
  880. pos_in_file = BufPos - context->enc_window_size;
  881. /*
  882. * First let's figure out the total history required from
  883. * BufPos backwards. For starters, we need all the bytes
  884. * we're going to recompress. We get that by seeing the
  885. * last time we output a block.
  886. */
  887. history_needed = BufPos - context->enc_bufpos_last_output_block;
  888. /*
  889. * Plus we will need window_size bytes before that (for matching
  890. * into) unless we're looking within the first window_size
  891. * bytes of the file.
  892. */
  893. if (context->enc_bufpos_last_output_block-context->enc_window_size < context->enc_window_size)
  894. history_needed += context->enc_bufpos_last_output_block - context->enc_window_size;
  895. else
  896. history_needed += context->enc_window_size;
  897. history_avail = (long) (&context->enc_MemWindow[BufPos] - &context->enc_RealMemWindow[0]);
  898. if (history_needed <= history_avail)
  899. {
  900. earliest_can_start_at = context->enc_bufpos_last_output_block;
  901. }
  902. else
  903. {
  904. /*
  905. * Not enough history available
  906. */
  907. return false;
  908. }
  909. start_at = earliest_can_start_at;
  910. (void) split_block(
  911. context,
  912. 0,
  913. context->enc_literals,
  914. context->enc_distances,
  915. &split_at_literal,
  916. NULL /* don't need # distances returned */
  917. );
  918. get_block_stats(
  919. context,
  920. 0,
  921. 0,
  922. split_at_literal
  923. );
  924. create_trees(context, false); /* don't generate codes */
  925. fix_tree_cost_estimates(context);
  926. #ifdef MULTIPLE_SEARCH_TREES
  927. /*
  928. * Now set all the tree root pointers to NULL
  929. * (don't need to reset the left/right pointers).
  930. */
  931. memset(context->enc_tree_root, 0, NUM_SEARCH_TREES * sizeof(ulong));
  932. #else
  933. context->enc_single_tree_root = 0;
  934. #endif
  935. /*
  936. * Clear item array and reset literal and distance
  937. * counters
  938. */
  939. memset(context->enc_ItemType, 0, (MAX_LITERAL_ITEMS/8));
  940. /*
  941. * Reset encoder state
  942. */
  943. context->enc_last_matchpos_offset[0] = 1;
  944. context->enc_last_matchpos_offset[1] = 1;
  945. context->enc_last_matchpos_offset[2] = 1;
  946. context->enc_repeated_offset_at_literal_zero[0] = 1;
  947. context->enc_repeated_offset_at_literal_zero[1] = 1;
  948. context->enc_repeated_offset_at_literal_zero[2] = 1;
  949. context->enc_input_running_total = 0;
  950. context->enc_literals = 0;
  951. context->enc_distances = 0;
  952. context->enc_need_to_recalc_stats = true;
  953. context->enc_next_tree_create = split_at_literal;
  954. *bufpos_ptr = start_at;
  955. return true;
  956. }