mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			699 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			699 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Java
		
	
	
	
/* DeflaterEngine.java --
 | 
						|
   Copyright (C) 2001, 2004, 2005  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
package java.util.zip;
 | 
						|
 | 
						|
class DeflaterEngine implements DeflaterConstants
 | 
						|
{
 | 
						|
  private static final int TOO_FAR = 4096;
 | 
						|
 | 
						|
  private int ins_h;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Hashtable, hashing three characters to an index for window, so
 | 
						|
   * that window[index]..window[index+2] have this hash code.
 | 
						|
   * Note that the array should really be unsigned short, so you need
 | 
						|
   * to and the values with 0xffff.
 | 
						|
   */
 | 
						|
  private short[] head;
 | 
						|
 | 
						|
  /**
 | 
						|
   * prev[index & WMASK] points to the previous index that has the
 | 
						|
   * same hash code as the string starting at index.  This way
 | 
						|
   * entries with the same hash code are in a linked list.
 | 
						|
   * Note that the array should really be unsigned short, so you need
 | 
						|
   * to and the values with 0xffff.
 | 
						|
   */
 | 
						|
  private short[] prev;
 | 
						|
 | 
						|
  private int matchStart, matchLen;
 | 
						|
  private boolean prevAvailable;
 | 
						|
  private int blockStart;
 | 
						|
 | 
						|
  /**
 | 
						|
   * strstart points to the current character in window.
 | 
						|
   */
 | 
						|
  private int strstart;
 | 
						|
 | 
						|
  /**
 | 
						|
   * lookahead is the number of characters starting at strstart in
 | 
						|
   * window that are valid.
 | 
						|
   * So window[strstart] until window[strstart+lookahead-1] are valid
 | 
						|
   * characters.
 | 
						|
   */
 | 
						|
  private int lookahead;
 | 
						|
 | 
						|
  /**
 | 
						|
   * This array contains the part of the uncompressed stream that
 | 
						|
   * is of relevance.  The current character is indexed by strstart.
 | 
						|
   */
 | 
						|
  private byte[] window;
 | 
						|
 | 
						|
  private int strategy, max_chain, max_lazy, niceLength, goodLength;
 | 
						|
 | 
						|
  /** The current compression function. */
 | 
						|
  private int comprFunc;
 | 
						|
 | 
						|
  /** The input data for compression. */
 | 
						|
  private byte[] inputBuf;
 | 
						|
 | 
						|
  /** The total bytes of input read. */
 | 
						|
  private long totalIn;
 | 
						|
 | 
						|
  /** The offset into inputBuf, where input data starts. */
 | 
						|
  private int inputOff;
 | 
						|
 | 
						|
  /** The end offset of the input data. */
 | 
						|
  private int inputEnd;
 | 
						|
 | 
						|
  private DeflaterPending pending;
 | 
						|
  private DeflaterHuffman huffman;
 | 
						|
 | 
						|
  /** The adler checksum */
 | 
						|
  private Adler32 adler;
 | 
						|
 | 
						|
  /* DEFLATE ALGORITHM:
 | 
						|
   *
 | 
						|
   * The uncompressed stream is inserted into the window array.  When
 | 
						|
   * the window array is full the first half is thrown away and the
 | 
						|
   * second half is copied to the beginning.
 | 
						|
   *
 | 
						|
   * The head array is a hash table.  Three characters build a hash value
 | 
						|
   * and they the value points to the corresponding index in window of
 | 
						|
   * the last string with this hash.  The prev array implements a
 | 
						|
   * linked list of matches with the same hash: prev[index & WMASK] points
 | 
						|
   * to the previous index with the same hash.
 | 
						|
   *
 | 
						|
   *
 | 
						|
   */
 | 
						|
 | 
						|
 | 
						|
  DeflaterEngine(DeflaterPending pending) {
 | 
						|
    this.pending = pending;
 | 
						|
    huffman = new DeflaterHuffman(pending);
 | 
						|
    adler = new Adler32();
 | 
						|
 | 
						|
    window = new byte[2*WSIZE];
 | 
						|
    head   = new short[HASH_SIZE];
 | 
						|
    prev   = new short[WSIZE];
 | 
						|
 | 
						|
    /* We start at index 1, to avoid a implementation deficiency, that
 | 
						|
     * we cannot build a repeat pattern at index 0.
 | 
						|
     */
 | 
						|
    blockStart = strstart = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  public void reset()
 | 
						|
  {
 | 
						|
    huffman.reset();
 | 
						|
    adler.reset();
 | 
						|
    blockStart = strstart = 1;
 | 
						|
    lookahead = 0;
 | 
						|
    totalIn = 0;
 | 
						|
    prevAvailable = false;
 | 
						|
    matchLen = MIN_MATCH - 1;
 | 
						|
    for (int i = 0; i < HASH_SIZE; i++)
 | 
						|
      head[i] = 0;
 | 
						|
    for (int i = 0; i < WSIZE; i++)
 | 
						|
      prev[i] = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  public final void resetAdler()
 | 
						|
  {
 | 
						|
    adler.reset();
 | 
						|
  }
 | 
						|
 | 
						|
  public final int getAdler()
 | 
						|
  {
 | 
						|
    int chksum = (int) adler.getValue();
 | 
						|
    return chksum;
 | 
						|
  }
 | 
						|
 | 
						|
  public final long getTotalIn()
 | 
						|
  {
 | 
						|
    return totalIn;
 | 
						|
  }
 | 
						|
 | 
						|
  public final void setStrategy(int strat)
 | 
						|
  {
 | 
						|
    strategy = strat;
 | 
						|
  }
 | 
						|
 | 
						|
  public void setLevel(int lvl)
 | 
						|
  {
 | 
						|
    goodLength = DeflaterConstants.GOOD_LENGTH[lvl];
 | 
						|
    max_lazy    = DeflaterConstants.MAX_LAZY[lvl];
 | 
						|
    niceLength = DeflaterConstants.NICE_LENGTH[lvl];
 | 
						|
    max_chain   = DeflaterConstants.MAX_CHAIN[lvl];
 | 
						|
 | 
						|
    if (DeflaterConstants.COMPR_FUNC[lvl] != comprFunc)
 | 
						|
      {
 | 
						|
        if (DeflaterConstants.DEBUGGING)
 | 
						|
          System.err.println("Change from "+comprFunc +" to "
 | 
						|
                             + DeflaterConstants.COMPR_FUNC[lvl]);
 | 
						|
        switch (comprFunc)
 | 
						|
          {
 | 
						|
          case DEFLATE_STORED:
 | 
						|
            if (strstart > blockStart)
 | 
						|
              {
 | 
						|
                huffman.flushStoredBlock(window, blockStart,
 | 
						|
                                         strstart - blockStart, false);
 | 
						|
                blockStart = strstart;
 | 
						|
              }
 | 
						|
            updateHash();
 | 
						|
            break;
 | 
						|
          case DEFLATE_FAST:
 | 
						|
            if (strstart > blockStart)
 | 
						|
              {
 | 
						|
                huffman.flushBlock(window, blockStart, strstart - blockStart,
 | 
						|
                                   false);
 | 
						|
                blockStart = strstart;
 | 
						|
              }
 | 
						|
            break;
 | 
						|
          case DEFLATE_SLOW:
 | 
						|
            if (prevAvailable)
 | 
						|
              huffman.tallyLit(window[strstart-1] & 0xff);
 | 
						|
            if (strstart > blockStart)
 | 
						|
              {
 | 
						|
                huffman.flushBlock(window, blockStart, strstart - blockStart,
 | 
						|
                                   false);
 | 
						|
                blockStart = strstart;
 | 
						|
              }
 | 
						|
            prevAvailable = false;
 | 
						|
            matchLen = MIN_MATCH - 1;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        comprFunc = COMPR_FUNC[lvl];
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  private void updateHash() {
 | 
						|
    if (DEBUGGING)
 | 
						|
      System.err.println("updateHash: "+strstart);
 | 
						|
    ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1];
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Inserts the current string in the head hash and returns the previous
 | 
						|
   * value for this hash.
 | 
						|
   */
 | 
						|
  private int insertString() {
 | 
						|
    short match;
 | 
						|
    int hash = ((ins_h << HASH_SHIFT) ^ window[strstart + (MIN_MATCH -1)])
 | 
						|
      & HASH_MASK;
 | 
						|
 | 
						|
    if (DEBUGGING)
 | 
						|
      {
 | 
						|
        if (hash != (((window[strstart] << (2*HASH_SHIFT))
 | 
						|
                      ^ (window[strstart + 1] << HASH_SHIFT)
 | 
						|
                      ^ (window[strstart + 2])) & HASH_MASK))
 | 
						|
          throw new InternalError("hash inconsistent: "+hash+"/"
 | 
						|
                                  +window[strstart]+","
 | 
						|
                                  +window[strstart+1]+","
 | 
						|
                                  +window[strstart+2]+","+HASH_SHIFT);
 | 
						|
      }
 | 
						|
 | 
						|
    prev[strstart & WMASK] = match = head[hash];
 | 
						|
    head[hash] = (short) strstart;
 | 
						|
    ins_h = hash;
 | 
						|
    return match & 0xffff;
 | 
						|
  }
 | 
						|
 | 
						|
  private void slideWindow()
 | 
						|
  {
 | 
						|
    System.arraycopy(window, WSIZE, window, 0, WSIZE);
 | 
						|
    matchStart -= WSIZE;
 | 
						|
    strstart -= WSIZE;
 | 
						|
    blockStart -= WSIZE;
 | 
						|
 | 
						|
    /* Slide the hash table (could be avoided with 32 bit values
 | 
						|
     * at the expense of memory usage).
 | 
						|
     */
 | 
						|
    for (int i = 0; i < HASH_SIZE; i++)
 | 
						|
      {
 | 
						|
        int m = head[i] & 0xffff;
 | 
						|
        head[i] = m >= WSIZE ? (short) (m - WSIZE) : 0;
 | 
						|
      }
 | 
						|
 | 
						|
    /* Slide the prev table.
 | 
						|
     */
 | 
						|
    for (int i = 0; i < WSIZE; i++)
 | 
						|
      {
 | 
						|
        int m = prev[i] & 0xffff;
 | 
						|
        prev[i] = m >= WSIZE ? (short) (m - WSIZE) : 0;
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Fill the window when the lookahead becomes insufficient.
 | 
						|
   * Updates strstart and lookahead.
 | 
						|
   *
 | 
						|
   * OUT assertions: strstart + lookahead <= 2*WSIZE
 | 
						|
   *    lookahead >= MIN_LOOKAHEAD or inputOff == inputEnd
 | 
						|
   */
 | 
						|
  private void fillWindow()
 | 
						|
  {
 | 
						|
    /* If the window is almost full and there is insufficient lookahead,
 | 
						|
     * move the upper half to the lower one to make room in the upper half.
 | 
						|
     */
 | 
						|
    if (strstart >= WSIZE + MAX_DIST)
 | 
						|
      slideWindow();
 | 
						|
 | 
						|
    /* If there is not enough lookahead, but still some input left,
 | 
						|
     * read in the input
 | 
						|
     */
 | 
						|
    while (lookahead < DeflaterConstants.MIN_LOOKAHEAD && inputOff < inputEnd)
 | 
						|
      {
 | 
						|
        int more = 2*WSIZE - lookahead - strstart;
 | 
						|
 | 
						|
        if (more > inputEnd - inputOff)
 | 
						|
          more = inputEnd - inputOff;
 | 
						|
 | 
						|
        System.arraycopy(inputBuf, inputOff,
 | 
						|
                         window, strstart + lookahead, more);
 | 
						|
        adler.update(inputBuf, inputOff, more);
 | 
						|
        inputOff += more;
 | 
						|
        totalIn  += more;
 | 
						|
        lookahead += more;
 | 
						|
      }
 | 
						|
 | 
						|
    if (lookahead >= MIN_MATCH)
 | 
						|
      updateHash();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Find the best (longest) string in the window matching the
 | 
						|
   * string starting at strstart.
 | 
						|
   *
 | 
						|
   * Preconditions:
 | 
						|
   *    strstart + MAX_MATCH <= window.length.
 | 
						|
   *
 | 
						|
   *
 | 
						|
   * @param curMatch
 | 
						|
   */
 | 
						|
  private boolean findLongestMatch(int curMatch) {
 | 
						|
    int chainLength = this.max_chain;
 | 
						|
    int niceLength = this.niceLength;
 | 
						|
    short[] prev = this.prev;
 | 
						|
    int scan  = this.strstart;
 | 
						|
    int match;
 | 
						|
    int best_end = this.strstart + matchLen;
 | 
						|
    int best_len = Math.max(matchLen, MIN_MATCH - 1);
 | 
						|
 | 
						|
    int limit = Math.max(strstart - MAX_DIST, 0);
 | 
						|
 | 
						|
    int strend = scan + MAX_MATCH - 1;
 | 
						|
    byte scan_end1 = window[best_end - 1];
 | 
						|
    byte scan_end  = window[best_end];
 | 
						|
 | 
						|
    /* Do not waste too much time if we already have a good match: */
 | 
						|
    if (best_len >= this.goodLength)
 | 
						|
      chainLength >>= 2;
 | 
						|
 | 
						|
    /* Do not look for matches beyond the end of the input. This is necessary
 | 
						|
     * to make deflate deterministic.
 | 
						|
     */
 | 
						|
    if (niceLength > lookahead)
 | 
						|
      niceLength = lookahead;
 | 
						|
 | 
						|
    if (DeflaterConstants.DEBUGGING
 | 
						|
        && strstart > 2*WSIZE - MIN_LOOKAHEAD)
 | 
						|
      throw new InternalError("need lookahead");
 | 
						|
 | 
						|
    do {
 | 
						|
      if (DeflaterConstants.DEBUGGING && curMatch >= strstart)
 | 
						|
        throw new InternalError("future match");
 | 
						|
      if (window[curMatch + best_len] != scan_end
 | 
						|
          || window[curMatch + best_len - 1] != scan_end1
 | 
						|
          || window[curMatch] != window[scan]
 | 
						|
          || window[curMatch+1] != window[scan + 1])
 | 
						|
        continue;
 | 
						|
 | 
						|
      match = curMatch + 2;
 | 
						|
      scan += 2;
 | 
						|
 | 
						|
      /* We check for insufficient lookahead only every 8th comparison;
 | 
						|
       * the 256th check will be made at strstart+258.
 | 
						|
       */
 | 
						|
      while (window[++scan] == window[++match]
 | 
						|
             && window[++scan] == window[++match]
 | 
						|
             && window[++scan] == window[++match]
 | 
						|
             && window[++scan] == window[++match]
 | 
						|
             && window[++scan] == window[++match]
 | 
						|
             && window[++scan] == window[++match]
 | 
						|
             && window[++scan] == window[++match]
 | 
						|
             && window[++scan] == window[++match]
 | 
						|
             && scan < strend)
 | 
						|
        ;
 | 
						|
 | 
						|
      if (scan > best_end) {
 | 
						|
//      if (DeflaterConstants.DEBUGGING && ins_h == 0)
 | 
						|
//        System.err.println("Found match: "+curMatch+"-"+(scan-strstart));
 | 
						|
        matchStart = curMatch;
 | 
						|
        best_end = scan;
 | 
						|
        best_len = scan - strstart;
 | 
						|
        if (best_len >= niceLength)
 | 
						|
          break;
 | 
						|
 | 
						|
        scan_end1  = window[best_end-1];
 | 
						|
        scan_end   = window[best_end];
 | 
						|
      }
 | 
						|
      scan = strstart;
 | 
						|
    } while ((curMatch = (prev[curMatch & WMASK] & 0xffff)) > limit
 | 
						|
             && --chainLength != 0);
 | 
						|
 | 
						|
    matchLen = Math.min(best_len, lookahead);
 | 
						|
    return matchLen >= MIN_MATCH;
 | 
						|
  }
 | 
						|
 | 
						|
  void setDictionary(byte[] buffer, int offset, int length) {
 | 
						|
    if (DeflaterConstants.DEBUGGING && strstart != 1)
 | 
						|
      throw new IllegalStateException("strstart not 1");
 | 
						|
    adler.update(buffer, offset, length);
 | 
						|
    if (length < MIN_MATCH)
 | 
						|
      return;
 | 
						|
    if (length > MAX_DIST) {
 | 
						|
      offset += length - MAX_DIST;
 | 
						|
      length = MAX_DIST;
 | 
						|
    }
 | 
						|
 | 
						|
    System.arraycopy(buffer, offset, window, strstart, length);
 | 
						|
 | 
						|
    updateHash();
 | 
						|
    length--;
 | 
						|
    while (--length > 0)
 | 
						|
      {
 | 
						|
        insertString();
 | 
						|
        strstart++;
 | 
						|
      }
 | 
						|
    strstart += 2;
 | 
						|
    blockStart = strstart;
 | 
						|
  }
 | 
						|
 | 
						|
  private boolean deflateStored(boolean flush, boolean finish)
 | 
						|
  {
 | 
						|
    if (!flush && lookahead == 0)
 | 
						|
      return false;
 | 
						|
 | 
						|
    strstart += lookahead;
 | 
						|
    lookahead = 0;
 | 
						|
 | 
						|
    int storedLen = strstart - blockStart;
 | 
						|
 | 
						|
    if ((storedLen >= DeflaterConstants.MAX_BLOCK_SIZE)
 | 
						|
        /* Block is full */
 | 
						|
        || (blockStart < WSIZE && storedLen >= MAX_DIST)
 | 
						|
        /* Block may move out of window */
 | 
						|
        || flush)
 | 
						|
      {
 | 
						|
        boolean lastBlock = finish;
 | 
						|
        if (storedLen > DeflaterConstants.MAX_BLOCK_SIZE)
 | 
						|
          {
 | 
						|
            storedLen = DeflaterConstants.MAX_BLOCK_SIZE;
 | 
						|
            lastBlock = false;
 | 
						|
          }
 | 
						|
 | 
						|
        if (DeflaterConstants.DEBUGGING)
 | 
						|
          System.err.println("storedBlock["+storedLen+","+lastBlock+"]");
 | 
						|
 | 
						|
        huffman.flushStoredBlock(window, blockStart, storedLen, lastBlock);
 | 
						|
        blockStart += storedLen;
 | 
						|
        return !lastBlock;
 | 
						|
      }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  private boolean deflateFast(boolean flush, boolean finish)
 | 
						|
  {
 | 
						|
    if (lookahead < MIN_LOOKAHEAD && !flush)
 | 
						|
      return false;
 | 
						|
 | 
						|
    while (lookahead >= MIN_LOOKAHEAD || flush)
 | 
						|
      {
 | 
						|
        if (lookahead == 0)
 | 
						|
          {
 | 
						|
            /* We are flushing everything */
 | 
						|
            huffman.flushBlock(window, blockStart, strstart - blockStart,
 | 
						|
                               finish);
 | 
						|
            blockStart = strstart;
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
 | 
						|
        if (strstart > 2 * WSIZE - MIN_LOOKAHEAD)
 | 
						|
          {
 | 
						|
            /* slide window, as findLongestMatch need this.
 | 
						|
             * This should only happen when flushing and the window
 | 
						|
             * is almost full.
 | 
						|
             */
 | 
						|
            slideWindow();
 | 
						|
          }
 | 
						|
 | 
						|
        int hashHead;
 | 
						|
        if (lookahead >= MIN_MATCH
 | 
						|
            && (hashHead = insertString()) != 0
 | 
						|
            && strategy != Deflater.HUFFMAN_ONLY
 | 
						|
            && strstart - hashHead <= MAX_DIST
 | 
						|
            && findLongestMatch(hashHead))
 | 
						|
          {
 | 
						|
            /* longestMatch sets matchStart and matchLen */
 | 
						|
            if (DeflaterConstants.DEBUGGING)
 | 
						|
              {
 | 
						|
                for (int i = 0 ; i < matchLen; i++)
 | 
						|
                  {
 | 
						|
                    if (window[strstart+i] != window[matchStart + i])
 | 
						|
                      throw new InternalError();
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            boolean full = huffman.tallyDist(strstart - matchStart, matchLen);
 | 
						|
 | 
						|
            lookahead -= matchLen;
 | 
						|
            if (matchLen <= max_lazy && lookahead >= MIN_MATCH)
 | 
						|
              {
 | 
						|
                while (--matchLen > 0)
 | 
						|
                  {
 | 
						|
                    strstart++;
 | 
						|
                    insertString();
 | 
						|
                  }
 | 
						|
                strstart++;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                strstart += matchLen;
 | 
						|
                if (lookahead >= MIN_MATCH - 1)
 | 
						|
                  updateHash();
 | 
						|
              }
 | 
						|
            matchLen = MIN_MATCH - 1;
 | 
						|
            if (!full)
 | 
						|
              continue;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            /* No match found */
 | 
						|
            huffman.tallyLit(window[strstart] & 0xff);
 | 
						|
            strstart++;
 | 
						|
            lookahead--;
 | 
						|
          }
 | 
						|
 | 
						|
        if (huffman.isFull())
 | 
						|
          {
 | 
						|
            boolean lastBlock = finish && lookahead == 0;
 | 
						|
            huffman.flushBlock(window, blockStart, strstart - blockStart,
 | 
						|
                               lastBlock);
 | 
						|
            blockStart = strstart;
 | 
						|
            return !lastBlock;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  private boolean deflateSlow(boolean flush, boolean finish)
 | 
						|
  {
 | 
						|
    if (lookahead < MIN_LOOKAHEAD && !flush)
 | 
						|
      return false;
 | 
						|
 | 
						|
    while (lookahead >= MIN_LOOKAHEAD || flush)
 | 
						|
      {
 | 
						|
        if (lookahead == 0)
 | 
						|
          {
 | 
						|
            if (prevAvailable)
 | 
						|
              huffman.tallyLit(window[strstart-1] & 0xff);
 | 
						|
            prevAvailable = false;
 | 
						|
 | 
						|
            /* We are flushing everything */
 | 
						|
            if (DeflaterConstants.DEBUGGING && !flush)
 | 
						|
              throw new InternalError("Not flushing, but no lookahead");
 | 
						|
            huffman.flushBlock(window, blockStart, strstart - blockStart,
 | 
						|
                               finish);
 | 
						|
            blockStart = strstart;
 | 
						|
            return false;
 | 
						|
          }
 | 
						|
 | 
						|
        if (strstart >= 2 * WSIZE - MIN_LOOKAHEAD)
 | 
						|
          {
 | 
						|
            /* slide window, as findLongestMatch need this.
 | 
						|
             * This should only happen when flushing and the window
 | 
						|
             * is almost full.
 | 
						|
             */
 | 
						|
            slideWindow();
 | 
						|
          }
 | 
						|
 | 
						|
        int prevMatch = matchStart;
 | 
						|
        int prevLen = matchLen;
 | 
						|
        if (lookahead >= MIN_MATCH)
 | 
						|
          {
 | 
						|
            int hashHead = insertString();
 | 
						|
            if (strategy != Deflater.HUFFMAN_ONLY
 | 
						|
                && hashHead != 0 && strstart - hashHead <= MAX_DIST
 | 
						|
                && findLongestMatch(hashHead))
 | 
						|
              {
 | 
						|
                /* longestMatch sets matchStart and matchLen */
 | 
						|
 | 
						|
                /* Discard match if too small and too far away */
 | 
						|
                if (matchLen <= 5
 | 
						|
                    && (strategy == Deflater.FILTERED
 | 
						|
                        || (matchLen == MIN_MATCH
 | 
						|
                            && strstart - matchStart > TOO_FAR))) {
 | 
						|
                  matchLen = MIN_MATCH - 1;
 | 
						|
                }
 | 
						|
              }
 | 
						|
          }
 | 
						|
 | 
						|
        /* previous match was better */
 | 
						|
        if (prevLen >= MIN_MATCH && matchLen <= prevLen)
 | 
						|
          {
 | 
						|
            if (DeflaterConstants.DEBUGGING)
 | 
						|
              {
 | 
						|
                for (int i = 0 ; i < matchLen; i++)
 | 
						|
                  {
 | 
						|
                    if (window[strstart-1+i] != window[prevMatch + i])
 | 
						|
                      throw new InternalError();
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            huffman.tallyDist(strstart - 1 - prevMatch, prevLen);
 | 
						|
            prevLen -= 2;
 | 
						|
            do
 | 
						|
              {
 | 
						|
                strstart++;
 | 
						|
                lookahead--;
 | 
						|
                if (lookahead >= MIN_MATCH)
 | 
						|
                  insertString();
 | 
						|
              }
 | 
						|
            while (--prevLen > 0);
 | 
						|
            strstart ++;
 | 
						|
            lookahead--;
 | 
						|
            prevAvailable = false;
 | 
						|
            matchLen = MIN_MATCH - 1;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            if (prevAvailable)
 | 
						|
              huffman.tallyLit(window[strstart-1] & 0xff);
 | 
						|
            prevAvailable = true;
 | 
						|
            strstart++;
 | 
						|
            lookahead--;
 | 
						|
          }
 | 
						|
 | 
						|
        if (huffman.isFull())
 | 
						|
          {
 | 
						|
            int len = strstart - blockStart;
 | 
						|
            if (prevAvailable)
 | 
						|
              len--;
 | 
						|
            boolean lastBlock = (finish && lookahead == 0 && !prevAvailable);
 | 
						|
            huffman.flushBlock(window, blockStart, len, lastBlock);
 | 
						|
            blockStart += len;
 | 
						|
            return !lastBlock;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean deflate(boolean flush, boolean finish)
 | 
						|
  {
 | 
						|
    boolean progress;
 | 
						|
    do
 | 
						|
      {
 | 
						|
        fillWindow();
 | 
						|
        boolean canFlush = flush && inputOff == inputEnd;
 | 
						|
        if (DeflaterConstants.DEBUGGING)
 | 
						|
          System.err.println("window: ["+blockStart+","+strstart+","
 | 
						|
                             +lookahead+"], "+comprFunc+","+canFlush);
 | 
						|
        switch (comprFunc)
 | 
						|
          {
 | 
						|
          case DEFLATE_STORED:
 | 
						|
            progress = deflateStored(canFlush, finish);
 | 
						|
            break;
 | 
						|
          case DEFLATE_FAST:
 | 
						|
            progress = deflateFast(canFlush, finish);
 | 
						|
            break;
 | 
						|
          case DEFLATE_SLOW:
 | 
						|
            progress = deflateSlow(canFlush, finish);
 | 
						|
            break;
 | 
						|
          default:
 | 
						|
            throw new InternalError();
 | 
						|
          }
 | 
						|
      }
 | 
						|
    while (pending.isFlushed()  /* repeat while we have no pending output */
 | 
						|
           && progress);        /* and progress was made */
 | 
						|
 | 
						|
    return progress;
 | 
						|
  }
 | 
						|
 | 
						|
  public void setInput(byte[] buf, int off, int len)
 | 
						|
  {
 | 
						|
    if (inputOff < inputEnd)
 | 
						|
      throw new IllegalStateException
 | 
						|
        ("Old input was not completely processed");
 | 
						|
 | 
						|
    int end = off + len;
 | 
						|
 | 
						|
    /* We want to throw an ArrayIndexOutOfBoundsException early.  The
 | 
						|
     * check is very tricky: it also handles integer wrap around.
 | 
						|
     */
 | 
						|
    if (0 > off || off > end || end > buf.length)
 | 
						|
      throw new ArrayIndexOutOfBoundsException();
 | 
						|
 | 
						|
    inputBuf = buf;
 | 
						|
    inputOff = off;
 | 
						|
    inputEnd = end;
 | 
						|
  }
 | 
						|
 | 
						|
  public final boolean needsInput()
 | 
						|
  {
 | 
						|
    return inputEnd == inputOff;
 | 
						|
  }
 | 
						|
}
 |