Summary

Class:ICSharpCode.SharpZipLib.Zip.Compression.DeflaterEngine
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterEngine.cs
Covered lines:238
Uncovered lines:37
Coverable lines:275
Total lines:812
Line coverage:86.5%
Branch coverage:84.4%

Metrics

MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
Deflate(...)691.6785.71
SetInput(...)766.6753.85
NeedsInput()1100100
SetDictionary(...)400
Reset()3100100
ResetAdler()100
SetLevel(...)1165.3863.16
FillWindow()6100100
UpdateHash()1100100
InsertString()1100100
SlideWindow()7100100
FindLongestMatch(...)2010094.87
DeflateStored(...)8100100
DeflateFast(...)1893.9487.88
DeflateSlow(...)2510093.33

File(s)

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\Compression\DeflaterEngine.cs

#LineLine coverage
 1using System;
 2using ICSharpCode.SharpZipLib.Checksum;
 3
 4namespace ICSharpCode.SharpZipLib.Zip.Compression
 5{
 6  /// <summary>
 7  /// Strategies for deflater
 8  /// </summary>
 9  public enum DeflateStrategy
 10  {
 11    /// <summary>
 12    /// The default strategy
 13    /// </summary>
 14    Default = 0,
 15
 16    /// <summary>
 17    /// This strategy will only allow longer string repetitions.  It is
 18    /// useful for random data with a small character set.
 19    /// </summary>
 20    Filtered = 1,
 21
 22
 23    /// <summary>
 24    /// This strategy will not look for string repetitions at all.  It
 25    /// only encodes with Huffman trees (which means, that more common
 26    /// characters get a smaller encoding.
 27    /// </summary>
 28    HuffmanOnly = 2
 29  }
 30
 31  // DEFLATE ALGORITHM:
 32  //
 33  // The uncompressed stream is inserted into the window array.  When
 34  // the window array is full the first half is thrown away and the
 35  // second half is copied to the beginning.
 36  //
 37  // The head array is a hash table.  Three characters build a hash value
 38  // and they the value points to the corresponding index in window of
 39  // the last string with this hash.  The prev array implements a
 40  // linked list of matches with the same hash: prev[index & WMASK] points
 41  // to the previous index with the same hash.
 42  //
 43
 44
 45  /// <summary>
 46  /// Low level compression engine for deflate algorithm which uses a 32K sliding window
 47  /// with secondary compression from Huffman/Shannon-Fano codes.
 48  /// </summary>
 49  public class DeflaterEngine
 50  {
 51    #region Constants
 52    const int TooFar = 4096;
 53    #endregion
 54
 55    #region Constructors
 56    /// <summary>
 57    /// Construct instance with pending buffer
 58    /// </summary>
 59    /// <param name="pending">
 60    /// Pending buffer to use
 61    /// </param>>
 27362    public DeflaterEngine(DeflaterPending pending)
 63    {
 27364      this.pending = pending;
 27365      huffman = new DeflaterHuffman(pending);
 27366      adler = new Adler32();
 67
 27368      window = new byte[2 * DeflaterConstants.WSIZE];
 27369      head = new short[DeflaterConstants.HASH_SIZE];
 27370      prev = new short[DeflaterConstants.WSIZE];
 71
 72      // We start at index 1, to avoid an implementation deficiency, that
 73      // we cannot build a repeat pattern at index 0.
 27374      blockStart = strstart = 1;
 27375    }
 76
 77    #endregion
 78
 79    /// <summary>
 80    /// Deflate drives actual compression of data
 81    /// </summary>
 82    /// <param name="flush">True to flush input buffers</param>
 83    /// <param name="finish">Finish deflation with the current input.</param>
 84    /// <returns>Returns true if progress has been made.</returns>
 85    public bool Deflate(bool flush, bool finish)
 86    {
 87      bool progress;
 88      do {
 914089        FillWindow();
 914090        bool canFlush = flush && (inputOff == inputEnd);
 91
 92#if DebugDeflation
 93        if (DeflaterConstants.DEBUGGING) {
 94          Console.WriteLine("window: [" + blockStart + "," + strstart + ","
 95                + lookahead + "], " + compressionFunction + "," + canFlush);
 96        }
 97#endif
 914098         switch (compressionFunction) {
 99          case DeflaterConstants.DEFLATE_STORED:
 1373100            progress = DeflateStored(canFlush, finish);
 1373101            break;
 102          case DeflaterConstants.DEFLATE_FAST:
 3236103            progress = DeflateFast(canFlush, finish);
 3236104            break;
 105          case DeflaterConstants.DEFLATE_SLOW:
 4531106            progress = DeflateSlow(canFlush, finish);
 4531107            break;
 108          default:
 0109            throw new InvalidOperationException("unknown compressionFunction");
 110        }
 9140111       } while (pending.IsFlushed && progress); // repeat while we have no pending output and progress was made
 4878112      return progress;
 113    }
 114
 115    /// <summary>
 116    /// Sets input data to be deflated.  Should only be called when <code>NeedsInput()</code>
 117    /// returns true
 118    /// </summary>
 119    /// <param name="buffer">The buffer containing input data.</param>
 120    /// <param name="offset">The offset of the first byte of data.</param>
 121    /// <param name="count">The number of bytes of data to use as input.</param>
 122    public void SetInput(byte[] buffer, int offset, int count)
 123    {
 4479124       if (buffer == null) {
 0125        throw new ArgumentNullException(nameof(buffer));
 126      }
 127
 4479128       if (offset < 0) {
 0129        throw new ArgumentOutOfRangeException(nameof(offset));
 130      }
 131
 4479132       if (count < 0) {
 0133        throw new ArgumentOutOfRangeException(nameof(count));
 134      }
 135
 4479136       if (inputOff < inputEnd) {
 0137        throw new InvalidOperationException("Old input was not completely processed");
 138      }
 139
 4479140      int end = offset + count;
 141
 142      /* We want to throw an ArrayIndexOutOfBoundsException early.  The
 143      * check is very tricky: it also handles integer wrap around.
 144      */
 4479145       if ((offset > end) || (end > buffer.Length)) {
 0146        throw new ArgumentOutOfRangeException(nameof(count));
 147      }
 148
 4479149      inputBuf = buffer;
 4479150      inputOff = offset;
 4479151      inputEnd = end;
 4479152    }
 153
 154    /// <summary>
 155    /// Determines if more <see cref="SetInput">input</see> is needed.
 156    /// </summary>
 157    /// <returns>Return true if input is needed via <see cref="SetInput">SetInput</see></returns>
 158    public bool NeedsInput()
 159    {
 16258160      return (inputEnd == inputOff);
 161    }
 162
 163    /// <summary>
 164    /// Set compression dictionary
 165    /// </summary>
 166    /// <param name="buffer">The buffer containing the dictionary data</param>
 167    /// <param name="offset">The offset in the buffer for the first byte of data</param>
 168    /// <param name="length">The length of the dictionary data.</param>
 169    public void SetDictionary(byte[] buffer, int offset, int length)
 170    {
 171#if DebugDeflation
 172      if (DeflaterConstants.DEBUGGING && (strstart != 1) )
 173      {
 174        throw new InvalidOperationException("strstart not 1");
 175      }
 176#endif
 0177      adler.Update(buffer, offset, length);
 0178       if (length < DeflaterConstants.MIN_MATCH) {
 0179        return;
 180      }
 181
 0182       if (length > DeflaterConstants.MAX_DIST) {
 0183        offset += length - DeflaterConstants.MAX_DIST;
 0184        length = DeflaterConstants.MAX_DIST;
 185      }
 186
 0187      System.Array.Copy(buffer, offset, window, strstart, length);
 188
 0189      UpdateHash();
 0190      --length;
 0191       while (--length > 0) {
 0192        InsertString();
 0193        strstart++;
 194      }
 0195      strstart += 2;
 0196      blockStart = strstart;
 0197    }
 198
 199    /// <summary>
 200    /// Reset internal state
 201    /// </summary>
 202    public void Reset()
 203    {
 392204      huffman.Reset();
 392205      adler.Reset();
 392206      blockStart = strstart = 1;
 392207      lookahead = 0;
 392208      totalIn = 0;
 392209      prevAvailable = false;
 392210      matchLen = DeflaterConstants.MIN_MATCH - 1;
 211
 25690896212       for (int i = 0; i < DeflaterConstants.HASH_SIZE; i++) {
 12845056213        head[i] = 0;
 214      }
 215
 25690896216       for (int i = 0; i < DeflaterConstants.WSIZE; i++) {
 12845056217        prev[i] = 0;
 218      }
 392219    }
 220
 221    /// <summary>
 222    /// Reset Adler checksum
 223    /// </summary>
 224    public void ResetAdler()
 225    {
 0226      adler.Reset();
 0227    }
 228
 229    /// <summary>
 230    /// Get current value of Adler checksum
 231    /// </summary>
 232    public int Adler {
 233      get {
 14234        return unchecked((int)adler.Value);
 235      }
 236    }
 237
 238    /// <summary>
 239    /// Total data processed
 240    /// </summary>
 241    public long TotalIn {
 242      get {
 9243        return totalIn;
 244      }
 245    }
 246
 247    /// <summary>
 248    /// Get/set the <see cref="DeflateStrategy">deflate strategy</see>
 249    /// </summary>
 250    public DeflateStrategy Strategy {
 251      get {
 0252        return strategy;
 253      }
 254      set {
 273255        strategy = value;
 273256      }
 257    }
 258
 259    /// <summary>
 260    /// Set the deflate level (0-9)
 261    /// </summary>
 262    /// <param name="level">The value to set the level to.</param>
 263    public void SetLevel(int level)
 264    {
 327265       if ((level < 0) || (level > 9)) {
 0266        throw new ArgumentOutOfRangeException(nameof(level));
 267      }
 268
 327269      goodLength = DeflaterConstants.GOOD_LENGTH[level];
 327270      max_lazy = DeflaterConstants.MAX_LAZY[level];
 327271      niceLength = DeflaterConstants.NICE_LENGTH[level];
 327272      max_chain = DeflaterConstants.MAX_CHAIN[level];
 273
 327274       if (DeflaterConstants.COMPR_FUNC[level] != compressionFunction) {
 275
 276#if DebugDeflation
 277        if (DeflaterConstants.DEBUGGING) {
 278           Console.WriteLine("Change from " + compressionFunction + " to "
 279                      + DeflaterConstants.COMPR_FUNC[level]);
 280        }
 281#endif
 309282         switch (compressionFunction) {
 283          case DeflaterConstants.DEFLATE_STORED:
 272284             if (strstart > blockStart) {
 0285              huffman.FlushStoredBlock(window, blockStart,
 0286                strstart - blockStart, false);
 0287              blockStart = strstart;
 288            }
 272289            UpdateHash();
 272290            break;
 291
 292          case DeflaterConstants.DEFLATE_FAST:
 6293             if (strstart > blockStart) {
 0294              huffman.FlushBlock(window, blockStart, strstart - blockStart,
 0295                false);
 0296              blockStart = strstart;
 297            }
 0298            break;
 299
 300          case DeflaterConstants.DEFLATE_SLOW:
 31301             if (prevAvailable) {
 0302              huffman.TallyLit(window[strstart - 1] & 0xff);
 303            }
 31304             if (strstart > blockStart) {
 0305              huffman.FlushBlock(window, blockStart, strstart - blockStart, false);
 0306              blockStart = strstart;
 307            }
 31308            prevAvailable = false;
 31309            matchLen = DeflaterConstants.MIN_MATCH - 1;
 310            break;
 311        }
 309312        compressionFunction = DeflaterConstants.COMPR_FUNC[level];
 313      }
 327314    }
 315
 316    /// <summary>
 317    /// Fill the window
 318    /// </summary>
 319    public void FillWindow()
 320    {
 321      /* If the window is almost full and there is insufficient lookahead,
 322       * move the upper half to the lower one to make room in the upper half.
 323       */
 9140324       if (strstart >= DeflaterConstants.WSIZE + DeflaterConstants.MAX_DIST) {
 20325        SlideWindow();
 326      }
 327
 328      /* If there is not enough lookahead, but still some input left,
 329       * read in the input
 330       */
 13659331       while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd) {
 4519332        int more = 2 * DeflaterConstants.WSIZE - lookahead - strstart;
 333
 4519334         if (more > inputEnd - inputOff) {
 4479335          more = inputEnd - inputOff;
 336        }
 337
 4519338        System.Array.Copy(inputBuf, inputOff, window, strstart + lookahead, more);
 4519339        adler.Update(inputBuf, inputOff, more);
 340
 4519341        inputOff += more;
 4519342        totalIn += more;
 4519343        lookahead += more;
 344      }
 345
 9140346       if (lookahead >= DeflaterConstants.MIN_MATCH) {
 8381347        UpdateHash();
 348      }
 9140349    }
 350
 351    void UpdateHash()
 352    {
 353      /*
 354            if (DEBUGGING) {
 355              Console.WriteLine("updateHash: "+strstart);
 356            }
 357      */
 8653358      ins_h = (window[strstart] << DeflaterConstants.HASH_SHIFT) ^ window[strstart + 1];
 8653359    }
 360
 361    /// <summary>
 362    /// Inserts the current string in the head hash and returns the previous
 363    /// value for this hash.
 364    /// </summary>
 365    /// <returns>The previous hash value</returns>
 366    int InsertString()
 367    {
 368      short match;
 3625693369      int hash = ((ins_h << DeflaterConstants.HASH_SHIFT) ^ window[strstart + (DeflaterConstants.MIN_MATCH - 1)]) & Defl
 370
 371#if DebugDeflation
 372      if (DeflaterConstants.DEBUGGING)
 373      {
 374        if (hash != (((window[strstart] << (2*HASH_SHIFT)) ^
 375                  (window[strstart + 1] << HASH_SHIFT) ^
 376                  (window[strstart + 2])) & HASH_MASK)) {
 377            throw new SharpZipBaseException("hash inconsistent: " + hash + "/"
 378                        +window[strstart] + ","
 379                        +window[strstart + 1] + ","
 380                        +window[strstart + 2] + "," + HASH_SHIFT);
 381          }
 382      }
 383#endif
 3625693384      prev[strstart & DeflaterConstants.WMASK] = match = head[hash];
 3625693385      head[hash] = unchecked((short)strstart);
 3625693386      ins_h = hash;
 3625693387      return match & 0xffff;
 388    }
 389
 390    void SlideWindow()
 391    {
 40392      Array.Copy(window, DeflaterConstants.WSIZE, window, 0, DeflaterConstants.WSIZE);
 40393      matchStart -= DeflaterConstants.WSIZE;
 40394      strstart -= DeflaterConstants.WSIZE;
 40395      blockStart -= DeflaterConstants.WSIZE;
 396
 397      // Slide the hash table (could be avoided with 32 bit values
 398      // at the expense of memory usage).
 2621520399       for (int i = 0; i < DeflaterConstants.HASH_SIZE; ++i) {
 1310720400        int m = head[i] & 0xffff;
 1310720401         head[i] = (short)(m >= DeflaterConstants.WSIZE ? (m - DeflaterConstants.WSIZE) : 0);
 402      }
 403
 404      // Slide the prev table.
 2621520405       for (int i = 0; i < DeflaterConstants.WSIZE; i++) {
 1310720406        int m = prev[i] & 0xffff;
 1310720407         prev[i] = (short)(m >= DeflaterConstants.WSIZE ? (m - DeflaterConstants.WSIZE) : 0);
 408      }
 40409    }
 410
 411    /// <summary>
 412    /// Find the best (longest) string in the window matching the
 413    /// string starting at strstart.
 414    ///
 415    /// Preconditions:
 416    /// <code>
 417    /// strstart + DeflaterConstants.MAX_MATCH &lt;= window.length.</code>
 418    /// </summary>
 419    /// <param name="curMatch"></param>
 420    /// <returns>True if a match greater than the minimum length is found</returns>
 421    bool FindLongestMatch(int curMatch)
 422    {
 1801927423      int chainLength = this.max_chain;
 1801927424      int niceLength = this.niceLength;
 1801927425      short[] prev = this.prev;
 1801927426      int scan = this.strstart;
 427      int match;
 1801927428      int best_end = this.strstart + matchLen;
 1801927429      int best_len = Math.Max(matchLen, DeflaterConstants.MIN_MATCH - 1);
 430
 1801927431      int limit = Math.Max(strstart - DeflaterConstants.MAX_DIST, 0);
 432
 1801927433      int strend = strstart + DeflaterConstants.MAX_MATCH - 1;
 1801927434      byte scan_end1 = window[best_end - 1];
 1801927435      byte scan_end = window[best_end];
 436
 437      // Do not waste too much time if we already have a good match:
 1801927438       if (best_len >= this.goodLength) {
 66439        chainLength >>= 2;
 440      }
 441
 442      /* Do not look for matches beyond the end of the input. This is necessary
 443      * to make deflate deterministic.
 444      */
 1801927445       if (niceLength > lookahead) {
 3257446        niceLength = lookahead;
 447      }
 448
 449#if DebugDeflation
 450
 451      if (DeflaterConstants.DEBUGGING && (strstart > 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD))
 452      {
 453        throw new InvalidOperationException("need lookahead");
 454      }
 455#endif
 456
 457      do {
 458
 459#if DebugDeflation
 460
 461        if (DeflaterConstants.DEBUGGING && (curMatch >= strstart) )
 462        {
 463          throw new InvalidOperationException("no future");
 464        }
 465#endif
 2700341466         if (window[curMatch + best_len] != scan_end ||
 2700341467          window[curMatch + best_len - 1] != scan_end1 ||
 2700341468          window[curMatch] != window[scan] ||
 2700341469          window[curMatch + 1] != window[scan + 1]) {
 470          continue;
 471        }
 472
 5274473        match = curMatch + 2;
 5274474        scan += 2;
 475
 476        /* We check for insufficient lookahead only every 8th comparison;
 477        * the 256th check will be made at strstart + 258.
 478        */
 9174479         while (
 9174480          window[++scan] == window[++match] &&
 9174481          window[++scan] == window[++match] &&
 9174482          window[++scan] == window[++match] &&
 9174483          window[++scan] == window[++match] &&
 9174484          window[++scan] == window[++match] &&
 9174485          window[++scan] == window[++match] &&
 9174486          window[++scan] == window[++match] &&
 9174487          window[++scan] == window[++match] &&
 9174488          (scan < strend)) {
 489          // Do nothing
 490        }
 491
 5274492         if (scan > best_end) {
 493#if DebugDeflation
 494          if (DeflaterConstants.DEBUGGING && (ins_h == 0) )
 495            Console.Error.WriteLine("Found match: " + curMatch + "-" + (scan - strstart));
 496#endif
 5212497          matchStart = curMatch;
 5212498          best_end = scan;
 5212499          best_len = scan - strstart;
 500
 5212501           if (best_len >= niceLength) {
 502            break;
 503          }
 504
 5136505          scan_end1 = window[best_end - 1];
 5136506          scan_end = window[best_end];
 507        }
 5198508        scan = strstart;
 2700265509       } while ((curMatch = (prev[curMatch & DeflaterConstants.WMASK] & 0xffff)) > limit && --chainLength != 0);
 510
 1801927511      matchLen = Math.Min(best_len, lookahead);
 1801927512      return matchLen >= DeflaterConstants.MIN_MATCH;
 513    }
 514
 515    bool DeflateStored(bool flush, bool finish)
 516    {
 1373517       if (!flush && (lookahead == 0)) {
 676518        return false;
 519      }
 520
 697521      strstart += lookahead;
 697522      lookahead = 0;
 523
 697524      int storedLength = strstart - blockStart;
 525
 697526       if ((storedLength >= DeflaterConstants.MAX_BLOCK_SIZE) || // Block is full
 697527        (blockStart < DeflaterConstants.WSIZE && storedLength >= DeflaterConstants.MAX_DIST) ||   // Block may move out 
 697528        flush) {
 21529        bool lastBlock = finish;
 21530         if (storedLength > DeflaterConstants.MAX_BLOCK_SIZE) {
 2531          storedLength = DeflaterConstants.MAX_BLOCK_SIZE;
 2532          lastBlock = false;
 533        }
 534
 535#if DebugDeflation
 536        if (DeflaterConstants.DEBUGGING)
 537        {
 538           Console.WriteLine("storedBlock[" + storedLength + "," + lastBlock + "]");
 539        }
 540#endif
 541
 21542        huffman.FlushStoredBlock(window, blockStart, storedLength, lastBlock);
 21543        blockStart += storedLength;
 21544        return !lastBlock;
 545      }
 676546      return true;
 547    }
 548
 549    bool DeflateFast(bool flush, bool finish)
 550    {
 3236551       if (lookahead < DeflaterConstants.MIN_LOOKAHEAD && !flush) {
 1526552        return false;
 553      }
 554
 1597843555       while (lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) {
 1596259556         if (lookahead == 0) {
 557          // We are flushing everything
 30558          huffman.FlushBlock(window, blockStart, strstart - blockStart, finish);
 30559          blockStart = strstart;
 30560          return false;
 561        }
 562
 1596229563         if (strstart > 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD) {
 564          /* slide window, as FindLongestMatch needs this.
 565           * This should only happen when flushing and the window
 566           * is almost full.
 567           */
 0568          SlideWindow();
 569        }
 570
 571        int hashHead;
 1596229572         if (lookahead >= DeflaterConstants.MIN_MATCH &&
 1596229573          (hashHead = InsertString()) != 0 &&
 1596229574          strategy != DeflateStrategy.HuffmanOnly &&
 1596229575          strstart - hashHead <= DeflaterConstants.MAX_DIST &&
 1596229576          FindLongestMatch(hashHead)) {
 577          // longestMatch sets matchStart and matchLen
 578#if DebugDeflation
 579          if (DeflaterConstants.DEBUGGING)
 580          {
 581            for (int i = 0 ; i < matchLen; i++) {
 582              if (window[strstart + i] != window[matchStart + i]) {
 583                throw new SharpZipBaseException("Match failure");
 584              }
 585            }
 586          }
 587#endif
 588
 2203589          bool full = huffman.TallyDist(strstart - matchStart, matchLen);
 590
 2203591          lookahead -= matchLen;
 2203592           if (matchLen <= max_lazy && lookahead >= DeflaterConstants.MIN_MATCH) {
 6608593             while (--matchLen > 0) {
 4408594              ++strstart;
 4408595              InsertString();
 596            }
 2200597            ++strstart;
 2200598          } else {
 3599            strstart += matchLen;
 3600             if (lookahead >= DeflaterConstants.MIN_MATCH - 1) {
 0601              UpdateHash();
 602            }
 603          }
 2203604          matchLen = DeflaterConstants.MIN_MATCH - 1;
 2203605           if (!full) {
 2203606            continue;
 607          }
 608        } else {
 609          // No match found
 1594026610          huffman.TallyLit(window[strstart] & 0xff);
 1594026611          ++strstart;
 1594026612          --lookahead;
 613        }
 614
 1594026615         if (huffman.IsFull()) {
 96616          bool lastBlock = finish && (lookahead == 0);
 96617          huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock);
 96618          blockStart = strstart;
 96619          return !lastBlock;
 620        }
 621      }
 1584622      return true;
 623    }
 624
 625    bool DeflateSlow(bool flush, bool finish)
 626    {
 4531627       if (lookahead < DeflaterConstants.MIN_LOOKAHEAD && !flush) {
 2145628        return false;
 629      }
 630
 2011632631       while (lookahead >= DeflaterConstants.MIN_LOOKAHEAD || flush) {
 2009630632         if (lookahead == 0) {
 264633           if (prevAvailable) {
 205634            huffman.TallyLit(window[strstart - 1] & 0xff);
 635          }
 264636          prevAvailable = false;
 637
 638          // We are flushing everything
 639#if DebugDeflation
 640          if (DeflaterConstants.DEBUGGING && !flush)
 641          {
 642            throw new SharpZipBaseException("Not flushing, but no lookahead");
 643          }
 644#endif
 264645          huffman.FlushBlock(window, blockStart, strstart - blockStart,
 264646            finish);
 264647          blockStart = strstart;
 264648          return false;
 649        }
 650
 2009366651         if (strstart >= 2 * DeflaterConstants.WSIZE - DeflaterConstants.MIN_LOOKAHEAD) {
 652          /* slide window, as FindLongestMatch needs this.
 653           * This should only happen when flushing and the window
 654           * is almost full.
 655           */
 20656          SlideWindow();
 657        }
 658
 2009366659        int prevMatch = matchStart;
 2009366660        int prevLen = matchLen;
 2009366661         if (lookahead >= DeflaterConstants.MIN_MATCH) {
 662
 2008972663          int hashHead = InsertString();
 664
 2008972665           if (strategy != DeflateStrategy.HuffmanOnly &&
 2008972666            hashHead != 0 &&
 2008972667            strstart - hashHead <= DeflaterConstants.MAX_DIST &&
 2008972668            FindLongestMatch(hashHead)) {
 669
 670            // longestMatch sets matchStart and matchLen
 671
 672            // Discard match if too small and too far away
 3376673             if (matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == DeflaterConstants.MIN_MATCH && st
 2383674              matchLen = DeflaterConstants.MIN_MATCH - 1;
 675            }
 676          }
 677        }
 678
 679        // previous match was better
 2009366680         if ((prevLen >= DeflaterConstants.MIN_MATCH) && (matchLen <= prevLen)) {
 681#if DebugDeflation
 682          if (DeflaterConstants.DEBUGGING)
 683          {
 684             for (int i = 0 ; i < matchLen; i++) {
 685              if (window[strstart-1+i] != window[prevMatch + i])
 686               throw new SharpZipBaseException();
 687            }
 688          }
 689#endif
 625690          huffman.TallyDist(strstart - 1 - prevMatch, prevLen);
 625691          prevLen -= 2;
 692          do {
 16197693            strstart++;
 16197694            lookahead--;
 16197695             if (lookahead >= DeflaterConstants.MIN_MATCH) {
 16135696              InsertString();
 697            }
 16197698           } while (--prevLen > 0);
 699
 625700          strstart++;
 625701          lookahead--;
 625702          prevAvailable = false;
 625703          matchLen = DeflaterConstants.MIN_MATCH - 1;
 625704        } else {
 2008741705           if (prevAvailable) {
 2007911706            huffman.TallyLit(window[strstart - 1] & 0xff);
 707          }
 2008741708          prevAvailable = true;
 2008741709          strstart++;
 2008741710          lookahead--;
 711        }
 712
 2009366713         if (huffman.IsFull()) {
 120714          int len = strstart - blockStart;
 120715           if (prevAvailable) {
 120716            len--;
 717          }
 120718          bool lastBlock = (finish && (lookahead == 0) && !prevAvailable);
 120719          huffman.FlushBlock(window, blockStart, len, lastBlock);
 120720          blockStart += len;
 120721          return !lastBlock;
 722        }
 723      }
 2002724      return true;
 725    }
 726
 727    #region Instance Fields
 728
 729    // Hash index of string to be inserted
 730    int ins_h;
 731
 732    /// <summary>
 733    /// Hashtable, hashing three characters to an index for window, so
 734    /// that window[index]..window[index+2] have this hash code.
 735    /// Note that the array should really be unsigned short, so you need
 736    /// to and the values with 0xffff.
 737    /// </summary>
 738    short[] head;
 739
 740    /// <summary>
 741    /// <code>prev[index &amp; WMASK]</code> points to the previous index that has the
 742    /// same hash code as the string starting at index.  This way
 743    /// entries with the same hash code are in a linked list.
 744    /// Note that the array should really be unsigned short, so you need
 745    /// to and the values with 0xffff.
 746    /// </summary>
 747    short[] prev;
 748
 749    int matchStart;
 750    // Length of best match
 751    int matchLen;
 752    // Set if previous match exists
 753    bool prevAvailable;
 754    int blockStart;
 755
 756    /// <summary>
 757    /// Points to the current character in the window.
 758    /// </summary>
 759    int strstart;
 760
 761    /// <summary>
 762    /// lookahead is the number of characters starting at strstart in
 763    /// window that are valid.
 764    /// So window[strstart] until window[strstart+lookahead-1] are valid
 765    /// characters.
 766    /// </summary>
 767    int lookahead;
 768
 769    /// <summary>
 770    /// This array contains the part of the uncompressed stream that
 771    /// is of relevance.  The current character is indexed by strstart.
 772    /// </summary>
 773    byte[] window;
 774
 775    DeflateStrategy strategy;
 776    int max_chain, max_lazy, niceLength, goodLength;
 777
 778    /// <summary>
 779    /// The current compression function.
 780    /// </summary>
 781    int compressionFunction;
 782
 783    /// <summary>
 784    /// The input data for compression.
 785    /// </summary>
 786    byte[] inputBuf;
 787
 788    /// <summary>
 789    /// The total bytes of input read.
 790    /// </summary>
 791    long totalIn;
 792
 793    /// <summary>
 794    /// The offset into inputBuf, where input data starts.
 795    /// </summary>
 796    int inputOff;
 797
 798    /// <summary>
 799    /// The end offset of the input data.
 800    /// </summary>
 801    int inputEnd;
 802
 803    DeflaterPending pending;
 804    DeflaterHuffman huffman;
 805
 806    /// <summary>
 807    /// The adler checksum
 808    /// </summary>
 809    Adler32 adler;
 810    #endregion
 811  }
 812}