/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
- /*
- nochump.util.zip.Inflater
- Copyright (C) 2007 David Chang (dchang@nochump.com)
- This file is part of nochump.util.zip.
- nochump.util.zip is free software: you can redistribute it and/or modify
- it under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- nochump.util.zip is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with Foobar. If not, see <http://www.gnu.org/licenses/>.
- */
- package nochump.util.zip {
-
- import flash.utils.Endian;
- import flash.utils.ByteArray;
-
- /**
- * Inflater is used to decompress data that has been compressed according
- * to the "deflate" standard described in rfc1950.
- *
- * The usage is as following. First you have to set some input with
- * <code>setInput()</code>, then inflate() it.
- *
- * This implementation is a port of Puff by Mark Addler that comes with
- * the zlip data compression library. It is not the fastest routine as
- * he intended it for learning purposes, his actual optimized inflater code
- * is very different. I went with this approach basically because I got a
- * headache looking at the optimized inflater code and porting this
- * was a breeze. The speed should be adequate but there is plenty of room
- * for improvements here.
- *
- * @author dchang
- */
- public class Inflater {
-
- private static const MAXBITS:int = 15; // maximum bits in a code
- private static const MAXLCODES:int = 286; // maximum number of literal/length codes
- private static const MAXDCODES:int = 30; // maximum number of distance codes
- private static const MAXCODES:int = MAXLCODES + MAXDCODES; // maximum codes lengths to read
- private static const FIXLCODES:int = 288; // number of fixed literal/length codes
- // Size base for length codes 257..285
- 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];
- // Extra bits for length codes 257..285
- 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];
- // Offset base for distance codes 0..29
- 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];
- // Extra bits for distance codes 0..29
- 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];
- private var inbuf:ByteArray; // input buffer
- private var incnt:uint; // bytes read so far
- private var bitbuf:int; // bit buffer
- private var bitcnt:int; // number of bits in bit buffer
- // Huffman code decoding tables
- private var lencode:Object;
- private var distcode:Object;
-
- /**
- * Sets the input.
- *
- * @param buf the input.
- */
- public function setInput(buf:ByteArray):void {
- inbuf = buf;
- inbuf.endian = Endian.LITTLE_ENDIAN;
- }
-
- /**
- * Inflates the compressed stream to the output buffer.
- *
- * @param buf the output buffer.
- */
- public function inflate(buf:ByteArray):uint {
- incnt = bitbuf = bitcnt = 0;
- var err:int = 0;
- do { // process blocks until last block or error
- var last:int = bits(1); // one if last block
- var type:int = bits(2); // block type 0..3
-
- if(type == 0) stored(buf); // uncompressed block
- else if(type == 3) throw new Error('invalid block type (type == 3)', -1);
- else { // compressed block
- lencode = {count:[], symbol:[]};
- distcode = {count:[], symbol:[]};
- if(type == 1) constructFixedTables();
- else if(type == 2) err = constructDynamicTables();
- if(err != 0) return err;
- err = codes(buf); // decode data until end-of-block code
- }
- if(err != 0) break; // return with error
- } while(!last);
- return err;
- }
-
- private function bits(need:int):int {
- // bit accumulator (can use up to 20 bits)
- // load at least need bits into val
- var val:int = bitbuf;
- while(bitcnt < need) {
- if (incnt == inbuf.length) throw new Error('available inflate data did not terminate', 2);
- val |= inbuf[incnt++] << bitcnt; // load eight bits
- bitcnt += 8;
- }
- // drop need bits and update buffer, always zero to seven bits left
- bitbuf = val >> need;
- bitcnt -= need;
- // return need bits, zeroing the bits above that
- return val & ((1 << need) - 1);
- }
-
- private function construct(h:Object, length:Array, n:int):int {
- var offs:Array = []; // offsets in symbol table for each length
- // count number of codes of each length
- for(var len:int = 0; len <= MAXBITS; len++) h.count[len] = 0;
- // assumes lengths are within bounds
- for(var symbol:int = 0; symbol < n; symbol++) h.count[length[symbol]]++;
- // no codes! complete, but decode() will fail
- if(h.count[0] == n) return 0;
- // check for an over-subscribed or incomplete set of lengths
- var left:int = 1; // one possible code of zero length
- for(len = 1; len <= MAXBITS; len++) {
- left <<= 1; // one more bit, double codes left
- left -= h.count[len]; // deduct count from possible codes
- if(left < 0) return left; // over-subscribed--return negative
- } // left > 0 means incomplete
- // generate offsets into symbol table for each length for sorting
- offs[1] = 0;
- for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h.count[len];
- // put symbols in table sorted by length, by symbol order within each length
- for(symbol = 0; symbol < n; symbol++)
- if(length[symbol] != 0) h.symbol[offs[length[symbol]]++] = symbol;
- // return zero for complete set, positive for incomplete set
- return left;
- }
-
- private function decode(h:Object):int {
- var code:int = 0; // len bits being decoded
- var first:int = 0; // first code of length len
- var index:int = 0; // index of first code of length len in symbol table
- for(var len:int = 1; len <= MAXBITS; len++) { // current number of bits in code
- code |= bits(1); // get next bit
- var count:int = h.count[len]; // number of codes of length len
- // if length len, return symbol
- if(code < first + count) return h.symbol[index + (code - first)];
- index += count; // else update for next length
- first += count;
- first <<= 1;
- code <<= 1;
- }
- return -9; // ran out of codes
- }
-
- private function codes(buf:ByteArray):int {
- // decode literals and length/distance pairs
- do {
- var symbol:int = decode(lencode);
- if(symbol < 0) return symbol; // invalid symbol
- if(symbol < 256) buf[buf.length] = symbol; // literal: symbol is the byte
- else if(symbol > 256) { // length
- // get and compute length
- symbol -= 257;
- if(symbol >= 29) throw new Error("invalid literal/length or distance code in fixed or dynamic block", -9);
- var len:int = LENS[symbol] + bits(LEXT[symbol]); // length for copy
- // get and check distance
- symbol = decode(distcode);
- if(symbol < 0) return symbol; // invalid symbol
- var dist:uint = DISTS[symbol] + bits(DEXT[symbol]); // distance for copy
- if(dist > buf.length) throw new Error("distance is too far back in fixed or dynamic block", -10);
- // copy length bytes from distance bytes back
- while(len--) buf[buf.length] = buf[buf.length - dist];
- }
- } while (symbol != 256); // end of block symbol
- return 0; // done with a valid fixed or dynamic block
- }
-
- private function stored(buf:ByteArray):void {
- // discard leftover bits from current byte (assumes s->bitcnt < 8)
- bitbuf = 0;
- bitcnt = 0;
- // get length and check against its one's complement
- if(incnt + 4 > inbuf.length) throw new Error('available inflate data did not terminate', 2);
- var len:uint = inbuf[incnt++]; // length of stored block
- len |= inbuf[incnt++] << 8;
- if(inbuf[incnt++] != (~len & 0xff) || inbuf[incnt++] != ((~len >> 8) & 0xff))
- throw new Error("stored block length did not match one's complement", -2);
- if(incnt + len > inbuf.length) throw new Error('available inflate data did not terminate', 2);
- while(len--) buf[buf.length] = inbuf[incnt++]; // copy len bytes from in to out
- }
-
- private function constructFixedTables():void {
- var lengths:Array = [];
- // literal/length table
- for(var symbol:int = 0; symbol < 144; symbol++) lengths[symbol] = 8;
- for(; symbol < 256; symbol++) lengths[symbol] = 9;
- for(; symbol < 280; symbol++) lengths[symbol] = 7;
- for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
- construct(lencode, lengths, FIXLCODES);
- // distance table
- for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
- construct(distcode, lengths, MAXDCODES);
- }
-
- private function constructDynamicTables():int {
- var lengths:Array = []; // descriptor code lengths
- // permutation of code length codes
- var order:Array = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
- // get number of lengths in each table, check lengths
- var nlen:int = bits(5) + 257;
- var ndist:int = bits(5) + 1;
- var ncode:int = bits(4) + 4; // number of lengths in descriptor
- if(nlen > MAXLCODES || ndist > MAXDCODES) throw new Error("dynamic block code description: too many length or distance codes", -3);
- // read code length code lengths (really), missing lengths are zero
- for(var index:int = 0; index < ncode; index++) lengths[order[index]] = bits(3);
- for(; index < 19; index++) lengths[order[index]] = 0;
- // build huffman table for code lengths codes (use lencode temporarily)
- var err:int = construct(lencode, lengths, 19);
- if(err != 0) throw new Error("dynamic block code description: code lengths codes incomplete", -4);
- // read length/literal and distance code length tables
- index = 0;
- while(index < nlen + ndist) {
- var symbol:int; // decoded value
- var len:int; // last length to repeat
- symbol = decode(lencode);
- if(symbol < 16) lengths[index++] = symbol; // length in 0..15
- else { // repeat instruction
- len = 0; // assume repeating zeros
- if(symbol == 16) { // repeat last length 3..6 times
- if(index == 0) throw new Error("dynamic block code description: repeat lengths with no first length", -5);
- len = lengths[index - 1]; // last length
- symbol = 3 + bits(2);
- }
- else if(symbol == 17) symbol = 3 + bits(3); // repeat zero 3..10 times
- else symbol = 11 + bits(7); // == 18, repeat zero 11..138 times
- if(index + symbol > nlen + ndist)
- throw new Error("dynamic block code description: repeat more than specified lengths", -6);
- while(symbol--) lengths[index++] = len; // repeat last or zero symbol times
- }
- }
- // build huffman table for literal/length codes
- err = construct(lencode, lengths, nlen);
- // only allow incomplete codes if just one code
- if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
- throw new Error("dynamic block code description: invalid literal/length code lengths", -7);
- // build huffman table for distance codes
- err = construct(distcode, lengths.slice(nlen), ndist);
- // only allow incomplete codes if just one code
- if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
- throw new Error("dynamic block code description: invalid distance code lengths", -8);
- return err;
- }
-
- }
-
- }