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;
 | |
|   }
 | |
| }
 |