PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/resources/Papervision3D_2.0.883/nochump/util/zip/Inflater.as

https://github.com/nunomorgadinho/Calamity
ActionScript | 262 lines | 166 code | 16 blank | 80 comment | 75 complexity | 74c5545a0c2123eaa04996d88437ce86 MD5 | raw file
  1. /*
  2. nochump.util.zip.Inflater
  3. Copyright (C) 2007 David Chang (dchang@nochump.com)
  4. This file is part of nochump.util.zip.
  5. nochump.util.zip is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. nochump.util.zip is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with Foobar. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. package nochump.util.zip {
  17. import flash.utils.Endian;
  18. import flash.utils.ByteArray;
  19. /**
  20. * Inflater is used to decompress data that has been compressed according
  21. * to the "deflate" standard described in rfc1950.
  22. *
  23. * The usage is as following. First you have to set some input with
  24. * <code>setInput()</code>, then inflate() it.
  25. *
  26. * This implementation is a port of Puff by Mark Addler that comes with
  27. * the zlip data compression library. It is not the fastest routine as
  28. * he intended it for learning purposes, his actual optimized inflater code
  29. * is very different. I went with this approach basically because I got a
  30. * headache looking at the optimized inflater code and porting this
  31. * was a breeze. The speed should be adequate but there is plenty of room
  32. * for improvements here.
  33. *
  34. * @author dchang
  35. */
  36. public class Inflater {
  37. private static const MAXBITS:int = 15; // maximum bits in a code
  38. private static const MAXLCODES:int = 286; // maximum number of literal/length codes
  39. private static const MAXDCODES:int = 30; // maximum number of distance codes
  40. private static const MAXCODES:int = MAXLCODES + MAXDCODES; // maximum codes lengths to read
  41. private static const FIXLCODES:int = 288; // number of fixed literal/length codes
  42. // Size base for length codes 257..285
  43. private static const LENS:Array = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258];
  44. // Extra bits for length codes 257..285
  45. private static const LEXT:Array = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0];
  46. // Offset base for distance codes 0..29
  47. private static const DISTS:Array = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577];
  48. // Extra bits for distance codes 0..29
  49. private static const DEXT:Array = [ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
  50. private var inbuf:ByteArray; // input buffer
  51. private var incnt:uint; // bytes read so far
  52. private var bitbuf:int; // bit buffer
  53. private var bitcnt:int; // number of bits in bit buffer
  54. // Huffman code decoding tables
  55. private var lencode:Object;
  56. private var distcode:Object;
  57. /**
  58. * Sets the input.
  59. *
  60. * @param buf the input.
  61. */
  62. public function setInput(buf:ByteArray):void {
  63. inbuf = buf;
  64. inbuf.endian = Endian.LITTLE_ENDIAN;
  65. }
  66. /**
  67. * Inflates the compressed stream to the output buffer.
  68. *
  69. * @param buf the output buffer.
  70. */
  71. public function inflate(buf:ByteArray):uint {
  72. incnt = bitbuf = bitcnt = 0;
  73. var err:int = 0;
  74. do { // process blocks until last block or error
  75. var last:int = bits(1); // one if last block
  76. var type:int = bits(2); // block type 0..3
  77. if(type == 0) stored(buf); // uncompressed block
  78. else if(type == 3) throw new Error('invalid block type (type == 3)', -1);
  79. else { // compressed block
  80. lencode = {count:[], symbol:[]};
  81. distcode = {count:[], symbol:[]};
  82. if(type == 1) constructFixedTables();
  83. else if(type == 2) err = constructDynamicTables();
  84. if(err != 0) return err;
  85. err = codes(buf); // decode data until end-of-block code
  86. }
  87. if(err != 0) break; // return with error
  88. } while(!last);
  89. return err;
  90. }
  91. private function bits(need:int):int {
  92. // bit accumulator (can use up to 20 bits)
  93. // load at least need bits into val
  94. var val:int = bitbuf;
  95. while(bitcnt < need) {
  96. if (incnt == inbuf.length) throw new Error('available inflate data did not terminate', 2);
  97. val |= inbuf[incnt++] << bitcnt; // load eight bits
  98. bitcnt += 8;
  99. }
  100. // drop need bits and update buffer, always zero to seven bits left
  101. bitbuf = val >> need;
  102. bitcnt -= need;
  103. // return need bits, zeroing the bits above that
  104. return val & ((1 << need) - 1);
  105. }
  106. private function construct(h:Object, length:Array, n:int):int {
  107. var offs:Array = []; // offsets in symbol table for each length
  108. // count number of codes of each length
  109. for(var len:int = 0; len <= MAXBITS; len++) h.count[len] = 0;
  110. // assumes lengths are within bounds
  111. for(var symbol:int = 0; symbol < n; symbol++) h.count[length[symbol]]++;
  112. // no codes! complete, but decode() will fail
  113. if(h.count[0] == n) return 0;
  114. // check for an over-subscribed or incomplete set of lengths
  115. var left:int = 1; // one possible code of zero length
  116. for(len = 1; len <= MAXBITS; len++) {
  117. left <<= 1; // one more bit, double codes left
  118. left -= h.count[len]; // deduct count from possible codes
  119. if(left < 0) return left; // over-subscribed--return negative
  120. } // left > 0 means incomplete
  121. // generate offsets into symbol table for each length for sorting
  122. offs[1] = 0;
  123. for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h.count[len];
  124. // put symbols in table sorted by length, by symbol order within each length
  125. for(symbol = 0; symbol < n; symbol++)
  126. if(length[symbol] != 0) h.symbol[offs[length[symbol]]++] = symbol;
  127. // return zero for complete set, positive for incomplete set
  128. return left;
  129. }
  130. private function decode(h:Object):int {
  131. var code:int = 0; // len bits being decoded
  132. var first:int = 0; // first code of length len
  133. var index:int = 0; // index of first code of length len in symbol table
  134. for(var len:int = 1; len <= MAXBITS; len++) { // current number of bits in code
  135. code |= bits(1); // get next bit
  136. var count:int = h.count[len]; // number of codes of length len
  137. // if length len, return symbol
  138. if(code < first + count) return h.symbol[index + (code - first)];
  139. index += count; // else update for next length
  140. first += count;
  141. first <<= 1;
  142. code <<= 1;
  143. }
  144. return -9; // ran out of codes
  145. }
  146. private function codes(buf:ByteArray):int {
  147. // decode literals and length/distance pairs
  148. do {
  149. var symbol:int = decode(lencode);
  150. if(symbol < 0) return symbol; // invalid symbol
  151. if(symbol < 256) buf[buf.length] = symbol; // literal: symbol is the byte
  152. else if(symbol > 256) { // length
  153. // get and compute length
  154. symbol -= 257;
  155. if(symbol >= 29) throw new Error("invalid literal/length or distance code in fixed or dynamic block", -9);
  156. var len:int = LENS[symbol] + bits(LEXT[symbol]); // length for copy
  157. // get and check distance
  158. symbol = decode(distcode);
  159. if(symbol < 0) return symbol; // invalid symbol
  160. var dist:uint = DISTS[symbol] + bits(DEXT[symbol]); // distance for copy
  161. if(dist > buf.length) throw new Error("distance is too far back in fixed or dynamic block", -10);
  162. // copy length bytes from distance bytes back
  163. while(len--) buf[buf.length] = buf[buf.length - dist];
  164. }
  165. } while (symbol != 256); // end of block symbol
  166. return 0; // done with a valid fixed or dynamic block
  167. }
  168. private function stored(buf:ByteArray):void {
  169. // discard leftover bits from current byte (assumes s->bitcnt < 8)
  170. bitbuf = 0;
  171. bitcnt = 0;
  172. // get length and check against its one's complement
  173. if(incnt + 4 > inbuf.length) throw new Error('available inflate data did not terminate', 2);
  174. var len:uint = inbuf[incnt++]; // length of stored block
  175. len |= inbuf[incnt++] << 8;
  176. if(inbuf[incnt++] != (~len & 0xff) || inbuf[incnt++] != ((~len >> 8) & 0xff))
  177. throw new Error("stored block length did not match one's complement", -2);
  178. if(incnt + len > inbuf.length) throw new Error('available inflate data did not terminate', 2);
  179. while(len--) buf[buf.length] = inbuf[incnt++]; // copy len bytes from in to out
  180. }
  181. private function constructFixedTables():void {
  182. var lengths:Array = [];
  183. // literal/length table
  184. for(var symbol:int = 0; symbol < 144; symbol++) lengths[symbol] = 8;
  185. for(; symbol < 256; symbol++) lengths[symbol] = 9;
  186. for(; symbol < 280; symbol++) lengths[symbol] = 7;
  187. for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
  188. construct(lencode, lengths, FIXLCODES);
  189. // distance table
  190. for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
  191. construct(distcode, lengths, MAXDCODES);
  192. }
  193. private function constructDynamicTables():int {
  194. var lengths:Array = []; // descriptor code lengths
  195. // permutation of code length codes
  196. var order:Array = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
  197. // get number of lengths in each table, check lengths
  198. var nlen:int = bits(5) + 257;
  199. var ndist:int = bits(5) + 1;
  200. var ncode:int = bits(4) + 4; // number of lengths in descriptor
  201. if(nlen > MAXLCODES || ndist > MAXDCODES) throw new Error("dynamic block code description: too many length or distance codes", -3);
  202. // read code length code lengths (really), missing lengths are zero
  203. for(var index:int = 0; index < ncode; index++) lengths[order[index]] = bits(3);
  204. for(; index < 19; index++) lengths[order[index]] = 0;
  205. // build huffman table for code lengths codes (use lencode temporarily)
  206. var err:int = construct(lencode, lengths, 19);
  207. if(err != 0) throw new Error("dynamic block code description: code lengths codes incomplete", -4);
  208. // read length/literal and distance code length tables
  209. index = 0;
  210. while(index < nlen + ndist) {
  211. var symbol:int; // decoded value
  212. var len:int; // last length to repeat
  213. symbol = decode(lencode);
  214. if(symbol < 16) lengths[index++] = symbol; // length in 0..15
  215. else { // repeat instruction
  216. len = 0; // assume repeating zeros
  217. if(symbol == 16) { // repeat last length 3..6 times
  218. if(index == 0) throw new Error("dynamic block code description: repeat lengths with no first length", -5);
  219. len = lengths[index - 1]; // last length
  220. symbol = 3 + bits(2);
  221. }
  222. else if(symbol == 17) symbol = 3 + bits(3); // repeat zero 3..10 times
  223. else symbol = 11 + bits(7); // == 18, repeat zero 11..138 times
  224. if(index + symbol > nlen + ndist)
  225. throw new Error("dynamic block code description: repeat more than specified lengths", -6);
  226. while(symbol--) lengths[index++] = len; // repeat last or zero symbol times
  227. }
  228. }
  229. // build huffman table for literal/length codes
  230. err = construct(lencode, lengths, nlen);
  231. // only allow incomplete codes if just one code
  232. if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
  233. throw new Error("dynamic block code description: invalid literal/length code lengths", -7);
  234. // build huffman table for distance codes
  235. err = construct(distcode, lengths.slice(nlen), ndist);
  236. // only allow incomplete codes if just one code
  237. if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
  238. throw new Error("dynamic block code description: invalid distance code lengths", -8);
  239. return err;
  240. }
  241. }
  242. }