mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			777 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			777 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* DeflaterHuffman.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;
 | |
| 
 | |
| /**
 | |
|  * This is the DeflaterHuffman class.
 | |
|  *
 | |
|  * This class is <i>not</i> thread safe.  This is inherent in the API, due
 | |
|  * to the split of deflate and setInput.
 | |
|  *
 | |
|  * @author Jochen Hoenicke
 | |
|  * @date Jan 6, 2000
 | |
|  */
 | |
| class DeflaterHuffman
 | |
| {
 | |
|   private static final int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
 | |
|   private static final int LITERAL_NUM = 286;
 | |
|   private static final int DIST_NUM = 30;
 | |
|   private static final int BITLEN_NUM = 19;
 | |
|   private static final int REP_3_6    = 16;
 | |
|   private static final int REP_3_10   = 17;
 | |
|   private static final int REP_11_138 = 18;
 | |
|   private static final int EOF_SYMBOL = 256;
 | |
|   private static final int[] BL_ORDER =
 | |
|   { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
 | |
| 
 | |
|   private static final String bit4Reverse =
 | |
|     "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017";
 | |
| 
 | |
|   class Tree {
 | |
|     short[] freqs;
 | |
|     short[] codes;
 | |
|     byte[]  length;
 | |
|     int[]   bl_counts;
 | |
|     int     minNumCodes, numCodes;
 | |
|     int     maxLength;
 | |
| 
 | |
|     Tree(int elems, int minCodes, int maxLength) {
 | |
|       this.minNumCodes = minCodes;
 | |
|       this.maxLength  = maxLength;
 | |
|       freqs  = new short[elems];
 | |
|       bl_counts = new int[maxLength];
 | |
|     }
 | |
| 
 | |
|     void reset() {
 | |
|       for (int i = 0; i < freqs.length; i++)
 | |
|         freqs[i] = 0;
 | |
|       codes = null;
 | |
|       length = null;
 | |
|     }
 | |
| 
 | |
|     final void writeSymbol(int code)
 | |
|     {
 | |
|       if (DeflaterConstants.DEBUGGING)
 | |
|         {
 | |
|           freqs[code]--;
 | |
| //        System.err.print("writeSymbol("+freqs.length+","+code+"): ");
 | |
|         }
 | |
|       pending.writeBits(codes[code] & 0xffff, length[code]);
 | |
|     }
 | |
| 
 | |
|     final void checkEmpty()
 | |
|     {
 | |
|       boolean empty = true;
 | |
|       for (int i = 0; i < freqs.length; i++)
 | |
|         if (freqs[i] != 0)
 | |
|           {
 | |
|             System.err.println("freqs["+i+"] == "+freqs[i]);
 | |
|             empty = false;
 | |
|           }
 | |
|       if (!empty)
 | |
|         throw new InternalError();
 | |
|       System.err.println("checkEmpty suceeded!");
 | |
|     }
 | |
| 
 | |
|     void setStaticCodes(short[] stCodes, byte[] stLength)
 | |
|     {
 | |
|       codes = stCodes;
 | |
|       length = stLength;
 | |
|     }
 | |
| 
 | |
|     public void buildCodes() {
 | |
|       int[] nextCode = new int[maxLength];
 | |
|       int code = 0;
 | |
|       codes = new short[freqs.length];
 | |
| 
 | |
|       if (DeflaterConstants.DEBUGGING)
 | |
|         System.err.println("buildCodes: "+freqs.length);
 | |
|       for (int bits = 0; bits < maxLength; bits++)
 | |
|         {
 | |
|           nextCode[bits] = code;
 | |
|           code += bl_counts[bits] << (15 - bits);
 | |
|           if (DeflaterConstants.DEBUGGING)
 | |
|             System.err.println("bits: "+(bits+1)+" count: "+bl_counts[bits]
 | |
|                                +" nextCode: "+Integer.toHexString(code));
 | |
|         }
 | |
|       if (DeflaterConstants.DEBUGGING && code != 65536)
 | |
|         throw new RuntimeException("Inconsistent bl_counts!");
 | |
| 
 | |
|       for (int i=0; i < numCodes; i++)
 | |
|         {
 | |
|           int bits = length[i];
 | |
|           if (bits > 0)
 | |
|             {
 | |
|               if (DeflaterConstants.DEBUGGING)
 | |
|                 System.err.println("codes["+i+"] = rev("
 | |
|                                    +Integer.toHexString(nextCode[bits-1])+"),"
 | |
|                                    +bits);
 | |
|               codes[i] = bitReverse(nextCode[bits-1]);
 | |
|               nextCode[bits-1] += 1 << (16 - bits);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     private void buildLength(int childs[])
 | |
|     {
 | |
|       this.length = new byte [freqs.length];
 | |
|       int numNodes = childs.length / 2;
 | |
|       int numLeafs = (numNodes + 1) / 2;
 | |
|       int overflow = 0;
 | |
| 
 | |
|       for (int i = 0; i < maxLength; i++)
 | |
|         bl_counts[i] = 0;
 | |
| 
 | |
|       /* First calculate optimal bit lengths */
 | |
|       int lengths[] = new int[numNodes];
 | |
|       lengths[numNodes-1] = 0;
 | |
|       for (int i = numNodes - 1; i >= 0; i--)
 | |
|         {
 | |
|           if (childs[2*i+1] != -1)
 | |
|             {
 | |
|               int bitLength = lengths[i] + 1;
 | |
|               if (bitLength > maxLength)
 | |
|                 {
 | |
|                   bitLength = maxLength;
 | |
|                   overflow++;
 | |
|                 }
 | |
|               lengths[childs[2*i]] = lengths[childs[2*i+1]] = bitLength;
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               /* A leaf node */
 | |
|               int bitLength = lengths[i];
 | |
|               bl_counts[bitLength - 1]++;
 | |
|               this.length[childs[2*i]] = (byte) lengths[i];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       if (DeflaterConstants.DEBUGGING)
 | |
|         {
 | |
|           System.err.println("Tree "+freqs.length+" lengths:");
 | |
|           for (int i=0; i < numLeafs; i++)
 | |
|             System.err.println("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
 | |
|                                + " len: "+length[childs[2*i]]);
 | |
|         }
 | |
| 
 | |
|       if (overflow == 0)
 | |
|         return;
 | |
| 
 | |
|       int incrBitLen = maxLength - 1;
 | |
|       do
 | |
|         {
 | |
|           /* Find the first bit length which could increase: */
 | |
|           while (bl_counts[--incrBitLen] == 0)
 | |
|             ;
 | |
| 
 | |
|           /* Move this node one down and remove a corresponding
 | |
|            * amount of overflow nodes.
 | |
|            */
 | |
|           do
 | |
|             {
 | |
|               bl_counts[incrBitLen]--;
 | |
|               bl_counts[++incrBitLen]++;
 | |
|               overflow -= 1 << (maxLength - 1 - incrBitLen);
 | |
|             }
 | |
|           while (overflow > 0 && incrBitLen < maxLength - 1);
 | |
|         }
 | |
|       while (overflow > 0);
 | |
| 
 | |
|       /* We may have overshot above.  Move some nodes from maxLength to
 | |
|        * maxLength-1 in that case.
 | |
|        */
 | |
|       bl_counts[maxLength-1] += overflow;
 | |
|       bl_counts[maxLength-2] -= overflow;
 | |
| 
 | |
|       /* Now recompute all bit lengths, scanning in increasing
 | |
|        * frequency.  It is simpler to reconstruct all lengths instead of
 | |
|        * fixing only the wrong ones. This idea is taken from 'ar'
 | |
|        * written by Haruhiko Okumura.
 | |
|        *
 | |
|        * The nodes were inserted with decreasing frequency into the childs
 | |
|        * array.
 | |
|        */
 | |
|       int nodePtr = 2 * numLeafs;
 | |
|       for (int bits = maxLength; bits != 0; bits--)
 | |
|         {
 | |
|           int n = bl_counts[bits-1];
 | |
|           while (n > 0)
 | |
|             {
 | |
|               int childPtr = 2*childs[nodePtr++];
 | |
|               if (childs[childPtr + 1] == -1)
 | |
|                 {
 | |
|                   /* We found another leaf */
 | |
|                   length[childs[childPtr]] = (byte) bits;
 | |
|                   n--;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|       if (DeflaterConstants.DEBUGGING)
 | |
|         {
 | |
|           System.err.println("*** After overflow elimination. ***");
 | |
|           for (int i=0; i < numLeafs; i++)
 | |
|             System.err.println("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
 | |
|                                + " len: "+length[childs[2*i]]);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void buildTree()
 | |
|     {
 | |
|       int numSymbols = freqs.length;
 | |
| 
 | |
|       /* heap is a priority queue, sorted by frequency, least frequent
 | |
|        * nodes first.  The heap is a binary tree, with the property, that
 | |
|        * the parent node is smaller than both child nodes.  This assures
 | |
|        * that the smallest node is the first parent.
 | |
|        *
 | |
|        * The binary tree is encoded in an array:  0 is root node and
 | |
|        * the nodes 2*n+1, 2*n+2 are the child nodes of node n.
 | |
|        */
 | |
|       int[] heap = new int[numSymbols];
 | |
|       int heapLen = 0;
 | |
|       int maxCode = 0;
 | |
|       for (int n = 0; n < numSymbols; n++)
 | |
|         {
 | |
|           int freq = freqs[n];
 | |
|           if (freq != 0)
 | |
|             {
 | |
|               /* Insert n into heap */
 | |
|               int pos = heapLen++;
 | |
|               int ppos;
 | |
|               while (pos > 0 &&
 | |
|                      freqs[heap[ppos = (pos - 1) / 2]] > freq) {
 | |
|                 heap[pos] = heap[ppos];
 | |
|                 pos = ppos;
 | |
|               }
 | |
|               heap[pos] = n;
 | |
|               maxCode = n;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|       /* We could encode a single literal with 0 bits but then we
 | |
|        * don't see the literals.  Therefore we force at least two
 | |
|        * literals to avoid this case.  We don't care about order in
 | |
|        * this case, both literals get a 1 bit code.
 | |
|        */
 | |
|       while (heapLen < 2)
 | |
|         {
 | |
|           int node = maxCode < 2 ? ++maxCode : 0;
 | |
|           heap[heapLen++] = node;
 | |
|         }
 | |
| 
 | |
|       numCodes = Math.max(maxCode + 1, minNumCodes);
 | |
| 
 | |
|       int numLeafs = heapLen;
 | |
|       int[] childs = new int[4*heapLen - 2];
 | |
|       int[] values = new int[2*heapLen - 1];
 | |
|       int numNodes = numLeafs;
 | |
|       for (int i = 0; i < heapLen; i++)
 | |
|         {
 | |
|           int node = heap[i];
 | |
|           childs[2*i]   = node;
 | |
|           childs[2*i+1] = -1;
 | |
|           values[i] = freqs[node] << 8;
 | |
|           heap[i] = i;
 | |
|         }
 | |
| 
 | |
|       /* Construct the Huffman tree by repeatedly combining the least two
 | |
|        * frequent nodes.
 | |
|        */
 | |
|       do
 | |
|         {
 | |
|           int first = heap[0];
 | |
|           int last  = heap[--heapLen];
 | |
| 
 | |
|           /* Propagate the hole to the leafs of the heap */
 | |
|           int ppos = 0;
 | |
|           int path = 1;
 | |
|           while (path < heapLen)
 | |
|             {
 | |
|               if (path + 1 < heapLen
 | |
|                   && values[heap[path]] > values[heap[path+1]])
 | |
|                 path++;
 | |
| 
 | |
|               heap[ppos] = heap[path];
 | |
|               ppos = path;
 | |
|               path = path * 2 + 1;
 | |
|             }
 | |
| 
 | |
|           /* Now propagate the last element down along path.  Normally
 | |
|            * it shouldn't go too deep.
 | |
|            */
 | |
|           int lastVal = values[last];
 | |
|           while ((path = ppos) > 0
 | |
|                  && values[heap[ppos = (path - 1)/2]] > lastVal)
 | |
|             heap[path] = heap[ppos];
 | |
|           heap[path] = last;
 | |
| 
 | |
| 
 | |
|           int second = heap[0];
 | |
| 
 | |
|           /* Create a new node father of first and second */
 | |
|           last = numNodes++;
 | |
|           childs[2*last] = first;
 | |
|           childs[2*last+1] = second;
 | |
|           int mindepth = Math.min(values[first] & 0xff, values[second] & 0xff);
 | |
|           values[last] = lastVal = values[first] + values[second] - mindepth + 1;
 | |
| 
 | |
|           /* Again, propagate the hole to the leafs */
 | |
|           ppos = 0;
 | |
|           path = 1;
 | |
|           while (path < heapLen)
 | |
|             {
 | |
|               if (path + 1 < heapLen
 | |
|                   && values[heap[path]] > values[heap[path+1]])
 | |
|                 path++;
 | |
| 
 | |
|               heap[ppos] = heap[path];
 | |
|               ppos = path;
 | |
|               path = ppos * 2 + 1;
 | |
|             }
 | |
| 
 | |
|           /* Now propagate the new element down along path */
 | |
|           while ((path = ppos) > 0
 | |
|                  && values[heap[ppos = (path - 1)/2]] > lastVal)
 | |
|             heap[path] = heap[ppos];
 | |
|           heap[path] = last;
 | |
|         }
 | |
|       while (heapLen > 1);
 | |
| 
 | |
|       if (heap[0] != childs.length / 2 - 1)
 | |
|         throw new RuntimeException("Weird!");
 | |
| 
 | |
|       buildLength(childs);
 | |
|     }
 | |
| 
 | |
|     int getEncodedLength()
 | |
|     {
 | |
|       int len = 0;
 | |
|       for (int i = 0; i < freqs.length; i++)
 | |
|         len += freqs[i] * length[i];
 | |
|       return len;
 | |
|     }
 | |
| 
 | |
|     void calcBLFreq(Tree blTree) {
 | |
|       int max_count;               /* max repeat count */
 | |
|       int min_count;               /* min repeat count */
 | |
|       int count;                   /* repeat count of the current code */
 | |
|       int curlen = -1;             /* length of current code */
 | |
| 
 | |
|       int i = 0;
 | |
|       while (i < numCodes)
 | |
|         {
 | |
|           count = 1;
 | |
|           int nextlen = length[i];
 | |
|           if (nextlen == 0)
 | |
|             {
 | |
|               max_count = 138;
 | |
|               min_count = 3;
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               max_count = 6;
 | |
|               min_count = 3;
 | |
|               if (curlen != nextlen)
 | |
|                 {
 | |
|                   blTree.freqs[nextlen]++;
 | |
|                   count = 0;
 | |
|                 }
 | |
|             }
 | |
|           curlen = nextlen;
 | |
|           i++;
 | |
| 
 | |
|           while (i < numCodes && curlen == length[i])
 | |
|             {
 | |
|               i++;
 | |
|               if (++count >= max_count)
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|           if (count < min_count)
 | |
|             blTree.freqs[curlen] += count;
 | |
|           else if (curlen != 0)
 | |
|             blTree.freqs[REP_3_6]++;
 | |
|           else if (count <= 10)
 | |
|             blTree.freqs[REP_3_10]++;
 | |
|           else
 | |
|             blTree.freqs[REP_11_138]++;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void writeTree(Tree blTree)
 | |
|     {
 | |
|       int max_count;               /* max repeat count */
 | |
|       int min_count;               /* min repeat count */
 | |
|       int count;                   /* repeat count of the current code */
 | |
|       int curlen = -1;             /* length of current code */
 | |
| 
 | |
|       int i = 0;
 | |
|       while (i < numCodes)
 | |
|         {
 | |
|           count = 1;
 | |
|           int nextlen = length[i];
 | |
|           if (nextlen == 0)
 | |
|             {
 | |
|               max_count = 138;
 | |
|               min_count = 3;
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               max_count = 6;
 | |
|               min_count = 3;
 | |
|               if (curlen != nextlen)
 | |
|                 {
 | |
|                   blTree.writeSymbol(nextlen);
 | |
|                   count = 0;
 | |
|                 }
 | |
|             }
 | |
|           curlen = nextlen;
 | |
|           i++;
 | |
| 
 | |
|           while (i < numCodes && curlen == length[i])
 | |
|             {
 | |
|               i++;
 | |
|               if (++count >= max_count)
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|           if (count < min_count)
 | |
|             {
 | |
|               while (count-- > 0)
 | |
|                 blTree.writeSymbol(curlen);
 | |
|             }
 | |
|           else if (curlen != 0)
 | |
|             {
 | |
|               blTree.writeSymbol(REP_3_6);
 | |
|               pending.writeBits(count - 3, 2);
 | |
|             }
 | |
|           else if (count <= 10)
 | |
|             {
 | |
|               blTree.writeSymbol(REP_3_10);
 | |
|               pending.writeBits(count - 3, 3);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               blTree.writeSymbol(REP_11_138);
 | |
|               pending.writeBits(count - 11, 7);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
|   DeflaterPending pending;
 | |
|   private Tree literalTree, distTree, blTree;
 | |
| 
 | |
|   private short d_buf[];
 | |
|   private byte l_buf[];
 | |
|   private int last_lit;
 | |
|   private int extra_bits;
 | |
| 
 | |
|   private static short staticLCodes[];
 | |
|   private static byte  staticLLength[];
 | |
|   private static short staticDCodes[];
 | |
|   private static byte  staticDLength[];
 | |
| 
 | |
|   /**
 | |
|    * Reverse the bits of a 16 bit value.
 | |
|    */
 | |
|   static short bitReverse(int value) {
 | |
|     return (short) (bit4Reverse.charAt(value & 0xf) << 12
 | |
|                     | bit4Reverse.charAt((value >> 4) & 0xf) << 8
 | |
|                     | bit4Reverse.charAt((value >> 8) & 0xf) << 4
 | |
|                     | bit4Reverse.charAt(value >> 12));
 | |
|   }
 | |
| 
 | |
|   static {
 | |
|     /* See RFC 1951 3.2.6 */
 | |
|     /* Literal codes */
 | |
|     staticLCodes = new short[LITERAL_NUM];
 | |
|     staticLLength = new byte[LITERAL_NUM];
 | |
|     int i = 0;
 | |
|     while (i < 144) {
 | |
|       staticLCodes[i] = bitReverse((0x030 + i) << 8);
 | |
|       staticLLength[i++] = 8;
 | |
|     }
 | |
|     while (i < 256) {
 | |
|       staticLCodes[i] = bitReverse((0x190 - 144 + i) << 7);
 | |
|       staticLLength[i++] = 9;
 | |
|     }
 | |
|     while (i < 280) {
 | |
|       staticLCodes[i] = bitReverse((0x000 - 256 + i) << 9);
 | |
|       staticLLength[i++] = 7;
 | |
|     }
 | |
|     while (i < LITERAL_NUM) {
 | |
|       staticLCodes[i] = bitReverse((0x0c0 - 280 + i)  << 8);
 | |
|       staticLLength[i++] = 8;
 | |
|     }
 | |
| 
 | |
|     /* Distant codes */
 | |
|     staticDCodes = new short[DIST_NUM];
 | |
|     staticDLength = new byte[DIST_NUM];
 | |
|     for (i = 0; i < DIST_NUM; i++) {
 | |
|       staticDCodes[i] = bitReverse(i << 11);
 | |
|       staticDLength[i] = 5;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   public DeflaterHuffman(DeflaterPending pending)
 | |
|   {
 | |
|     this.pending = pending;
 | |
| 
 | |
|     literalTree = new Tree(LITERAL_NUM, 257, 15);
 | |
|     distTree    = new Tree(DIST_NUM, 1, 15);
 | |
|     blTree      = new Tree(BITLEN_NUM, 4, 7);
 | |
| 
 | |
|     d_buf = new short[BUFSIZE];
 | |
|     l_buf = new byte [BUFSIZE];
 | |
|   }
 | |
| 
 | |
|   public final void reset() {
 | |
|     last_lit = 0;
 | |
|     extra_bits = 0;
 | |
|     literalTree.reset();
 | |
|     distTree.reset();
 | |
|     blTree.reset();
 | |
|   }
 | |
| 
 | |
|   private int l_code(int len) {
 | |
|     if (len == 255)
 | |
|       return 285;
 | |
| 
 | |
|     int code = 257;
 | |
|     while (len >= 8)
 | |
|       {
 | |
|         code += 4;
 | |
|         len >>= 1;
 | |
|       }
 | |
|     return code + len;
 | |
|   }
 | |
| 
 | |
|   private int d_code(int distance) {
 | |
|     int code = 0;
 | |
|     while (distance >= 4)
 | |
|       {
 | |
|         code += 2;
 | |
|         distance >>= 1;
 | |
|       }
 | |
|     return code + distance;
 | |
|   }
 | |
| 
 | |
|   public void sendAllTrees(int blTreeCodes) {
 | |
|     blTree.buildCodes();
 | |
|     literalTree.buildCodes();
 | |
|     distTree.buildCodes();
 | |
|     pending.writeBits(literalTree.numCodes - 257, 5);
 | |
|     pending.writeBits(distTree.numCodes - 1, 5);
 | |
|     pending.writeBits(blTreeCodes - 4, 4);
 | |
|     for (int rank = 0; rank < blTreeCodes; rank++)
 | |
|       pending.writeBits(blTree.length[BL_ORDER[rank]], 3);
 | |
|     literalTree.writeTree(blTree);
 | |
|     distTree.writeTree(blTree);
 | |
|     if (DeflaterConstants.DEBUGGING)
 | |
|       blTree.checkEmpty();
 | |
|   }
 | |
| 
 | |
|   public void compressBlock() {
 | |
|     for (int i = 0; i < last_lit; i++)
 | |
|       {
 | |
|         int litlen = l_buf[i] & 0xff;
 | |
|         int dist = d_buf[i];
 | |
|         if (dist-- != 0)
 | |
|           {
 | |
|             if (DeflaterConstants.DEBUGGING)
 | |
|               System.err.print("["+(dist+1)+","+(litlen+3)+"]: ");
 | |
| 
 | |
|             int lc = l_code(litlen);
 | |
|             literalTree.writeSymbol(lc);
 | |
| 
 | |
|             int bits = (lc - 261) / 4;
 | |
|             if (bits > 0 && bits <= 5)
 | |
|               pending.writeBits(litlen & ((1 << bits) - 1), bits);
 | |
| 
 | |
|             int dc = d_code(dist);
 | |
|             distTree.writeSymbol(dc);
 | |
| 
 | |
|             bits = dc / 2 - 1;
 | |
|             if (bits > 0)
 | |
|               pending.writeBits(dist & ((1 << bits) - 1), bits);
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             if (DeflaterConstants.DEBUGGING)
 | |
|               {
 | |
|                 if (litlen > 32 && litlen < 127)
 | |
|                   System.err.print("("+(char)litlen+"): ");
 | |
|                 else
 | |
|                   System.err.print("{"+litlen+"}: ");
 | |
|               }
 | |
|             literalTree.writeSymbol(litlen);
 | |
|           }
 | |
|       }
 | |
|     if (DeflaterConstants.DEBUGGING)
 | |
|       System.err.print("EOF: ");
 | |
|     literalTree.writeSymbol(EOF_SYMBOL);
 | |
|     if (DeflaterConstants.DEBUGGING)
 | |
|       {
 | |
|         literalTree.checkEmpty();
 | |
|         distTree.checkEmpty();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void flushStoredBlock(byte[] stored,
 | |
|                                int stored_offset, int stored_len,
 | |
|                                boolean lastBlock) {
 | |
|     if (DeflaterConstants.DEBUGGING)
 | |
|       System.err.println("Flushing stored block "+ stored_len);
 | |
|     pending.writeBits((DeflaterConstants.STORED_BLOCK << 1)
 | |
|                       + (lastBlock ? 1 : 0), 3);
 | |
|     pending.alignToByte();
 | |
|     pending.writeShort(stored_len);
 | |
|     pending.writeShort(~stored_len);
 | |
|     pending.writeBlock(stored, stored_offset, stored_len);
 | |
|     reset();
 | |
|   }
 | |
| 
 | |
|   public void flushBlock(byte[] stored, int stored_offset, int stored_len,
 | |
|                          boolean lastBlock) {
 | |
|     literalTree.freqs[EOF_SYMBOL]++;
 | |
| 
 | |
|     /* Build trees */
 | |
|     literalTree.buildTree();
 | |
|     distTree.buildTree();
 | |
| 
 | |
|     /* Calculate bitlen frequency */
 | |
|     literalTree.calcBLFreq(blTree);
 | |
|     distTree.calcBLFreq(blTree);
 | |
| 
 | |
|     /* Build bitlen tree */
 | |
|     blTree.buildTree();
 | |
| 
 | |
|     int blTreeCodes = 4;
 | |
|     for (int i = 18; i > blTreeCodes; i--)
 | |
|       {
 | |
|         if (blTree.length[BL_ORDER[i]] > 0)
 | |
|           blTreeCodes = i+1;
 | |
|       }
 | |
|     int opt_len = 14 + blTreeCodes * 3 + blTree.getEncodedLength()
 | |
|       + literalTree.getEncodedLength() + distTree.getEncodedLength()
 | |
|       + extra_bits;
 | |
| 
 | |
|     int static_len = extra_bits;
 | |
|     for (int i = 0; i < LITERAL_NUM; i++)
 | |
|       static_len += literalTree.freqs[i] * staticLLength[i];
 | |
|     for (int i = 0; i < DIST_NUM; i++)
 | |
|       static_len += distTree.freqs[i] * staticDLength[i];
 | |
|     if (opt_len >= static_len)
 | |
|       {
 | |
|         /* Force static trees */
 | |
|         opt_len = static_len;
 | |
|       }
 | |
| 
 | |
|     if (stored_offset >= 0 && stored_len+4 < opt_len >> 3)
 | |
|       {
 | |
|         /* Store Block */
 | |
|         if (DeflaterConstants.DEBUGGING)
 | |
|           System.err.println("Storing, since " + stored_len + " < " + opt_len
 | |
|                              + " <= " + static_len);
 | |
|         flushStoredBlock(stored, stored_offset, stored_len, lastBlock);
 | |
|       }
 | |
|     else if (opt_len == static_len)
 | |
|       {
 | |
|         /* Encode with static tree */
 | |
|         pending.writeBits((DeflaterConstants.STATIC_TREES << 1)
 | |
|                           + (lastBlock ? 1 : 0), 3);
 | |
|         literalTree.setStaticCodes(staticLCodes, staticLLength);
 | |
|         distTree.setStaticCodes(staticDCodes, staticDLength);
 | |
|         compressBlock();
 | |
|         reset();
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         /* Encode with dynamic tree */
 | |
|         pending.writeBits((DeflaterConstants.DYN_TREES << 1)
 | |
|                           + (lastBlock ? 1 : 0), 3);
 | |
|         sendAllTrees(blTreeCodes);
 | |
|         compressBlock();
 | |
|         reset();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public final boolean isFull()
 | |
|   {
 | |
|     return last_lit == BUFSIZE;
 | |
|   }
 | |
| 
 | |
|   public final boolean tallyLit(int lit)
 | |
|   {
 | |
|     if (DeflaterConstants.DEBUGGING)
 | |
|       {
 | |
|         if (lit > 32 && lit < 127)
 | |
|           System.err.println("("+(char)lit+")");
 | |
|         else
 | |
|           System.err.println("{"+lit+"}");
 | |
|       }
 | |
|     d_buf[last_lit] = 0;
 | |
|     l_buf[last_lit++] = (byte) lit;
 | |
|     literalTree.freqs[lit]++;
 | |
|     return last_lit == BUFSIZE;
 | |
|   }
 | |
| 
 | |
|   public final boolean tallyDist(int dist, int len)
 | |
|   {
 | |
|     if (DeflaterConstants.DEBUGGING)
 | |
|       System.err.println("["+dist+","+len+"]");
 | |
| 
 | |
|     d_buf[last_lit] = (short) dist;
 | |
|     l_buf[last_lit++] = (byte) (len - 3);
 | |
| 
 | |
|     int lc = l_code(len-3);
 | |
|     literalTree.freqs[lc]++;
 | |
|     if (lc >= 265 && lc < 285)
 | |
|       extra_bits += (lc - 261) / 4;
 | |
| 
 | |
|     int dc = d_code(dist-1);
 | |
|     distTree.freqs[dc]++;
 | |
|     if (dc >= 4)
 | |
|       extra_bits += dc / 2 - 1;
 | |
|     return last_lit == BUFSIZE;
 | |
|   }
 | |
| }
 |