PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/Common/SharpZipLib/Zip/Compression/DeflaterEngine.cs

http://tsanie-shellextension.googlecode.com/
C# | 869 lines | 535 code | 110 blank | 224 comment | 151 complexity | 0de92548f8ca5af585115754ed9b8bd0 MD5 | raw file
  1. // DeflaterEngine.cs
  2. //
  3. // Copyright (C) 2001 Mike Krueger
  4. // Copyright (C) 2004 John Reilly
  5. //
  6. // This file was translated from java, it was part of the GNU Classpath
  7. // Copyright (C) 2001 Free Software Foundation, Inc.
  8. //
  9. // This program is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public License
  11. // as published by the Free Software Foundation; either version 2
  12. // of the License, or (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. // GNU General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public License
  20. // along with this program; if not, write to the Free Software
  21. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. //
  23. // Linking this library statically or dynamically with other modules is
  24. // making a combined work based on this library. Thus, the terms and
  25. // conditions of the GNU General Public License cover the whole
  26. // combination.
  27. //
  28. // As a special exception, the copyright holders of this library give you
  29. // permission to link this library with independent modules to produce an
  30. // executable, regardless of the license terms of these independent
  31. // modules, and to copy and distribute the resulting executable under
  32. // terms of your choice, provided that you also meet, for each linked
  33. // independent module, the terms and conditions of the license of that
  34. // module. An independent module is a module which is not derived from
  35. // or based on this library. If you modify this library, you may extend
  36. // this exception to your version of the library, but you are not
  37. // obligated to do so. If you do not wish to do so, delete this
  38. // exception statement from your version.
  39. using System;
  40. using SharpZipLib.Checksums;
  41. namespace SharpZipLib.Zip.Compression
  42. {
  43. /// <summary>
  44. /// Strategies for deflater
  45. /// </summary>
  46. public enum DeflateStrategy
  47. {
  48. /// <summary>
  49. /// The default strategy
  50. /// </summary>
  51. Default = 0,
  52. /// <summary>
  53. /// This strategy will only allow longer string repetitions. It is
  54. /// useful for random data with a small character set.
  55. /// </summary>
  56. Filtered = 1,
  57. /// <summary>
  58. /// This strategy will not look for string repetitions at all. It
  59. /// only encodes with Huffman trees (which means, that more common
  60. /// characters get a smaller encoding.
  61. /// </summary>
  62. HuffmanOnly = 2
  63. }
  64. // DEFLATE ALGORITHM:
  65. //
  66. // The uncompressed stream is inserted into the window array. When
  67. // the window array is full the first half is thrown away and the
  68. // second half is copied to the beginning.
  69. //
  70. // The head array is a hash table. Three characters build a hash value
  71. // and they the value points to the corresponding index in window of
  72. // the last string with this hash. The prev array implements a
  73. // linked list of matches with the same hash: prev[index & WMASK] points
  74. // to the previous index with the same hash.
  75. //
  76. /// <summary>
  77. /// Low level compression engine for deflate algorithm which uses a 32K sliding window
  78. /// with secondary compression from Huffman/Shannon-Fano codes.
  79. /// </summary>
  80. public class DeflaterEngine : DeflaterConstants
  81. {
  82. #region Constants
  83. const int TooFar = 4096;
  84. #endregion
  85. #region Constructors
  86. /// <summary>
  87. /// Construct instance with pending buffer
  88. /// </summary>
  89. /// <param name="pending">
  90. /// Pending buffer to use
  91. /// </param>>
  92. public DeflaterEngine(DeflaterPending pending)
  93. {
  94. this.pending = pending;
  95. huffman = new DeflaterHuffman(pending);
  96. adler = new Adler32();
  97. window = new byte[2 * WSIZE];
  98. head = new short[HASH_SIZE];
  99. prev = new short[WSIZE];
  100. // We start at index 1, to avoid an implementation deficiency, that
  101. // we cannot build a repeat pattern at index 0.
  102. blockStart = strstart = 1;
  103. }
  104. #endregion
  105. /// <summary>
  106. /// Deflate drives actual compression of data
  107. /// </summary>
  108. /// <param name="flush">True to flush input buffers</param>
  109. /// <param name="finish">Finish deflation with the current input.</param>
  110. /// <returns>Returns true if progress has been made.</returns>
  111. public bool Deflate(bool flush, bool finish)
  112. {
  113. bool progress;
  114. do
  115. {
  116. FillWindow();
  117. bool canFlush = flush && (inputOff == inputEnd);
  118. #if DebugDeflation
  119. if (DeflaterConstants.DEBUGGING) {
  120. Console.WriteLine("window: [" + blockStart + "," + strstart + ","
  121. + lookahead + "], " + compressionFunction + "," + canFlush);
  122. }
  123. #endif
  124. switch (compressionFunction)
  125. {
  126. case DEFLATE_STORED:
  127. progress = DeflateStored(canFlush, finish);
  128. break;
  129. case DEFLATE_FAST:
  130. progress = DeflateFast(canFlush, finish);
  131. break;
  132. case DEFLATE_SLOW:
  133. progress = DeflateSlow(canFlush, finish);
  134. break;
  135. default:
  136. throw new InvalidOperationException("unknown compressionFunction");
  137. }
  138. } while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
  139. return progress;
  140. }
  141. /// <summary>
  142. /// Sets input data to be deflated. Should only be called when <code>NeedsInput()</code>
  143. /// returns true
  144. /// </summary>
  145. /// <param name="buffer">The buffer containing input data.</param>
  146. /// <param name="offset">The offset of the first byte of data.</param>
  147. /// <param name="count">The number of bytes of data to use as input.</param>
  148. public void SetInput(byte[] buffer, int offset, int count)
  149. {
  150. if ( buffer == null )
  151. {
  152. throw new ArgumentNullException("buffer");
  153. }
  154. if ( offset < 0 )
  155. {
  156. throw new ArgumentOutOfRangeException("offset");
  157. }
  158. if ( count < 0 )
  159. {
  160. throw new ArgumentOutOfRangeException("count");
  161. }
  162. if (inputOff < inputEnd)
  163. {
  164. throw new InvalidOperationException("Old input was not completely processed");
  165. }
  166. int end = offset + count;
  167. /* We want to throw an ArrayIndexOutOfBoundsException early. The
  168. * check is very tricky: it also handles integer wrap around.
  169. */
  170. if ((offset > end) || (end > buffer.Length) )
  171. {
  172. throw new ArgumentOutOfRangeException("count");
  173. }
  174. inputBuf = buffer;
  175. inputOff = offset;
  176. inputEnd = end;
  177. }
  178. /// <summary>
  179. /// Determines if more <see cref="SetInput">input</see> is needed.
  180. /// </summary>
  181. /// <returns>Return true if input is needed via <see cref="SetInput">SetInput</see></returns>
  182. public bool NeedsInput()
  183. {
  184. return (inputEnd == inputOff);
  185. }
  186. /// <summary>
  187. /// Set compression dictionary
  188. /// </summary>
  189. /// <param name="buffer">The buffer containing the dictionary data</param>
  190. /// <param name="offset">The offset in the buffer for the first byte of data</param>
  191. /// <param name="length">The length of the dictionary data.</param>
  192. public void SetDictionary(byte[] buffer, int offset, int length)
  193. {
  194. #if DebugDeflation
  195. if (DeflaterConstants.DEBUGGING && (strstart != 1) )
  196. {
  197. throw new InvalidOperationException("strstart not 1");
  198. }
  199. #endif
  200. adler.Update(buffer, offset, length);
  201. if (length < MIN_MATCH)
  202. {
  203. return;
  204. }
  205. if (length > MAX_DIST)
  206. {
  207. offset += length - MAX_DIST;
  208. length = MAX_DIST;
  209. }
  210. System.Array.Copy(buffer, offset, window, strstart, length);
  211. UpdateHash();
  212. --length;
  213. while (--length > 0)
  214. {
  215. InsertString();
  216. strstart++;
  217. }
  218. strstart += 2;
  219. blockStart = strstart;
  220. }
  221. /// <summary>
  222. /// Reset internal state
  223. /// </summary>
  224. public void Reset()
  225. {
  226. huffman.Reset();
  227. adler.Reset();
  228. blockStart = strstart = 1;
  229. lookahead = 0;
  230. totalIn = 0;
  231. prevAvailable = false;
  232. matchLen = MIN_MATCH - 1;
  233. for (int i = 0; i < HASH_SIZE; i++) {
  234. head[i] = 0;
  235. }
  236. for (int i = 0; i < WSIZE; i++) {
  237. prev[i] = 0;
  238. }
  239. }
  240. /// <summary>
  241. /// Reset Adler checksum
  242. /// </summary>
  243. public void ResetAdler()
  244. {
  245. adler.Reset();
  246. }
  247. /// <summary>
  248. /// Get current value of Adler checksum
  249. /// </summary>
  250. public int Adler {
  251. get {
  252. return unchecked((int)adler.Value);
  253. }
  254. }
  255. /// <summary>
  256. /// Total data processed
  257. /// </summary>
  258. public long TotalIn {
  259. get {
  260. return totalIn;
  261. }
  262. }
  263. /// <summary>
  264. /// Get/set the <see cref="DeflateStrategy">deflate strategy</see>
  265. /// </summary>
  266. public DeflateStrategy Strategy {
  267. get {
  268. return strategy;
  269. }
  270. set {
  271. strategy = value;
  272. }
  273. }
  274. /// <summary>
  275. /// Set the deflate level (0-9)
  276. /// </summary>
  277. /// <param name="level">The value to set the level to.</param>
  278. public void SetLevel(int level)
  279. {
  280. if ( (level < 0) || (level > 9) )
  281. {
  282. throw new ArgumentOutOfRangeException("level");
  283. }
  284. goodLength = DeflaterConstants.GOOD_LENGTH[level];
  285. max_lazy = DeflaterConstants.MAX_LAZY[level];
  286. niceLength = DeflaterConstants.NICE_LENGTH[level];
  287. max_chain = DeflaterConstants.MAX_CHAIN[level];
  288. if (DeflaterConstants.COMPR_FUNC[level] != compressionFunction) {
  289. #if DebugDeflation
  290. if (DeflaterConstants.DEBUGGING) {
  291. Console.WriteLine("Change from " + compressionFunction + " to "
  292. + DeflaterConstants.COMPR_FUNC[level]);
  293. }
  294. #endif
  295. switch (compressionFunction) {
  296. case DEFLATE_STORED:
  297. if (strstart > blockStart) {
  298. huffman.FlushStoredBlock(window, blockStart,
  299. strstart - blockStart, false);
  300. blockStart = strstart;
  301. }
  302. UpdateHash();
  303. break;
  304. case DEFLATE_FAST:
  305. if (strstart > blockStart) {
  306. huffman.FlushBlock(window, blockStart, strstart - blockStart,
  307. false);
  308. blockStart = strstart;
  309. }
  310. break;
  311. case DEFLATE_SLOW:
  312. if (prevAvailable) {
  313. huffman.TallyLit(window[strstart-1] & 0xff);
  314. }
  315. if (strstart > blockStart) {
  316. huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
  317. blockStart = strstart;
  318. }
  319. prevAvailable = false;
  320. matchLen = MIN_MATCH - 1;
  321. break;
  322. }
  323. compressionFunction = COMPR_FUNC[level];
  324. }
  325. }
  326. /// <summary>
  327. /// Fill the window
  328. /// </summary>
  329. public void FillWindow()
  330. {
  331. /* If the window is almost full and there is insufficient lookahead,
  332. * move the upper half to the lower one to make room in the upper half.
  333. */
  334. if (strstart >= WSIZE + MAX_DIST)
  335. {
  336. SlideWindow();
  337. }
  338. /* If there is not enough lookahead, but still some input left,
  339. * read in the input
  340. */
  341. while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd)
  342. {
  343. int more = 2 * WSIZE - lookahead - strstart;
  344. if (more > inputEnd - inputOff)
  345. {
  346. more = inputEnd - inputOff;
  347. }
  348. System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
  349. adler.Update(inputBuf, inputOff, more);
  350. inputOff += more;
  351. totalIn += more;
  352. lookahead += more;
  353. }
  354. if (lookahead >= MIN_MATCH)
  355. {
  356. UpdateHash();
  357. }
  358. }
  359. void UpdateHash()
  360. {
  361. /*
  362. if (DEBUGGING) {
  363. Console.WriteLine("updateHash: "+strstart);
  364. }
  365. */
  366. ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
  367. }
  368. /// <summary>
  369. /// Inserts the current string in the head hash and returns the previous
  370. /// value for this hash.
  371. /// </summary>
  372. /// <returns>The previous hash value</returns>
  373. int InsertString()
  374. {
  375. short match;
  376. int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)]) & HASH_MASK;
  377. #if DebugDeflation
  378. if (DeflaterConstants.DEBUGGING)
  379. {
  380. if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^
  381. (window[strstart + 1] << HASH_SHIFT) ^
  382. (window[strstart + 2])) & HASH_MASK)) {
  383. throw new SharpZipBaseException("hash inconsistent: " + hash + "/"
  384. +window[strstart] + ","
  385. +window[strstart + 1] + ","
  386. +window[strstart + 2] + "," + HASH_SHIFT);
  387. }
  388. }
  389. #endif
  390. prev[strstart & WMASK] = match = head[hash];
  391. head[hash] = unchecked((short)strstart);
  392. ins_h = hash;
  393. return match & 0xffff;
  394. }
  395. void SlideWindow()
  396. {
  397. Array.Copy(window, WSIZE, window, 0, WSIZE);
  398. matchStart -= WSIZE;
  399. strstart -= WSIZE;
  400. blockStart -= WSIZE;
  401. // Slide the hash table (could be avoided with 32 bit values
  402. // at the expense of memory usage).
  403. for (int i = 0; i < HASH_SIZE; ++i) {
  404. int m = head[i] & 0xffff;
  405. head[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
  406. }
  407. // Slide the prev table.
  408. for (int i = 0; i < WSIZE; i++) {
  409. int m = prev[i] & 0xffff;
  410. prev[i] = (short)(m >= WSIZE ? (m - WSIZE) : 0);
  411. }
  412. }
  413. /// <summary>
  414. /// Find the best (longest) string in the window matching the
  415. /// string starting at strstart.
  416. ///
  417. /// Preconditions:
  418. /// <code>
  419. /// strstart + MAX_MATCH &lt;= window.length.</code>
  420. /// </summary>
  421. /// <param name="curMatch"></param>
  422. /// <returns>True if a match greater than the minimum length is found</returns>
  423. bool FindLongestMatch(int curMatch)
  424. {
  425. int chainLength = this.max_chain;
  426. int niceLength = this.niceLength;
  427. short[] prev = this.prev;
  428. int scan = this.strstart;
  429. int match;
  430. int best_end = this.strstart + matchLen;
  431. int best_len = Math.Max(matchLen, MIN_MATCH - 1);
  432. int limit = Math.Max(strstart - MAX_DIST, 0);
  433. int strend = strstart + MAX_MATCH - 1;
  434. byte scan_end1 = window[best_end - 1];
  435. byte scan_end = window[best_end];
  436. // Do not waste too much time if we already have a good match:
  437. if (best_len >= this.goodLength) {
  438. chainLength >>= 2;
  439. }
  440. /* Do not look for matches beyond the end of the input. This is necessary
  441. * to make deflate deterministic.
  442. */
  443. if (niceLength > lookahead) {
  444. niceLength = lookahead;
  445. }
  446. #if DebugDeflation
  447. if (DeflaterConstants.DEBUGGING && (strstart > 2 * WSIZE - MIN_LOOKAHEAD))
  448. {
  449. throw new InvalidOperationException("need lookahead");
  450. }
  451. #endif
  452. do {
  453. #if DebugDeflation
  454. if (DeflaterConstants.DEBUGGING && (curMatch >= strstart) )
  455. {
  456. throw new InvalidOperationException("no future");
  457. }
  458. #endif
  459. if (window[curMatch + best_len] != scan_end ||
  460. window[curMatch + best_len - 1] != scan_end1 ||
  461. window[curMatch] != window[scan] ||
  462. window[curMatch + 1] != window[scan + 1]) {
  463. continue;
  464. }
  465. match = curMatch + 2;
  466. scan += 2;
  467. /* We check for insufficient lookahead only every 8th comparison;
  468. * the 256th check will be made at strstart + 258.
  469. */
  470. while (
  471. window[++scan] == window[++match] &&
  472. window[++scan] == window[++match] &&
  473. window[++scan] == window[++match] &&
  474. window[++scan] == window[++match] &&
  475. window[++scan] == window[++match] &&
  476. window[++scan] == window[++match] &&
  477. window[++scan] == window[++match] &&
  478. window[++scan] == window[++match] &&
  479. (scan < strend))
  480. {
  481. // Do nothing
  482. }
  483. if (scan > best_end) {
  484. #if DebugDeflation
  485. if (DeflaterConstants.DEBUGGING && (ins_h == 0) )
  486. Console.Error.WriteLine("Found match: " + curMatch + "-" + (scan - strstart));
  487. #endif
  488. matchStart = curMatch;
  489. best_end = scan;
  490. best_len = scan - strstart;
  491. if (best_len >= niceLength) {
  492. break;
  493. }
  494. scan_end1 = window[best_end - 1];
  495. scan_end = window[best_end];
  496. }
  497. scan = strstart;
  498. } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit && --chainLength != 0);
  499. matchLen = Math.Min(best_len, lookahead);
  500. return matchLen >= MIN_MATCH;
  501. }
  502. bool DeflateStored(bool flush, bool finish)
  503. {
  504. if (!flush && (lookahead == 0)) {
  505. return false;
  506. }
  507. strstart += lookahead;
  508. lookahead = 0;
  509. int storedLength = strstart - blockStart;
  510. if ((storedLength >= DeflaterConstants.MAX_BLOCK_SIZE) || // Block is full
  511. (blockStart < WSIZE && storedLength >= MAX_DIST) || // Block may move out of window
  512. flush) {
  513. bool lastBlock = finish;
  514. if (storedLength > DeflaterConstants.MAX_BLOCK_SIZE) {
  515. storedLength = DeflaterConstants.MAX_BLOCK_SIZE;
  516. lastBlock = false;
  517. }
  518. #if DebugDeflation
  519. if (DeflaterConstants.DEBUGGING)
  520. {
  521. Console.WriteLine("storedBlock[" + storedLength + "," + lastBlock + "]");
  522. }
  523. #endif
  524. huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock);
  525. blockStart += storedLength;
  526. return !lastBlock;
  527. }
  528. return true;
  529. }
  530. bool DeflateFast(bool flush, bool finish)
  531. {
  532. if (lookahead < MIN_LOOKAHEAD && !flush) {
  533. return false;
  534. }
  535. while (lookahead >= MIN_LOOKAHEAD || flush) {
  536. if (lookahead == 0) {
  537. // We are flushing everything
  538. huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
  539. blockStart = strstart;
  540. return false;
  541. }
  542. if (strstart > 2 * WSIZE - MIN_LOOKAHEAD) {
  543. /* slide window, as FindLongestMatch needs this.
  544. * This should only happen when flushing and the window
  545. * is almost full.
  546. */
  547. SlideWindow();
  548. }
  549. int hashHead;
  550. if (lookahead >= MIN_MATCH &&
  551. (hashHead = InsertString()) != 0 &&
  552. strategy != DeflateStrategy.HuffmanOnly &&
  553. strstart - hashHead <= MAX_DIST &&
  554. FindLongestMatch(hashHead)) {
  555. // longestMatch sets matchStart and matchLen
  556. #if DebugDeflation
  557. if (DeflaterConstants.DEBUGGING)
  558. {
  559. for (int i = 0 ; i < matchLen; i++) {
  560. if (window[strstart + i] != window[matchStart + i]) {
  561. throw new SharpZipBaseException("Match failure");
  562. }
  563. }
  564. }
  565. #endif
  566. bool full = huffman.TallyDist(strstart - matchStart, matchLen);
  567. lookahead -= matchLen;
  568. if (matchLen <= max_lazy && lookahead >= MIN_MATCH) {
  569. while (--matchLen > 0) {
  570. ++strstart;
  571. InsertString();
  572. }
  573. ++strstart;
  574. } else {
  575. strstart += matchLen;
  576. if (lookahead >= MIN_MATCH - 1) {
  577. UpdateHash();
  578. }
  579. }
  580. matchLen = MIN_MATCH - 1;
  581. if (!full) {
  582. continue;
  583. }
  584. } else {
  585. // No match found
  586. huffman.TallyLit(window[strstart] & 0xff);
  587. ++strstart;
  588. --lookahead;
  589. }
  590. if (huffman.IsFull()) {
  591. bool lastBlock = finish && (lookahead == 0);
  592. huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
  593. blockStart = strstart;
  594. return !lastBlock;
  595. }
  596. }
  597. return true;
  598. }
  599. bool DeflateSlow(bool flush, bool finish)
  600. {
  601. if (lookahead < MIN_LOOKAHEAD && !flush) {
  602. return false;
  603. }
  604. while (lookahead >= MIN_LOOKAHEAD || flush) {
  605. if (lookahead == 0) {
  606. if (prevAvailable) {
  607. huffman.TallyLit(window[strstart-1] & 0xff);
  608. }
  609. prevAvailable = false;
  610. // We are flushing everything
  611. #if DebugDeflation
  612. if (DeflaterConstants.DEBUGGING && !flush)
  613. {
  614. throw new SharpZipBaseException("Not flushing, but no lookahead");
  615. }
  616. #endif
  617. huffman.FlushBlock(window, blockStart, strstart - blockStart,
  618. finish);
  619. blockStart = strstart;
  620. return false;
  621. }
  622. if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD) {
  623. /* slide window, as FindLongestMatch needs this.
  624. * This should only happen when flushing and the window
  625. * is almost full.
  626. */
  627. SlideWindow();
  628. }
  629. int prevMatch = matchStart;
  630. int prevLen = matchLen;
  631. if (lookahead >= MIN_MATCH) {
  632. int hashHead = InsertString();
  633. if (strategy != DeflateStrategy.HuffmanOnly &&
  634. hashHead != 0 &&
  635. strstart - hashHead <= MAX_DIST &&
  636. FindLongestMatch(hashHead)) {
  637. // longestMatch sets matchStart and matchLen
  638. // Discard match if too small and too far away
  639. if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == MIN_MATCH && strstart - matchStart > TooFar))) {
  640. matchLen = MIN_MATCH - 1;
  641. }
  642. }
  643. }
  644. // previous match was better
  645. if ((prevLen >= MIN_MATCH) && (matchLen <= prevLen) ) {
  646. #if DebugDeflation
  647. if (DeflaterConstants.DEBUGGING)
  648. {
  649. for (int i = 0 ; i < matchLen; i++) {
  650. if (window[strstart-1+i] != window[prevMatch + i])
  651. throw new SharpZipBaseException();
  652. }
  653. }
  654. #endif
  655. huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
  656. prevLen -= 2;
  657. do {
  658. strstart++;
  659. lookahead--;
  660. if (lookahead >= MIN_MATCH) {
  661. InsertString();
  662. }
  663. } while (--prevLen > 0);
  664. strstart ++;
  665. lookahead--;
  666. prevAvailable = false;
  667. matchLen = MIN_MATCH - 1;
  668. } else {
  669. if (prevAvailable) {
  670. huffman.TallyLit(window[strstart-1] & 0xff);
  671. }
  672. prevAvailable = true;
  673. strstart++;
  674. lookahead--;
  675. }
  676. if (huffman.IsFull()) {
  677. int len = strstart - blockStart;
  678. if (prevAvailable) {
  679. len--;
  680. }
  681. bool lastBlock = (finish && (lookahead == 0) && !prevAvailable);
  682. huffman.FlushBlock(window, blockStart, len, lastBlock);
  683. blockStart += len;
  684. return !lastBlock;
  685. }
  686. }
  687. return true;
  688. }
  689. #region Instance Fields
  690. // Hash index of string to be inserted
  691. int ins_h;
  692. /// <summary>
  693. /// Hashtable, hashing three characters to an index for window, so
  694. /// that window[index]..window[index+2] have this hash code.
  695. /// Note that the array should really be unsigned short, so you need
  696. /// to and the values with 0xffff.
  697. /// </summary>
  698. short[] head;
  699. /// <summary>
  700. /// <code>prev[index &amp; WMASK]</code> points to the previous index that has the
  701. /// same hash code as the string starting at index. This way
  702. /// entries with the same hash code are in a linked list.
  703. /// Note that the array should really be unsigned short, so you need
  704. /// to and the values with 0xffff.
  705. /// </summary>
  706. short[] prev;
  707. int matchStart;
  708. // Length of best match
  709. int matchLen;
  710. // Set if previous match exists
  711. bool prevAvailable;
  712. int blockStart;
  713. /// <summary>
  714. /// Points to the current character in the window.
  715. /// </summary>
  716. int strstart;
  717. /// <summary>
  718. /// lookahead is the number of characters starting at strstart in
  719. /// window that are valid.
  720. /// So window[strstart] until window[strstart+lookahead-1] are valid
  721. /// characters.
  722. /// </summary>
  723. int lookahead;
  724. /// <summary>
  725. /// This array contains the part of the uncompressed stream that
  726. /// is of relevance. The current character is indexed by strstart.
  727. /// </summary>
  728. byte[] window;
  729. DeflateStrategy strategy;
  730. int max_chain, max_lazy, niceLength, goodLength;
  731. /// <summary>
  732. /// The current compression function.
  733. /// </summary>
  734. int compressionFunction;
  735. /// <summary>
  736. /// The input data for compression.
  737. /// </summary>
  738. byte[] inputBuf;
  739. /// <summary>
  740. /// The total bytes of input read.
  741. /// </summary>
  742. long totalIn;
  743. /// <summary>
  744. /// The offset into inputBuf, where input data starts.
  745. /// </summary>
  746. int inputOff;
  747. /// <summary>
  748. /// The end offset of the input data.
  749. /// </summary>
  750. int inputEnd;
  751. DeflaterPending pending;
  752. DeflaterHuffman huffman;
  753. /// <summary>
  754. /// The adler checksum
  755. /// </summary>
  756. Adler32 adler;
  757. #endregion
  758. }
  759. }