You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					346 lines
				
				12 KiB
			
		
		
			
		
	
	
					346 lines
				
				12 KiB
			| 
											2 years ago
										 | 'use strict'; | ||
|  | 
 | ||
|  | // (C) 1995-2013 Jean-loup Gailly and Mark Adler
 | ||
|  | // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
 | ||
|  | //
 | ||
|  | // This software is provided 'as-is', without any express or implied
 | ||
|  | // warranty. In no event will the authors be held liable for any damages
 | ||
|  | // arising from the use of this software.
 | ||
|  | //
 | ||
|  | // Permission is granted to anyone to use this software for any purpose,
 | ||
|  | // including commercial applications, and to alter it and redistribute it
 | ||
|  | // freely, subject to the following restrictions:
 | ||
|  | //
 | ||
|  | // 1. The origin of this software must not be misrepresented; you must not
 | ||
|  | //   claim that you wrote the original software. If you use this software
 | ||
|  | //   in a product, an acknowledgment in the product documentation would be
 | ||
|  | //   appreciated but is not required.
 | ||
|  | // 2. Altered source versions must be plainly marked as such, and must not be
 | ||
|  | //   misrepresented as being the original software.
 | ||
|  | // 3. This notice may not be removed or altered from any source distribution.
 | ||
|  | 
 | ||
|  | // See state defs from inflate.js
 | ||
|  | var BAD = 30;       /* got a data error -- remain here until reset */ | ||
|  | var TYPE = 12;      /* i: waiting for type bits, including last-flag bit */ | ||
|  | 
 | ||
