| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 | using System;using ICSharpCode.SharpZipLib.Zip.Compression.Streams;namespace ICSharpCode.SharpZipLib.Zip.Compression{	/// <summary>	/// Huffman tree used for inflation	/// </summary>	public class InflaterHuffmanTree	{		#region Constants		const int MAX_BITLEN = 15;		#endregion		#region Instance Fields		short[] tree;		#endregion		/// <summary>		/// Literal length tree		/// </summary>		public static InflaterHuffmanTree defLitLenTree;		/// <summary>		/// Distance tree		/// </summary>		public static InflaterHuffmanTree defDistTree;		static InflaterHuffmanTree()		{			try {				byte[] codeLengths = new byte[288];				int i = 0;				while (i < 144) {					codeLengths[i++] = 8;				}				while (i < 256) {					codeLengths[i++] = 9;				}				while (i < 280) {					codeLengths[i++] = 7;				}				while (i < 288) {					codeLengths[i++] = 8;				}				defLitLenTree = new InflaterHuffmanTree(codeLengths);				codeLengths = new byte[32];				i = 0;				while (i < 32) {					codeLengths[i++] = 5;				}				defDistTree = new InflaterHuffmanTree(codeLengths);			} catch (Exception) {				throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");			}		}		#region Constructors		/// <summary>		/// Constructs a Huffman tree from the array of code lengths.		/// </summary>		/// <param name = "codeLengths">		/// the array of code lengths		/// </param>		public InflaterHuffmanTree(byte[] codeLengths)		{			BuildTree(codeLengths);		}		#endregion		void BuildTree(byte[] codeLengths)		{			int[] blCount = new int[MAX_BITLEN + 1];			int[] nextCode = new int[MAX_BITLEN + 1];			for (int i = 0; i < codeLengths.Length; i++) {				int bits = codeLengths[i];				if (bits > 0) {					blCount[bits]++;				}			}			int code = 0;			int treeSize = 512;			for (int bits = 1; bits <= MAX_BITLEN; bits++) {				nextCode[bits] = code;				code += blCount[bits] << (16 - bits);				if (bits >= 10) {					/* We need an extra table for bit lengths >= 10. */					int start = nextCode[bits] & 0x1ff80;					int end = code & 0x1ff80;					treeSize += (end - start) >> (16 - bits);				}			}			/* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g						if (code != 65536) 						{							throw new SharpZipBaseException("Code lengths don't add up properly.");						}			*/			/* Now create and fill the extra tables from longest to shortest			* bit len.  This way the sub trees will be aligned.			*/			tree = new short[treeSize];			int treePtr = 512;			for (int bits = MAX_BITLEN; bits >= 10; bits--) {				int end = code & 0x1ff80;				code -= blCount[bits] << (16 - bits);				int start = code & 0x1ff80;				for (int i = start; i < end; i += 1 << 7) {					tree[DeflaterHuffman.BitReverse(i)] = (short)((-treePtr << 4) | bits);					treePtr += 1 << (bits - 9);				}			}			for (int i = 0; i < codeLengths.Length; i++) {				int bits = codeLengths[i];				if (bits == 0) {					continue;				}				code = nextCode[bits];				int revcode = DeflaterHuffman.BitReverse(code);				if (bits <= 9) {					do {						tree[revcode] = (short)((i << 4) | bits);						revcode += 1 << bits;					} while (revcode < 512);				} else {					int subTree = tree[revcode & 511];					int treeLen = 1 << (subTree & 15);					subTree = -(subTree >> 4);					do {						tree[subTree | (revcode >> 9)] = (short)((i << 4) | bits);						revcode += 1 << bits;					} while (revcode < treeLen);				}				nextCode[bits] = code + (1 << (16 - bits));			}		}		/// <summary>		/// Reads the next symbol from input.  The symbol is encoded using the		/// huffman tree.		/// </summary>		/// <param name="input">		/// input the input source.		/// </param>		/// <returns>		/// the next symbol, or -1 if not enough input is available.		/// </returns>		public int GetSymbol(StreamManipulator input)		{			int lookahead, symbol;			if ((lookahead = input.PeekBits(9)) >= 0) {				if ((symbol = tree[lookahead]) >= 0) {					input.DropBits(symbol & 15);					return symbol >> 4;				}				int subtree = -(symbol >> 4);				int bitlen = symbol & 15;				if ((lookahead = input.PeekBits(bitlen)) >= 0) {					symbol = tree[subtree | (lookahead >> 9)];					input.DropBits(symbol & 15);					return symbol >> 4;				} else {					int bits = input.AvailableBits;					lookahead = input.PeekBits(bits);					symbol = tree[subtree | (lookahead >> 9)];					if ((symbol & 15) <= bits) {						input.DropBits(symbol & 15);						return symbol >> 4;					} else {						return -1;					}				}			} else {				int bits = input.AvailableBits;				lookahead = input.PeekBits(bits);				symbol = tree[lookahead];				if (symbol >= 0 && (symbol & 15) <= bits) {					input.DropBits(symbol & 15);					return symbol >> 4;				} else {					return -1;				}			}		}	}}
 |