InflaterHuffmanTree.cs 4.7 KB

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