InflaterHuffmanTree.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace ICSharpCode.SharpZipLib.Zip.Compression
  5. {
  6. /// <summary>
  7. /// Huffman tree used for inflation
  8. /// </summary>
  9. public class InflaterHuffmanTree
  10. {
  11. #region Constants
  12. private const int MAX_BITLEN = 15;
  13. #endregion Constants
  14. #region Instance Fields
  15. private short[] tree;
  16. #endregion Instance Fields
  17. /// <summary>
  18. /// Literal length tree
  19. /// </summary>
  20. public static InflaterHuffmanTree defLitLenTree;
  21. /// <summary>
  22. /// Distance tree
  23. /// </summary>
  24. public static InflaterHuffmanTree defDistTree;
  25. static InflaterHuffmanTree()
  26. {
  27. try
  28. {
  29. byte[] codeLengths = new byte[288];
  30. int i = 0;
  31. while (i < 144)
  32. {
  33. codeLengths[i++] = 8;
  34. }
  35. while (i < 256)
  36. {
  37. codeLengths[i++] = 9;
  38. }
  39. while (i < 280)
  40. {
  41. codeLengths[i++] = 7;
  42. }
  43. while (i < 288)
  44. {
  45. codeLengths[i++] = 8;
  46. }
  47. defLitLenTree = new InflaterHuffmanTree(codeLengths);
  48. codeLengths = new byte[32];
  49. i = 0;
  50. while (i < 32)
  51. {
  52. codeLengths[i++] = 5;
  53. }
  54. defDistTree = new InflaterHuffmanTree(codeLengths);
  55. }
  56. catch (Exception)
  57. {
  58. throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");
  59. }
  60. }
  61. #region Constructors
  62. /// <summary>
  63. /// Constructs a Huffman tree from the array of code lengths.
  64. /// </summary>
  65. /// <param name = "codeLengths">
  66. /// the array of code lengths
  67. /// </param>
  68. public InflaterHuffmanTree(IList<byte> codeLengths)
  69. {
  70. BuildTree(codeLengths);
  71. }
  72. #endregion Constructors
  73. private void BuildTree(IList<byte> codeLengths)
  74. {
  75. int[] blCount = new int[MAX_BITLEN + 1];
  76. int[] nextCode = new int[MAX_BITLEN + 1];
  77. for (int i = 0; i < codeLengths.Count; i++)
  78. {
  79. int bits = codeLengths[i];
  80. if (bits > 0)
  81. {
  82. blCount[bits]++;
  83. }
  84. }
  85. int code = 0;
  86. int treeSize = 512;
  87. for (int bits = 1; bits <= MAX_BITLEN; bits++)
  88. {
  89. nextCode[bits] = code;
  90. code += blCount[bits] << (16 - bits);
  91. if (bits >= 10)
  92. {
  93. /* We need an extra table for bit lengths >= 10. */
  94. int start = nextCode[bits] & 0x1ff80;
  95. int end = code & 0x1ff80;
  96. treeSize += (end - start) >> (16 - bits);
  97. }
  98. }
  99. /* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
  100. if (code != 65536)
  101. {
  102. throw new SharpZipBaseException("Code lengths don't add up properly.");
  103. }
  104. */
  105. /* Now create and fill the extra tables from longest to shortest
  106. * bit len. This way the sub trees will be aligned.
  107. */
  108. tree = new short[treeSize];
  109. int treePtr = 512;
  110. for (int bits = MAX_BITLEN; bits >= 10; bits--)
  111. {
  112. int end = code & 0x1ff80;
  113. code -= blCount[bits] << (16 - bits);
  114. int start = code & 0x1ff80;
  115. for (int i = start; i < end; i += 1 << 7)
  116. {
  117. tree[DeflaterHuffman.BitReverse(i)] = (short)((-treePtr << 4) | bits);
  118. treePtr += 1 << (bits - 9);
  119. }
  120. }
  121. for (int i = 0; i < codeLengths.Count; i++)
  122. {
  123. int bits = codeLengths[i];
  124. if (bits == 0)
  125. {
  126. continue;
  127. }
  128. code = nextCode[bits];
  129. int revcode = DeflaterHuffman.BitReverse(code);
  130. if (bits <= 9)
  131. {
  132. do
  133. {
  134. tree[revcode] = (short)((i << 4) | bits);
  135. revcode += 1 << bits;
  136. } while (revcode < 512);
  137. }
  138. else
  139. {
  140. int subTree = tree[revcode & 511];
  141. int treeLen = 1 << (subTree & 15);
  142. subTree = -(subTree >> 4);
  143. do
  144. {
  145. tree[subTree | (revcode >> 9)] = (short)((i << 4) | bits);
  146. revcode += 1 << bits;
  147. } while (revcode < treeLen);
  148. }
  149. nextCode[bits] = code + (1 << (16 - bits));
  150. }
  151. }
  152. /// <summary>
  153. /// Reads the next symbol from input. The symbol is encoded using the
  154. /// huffman tree.
  155. /// </summary>
  156. /// <param name="input">
  157. /// input the input source.
  158. /// </param>
  159. /// <returns>
  160. /// the next symbol, or -1 if not enough input is available.
  161. /// </returns>
  162. public int GetSymbol(StreamManipulator input)
  163. {
  164. int lookahead, symbol;
  165. if ((lookahead = input.PeekBits(9)) >= 0)
  166. {
  167. symbol = tree[lookahead];
  168. int bitlen = symbol & 15;
  169. if (symbol >= 0)
  170. {
  171. if(bitlen == 0){
  172. throw new SharpZipBaseException("Encountered invalid codelength 0");
  173. }
  174. input.DropBits(bitlen);
  175. return symbol >> 4;
  176. }
  177. int subtree = -(symbol >> 4);
  178. if ((lookahead = input.PeekBits(bitlen)) >= 0)
  179. {
  180. symbol = tree[subtree | (lookahead >> 9)];
  181. input.DropBits(symbol & 15);
  182. return symbol >> 4;
  183. }
  184. else
  185. {
  186. int bits = input.AvailableBits;
  187. lookahead = input.PeekBits(bits);
  188. symbol = tree[subtree | (lookahead >> 9)];
  189. if ((symbol & 15) <= bits)
  190. {
  191. input.DropBits(symbol & 15);
  192. return symbol >> 4;
  193. }
  194. else
  195. {
  196. return -1;
  197. }
  198. }
  199. }
  200. else // Less than 9 bits
  201. {
  202. int bits = input.AvailableBits;
  203. lookahead = input.PeekBits(bits);
  204. symbol = tree[lookahead];
  205. if (symbol >= 0 && (symbol & 15) <= bits)
  206. {
  207. input.DropBits(symbol & 15);
  208. return symbol >> 4;
  209. }
  210. else
  211. {
  212. return -1;
  213. }
  214. }
  215. }
  216. }
  217. }