PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Compression/Deflaters/DeflaterEngine.cs

#
C# | 937 lines | 606 code | 97 blank | 234 comment | 98 complexity | 2d1e4feae1e961ca51f7cc678255273e MD5 | raw file
Possible License(s): Apache-2.0
  1. // Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
  2. // Authors of the original java version: Jochen Hoenicke, John Leuner
  3. // See http://www.ISeeSharpCode.com for more information.
  4. using System;
  5. using Delta.Utilities.Compression.Checksums;
  6. namespace Delta.Utilities.Compression.Deflaters
  7. {
  8. /// <summary>
  9. /// Low level compression engine for deflate algorithm which uses a
  10. /// 32K sliding window with secondary compression from
  11. /// Huffman/Shannon-Fano codes.
  12. /// </summary>
  13. /// <remarks>
  14. /// DEFLATE ALGORITHM:
  15. ///
  16. /// The uncompressed stream is inserted into the window array. When
  17. /// the window array is full the first half is thrown away and the
  18. /// second half is copied to the beginning.
  19. ///
  20. /// The head array is a hash table. Three characters build a hash value
  21. /// and they the value points to the corresponding index in window of
  22. /// the last string with this hash. The prev array implements a
  23. /// linked list of matches with the same hash: prev[index &amp; WMask] points
  24. /// to the previous index with the same hash.
  25. /// </remarks>
  26. public class DeflaterEngine : DeflaterConstants
  27. {
  28. #region Constants
  29. /// <summary>
  30. /// Length too far, reached limit at 4096 bytes.
  31. /// </summary>
  32. private const int LengthTooFar = 4096;
  33. #endregion
  34. #region Adler (Public)
  35. /// <summary>
  36. /// Get current value of Adler checksum
  37. /// </summary>
  38. public int Adler
  39. {
  40. get
  41. {
  42. return (int)adler.Value;
  43. }
  44. }
  45. #endregion
  46. #region TotalIn (Public)
  47. /// <summary>
  48. /// Total data processed
  49. /// </summary>
  50. public int TotalIn
  51. {
  52. get
  53. {
  54. return totalIn;
  55. }
  56. }
  57. #endregion
  58. #region Strategy (Public)
  59. /// <summary>
  60. /// Get/set the <see cref="DeflateStrategy">deflate strategy</see>
  61. /// </summary>
  62. public DeflateStrategy Strategy
  63. {
  64. get
  65. {
  66. return strategy;
  67. }
  68. set
  69. {
  70. strategy = value;
  71. }
  72. }
  73. #endregion
  74. #region Private
  75. #region ins_h (Private)
  76. /// <summary>
  77. /// Ins _h
  78. /// </summary>
  79. private int ins_h;
  80. #endregion
  81. #region head (Private)
  82. /// <summary>
  83. /// Hashtable, hashing three characters to an index for window, so
  84. /// that window[index]..window[index+2] have this hash code.
  85. /// Note that the array should really be unsigned short, so you need
  86. /// to and the values with 0xffff.
  87. /// </summary>
  88. private readonly short[] head;
  89. #endregion
  90. #region prev (Private)
  91. /// <summary>
  92. /// <code>prev[index &amp; WMask]</code> points to the previous index that
  93. /// has the same hash code as the string starting at index.
  94. /// This way entries with the same hash code are in a linked list.
  95. /// Note that the array should really be unsigned short, so you need
  96. /// to and the values with 0xffff.
  97. /// </summary>
  98. private readonly short[] prev;
  99. #endregion
  100. #region matchStart (Private)
  101. /// <summary>
  102. /// Match Start
  103. /// </summary>
  104. private int matchStart;
  105. #endregion
  106. #region matchLen (Private)
  107. /// <summary>
  108. /// Match Length
  109. /// </summary>
  110. private int matchLen;
  111. #endregion
  112. #region prevAvailable (Private)
  113. /// <summary>
  114. /// Prev Available
  115. /// </summary>
  116. private bool prevAvailable;
  117. #endregion
  118. #region blockStart (Private)
  119. /// <summary>
  120. /// Block Start
  121. /// </summary>
  122. private int blockStart;
  123. #endregion
  124. #region strstart (Private)
  125. /// <summary>
  126. /// String Start
  127. /// </summary>
  128. private int strstart;
  129. #endregion
  130. #region lookahead (Private)
  131. /// <summary>
  132. /// lookahead is the number of characters starting at strstart in
  133. /// window that are valid.
  134. /// So window[strstart] until window[strstart+lookahead-1] are valid
  135. /// characters.
  136. /// </summary>
  137. private int lookahead;
  138. #endregion
  139. #region window (Private)
  140. /// <summary>
  141. /// This array contains the part of the uncompressed stream that
  142. /// is of relevance. The current character is indexed by strstart.
  143. /// </summary>
  144. private readonly byte[] window;
  145. #endregion
  146. #region strategy (Private)
  147. /// <summary>
  148. /// Deflate Strategy
  149. /// </summary>
  150. private DeflateStrategy strategy;
  151. #endregion
  152. #region max_chain (Private)
  153. /// <summary>
  154. /// Points to the current character in the window.
  155. /// </summary>
  156. private int max_chain;
  157. #endregion
  158. #region max_lazy (Private)
  159. /// <summary>
  160. /// Points to the current character in the window.
  161. /// </summary>
  162. private int max_lazy;
  163. #endregion
  164. #region niceLength (Private)
  165. /// <summary>
  166. /// Points to the current character in the window.
  167. /// </summary>
  168. private int niceLength;
  169. #endregion
  170. #region goodLength (Private)
  171. /// <summary>
  172. /// Points to the current character in the window.
  173. /// </summary>
  174. private int goodLength;
  175. #endregion
  176. #region comprFunc (Private)
  177. /// <summary>
  178. /// The current compression function.
  179. /// </summary>
  180. private int comprFunc;
  181. #endregion
  182. #region inputBuf (Private)
  183. /// <summary>
  184. /// The input data for compression.
  185. /// </summary>
  186. private byte[] inputBuf;
  187. #endregion
  188. #region totalIn (Private)
  189. /// <summary>
  190. /// The total bytes of input read.
  191. /// </summary>
  192. private int totalIn;
  193. #endregion
  194. #region inputOff (Private)
  195. /// <summary>
  196. /// The offset into inputBuf, where input data starts.
  197. /// </summary>
  198. private int inputOff;
  199. #endregion
  200. #region inputEnd (Private)
  201. /// <summary>
  202. /// The end offset of the input data.
  203. /// </summary>
  204. private int inputEnd;
  205. #endregion
  206. #region pending (Private)
  207. /// <summary>
  208. /// Pending
  209. /// </summary>
  210. private readonly DeflaterPending pending;
  211. #endregion
  212. #region huffman (Private)
  213. /// <summary>
  214. /// Huffman
  215. /// </summary>
  216. private readonly DeflaterHuffman huffman;
  217. #endregion
  218. #region adler (Private)
  219. /// <summary>
  220. /// The adler checksum
  221. /// </summary>
  222. private readonly Adler32 adler;
  223. #endregion
  224. #endregion
  225. #region Constructors
  226. /// <summary>
  227. /// Construct instance with pending buffer
  228. /// </summary>
  229. /// <param name="setPending">
  230. /// Pending buffer to use
  231. /// </param>>
  232. public DeflaterEngine(DeflaterPending setPending)
  233. {
  234. pending = setPending;
  235. huffman = new DeflaterHuffman(setPending);
  236. adler = new Adler32();
  237. window = new byte[2 * WSize];
  238. head = new short[HashSize];
  239. prev = new short[WSize];
  240. // We start at index 1, to avoid an implementation deficiency, that
  241. // we cannot build a repeat pattern at index 0.
  242. blockStart = strstart = 1;
  243. }
  244. #endregion
  245. #region Reset (Public)
  246. /// <summary>
  247. /// Reset internal state
  248. /// </summary>
  249. public void Reset()
  250. {
  251. huffman.Reset();
  252. adler.Reset();
  253. blockStart = strstart = 1;
  254. lookahead = 0;
  255. totalIn = 0;
  256. prevAvailable = false;
  257. matchLen = MinMatch - 1;
  258. for (int i = 0; i < HashSize; i++)
  259. {
  260. head[i] = 0;
  261. }
  262. for (int i = 0; i < WSize; i++)
  263. {
  264. prev[i] = 0;
  265. }
  266. }
  267. #endregion
  268. #region ResetAdler (Public)
  269. /// <summary>
  270. /// Reset Adler checksum
  271. /// </summary>
  272. public void ResetAdler()
  273. {
  274. adler.Reset();
  275. }
  276. #endregion
  277. #region SetLevel (Public)
  278. /// <summary>
  279. /// Set the deflate level (0-9)
  280. /// </summary>
  281. public void SetLevel(int lvl)
  282. {
  283. // Good length
  284. goodLength = GoodLength[lvl];
  285. max_lazy = MaxLazy[lvl];
  286. // Nice length
  287. niceLength = NiceLength[lvl];
  288. max_chain = MaxChain[lvl];
  289. if (CompressionFunction[lvl] != comprFunc)
  290. {
  291. switch (comprFunc)
  292. {
  293. case CompressionDeflateStored:
  294. if (strstart > blockStart)
  295. {
  296. huffman.FlushStoredBlock(window, blockStart,
  297. strstart - blockStart, false);
  298. blockStart = strstart;
  299. }
  300. UpdateHash();
  301. break;
  302. case CompressionDeflateFast:
  303. if (strstart > blockStart)
  304. {
  305. huffman.FlushBlock(window, blockStart, strstart - blockStart,
  306. false);
  307. blockStart = strstart;
  308. }
  309. break;
  310. case CompressionDeflateSlow:
  311. if (prevAvailable)
  312. {
  313. huffman.TallyLit(window[strstart - 1] & 0xff);
  314. }
  315. if (strstart > blockStart)
  316. {
  317. huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
  318. blockStart = strstart;
  319. }
  320. prevAvailable = false;
  321. matchLen = MinMatch - 1;
  322. break;
  323. }
  324. comprFunc = CompressionFunction[lvl];
  325. }
  326. }
  327. #endregion
  328. #region FillWindow (Public)
  329. /// <summary>
  330. /// Fill the window
  331. /// </summary>
  332. public void FillWindow()
  333. {
  334. // If the window is almost full and there is insufficient lookahead,
  335. // move the upper half to the lower one to make room in the upper half.
  336. if (strstart >= WSize + MaxDistance)
  337. {
  338. SlideWindow();
  339. }
  340. // If there is not enough lookahead, but still some input left,
  341. // read in the input.
  342. while (lookahead < MinLookAhead &&
  343. inputOff < inputEnd)
  344. {
  345. int more = 2 * WSize - lookahead - strstart;
  346. if (more > inputEnd - inputOff)
  347. {
  348. more = inputEnd - inputOff;
  349. }
  350. Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
  351. adler.Update(inputBuf, inputOff, more);
  352. inputOff += more;
  353. totalIn += more;
  354. lookahead += more;
  355. }
  356. if (lookahead >= MinMatch)
  357. {
  358. UpdateHash();
  359. }
  360. }
  361. #endregion
  362. #region SetDictionary (Public)
  363. /// <summary>
  364. /// Set compression dictionary
  365. /// </summary>
  366. public void SetDictionary(byte[] buffer, int offset, int length)
  367. {
  368. adler.Update(buffer, offset, length);
  369. if (length < MinMatch)
  370. {
  371. return;
  372. }
  373. if (length > MaxDistance)
  374. {
  375. offset += length - MaxDistance;
  376. length = MaxDistance;
  377. }
  378. Array.Copy(buffer, offset, window, strstart, length);
  379. UpdateHash();
  380. --length;
  381. while (--length > 0)
  382. {
  383. InsertString();
  384. strstart++;
  385. }
  386. strstart += 2;
  387. blockStart = strstart;
  388. }
  389. #endregion
  390. #region Deflate (Public)
  391. /// <summary>
  392. /// Deflate drives actual compression of data
  393. /// </summary>
  394. public bool Deflate(bool flush, bool finish)
  395. {
  396. bool progress;
  397. do
  398. {
  399. FillWindow();
  400. bool canFlush = flush && inputOff == inputEnd;
  401. switch (comprFunc)
  402. {
  403. case CompressionDeflateStored:
  404. progress = DeflateStored(canFlush, finish);
  405. break;
  406. case CompressionDeflateFast:
  407. progress = DeflateFast(canFlush, finish);
  408. break;
  409. case CompressionDeflateSlow:
  410. progress = DeflateSlow(canFlush, finish);
  411. break;
  412. default:
  413. throw new InvalidOperationException("unknown comprFunc");
  414. }
  415. // Repeat while we have no pending output and progress was made
  416. } while (pending.IsFlushed && progress);
  417. return progress;
  418. }
  419. #endregion
  420. #region SetInput (Public)
  421. /// <summary>
  422. /// Sets input data to be deflated.
  423. /// Should only be called when <code>NeedsInput()</code> returns true.
  424. /// </summary>
  425. /// <param name="buf">The buffer containing input data.</param>
  426. /// <param name="off">The index of the first byte of data.</param>
  427. /// <param name="len">The number of bytes of data to use as input.</param>
  428. public void SetInput(byte[] buf, int off, int len)
  429. {
  430. if (inputOff < inputEnd)
  431. {
  432. throw new InvalidOperationException(
  433. "Old input was not completely processed");
  434. }
  435. int end = off + len;
  436. // We want to throw an ArrayIndexOutOfBoundsException early.
  437. // The check is very tricky: it also handles integer wrap around.
  438. if (0 > off ||
  439. off > end ||
  440. end > buf.Length)
  441. {
  442. throw new ArgumentOutOfRangeException();
  443. }
  444. inputBuf = buf;
  445. inputOff = off;
  446. inputEnd = end;
  447. }
  448. #endregion
  449. #region NeedsInput (Public)
  450. /// <summary>
  451. /// Return true if input is needed via <see cref="SetInput">SetInput</see>
  452. /// </summary>
  453. public bool NeedsInput()
  454. {
  455. return inputEnd == inputOff;
  456. }
  457. #endregion
  458. #region Methods (Private)
  459. #region UpdateHash
  460. /// <summary>
  461. /// Update hash
  462. /// </summary>
  463. private void UpdateHash()
  464. {
  465. ins_h = (window[strstart] << HashShift) ^ window[strstart + 1];
  466. }
  467. #endregion
  468. #region InsertString
  469. /// <summary>
  470. /// Inserts the current string in the head hash and returns the previous
  471. /// value for this hash.
  472. /// </summary>
  473. /// <returns>The previous hash value</returns>
  474. private int InsertString()
  475. {
  476. short match;
  477. int hash =
  478. ((ins_h << HashShift) ^ window[strstart + (MinMatch - 1)]) &
  479. HashMask;
  480. prev[strstart & WMask] = match = head[hash];
  481. head[hash] = (short)strstart;
  482. ins_h = hash;
  483. return match & 0xffff;
  484. }
  485. #endregion
  486. #region SlideWindow
  487. /// <summary>
  488. /// Slide window
  489. /// </summary>
  490. private void SlideWindow()
  491. {
  492. Array.Copy(window, WSize, window, 0, WSize);
  493. matchStart -= WSize;
  494. strstart -= WSize;
  495. blockStart -= WSize;
  496. // Slide the hash table (could be avoided with 32 bit values
  497. // at the expense of memory usage).
  498. for (int i = 0; i < HashSize; ++i)
  499. {
  500. int m = head[i] & 0xffff;
  501. head[i] = (short)(m >= WSize
  502. ? (m - WSize)
  503. : 0);
  504. }
  505. // Slide the prev table.
  506. for (int i = 0; i < WSize; i++)
  507. {
  508. int m = prev[i] & 0xffff;
  509. prev[i] = (short)(m >= WSize
  510. ? (m - WSize)
  511. : 0);
  512. }
  513. }
  514. #endregion
  515. #region FindLongestMatch
  516. /// <summary>
  517. /// Find the best (longest) string in the window matching the
  518. /// string starting at strstart.
  519. ///
  520. /// Preconditions:
  521. /// <code>
  522. /// strstart + MaxMatch &lt;= window.length.</code>
  523. /// </summary>
  524. /// <param name="curMatch"></param>
  525. /// <returns>True if a match greater than the minimum length is found</returns>
  526. private bool FindLongestMatch(int curMatch)
  527. {
  528. int chainLength = max_chain;
  529. int tempNiceLength = niceLength;
  530. short[] tempPrev = prev;
  531. int scan = strstart;
  532. int match;
  533. int best_end = strstart + matchLen;
  534. int best_len = Math.Max(matchLen, MinMatch - 1);
  535. int limit = Math.Max(strstart - MaxDistance, 0);
  536. int strend = strstart + MaxMatch - 1;
  537. byte scan_end1 = window[best_end - 1];
  538. byte scan_end = window[best_end];
  539. // Do not waste too much time if we already have a good match:
  540. if (best_len >= goodLength)
  541. {
  542. chainLength >>= 2;
  543. }
  544. // Do not look for matches beyond the end of the input.
  545. // This is necessary to make deflate deterministic.
  546. if (tempNiceLength > lookahead)
  547. {
  548. tempNiceLength = lookahead;
  549. }
  550. do
  551. {
  552. if (window[curMatch + best_len] != scan_end ||
  553. window[curMatch + best_len - 1] != scan_end1 ||
  554. window[curMatch] != window[scan] ||
  555. window[curMatch + 1] != window[scan + 1])
  556. {
  557. continue;
  558. }
  559. match = curMatch + 2;
  560. scan += 2;
  561. // We check for insufficient lookahead only every 8th comparison;
  562. // the 256th check will be made at strstart + 258.
  563. while (window[++scan] == window[++match] &&
  564. window[++scan] == window[++match] &&
  565. window[++scan] == window[++match] &&
  566. window[++scan] == window[++match] &&
  567. window[++scan] == window[++match] &&
  568. window[++scan] == window[++match] &&
  569. window[++scan] == window[++match] &&
  570. window[++scan] == window[++match] &&
  571. scan < strend)
  572. {
  573. ;
  574. }
  575. if (scan > best_end)
  576. {
  577. matchStart = curMatch;
  578. best_end = scan;
  579. best_len = scan - strstart;
  580. if (best_len >= tempNiceLength)
  581. {
  582. break;
  583. }
  584. scan_end1 = window[best_end - 1];
  585. scan_end = window[best_end];
  586. }
  587. scan = strstart;
  588. } while ((curMatch = (tempPrev[curMatch & WMask] & 0xffff)) > limit &&
  589. --chainLength != 0);
  590. matchLen = Math.Min(best_len, lookahead);
  591. return matchLen >= MinMatch;
  592. }
  593. #endregion
  594. #region DeflateStored
  595. /// <summary>
  596. /// Deflate stored
  597. /// </summary>
  598. /// <param name="flush">Flush</param>
  599. /// <param name="finish">Finish</param>
  600. /// <returns>
  601. /// True if storing succeeded, false if nothing was stored.
  602. /// </returns>
  603. private bool DeflateStored(bool flush, bool finish)
  604. {
  605. if (!flush && lookahead == 0)
  606. {
  607. return false;
  608. }
  609. strstart += lookahead;
  610. lookahead = 0;
  611. int storedLen = strstart - blockStart;
  612. // Block is full or Block may move out of window
  613. if ((storedLen >= MaxBlockSize) ||
  614. (blockStart < WSize && storedLen >= MaxDistance) ||
  615. flush)
  616. {
  617. bool lastBlock = finish;
  618. if (storedLen > MaxBlockSize)
  619. {
  620. storedLen = MaxBlockSize;
  621. lastBlock = false;
  622. }
  623. huffman.FlushStoredBlock(window, blockStart, storedLen, lastBlock);
  624. blockStart += storedLen;
  625. return !lastBlock;
  626. }
  627. return true;
  628. }
  629. #endregion
  630. #region DeflateFast
  631. /// <summary>
  632. /// Deflate fast
  633. /// </summary>
  634. /// <param name="flush">Flush</param>
  635. /// <param name="finish">Finish</param>
  636. /// <returns>
  637. /// True if storing succeeded, false if nothing was stored.
  638. /// </returns>
  639. private bool DeflateFast(bool flush, bool finish)
  640. {
  641. if (lookahead < MinLookAhead && !flush)
  642. {
  643. return false;
  644. }
  645. while (lookahead >= MinLookAhead || flush)
  646. {
  647. if (lookahead == 0)
  648. {
  649. // We are flushing everything
  650. huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
  651. blockStart = strstart;
  652. return false;
  653. }
  654. if (strstart > 2 * WSize - MinLookAhead)
  655. {
  656. // slide window, as findLongestMatch needs this. This should only
  657. // happen when flushing and the window is almost full.
  658. SlideWindow();
  659. }
  660. int hashHead;
  661. if (lookahead >= MinMatch &&
  662. (hashHead = InsertString()) != 0 &&
  663. strategy != DeflateStrategy.HuffmanOnly &&
  664. strstart - hashHead <= MaxDistance &&
  665. FindLongestMatch(hashHead))
  666. {
  667. // longestMatch sets matchStart and matchLen
  668. // This stops problems with fast/low compression and index out of
  669. // range
  670. if (huffman.TallyDist(strstart - matchStart, matchLen))
  671. {
  672. bool lastBlock = finish && lookahead == 0;
  673. huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
  674. blockStart = strstart;
  675. }
  676. lookahead -= matchLen;
  677. if (matchLen <= max_lazy && lookahead >= MinMatch)
  678. {
  679. while (--matchLen > 0)
  680. {
  681. ++strstart;
  682. InsertString();
  683. }
  684. ++strstart;
  685. }
  686. else
  687. {
  688. strstart += matchLen;
  689. if (lookahead >= MinMatch - 1)
  690. {
  691. UpdateHash();
  692. }
  693. }
  694. matchLen = MinMatch - 1;
  695. continue;
  696. }
  697. else
  698. {
  699. /* No match found */
  700. huffman.TallyLit(window[strstart] & 0xff);
  701. ++strstart;
  702. --lookahead;
  703. }
  704. if (huffman.IsFull())
  705. {
  706. bool lastBlock = finish && lookahead == 0;
  707. huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
  708. blockStart = strstart;
  709. return !lastBlock;
  710. }
  711. }
  712. return true;
  713. }
  714. #endregion
  715. #region DeflateSlow
  716. /// <summary>
  717. /// Deflate slow
  718. /// </summary>
  719. /// <param name="flush">Flush</param>
  720. /// <param name="finish">Finish</param>
  721. /// <returns>
  722. /// True if storing succeeded, false if nothing was stored.
  723. /// </returns>
  724. private bool DeflateSlow(bool flush, bool finish)
  725. {
  726. if (lookahead < MinLookAhead && !flush)
  727. {
  728. return false;
  729. }
  730. while (lookahead >= MinLookAhead || flush)
  731. {
  732. if (lookahead == 0)
  733. {
  734. if (prevAvailable)
  735. {
  736. huffman.TallyLit(window[strstart - 1] & 0xff);
  737. }
  738. prevAvailable = false;
  739. // We are flushing everything
  740. huffman.FlushBlock(window, blockStart, strstart - blockStart,
  741. finish);
  742. blockStart = strstart;
  743. return false;
  744. }
  745. if (strstart >= 2 * WSize - MinLookAhead)
  746. {
  747. // slide window, as findLongestMatch need this. This should only
  748. // happen when flushing and the window is almost full.
  749. SlideWindow();
  750. }
  751. int prevMatch = matchStart;
  752. int prevLen = matchLen;
  753. DeflateSlowCheckLookAhead();
  754. prevLen = DeflateSlowCheckPreviousMatch(prevMatch, prevLen);
  755. if (huffman.IsFull())
  756. {
  757. int len = strstart - blockStart;
  758. if (prevAvailable)
  759. {
  760. len--;
  761. }
  762. bool lastBlock = (finish && lookahead == 0 && !prevAvailable);
  763. huffman.FlushBlock(window, blockStart, len, lastBlock);
  764. blockStart += len;
  765. return !lastBlock;
  766. }
  767. }
  768. return true;
  769. }
  770. #endregion
  771. #region DeflateSlowCheckLookAhead
  772. /// <summary>
  773. /// Deflate slow check look ahead
  774. /// </summary>
  775. private void DeflateSlowCheckLookAhead()
  776. {
  777. if (lookahead >= MinMatch)
  778. {
  779. int hashHead = InsertString();
  780. if (strategy != DeflateStrategy.HuffmanOnly &&
  781. hashHead != 0 && strstart - hashHead <= MaxDistance &&
  782. FindLongestMatch(hashHead))
  783. {
  784. // longestMatch sets matchStart and matchLen
  785. // Discard match if too small and too far away
  786. if (matchLen <= 5 &&
  787. (strategy == DeflateStrategy.Filtered ||
  788. (matchLen == MinMatch && strstart - matchStart > LengthTooFar)))
  789. {
  790. matchLen = MinMatch - 1;
  791. }
  792. }
  793. }
  794. }
  795. #endregion
  796. #region DeflateSlowCheckPreviousMatch
  797. /// <summary>
  798. /// Deflate slow check previous match
  799. /// </summary>
  800. /// <param name="prevMatch">Prev match</param>
  801. /// <param name="prevLen">Prev len</param>
  802. /// <returns>Int</returns>
  803. private int DeflateSlowCheckPreviousMatch(int prevMatch, int prevLen)
  804. {
  805. // previous match was better
  806. if (prevLen >= MinMatch &&
  807. matchLen <= prevLen)
  808. {
  809. huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
  810. prevLen -= 2;
  811. do
  812. {
  813. strstart++;
  814. lookahead--;
  815. if (lookahead >= MinMatch)
  816. {
  817. InsertString();
  818. }
  819. } while (--prevLen > 0);
  820. strstart++;
  821. lookahead--;
  822. prevAvailable = false;
  823. matchLen = MinMatch - 1;
  824. }
  825. else
  826. {
  827. if (prevAvailable)
  828. {
  829. huffman.TallyLit(window[strstart - 1] & 0xff);
  830. }
  831. prevAvailable = true;
  832. strstart++;
  833. lookahead--;
  834. }
  835. return prevLen;
  836. }
  837. #endregion
  838. #endregion
  839. }
  840. }