PageRenderTime 83ms CodeModel.GetById 40ms app.highlight 11ms RepoModel.GetById 29ms app.codeStats 0ms

/Utilities/Compression/Inflaters/InflaterHuffmanTree.cs

#
C# | 259 lines | 191 code | 19 blank | 49 comment | 23 complexity | eff5f103efb7fcdcb2f38cdff32faaaa MD5 | raw file
  1// Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
  2// Authors of the original java version: Jochen Hoenicke, John Leuner
  3// See http://www.ISeeSharpCode.com for more information.
  4
  5using System;
  6using Delta.Utilities.Compression.Deflaters;
  7using Delta.Utilities.Compression.Streams;
  8
  9namespace Delta.Utilities.Compression.Inflaters
 10{
 11	/// <summary>
 12	/// Huffman tree used for inflation
 13	/// </summary>
 14	public class InflaterHuffmanTree
 15	{
 16		#region Constants
 17		/// <summary>
 18		/// Maximum bit length
 19		/// </summary>
 20		private const int MaximumBitLength = 15;
 21		#endregion
 22
 23		#region defLitLenTree (Static)
 24		/// <summary>
 25		/// Literal length tree
 26		/// </summary>
 27		public static InflaterHuffmanTree defLitLenTree;
 28		#endregion
 29
 30		#region defDistTree (Static)
 31		/// <summary>
 32		/// Distance tree
 33		/// </summary>
 34		public static InflaterHuffmanTree defDistTree;
 35		#endregion
 36
 37		#region Private
 38
 39		#region tree (Private)
 40		/// <summary>
 41		/// Tree
 42		/// </summary>
 43		private short[] tree;
 44		#endregion
 45
 46		#endregion
 47
 48		#region Constructors
 49		/// <summary>
 50		/// Create inflater huffman tree
 51		/// </summary>
 52		static InflaterHuffmanTree()
 53		{
 54			try
 55			{
 56				byte[] codeLengths = new byte[288];
 57				int i = 0;
 58				while (i < 144)
 59				{
 60					codeLengths[i++] = 8;
 61				} // while (i)
 62				while (i < 256)
 63				{
 64					codeLengths[i++] = 9;
 65				} // while (i)
 66				while (i < 280)
 67				{
 68					codeLengths[i++] = 7;
 69				} // while (i)
 70				while (i < 288)
 71				{
 72					codeLengths[i++] = 8;
 73				} // while (i)
 74				defLitLenTree = new InflaterHuffmanTree(codeLengths);
 75
 76				codeLengths = new byte[32];
 77				i = 0;
 78				while (i < 32)
 79				{
 80					codeLengths[i++] = 5;
 81				} // while (i)
 82				defDistTree = new InflaterHuffmanTree(codeLengths);
 83			} // try
 84			catch (Exception)
 85			{
 86				throw new CompressionException(
 87					"InflaterHuffmanTree: static tree length illegal");
 88			} // catch (Exception)
 89		}
 90
 91		/// <summary>
 92		/// Constructs a Huffman tree from the array of code lengths.
 93		/// </summary>
 94		/// <param name = "codeLengths">
 95		/// the array of code lengths
 96		/// </param>
 97		public InflaterHuffmanTree(byte[] codeLengths)
 98		{
 99			BuildTree(codeLengths);
100		}
101		#endregion
102
103		#region GetSymbol (Public)
104		/// <summary>
105		/// Reads the next symbol from input.  The symbol is encoded using the
106		/// huffman tree.
107		/// </summary>
108		/// <param name="input">
109		/// input the input source.
110		/// </param>
111		/// <returns>
112		/// the next symbol, or -1 if not enough input is available.
113		/// </returns>
114		public int GetSymbol(StreamManipulator input)
115		{
116			int lookahead, symbol;
117			if ((lookahead = input.PeekBits(9)) >= 0)
118			{
119				if ((symbol = tree[lookahead]) >= 0)
120				{
121					input.DropBits(symbol & 15);
122					return symbol >> 4;
123				} // if (symbol)
124				int subtree = -(symbol >> 4);
125				int bitlen = symbol & 15;
126				if ((lookahead = input.PeekBits(bitlen)) >= 0)
127				{
128					symbol = tree[subtree | (lookahead >> 9)];
129					input.DropBits(symbol & 15);
130					return symbol >> 4;
131				} // if (lookahead)
132				else
133				{
134					int bits = input.AvailableBits;
135					lookahead = input.PeekBits(bits);
136					symbol = tree[subtree | (lookahead >> 9)];
137					if ((symbol & 15) <= bits)
138					{
139						input.DropBits(symbol & 15);
140						return symbol >> 4;
141					} // if (symbol)
142					else
143					{
144						return -1;
145					} // else
146				} // else
147			} // if (lookahead)
148			else
149			{
150				int bits = input.AvailableBits;
151				lookahead = input.PeekBits(bits);
152				symbol = tree[lookahead];
153				if (symbol >= 0 && (symbol & 15) <= bits)
154				{
155					input.DropBits(symbol & 15);
156					return symbol >> 4;
157				} // if (symbol)
158				else
159				{
160					return -1;
161				} // else
162			} // else
163		}
164		#endregion
165
166		#region Methods (Private)
167
168		#region BuildTree
169		/// <summary>
170		/// Build tree
171		/// </summary>
172		/// <param name="codeLengths">Code lengths</param>
173		private void BuildTree(byte[] codeLengths)
174		{
175			int[] blCount = new int[MaximumBitLength + 1];
176			int[] nextCode = new int[MaximumBitLength + 1];
177
178			for (int i = 0; i < codeLengths.Length; i++)
179			{
180				int bits = codeLengths[i];
181				if (bits > 0)
182				{
183					blCount[bits]++;
184				} // if (bits)
185			} // for (int)
186
187			int code = 0;
188			int treeSize = 512;
189			for (int bits = 1; bits <= MaximumBitLength; bits++)
190			{
191				nextCode[bits] = code;
192				code += blCount[bits] << (16 - bits);
193				if (bits >= 10)
194				{
195					/* We need an extra table for bit lengths >= 10. */
196					int start = nextCode[bits] & 0x1ff80;
197					int end = code & 0x1ff80;
198					treeSize += (end - start) >> (16 - bits);
199				} // if (bits)
200			} // for (bits)
201
202			// -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
203			//if (code != 65536) 
204			//{
205			//	throw new CompressionException("Code lengths don't add up properly.");
206			//}
207
208			// Now create and fill the extra tables from longest to shortest
209			// bit len.  This way the sub trees will be aligned.
210			tree = new short[treeSize];
211			int treePtr = 512;
212			for (int bits = MaximumBitLength; bits >= 10; bits--)
213			{
214				int end = code & 0x1ff80;
215				code -= blCount[bits] << (16 - bits);
216				int start = code & 0x1ff80;
217				for (int i = start; i < end; i += 1 << 7)
218				{
219					tree[DeflaterHuffman.BitReverse(i)] = (short)((-treePtr << 4) | bits);
220					treePtr += 1 << (bits - 9);
221				} // for (int)
222			} // for (bits)
223
224			for (int i = 0; i < codeLengths.Length; i++)
225			{
226				int bits = codeLengths[i];
227				if (bits == 0)
228				{
229					continue;
230				} // if (bits)
231				code = nextCode[bits];
232				int revcode = DeflaterHuffman.BitReverse(code);
233				if (bits <= 9)
234				{
235					do
236					{
237						tree[revcode] = (short)((i << 4) | bits);
238						revcode += 1 << bits;
239					} while (revcode < 512);
240				} // if (bits)
241				else
242				{
243					int subTree = tree[revcode & 511];
244					int treeLen = 1 << (subTree & 15);
245					subTree = -(subTree >> 4);
246					do
247					{
248						tree[subTree | (revcode >> 9)] = (short)((i << 4) | bits);
249						revcode += 1 << bits;
250					} while (revcode < treeLen);
251				} // else
252				nextCode[bits] = code + (1 << (16 - bits));
253			} // for (int)
254		}
255		#endregion
256
257		#endregion
258	}
259}