|  | /* | ||
|  |    Decode literal, length, and distance codes and write out the resulting | ||
|  |    literal and match bytes until either not enough input or output is | ||
|  |    available, an end-of-block is encountered, or a data error is encountered. | ||
|  |    When large enough input and output buffers are supplied to inflate(), for | ||
|  |    example, a 16K input buffer and a 64K output buffer, more than 95% of the | ||
|  |    inflate execution time is spent in this routine. | ||
|  | 
 | ||
|  |    Entry assumptions: | ||
|  | 
 | ||
|  |         state.mode === LEN | ||
|  |         strm.avail_in >= 6 | ||
|  |         strm.avail_out >= 258 | ||
|  |         start >= strm.avail_out | ||
|  |         state.bits < 8 | ||
|  | 
 | ||
|  |    On return, state.mode is one of: | ||
|  | 
 | ||
|  |         LEN -- ran out of enough output space or enough available input | ||
|  |         TYPE -- reached end of block code, inflate() to interpret next block | ||
|  |         BAD -- error in block data | ||
|  | 
 | ||
|  |    Notes: | ||
|  | 
 | ||
|  |     - The maximum input bits used by a length/distance pair is 15 bits for the | ||
|  |       length code, 5 bits for the length extra, 15 bits for the distance code, | ||
|  |       and 13 bits for the distance extra.  This totals 48 bits, or six bytes. | ||
|  |       Therefore if strm.avail_in >= 6, then there is enough input to avoid | ||
|  |       checking for available input while decoding. | ||
|  | 
 | ||
|  |     - The maximum bytes that a single length/distance pair can output is 258 | ||
|  |       bytes, which is the maximum length that can be coded.  inflate_fast() | ||
|  |       requires strm.avail_out >= 258 for each loop to avoid checking for | ||
|  |       output space. | ||
|  |  */ | ||
|  | module.exports = function inflate_fast(strm, start) { | ||
|  |   var state; | ||
|  |   var _in;                    /* local strm.input */ | ||
|  |   var last;                   /* have enough input while in < last */ | ||
|  |   var _out;                   /* local strm.output */ | ||
|  |   var beg;                    /* inflate()'s initial strm.output */ | ||
|  |   var end;                    /* while out < end, enough space available */ | ||
|  | //#ifdef INFLATE_STRICT
 | ||
|  |   var dmax;                   /* maximum distance from zlib header */ | ||
|  | //#endif
 | ||
|  |   var wsize;                  /* window size or zero if not using window */ | ||
|  |   var whave;                  /* valid bytes in the window */ | ||
|  |   var wnext;                  /* window write index */ | ||
|  |   // Use `s_window` instead `window`, avoid conflict with instrumentation tools
 | ||
|  |   var s_window;               /* allocated sliding window, if wsize != 0 */ | ||
|  |   var hold;                   /* local strm.hold */ | ||
|  |   var bits;                   /* local strm.bits */ | ||
|  |   var lcode;                  /* local strm.lencode */ | ||
|  |   var dcode;                  /* local strm.distcode */ | ||
|  |   var lmask;                  /* mask for first level of length codes */ | ||
|  |   var dmask;                  /* mask for first level of distance codes */ | ||
|  |   var here;                   /* retrieved table entry */ | ||
|  |   var op;                     /* code bits, operation, extra bits, or */ | ||
|  |                               /*  window position, window bytes to copy */ | ||
|  |   var len;                    /* match length, unused bytes */ | ||
|  |   var dist;                   /* match distance */ | ||
|  |   var from;                   /* where to copy match from */ | ||
|  |   var from_source; | ||
|  | 
 | ||
|  | 
 | ||
|  |   var input, output; // JS specific, because we have no pointers
 | ||
|  | 
 | ||
|  |   /* copy state to local variables */ | ||
|  |   state = strm.state; | ||
|  |   //here = state.here;
 | ||
|  |   _in = strm.next_in; | ||
|  |   input = strm.input; | ||
|  |   last = _in + (strm.avail_in - 5); | ||
|  |   _out = strm.next_out; | ||
|  |   output = strm.output; | ||
|  |   beg = _out - (start - strm.avail_out); | ||
|  |   end = _out + (strm.avail_out - 257); | ||
|  | //#ifdef INFLATE_STRICT
 | ||
|  |   dmax = state.dmax; | ||
|  | //#endif
 | ||
|  |   wsize = state.wsize; | ||
|  |   whave = state.whave; | ||
|  |   wnext = state.wnext; | ||
|  |   s_window = state.window; | ||
|  |   hold = state.hold; | ||
|  |   bits = state.bits; | ||
|  |   lcode = state.lencode; | ||
|  |   dcode = state.distcode; | ||
|  |   lmask = (1 << state.lenbits) - 1; | ||
|  |   dmask = (1 << state.distbits) - 1; | ||
|  | 
 | ||
|  | 
 | ||
|  |   /* decode literals and length/distances until end-of-block or not enough | ||
|  |      input data or output space */ | ||
|  | 
 | ||
|  |   top: | ||
|  |   do { | ||
|  |     if (bits < 15) { | ||
|  |       hold += input[_in++] << bits; | ||
|  |       bits += 8; | ||
|  |       hold += input[_in++] << bits; | ||
|  |       bits += 8; | ||
|  |     } | ||
|  | 
 | ||
|  |     here = lcode[hold & lmask]; | ||
|  | 
 | ||
|  |     dolen: | ||
|  |     for (;;) { // Goto emulation
 | ||
|  |       op = here >>> 24/*here.bits*/; | ||
|  |       hold >>>= op; | ||
|  |       bits -= op; | ||
|  |       op = (here >>> 16) & 0xff/*here.op*/; | ||
|  |       if (op === 0) {                          /* literal */ | ||
|  |         //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
 | ||
|  |         //        "inflate:         literal '%c'\n" :
 | ||
|  |         //        "inflate:         literal 0x%02x\n", here.val));
 | ||
|  |         output[_out++] = here & 0xffff/*here.val*/; | ||
|  |       } | ||
|  |       else if (op & 16) {                     /* length base */ | ||
|  |         len = here & 0xffff/*here.val*/; | ||
|  |         op &= 15;                           /* number of extra bits */ | ||
|  |         if (op) { | ||
|  |           if (bits < op) { | ||
|  |             hold += input[_in++] << bits; | ||
|  |             bits += 8; | ||
|  |           } | ||
|  |           len += hold & ((1 << op) - 1); | ||
|  |           hold >>>= op; | ||
|  |           bits -= op; | ||
|  |         } | ||
|  |         //Tracevv((stderr, "inflate:         length %u\n", len));
 | ||
|  |         if (bits < 15) { | ||
|  |           hold += input[_in++] << bits; | ||
|  |           bits += 8; | ||
|  |           hold += input[_in++] << bits; | ||
|  |           bits += 8; | ||
|  |         } | ||
|  |         here = dcode[hold & dmask]; | ||
|  | 
 | ||
|  |         dodist: | ||
|  |         for (;;) { // goto emulation
 | ||
|  |           op = here >>> 24/*here.bits*/; | ||
|  |           hold >>>= op; | ||
|  |           bits -= op; | ||
|  |           op = (here >>> 16) & 0xff/*here.op*/; | ||
|  | 
 | ||
|  |           if (op & 16) {                      /* distance base */ | ||
|  |             dist = here & 0xffff/*here.val*/; | ||
|  |             op &= 15;                       /* number of extra bits */ | ||
|  |             if (bits < op) { | ||
|  |               hold += input[_in++] << bits; | ||
|  |               bits += 8; | ||
|  |               if (bits < op) { | ||
|  |                 hold += input[_in++] << bits; | ||
|  |                 bits += 8; | ||
|  |               } | ||
|  |             } | ||
|  |             dist += hold & ((1 << op) - 1); | ||
|  | //#ifdef INFLATE_STRICT
 | ||
|  |             if (dist > dmax) { | ||
|  |               strm.msg = 'invalid distance too far back'; | ||
|  |               state.mode = BAD; | ||
|  |               break top; | ||
|  |             } | ||
|  | //#endif
 | ||
|  |             hold >>>= op; | ||
|  |             bits -= op; | ||
|  |             //Tracevv((stderr, "inflate:         distance %u\n", dist));
 | ||
|  |             op = _out - beg;                /* max distance in output */ | ||
|  |             if (dist > op) {                /* see if copy from window */ | ||
|  |               op = dist - op;               /* distance back in window */ | ||
|  |               if (op > whave) { | ||
|  |                 if (state.sane) { | ||
|  |                   strm.msg = 'invalid distance too far back'; | ||
|  |                   state.mode = BAD; | ||
|  |                   break top; | ||
|  |                 } | ||
|  | 
 | ||
|  | // (!) This block is disabled in zlib defaults,
 | ||
|  | // don't enable it for binary compatibility
 | ||
|  | //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
 | ||
|  | //                if (len <= op - whave) {
 | ||
|  | //                  do {
 | ||
|  | //                    output[_out++] = 0;
 | ||
|  | //                  } while (--len);
 | ||
|  | //                  continue top;
 | ||
|  | //                }
 | ||
|  | //                len -= op - whave;
 | ||
|  | //                do {
 | ||
|  | //                  output[_out++] = 0;
 | ||
|  | //                } while (--op > whave);
 | ||
|  | //                if (op === 0) {
 | ||
|  | //                  from = _out - dist;
 | ||
|  | //                  do {
 | ||
|  | //                    output[_out++] = output[from++];
 | ||
|  | //                  } while (--len);
 | ||
|  | //                  continue top;
 | ||
|  | //                }
 | ||
|  | //#endif
 | ||
|  |               } | ||
|  |               from = 0; // window index
 | ||
|  |               from_source = s_window; | ||
|  |               if (wnext === 0) {           /* very common case */ | ||
|  |                 from += wsize - op; | ||
|  |                 if (op < len) {         /* some from window */ | ||
|  |                   len -= op; | ||
|  |                   do { | ||
|  |                     output[_out++] = s_window[from++]; | ||
|  |                   } while (--op); | ||
|  |                   from = _out - dist;  /* rest from output */ | ||
|  |                   from_source = output; | ||
|  |                 } | ||
|  |               } | ||
|  |               else if (wnext < op) {      /* wrap around window */ | ||
|  |                 from += wsize + wnext - op; | ||
|  |                 op -= wnext; | ||
|  |                 if (op < len) {         /* some from end of window */ | ||
|  |                   len -= op; | ||
|  |                   do { | ||
|  |                     output[_out++] = s_window[from++]; | ||
|  |                   } while (--op); | ||
|  |                   from = 0; | ||
|  |                   if (wnext < len) {  /* some from start of window */ | ||
|  |                     op = wnext; | ||
|  |                     len -= op; | ||
|  |                     do { | ||
|  |                       output[_out++] = s_window[from++]; | ||
|  |                     } while (--op); | ||
|  |                     from = _out - dist;      /* rest from output */ | ||
|  |                     from_source = output; | ||
|  |                   } | ||
|  |                 } | ||
|  |               } | ||
|  |               else {                      /* contiguous in window */ | ||
|  |                 from += wnext - op; | ||
|  |                 if (op < len) {         /* some from window */ | ||
|  |                   len -= op; | ||
|  |                   do { | ||
|  |                     output[_out++] = s_window[from++]; | ||
|  |                   } while (--op); | ||
|  |                   from = _out - dist;  /* rest from output */ | ||
|  |                   from_source = output; | ||
|  |                 } | ||
|  |               } | ||
|  |               while (len > 2) { | ||
|  |                 output[_out++] = from_source[from++]; | ||
|  |                 output[_out++] = from_source[from++]; | ||
|  |                 output[_out++] = from_source[from++]; | ||
|  |                 len -= 3; | ||
|  |               } | ||
|  |               if (len) { | ||
|  |                 output[_out++] = from_source[from++]; | ||
|  |                 if (len > 1) { | ||
|  |                   output[_out++] = from_source[from++]; | ||
|  |                 } | ||
|  |               } | ||
|  |             } | ||
|  |             else { | ||
|  |               from = _out - dist;          /* copy direct from output */ | ||
|  |               do {                        /* minimum length is three */ | ||
|  |                 output[_out++] = output[from++]; | ||
|  |                 output[_out++] = output[from++]; | ||
|  |                 output[_out++] = output[from++]; | ||
|  |                 len -= 3; | ||
|  |               } while (len > 2); | ||
|  |               if (len) { | ||
|  |                 output[_out++] = output[from++]; | ||
|  |                 if (len > 1) { | ||
|  |                   output[_out++] = output[from++]; | ||
|  |                 } | ||
|  |               } | ||
|  |             } | ||
|  |           } | ||
|  |           else if ((op & 64) === 0) {          /* 2nd level distance code */ | ||
|  |             here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; | ||
|  |             continue dodist; | ||
|  |           } | ||
|  |           else { | ||
|  |             strm.msg = 'invalid distance code'; | ||
|  |             state.mode = BAD; | ||
|  |             break top; | ||
|  |           } | ||
|  | 
 | ||
|  |           break; // need to emulate goto via "continue"
 | ||
|  |         } | ||
|  |       } | ||
|  |       else if ((op & 64) === 0) {              /* 2nd level length code */ | ||
|  |         here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; | ||
|  |         continue dolen; | ||
|  |       } | ||
|  |       else if (op & 32) {                     /* end-of-block */ | ||
|  |         //Tracevv((stderr, "inflate:         end of block\n"));
 | ||
|  |         state.mode = TYPE; | ||
|  |         break top; | ||
|  |       } | ||
|  |       else { | ||
|  |         strm.msg = 'invalid literal/length code'; | ||
|  |         state.mode = BAD; | ||
|  |         break top; | ||
|  |       } | ||
|  | 
 | ||
|  |       break; // need to emulate goto via "continue"
 | ||
|  |     } | ||
|  |   } while (_in < last && _out < end); | ||
|  | 
 | ||
|  |   /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ | ||
|  |   len = bits >> 3; | ||
|  |   _in -= len; | ||
|  |   bits -= len << 3; | ||
|  |   hold &= (1 << bits) - 1; | ||
|  | 
 | ||
|  |   /* update state and return */ | ||
|  |   strm.next_in = _in; | ||
|  |   strm.next_out = _out; | ||
|  |   strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); | ||
|  |   strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); | ||
|  |   state.hold = hold; | ||
|  |   state.bits = bits; | ||
|  |   return; | ||
|  | }; |