PageRenderTime 73ms CodeModel.GetById 53ms app.highlight 17ms RepoModel.GetById 0ms app.codeStats 0ms

/2v/Picture_to_XML/src/nochump/util/zip/Inflater.as

https://github.com/jjmail-links/as3-examples
ActionScript | 265 lines | 166 code | 15 blank | 84 comment | 75 complexity | 109e506606f961fa393b76f0ffc4383b MD5 | raw file
  1/*
  2nochump.util.zip.Inflater
  3Copyright (c) 2008 David Chang (dchang@nochump.com)
  4
  5Permission is hereby granted, free of charge, to any person obtaining a copy
  6of this software and associated documentation files (the "Software"), to deal
  7in the Software without restriction, including without limitation the rights
  8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9copies of the Software, and to permit persons to whom the Software is
 10furnished to do so, subject to the following conditions:
 11
 12The above copyright notice and this permission notice shall be included in
 13all copies or substantial portions of the Software.
 14
 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21THE SOFTWARE.
 22*/
 23package nochump.util.zip {
 24	
 25	import flash.utils.Endian;
 26	import flash.utils.ByteArray;
 27	
 28	/**
 29	 * Inflater is used to decompress data that has been compressed according 
 30	 * to the "deflate" standard described in rfc1950.
 31	 *
 32	 * The usage is as following.  First you have to set some input with
 33	 * <code>setInput()</code>, then inflate() it.
 34	 * 
 35	 * This implementation is a port of Puff by Mark Addler that comes with
 36	 * the zlip data compression library.  It is not the fastest routine as
 37	 * he intended it for learning purposes, his actual optimized inflater code
 38	 * is very different.  I went with this approach basically because I got a
 39	 * headache looking at the optimized inflater code and porting this
 40	 * was a breeze.  The speed should be adequate but there is plenty of room
 41	 * for improvements here.
 42	 * 
 43	 * @author dchang
 44	 */
 45	public class Inflater {
 46		
 47		private static const MAXBITS:int = 15; // maximum bits in a code
 48		private static const MAXLCODES:int = 286; // maximum number of literal/length codes
 49		private static const MAXDCODES:int = 30; // maximum number of distance codes
 50		private static const MAXCODES:int = MAXLCODES + MAXDCODES; // maximum codes lengths to read
 51		private static const FIXLCODES:int = 288; // number of fixed literal/length codes
 52		// Size base for length codes 257..285
 53		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];
 54		// Extra bits for length codes 257..285
 55		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];
 56		// Offset base for distance codes 0..29
 57		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];
 58		// Extra bits for distance codes 0..29
 59		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];
 60
 61		private var inbuf:ByteArray; // input buffer
 62		private var incnt:uint; // bytes read so far
 63		private var bitbuf:int; // bit buffer
 64		private var bitcnt:int; // number of bits in bit buffer
 65		// Huffman code decoding tables
 66		private var lencode:Object;
 67		private var distcode:Object;
 68		
 69		/**
 70		 * Sets the input.
 71		 * 
 72		 * @param buf the input.
 73		 */
 74		public function setInput(buf:ByteArray):void {
 75			inbuf = buf;
 76			inbuf.endian = Endian.LITTLE_ENDIAN;
 77		}
 78		
 79		/**
 80		 * Inflates the compressed stream to the output buffer.
 81		 * 
 82		 * @param buf the output buffer.
 83		 */
 84		public function inflate(buf:ByteArray):uint {
 85			incnt = bitbuf = bitcnt = 0;
 86			var err:int = 0;
 87			do { // process blocks until last block or error
 88				var last:int = bits(1); // one if last block
 89				var type:int = bits(2); // block type 0..3
 90				//trace('	block type ' + type);
 91				if(type == 0) stored(buf); // uncompressed block
 92				else if(type == 3) throw new Error('invalid block type (type == 3)', -1);
 93				else { // compressed block
 94					lencode = {count:[], symbol:[]};
 95					distcode = {count:[], symbol:[]};
 96					if(type == 1) constructFixedTables();
 97					else if(type == 2) err = constructDynamicTables();
 98					if(err != 0) return err;
 99					err = codes(buf); // decode data until end-of-block code
100				}
101				if(err != 0) break; // return with error
102			} while(!last);
103			return err;
104		}
105		
106		private function bits(need:int):int {
107			// bit accumulator (can use up to 20 bits)
108			// load at least need bits into val
109			var val:int = bitbuf;
110			while(bitcnt < need) {
111				if (incnt == inbuf.length) throw new Error('available inflate data did not terminate', 2);
112				val |= inbuf[incnt++] << bitcnt; // load eight bits
113				bitcnt += 8;
114			}
115			// drop need bits and update buffer, always zero to seven bits left
116			bitbuf = val >> need;
117			bitcnt -= need;
118			// return need bits, zeroing the bits above that
119			return val & ((1 << need) - 1);
120		}
121		
122		private function construct(h:Object, length:Array, n:int):int {
123			var offs:Array = []; // offsets in symbol table for each length
124			// count number of codes of each length
125			for(var len:int = 0; len <= MAXBITS; len++) h.count[len] = 0;
126			// assumes lengths are within bounds
127			for(var symbol:int = 0; symbol < n; symbol++) h.count[length[symbol]]++;
128			// no codes! complete, but decode() will fail
129			if(h.count[0] == n) return 0;
130			// check for an over-subscribed or incomplete set of lengths
131			var left:int = 1; // one possible code of zero length
132			for(len = 1; len <= MAXBITS; len++) {
133				left <<= 1; // one more bit, double codes left
134				left -= h.count[len]; // deduct count from possible codes
135				if(left < 0) return left; // over-subscribed--return negative
136			} // left > 0 means incomplete
137			// generate offsets into symbol table for each length for sorting
138			offs[1] = 0;
139			for(len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + h.count[len];
140			// put symbols in table sorted by length, by symbol order within each length
141			for(symbol = 0; symbol < n; symbol++)
142				if(length[symbol] != 0) h.symbol[offs[length[symbol]]++] = symbol;
143			// return zero for complete set, positive for incomplete set
144			return left;
145		}
146		
147		private function decode(h:Object):int {
148			var code:int = 0; // len bits being decoded
149			var first:int = 0; // first code of length len
150			var index:int = 0; // index of first code of length len in symbol table
151			for(var len:int = 1; len <= MAXBITS; len++) { // current number of bits in code
152				code |= bits(1); // get next bit
153				var count:int = h.count[len]; // number of codes of length len
154				// if length len, return symbol
155				if(code < first + count) return h.symbol[index + (code - first)];
156				index += count; // else update for next length
157				first += count;
158				first <<= 1;
159				code <<= 1;
160			}
161			return -9; // ran out of codes
162		}
163		
164		private function codes(buf:ByteArray):int {
165			// decode literals and length/distance pairs
166			do {
167				var symbol:int = decode(lencode);
168				if(symbol < 0) return symbol; // invalid symbol
169				if(symbol < 256) buf[buf.length] = symbol; // literal: symbol is the byte
170				else if(symbol > 256) { // length
171					// get and compute length
172					symbol -= 257;
173					if(symbol >= 29) throw new Error("invalid literal/length or distance code in fixed or dynamic block", -9);
174					var len:int = LENS[symbol] + bits(LEXT[symbol]); // length for copy
175					// get and check distance
176					symbol = decode(distcode);
177					if(symbol < 0) return symbol; // invalid symbol
178					var dist:uint = DISTS[symbol] + bits(DEXT[symbol]); // distance for copy
179					if(dist > buf.length) throw new Error("distance is too far back in fixed or dynamic block", -10);
180					// copy length bytes from distance bytes back
181					while(len--) buf[buf.length] = buf[buf.length - dist];
182				}
183			} while (symbol != 256); // end of block symbol
184			return 0; // done with a valid fixed or dynamic block
185		}
186		
187		private function stored(buf:ByteArray):void {
188			// discard leftover bits from current byte (assumes s->bitcnt < 8)
189			bitbuf = 0;
190			bitcnt = 0;
191			// get length and check against its one's complement
192			if(incnt + 4 > inbuf.length) throw new Error('available inflate data did not terminate', 2);
193			var len:uint = inbuf[incnt++]; // length of stored block
194			len |= inbuf[incnt++] << 8;
195			if(inbuf[incnt++] != (~len & 0xff) || inbuf[incnt++] != ((~len >> 8) & 0xff))
196				throw new Error("stored block length did not match one's complement", -2);
197			if(incnt + len > inbuf.length) throw new Error('available inflate data did not terminate', 2);
198			while(len--) buf[buf.length] = inbuf[incnt++]; // copy len bytes from in to out
199		}
200		
201		private function constructFixedTables():void {
202			var lengths:Array = [];
203			// literal/length table
204			for(var symbol:int = 0; symbol < 144; symbol++) lengths[symbol] = 8;
205			for(; symbol < 256; symbol++) lengths[symbol] = 9;
206			for(; symbol < 280; symbol++) lengths[symbol] = 7;
207			for(; symbol < FIXLCODES; symbol++) lengths[symbol] = 8;
208			construct(lencode, lengths, FIXLCODES);
209			// distance table
210			for(symbol = 0; symbol < MAXDCODES; symbol++) lengths[symbol] = 5;
211			construct(distcode, lengths, MAXDCODES);
212		}
213		
214		private function constructDynamicTables():int {
215			var lengths:Array = []; // descriptor code lengths
216			// permutation of code length codes
217			var order:Array = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
218			// get number of lengths in each table, check lengths
219			var nlen:int = bits(5) + 257;
220			var ndist:int = bits(5) + 1;
221			var ncode:int = bits(4) + 4; // number of lengths in descriptor
222			if(nlen > MAXLCODES || ndist > MAXDCODES) throw new Error("dynamic block code description: too many length or distance codes", -3);
223			// read code length code lengths (really), missing lengths are zero
224			for(var index:int = 0; index < ncode; index++) lengths[order[index]] = bits(3);
225			for(; index < 19; index++) lengths[order[index]] = 0;
226			// build huffman table for code lengths codes (use lencode temporarily)
227			var err:int = construct(lencode, lengths, 19);
228			if(err != 0) throw new Error("dynamic block code description: code lengths codes incomplete", -4);
229			// read length/literal and distance code length tables
230			index = 0;
231			while(index < nlen + ndist) {
232				var symbol:int; // decoded value
233				var len:int; // last length to repeat
234				symbol = decode(lencode);
235				if(symbol < 16) lengths[index++] = symbol; // length in 0..15
236				else { // repeat instruction
237					len = 0; // assume repeating zeros
238					if(symbol == 16) { // repeat last length 3..6 times
239						if(index == 0) throw new Error("dynamic block code description: repeat lengths with no first length", -5);
240						len = lengths[index - 1]; // last length
241						symbol = 3 + bits(2);
242					}
243					else if(symbol == 17) symbol = 3 + bits(3); // repeat zero 3..10 times
244					else symbol = 11 + bits(7); // == 18, repeat zero 11..138 times
245					if(index + symbol > nlen + ndist)
246						throw new Error("dynamic block code description: repeat more than specified lengths", -6);
247					while(symbol--) lengths[index++] = len; // repeat last or zero symbol times
248				}
249			}
250			// build huffman table for literal/length codes
251			err = construct(lencode, lengths, nlen);
252			// only allow incomplete codes if just one code
253			if(err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
254				throw new Error("dynamic block code description: invalid literal/length code lengths", -7);
255			// build huffman table for distance codes
256			err = construct(distcode, lengths.slice(nlen), ndist);
257			// only allow incomplete codes if just one code
258			if(err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
259				throw new Error("dynamic block code description: invalid distance code lengths", -8);
260			return err;
261		}
262		
263	}
264	
265}