InflaterHuffmanTree.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // InflaterHuffmanTree.cs
  2. // Copyright (C) 2001 Mike Krueger
  3. //
  4. // This file was translated from java, it was part of the GNU Classpath
  5. // Copyright (C) 2001 Free Software Foundation, Inc.
  6. //
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU General Public License
  9. // as published by the Free Software Foundation; either version 2
  10. // of the License, or (at your option) any later version.
  11. //
  12. // This program is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. // GNU General Public License for more details.
  16. //
  17. // You should have received a copy of the GNU General Public License
  18. // along with this program; if not, write to the Free Software
  19. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. //
  21. // Linking this library statically or dynamically with other modules is
  22. // making a combined work based on this library. Thus, the terms and
  23. // conditions of the GNU General Public License cover the whole
  24. // combination.
  25. //
  26. // As a special exception, the copyright holders of this library give you
  27. // permission to link this library with independent modules to produce an
  28. // executable, regardless of the license terms of these independent
  29. // modules, and to copy and distribute the resulting executable under
  30. // terms of your choice, provided that you also meet, for each linked
  31. // independent module, the terms and conditions of the license of that
  32. // module. An independent module is a module which is not derived from
  33. // or based on this library. If you modify this library, you may extend
  34. // this exception to your version of the library, but you are not
  35. // obligated to do so. If you do not wish to do so, delete this
  36. // exception statement from your version.
  37. using System;
  38. using CommonMPQ.SharpZipLib.Zip.Compression.Streams;
  39. namespace CommonMPQ.SharpZipLib.Zip.Compression
  40. {
  41. /// <summary>
  42. /// Huffman tree used for inflation
  43. /// </summary>
  44. public class InflaterHuffmanTree
  45. {
  46. #region Constants
  47. const int MAX_BITLEN = 15;
  48. #endregion
  49. #region Instance Fields
  50. short[] tree;
  51. #endregion
  52. /// <summary>
  53. /// Literal length tree
  54. /// </summary>
  55. public static InflaterHuffmanTree defLitLenTree;
  56. /// <summary>
  57. /// Distance tree
  58. /// </summary>
  59. public static InflaterHuffmanTree defDistTree;
  60. static InflaterHuffmanTree()
  61. {
  62. try {
  63. byte[] codeLengths = new byte[288];
  64. int i = 0;
  65. while (i < 144) {
  66. codeLengths[i++] = 8;
  67. }
  68. while (i < 256) {
  69. codeLengths[i++] = 9;
  70. }
  71. while (i < 280) {
  72. codeLengths[i++] = 7;
  73. }
  74. while (i < 288) {
  75. codeLengths[i++] = 8;
  76. }
  77. defLitLenTree = new InflaterHuffmanTree(codeLengths);
  78. codeLengths = new byte[32];
  79. i = 0;
  80. while (i < 32) {
  81. codeLengths[i++] = 5;
  82. }
  83. defDistTree = new InflaterHuffmanTree(codeLengths);
  84. } catch (Exception) {
  85. throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal");
  86. }
  87. }
  88. #region Constructors
  89. /// <summary>
  90. /// Constructs a Huffman tree from the array of code lengths.
  91. /// </summary>
  92. /// <param name = "codeLengths">
  93. /// the array of code lengths
  94. /// </param>
  95. public InflaterHuffmanTree(byte[] codeLengths)
  96. {
  97. BuildTree(codeLengths);
  98. }
  99. #endregion
  100. void BuildTree(byte[] codeLengths)
  101. {
  102. int[] blCount = new int[MAX_BITLEN + 1];
  103. int[] nextCode = new int[MAX_BITLEN + 1];
  104. for (int i = 0; i < codeLengths.Length; i++) {
  105. int bits = codeLengths[i];
  106. if (bits > 0) {
  107. blCount[bits]++;
  108. }
  109. }
  110. int code = 0;
  111. int treeSize = 512;
  112. for (int bits = 1; bits <= MAX_BITLEN; bits++) {
  113. nextCode[bits] = code;
  114. code += blCount[bits] << (16 - bits);
  115. if (bits >= 10) {
  116. /* We need an extra table for bit lengths >= 10. */
  117. int start = nextCode[bits] & 0x1ff80;
  118. int end = code & 0x1ff80;
  119. treeSize += (end - start) >> (16 - bits);
  120. }
  121. }
  122. /* -jr comment this out! doesnt work for dynamic trees and pkzip 2.04g
  123. if (code != 65536)
  124. {
  125. throw new SharpZipBaseException("Code lengths don't add up properly.");
  126. }
  127. */
  128. /* Now create and fill the extra tables from longest to shortest
  129. * bit len. This way the sub trees will be aligned.
  130. */
  131. tree = new short[treeSize];
  132. int treePtr = 512;
  133. for (int bits = MAX_BITLEN; bits >= 10; bits--) {
  134. int end = code & 0x1ff80;
  135. code -= blCount[bits] << (16 - bits);
  136. int start = code & 0x1ff80;
  137. for (int i = start; i < end; i += 1 << 7) {
  138. tree[DeflaterHuffman.BitReverse(i)] = (short) ((-treePtr << 4) | bits);
  139. treePtr += 1 << (bits-9);
  140. }
  141. }
  142. for (int i = 0; i < codeLengths.Length; i++) {
  143. int bits = codeLengths[i];
  144. if (bits == 0) {
  145. continue;
  146. }
  147. code = nextCode[bits];
  148. int revcode = DeflaterHuffman.BitReverse(code);
  149. if (bits <= 9) {
  150. do {
  151. tree[revcode] = (short) ((i << 4) | bits);
  152. revcode += 1 << bits;
  153. } while (revcode < 512);
  154. } else {
  155. int subTree = tree[revcode & 511];
  156. int treeLen = 1 << (subTree & 15);
  157. subTree = -(subTree >> 4);
  158. do {
  159. tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
  160. revcode += 1 << bits;
  161. } while (revcode < treeLen);
  162. }
  163. nextCode[bits] = code + (1 << (16 - bits));
  164. }
  165. }
  166. /// <summary>
  167. /// Reads the next symbol from input. The symbol is encoded using the
  168. /// huffman tree.
  169. /// </summary>
  170. /// <param name="input">
  171. /// input the input source.
  172. /// </param>
  173. /// <returns>
  174. /// the next symbol, or -1 if not enough input is available.
  175. /// </returns>
  176. public int GetSymbol(StreamManipulator input)
  177. {
  178. int lookahead, symbol;
  179. if ((lookahead = input.PeekBits(9)) >= 0) {
  180. if ((symbol = tree[lookahead]) >= 0) {
  181. input.DropBits(symbol & 15);
  182. return symbol >> 4;
  183. }
  184. int subtree = -(symbol >> 4);
  185. int bitlen = symbol & 15;
  186. if ((lookahead = input.PeekBits(bitlen)) >= 0) {
  187. symbol = tree[subtree | (lookahead >> 9)];
  188. input.DropBits(symbol & 15);
  189. return symbol >> 4;
  190. } else {
  191. int bits = input.AvailableBits;
  192. lookahead = input.PeekBits(bits);
  193. symbol = tree[subtree | (lookahead >> 9)];
  194. if ((symbol & 15) <= bits) {
  195. input.DropBits(symbol & 15);
  196. return symbol >> 4;
  197. } else {
  198. return -1;
  199. }
  200. }
  201. } else {
  202. int bits = input.AvailableBits;
  203. lookahead = input.PeekBits(bits);
  204. symbol = tree[lookahead];
  205. if (symbol >= 0 && (symbol & 15) <= bits) {
  206. input.DropBits(symbol & 15);
  207. return symbol >> 4;
  208. } else {
  209. return -1;
  210. }
  211. }
  212. }
  213. }
  214. }