diff Zip/Compression/DeflaterHuffman.cs @ 1:94e25b786321

Re #311: can't read ZIP file packed by Linux app Archive Manager/File Roller Initial commit of clean SharpZipLib 0860 source. Only change is build paths.
author IBBoard <dev@ibboard.co.uk>
date Sat, 30 Oct 2010 14:03:17 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Zip/Compression/DeflaterHuffman.cs	Sat Oct 30 14:03:17 2010 +0000
@@ -0,0 +1,908 @@
+// DeflaterHuffman.cs
+//
+// Copyright (C) 2001 Mike Krueger
+// Copyright (C) 2004 John Reilly
+//
+// This file was translated from java, it was part of the GNU Classpath
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program 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
+// of the License, or (at your option) any later version.
+//
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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.
+
+using System;
+
+namespace ICSharpCode.SharpZipLib.Zip.Compression 
+{
+	
+	/// <summary>
+	/// 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 of the original java version : Jochen Hoenicke
+	/// </summary>
+	public class DeflaterHuffman
+	{
+		const  int BUFSIZE = 1 << (DeflaterConstants.DEFAULT_MEM_LEVEL + 6);
+		const  int LITERAL_NUM = 286;
+
+		// Number of distance codes
+		const  int DIST_NUM = 30;
+		// Number of codes used to transfer bit lengths
+		const  int BITLEN_NUM = 19;
+
+		// repeat previous bit length 3-6 times (2 bits of repeat count)
+		const  int REP_3_6    = 16;
+		// repeat a zero length 3-10 times  (3 bits of repeat count)
+		const  int REP_3_10   = 17;
+		// repeat a zero length 11-138 times  (7 bits of repeat count)
+		const  int REP_11_138 = 18;
+
+		const  int EOF_SYMBOL = 256;
+
+		// The lengths of the bit length codes are sent in order of decreasing
+ 		// probability, to avoid transmitting the lengths for unused bit length codes.
+		static readonly int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+		
+		static readonly byte[] bit4Reverse = {
+			0,
+			8,
+			4,
+			12,
+			2,
+			10,
+			6,
+			14,
+			1,
+			9,
+			5,
+			13,
+			3,
+			11,
+			7,
+			15
+		};
+
+		static short[] staticLCodes;
+		static byte[]  staticLLength;
+		static short[] staticDCodes;
+		static byte[]  staticDLength;
+		
+		class Tree 
+		{
+			#region Instance Fields
+			public short[] freqs;
+			
+			public byte[]  length;
+			
+			public int     minNumCodes;
+			
+			public int     numCodes;
+			
+			short[] codes;
+			int[]   bl_counts;
+			int     maxLength;
+			DeflaterHuffman dh;
+			#endregion
+
+			#region Constructors
+			public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength) 
+			{
+				this.dh =  dh;
+				this.minNumCodes = minCodes;
+				this.maxLength  = maxLength;
+				freqs  = new short[elems];
+				bl_counts = new int[maxLength];
+			}
+			
+			#endregion
+
+			/// <summary>
+			/// Resets the internal state of the tree
+			/// </summary>
+			public void Reset() 
+			{
+				for (int i = 0; i < freqs.Length; i++) {
+					freqs[i] = 0;
+				}
+				codes = null;
+				length = null;
+			}
+			
+			public void WriteSymbol(int code)
+			{
+				//				if (DeflaterConstants.DEBUGGING) {
+				//					freqs[code]--;
+				//					//  	  Console.Write("writeSymbol("+freqs.length+","+code+"): ");
+				//				}
+				dh.pending.WriteBits(codes[code] & 0xffff, length[code]);
+			}
+			
+			/// <summary>
+			/// Check that all frequencies are zero
+			/// </summary>
+			/// <exception cref="SharpZipBaseException">
+			/// At least one frequency is non-zero
+			/// </exception>
+			public void CheckEmpty()
+			{
+				bool empty = true;
+				for (int i = 0; i < freqs.Length; i++) {
+					if (freqs[i] != 0) {
+						//Console.WriteLine("freqs[" + i + "] == " + freqs[i]);
+						empty = false;
+					}
+				}
+				
+				if (!empty) {
+					throw new SharpZipBaseException("!Empty");
+				}
+			}
+
+			/// <summary>
+			/// Set static codes and length
+			/// </summary>
+			/// <param name="staticCodes">new codes</param>
+			/// <param name="staticLengths">length for new codes</param>
+			public void SetStaticCodes(short[] staticCodes, byte[] staticLengths)
+			{
+				codes = staticCodes;
+				length = staticLengths;
+			}
+			
+			/// <summary>
+			/// Build dynamic codes and lengths
+			/// </summary>
+			public void BuildCodes() 
+			{
+				int numSymbols = freqs.Length;
+				int[] nextCode = new int[maxLength];
+				int code = 0;
+
+				codes = new short[freqs.Length];
+				
+				//				if (DeflaterConstants.DEBUGGING) {
+				//					//Console.WriteLine("buildCodes: "+freqs.Length);
+				//				}
+				
+				for (int bits = 0; bits < maxLength; bits++) {
+					nextCode[bits] = code;
+					code += bl_counts[bits] << (15 - bits);
+
+					//					if (DeflaterConstants.DEBUGGING) {
+					//						//Console.WriteLine("bits: " + ( bits + 1) + " count: " + bl_counts[bits]
+					//						                  +" nextCode: "+code);
+					//					}
+				}
+
+#if DebugDeflation
+				if ( DeflaterConstants.DEBUGGING && (code != 65536) ) 
+				{
+					throw new SharpZipBaseException("Inconsistent bl_counts!");
+				}
+#endif				
+				for (int i=0; i < numCodes; i++) {
+					int bits = length[i];
+					if (bits > 0) {
+
+						//						if (DeflaterConstants.DEBUGGING) {
+						//								//Console.WriteLine("codes["+i+"] = rev(" + nextCode[bits-1]+"),
+						//								                  +bits);
+						//						}
+
+						codes[i] = BitReverse(nextCode[bits-1]);
+						nextCode[bits-1] += 1 << (16 - bits);
+					}
+				}
+			}
+			
+			public 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 SharpZipBaseException("Heap invariant violated");
+				}
+				
+				BuildLength(childs);
+			}
+			
+			/// <summary>
+			/// Get encoded length
+			/// </summary>
+			/// <returns>Encoded length, the sum of frequencies * lengths</returns>
+			public int GetEncodedLength()
+			{
+				int len = 0;
+				for (int i = 0; i < freqs.Length; i++) {
+					len += freqs[i] * length[i];
+				}
+				return len;
+			}
+			
+			/// <summary>
+			/// Scan a literal or distance tree to determine the frequencies of the codes
+			/// in the bit length tree.
+			/// </summary>
+			public 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] += (short)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]++;
+					}
+				}
+			}
+		
+			/// <summary>
+			/// Write tree values
+			/// </summary>
+			/// <param name="blTree">Tree to write</param>
+			public 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);
+						dh.pending.WriteBits(count - 3, 2);
+					} else if (count <= 10) {
+						blTree.WriteSymbol(REP_3_10);
+						dh.pending.WriteBits(count - 3, 3);
+					} else {
+						blTree.WriteSymbol(REP_11_138);
+						dh.pending.WriteBits(count - 11, 7);
+					}
+				}
+			}
+
+			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) {
+				//					//Console.WriteLine("Tree "+freqs.Length+" lengths:");
+				//					for (int i=0; i < numLeafs; i++) {
+				//						//Console.WriteLine("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
+					// number 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) {
+				//					//Console.WriteLine("*** After overflow elimination. ***");
+				//					for (int i=0; i < numLeafs; i++) {
+				//						//Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
+				//						                  + " len: "+length[childs[2*i]]);
+				//					}
+				//				}
+			}
+			
+		}
+
+		#region Instance Fields
+		/// <summary>
+		/// Pending buffer to use
+		/// </summary>
+		public DeflaterPending pending;
+		
+		Tree literalTree;
+		Tree distTree;
+		Tree blTree;
+		
+		// Buffer for distances
+		short[] d_buf;
+		byte[]  l_buf;
+		int last_lit;
+		int extra_bits;
+		#endregion
+
+		static DeflaterHuffman() 
+		{
+			// 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;
+			}
+			
+			// Distance 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;
+			}
+		}
+		
+		/// <summary>
+		/// Construct instance with pending buffer
+		/// </summary>
+		/// <param name="pending">Pending buffer to use</param>
+		public DeflaterHuffman(DeflaterPending pending)
+		{
+			this.pending = pending;
+			
+			literalTree = new Tree(this, LITERAL_NUM, 257, 15);
+			distTree    = new Tree(this, DIST_NUM, 1, 15);
+			blTree      = new Tree(this, BITLEN_NUM, 4, 7);
+			
+			d_buf = new short[BUFSIZE];
+			l_buf = new byte [BUFSIZE];
+		}
+
+		/// <summary>
+		/// Reset internal state
+		/// </summary>		
+		public void Reset() 
+		{
+			last_lit = 0;
+			extra_bits = 0;
+			literalTree.Reset();
+			distTree.Reset();
+			blTree.Reset();
+		}
+		
+		/// <summary>
+		/// Write all trees to pending buffer
+		/// </summary>
+		/// <param name="blTreeCodes">The number/rank of treecodes to send.</param>
+		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 DebugDeflation
+			if (DeflaterConstants.DEBUGGING) {
+				blTree.CheckEmpty();
+			}
+#endif
+		}
+
+		/// <summary>
+		/// Compress current buffer writing data to pending buffer
+		/// </summary>
+		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) {
+					//						Console.Write("["+(dist+1)+","+(litlen+3)+"]: ");
+					//					}
+					
+					int lc = Lcode(litlen);
+					literalTree.WriteSymbol(lc);
+					
+					int bits = (lc - 261) / 4;
+					if (bits > 0 && bits <= 5) {
+						pending.WriteBits(litlen & ((1 << bits) - 1), bits);
+					}
+					
+					int dc = Dcode(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) {
+					//							Console.Write("("+(char)litlen+"): ");
+					//						} else {
+					//							Console.Write("{"+litlen+"}: ");
+					//						}
+					//					}
+					literalTree.WriteSymbol(litlen);
+				}
+			}
+
+#if DebugDeflation
+			if (DeflaterConstants.DEBUGGING) {
+				Console.Write("EOF: ");
+			}
+#endif
+			literalTree.WriteSymbol(EOF_SYMBOL);
+
+#if DebugDeflation
+			if (DeflaterConstants.DEBUGGING) {
+				literalTree.CheckEmpty();
+				distTree.CheckEmpty();
+			}
+#endif
+		}
+		
+		/// <summary>
+		/// Flush block to output with no compression
+		/// </summary>
+		/// <param name="stored">Data to write</param>
+		/// <param name="storedOffset">Index of first byte to write</param>
+		/// <param name="storedLength">Count of bytes to write</param>
+		/// <param name="lastBlock">True if this is the last block</param>
+		public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
+		{
+#if DebugDeflation
+			//			if (DeflaterConstants.DEBUGGING) {
+			//				//Console.WriteLine("Flushing stored block "+ storedLength);
+			//			}
+#endif
+			pending.WriteBits((DeflaterConstants.STORED_BLOCK << 1) + (lastBlock ? 1 : 0), 3);
+			pending.AlignToByte();
+			pending.WriteShort(storedLength);
+			pending.WriteShort(~storedLength);
+			pending.WriteBlock(stored, storedOffset, storedLength);
+			Reset();
+		}
+
+		/// <summary>
+		/// Flush block to output with compression
+		/// </summary>		
+		/// <param name="stored">Data to flush</param>
+		/// <param name="storedOffset">Index of first byte to flush</param>
+		/// <param name="storedLength">Count of bytes to flush</param>
+		/// <param name="lastBlock">True if this is the last block</param>
+		public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool 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 (storedOffset >= 0 && storedLength + 4 < opt_len >> 3) {
+				// Store Block
+
+				//				if (DeflaterConstants.DEBUGGING) {
+				//					//Console.WriteLine("Storing, since " + storedLength + " < " + opt_len
+				//					                  + " <= " + static_len);
+				//				}
+				FlushStoredBlock(stored, storedOffset, storedLength, 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();
+			}
+		}
+		
+		/// <summary>
+		/// Get value indicating if internal buffer is full
+		/// </summary>
+		/// <returns>true if buffer is full</returns>
+		public bool IsFull()
+		{
+			return last_lit >= BUFSIZE;
+		}
+		
+		/// <summary>
+		/// Add literal to buffer
+		/// </summary>
+		/// <param name="literal">Literal value to add to buffer.</param>
+		/// <returns>Value indicating internal buffer is full</returns>
+		public bool TallyLit(int literal)
+		{
+			//			if (DeflaterConstants.DEBUGGING) {
+			//				if (lit > 32 && lit < 127) {
+			//					//Console.WriteLine("("+(char)lit+")");
+			//				} else {
+			//					//Console.WriteLine("{"+lit+"}");
+			//				}
+			//			}
+			d_buf[last_lit] = 0;
+			l_buf[last_lit++] = (byte)literal;
+			literalTree.freqs[literal]++;
+			return IsFull();
+		}
+		
+		/// <summary>
+		/// Add distance code and length to literal and distance trees
+		/// </summary>
+		/// <param name="distance">Distance code</param>
+		/// <param name="length">Length</param>
+		/// <returns>Value indicating if internal buffer is full</returns>
+		public bool TallyDist(int distance, int length)
+		{
+			//			if (DeflaterConstants.DEBUGGING) {
+			//				//Console.WriteLine("[" + distance + "," + length + "]");
+			//			}
+			
+			d_buf[last_lit]   = (short)distance;
+			l_buf[last_lit++] = (byte)(length - 3);
+			
+			int lc = Lcode(length - 3);
+			literalTree.freqs[lc]++;
+			if (lc >= 265 && lc < 285) {
+				extra_bits += (lc - 261) / 4;
+			}
+			
+			int dc = Dcode(distance - 1);
+			distTree.freqs[dc]++;
+			if (dc >= 4) {
+				extra_bits += dc / 2 - 1;
+			}
+			return IsFull();
+		}
+
+		
+		/// <summary>
+		/// Reverse the bits of a 16 bit value.
+		/// </summary>
+		/// <param name="toReverse">Value to reverse bits</param>
+		/// <returns>Value with bits reversed</returns>
+		public static short BitReverse(int toReverse) 
+		{
+			return (short) (bit4Reverse[toReverse & 0xF] << 12 | 
+			                bit4Reverse[(toReverse >> 4) & 0xF] << 8 | 
+			                bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
+			                bit4Reverse[toReverse >> 12]);
+		}
+		
+		static int Lcode(int length) 
+		{
+			if (length == 255) {
+				return 285;
+			}
+			
+			int code = 257;
+			while (length >= 8) {
+				code += 4;
+				length >>= 1;
+			}
+			return code + length;
+		}
+		
+		static int Dcode(int distance) 
+		{
+			int code = 0;
+			while (distance >= 4) {
+				code += 2;
+				distance >>= 1;
+			}
+			return code + distance;
+		}
+	}
+}