main
Raw Download raw file
  1// See state defs from inflate.js
  2var BAD = 30;       /* got a data error -- remain here until reset */
  3var TYPE = 12;      /* i: waiting for type bits, including last-flag bit */
  4
  5/*
  6   Decode literal, length, and distance codes and write out the resulting
  7   literal and match bytes until either not enough input or output is
  8   available, an end-of-block is encountered, or a data error is encountered.
  9   When large enough input and output buffers are supplied to inflate(), for
 10   example, a 16K input buffer and a 64K output buffer, more than 95% of the
 11   inflate execution time is spent in this routine.
 12
 13   Entry assumptions:
 14
 15        state.mode === LEN
 16        strm.avail_in >= 6
 17        strm.avail_out >= 258
 18        start >= strm.avail_out
 19        state.bits < 8
 20
 21   On return, state.mode is one of:
 22
 23        LEN -- ran out of enough output space or enough available input
 24        TYPE -- reached end of block code, inflate() to interpret next block
 25        BAD -- error in block data
 26
 27   Notes:
 28
 29    - The maximum input bits used by a length/distance pair is 15 bits for the
 30      length code, 5 bits for the length extra, 15 bits for the distance code,
 31      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
 32      Therefore if strm.avail_in >= 6, then there is enough input to avoid
 33      checking for available input while decoding.
 34
 35    - The maximum bytes that a single length/distance pair can output is 258
 36      bytes, which is the maximum length that can be coded.  inflate_fast()
 37      requires strm.avail_out >= 258 for each loop to avoid checking for
 38      output space.
 39 */
 40export default function inflate_fast(strm, start) {
 41  var state;
 42  var _in;                    /* local strm.input */
 43  var last;                   /* have enough input while in < last */
 44  var _out;                   /* local strm.output */
 45  var beg;                    /* inflate()'s initial strm.output */
 46  var end;                    /* while out < end, enough space available */
 47//#ifdef INFLATE_STRICT
 48  var dmax;                   /* maximum distance from zlib header */
 49//#endif
 50  var wsize;                  /* window size or zero if not using window */
 51  var whave;                  /* valid bytes in the window */
 52  var wnext;                  /* window write index */
 53  // Use `s_window` instead `window`, avoid conflict with instrumentation tools
 54  var s_window;               /* allocated sliding window, if wsize != 0 */
 55  var hold;                   /* local strm.hold */
 56  var bits;                   /* local strm.bits */
 57  var lcode;                  /* local strm.lencode */
 58  var dcode;                  /* local strm.distcode */
 59  var lmask;                  /* mask for first level of length codes */
 60  var dmask;                  /* mask for first level of distance codes */
 61  var here;                   /* retrieved table entry */
 62  var op;                     /* code bits, operation, extra bits, or */
 63                              /*  window position, window bytes to copy */
 64  var len;                    /* match length, unused bytes */
 65  var dist;                   /* match distance */
 66  var from;                   /* where to copy match from */
 67  var from_source;
 68
 69
 70  var input, output; // JS specific, because we have no pointers
 71
 72  /* copy state to local variables */
 73  state = strm.state;
 74  //here = state.here;
 75  _in = strm.next_in;
 76  input = strm.input;
 77  last = _in + (strm.avail_in - 5);
 78  _out = strm.next_out;
 79  output = strm.output;
 80  beg = _out - (start - strm.avail_out);
 81  end = _out + (strm.avail_out - 257);
 82//#ifdef INFLATE_STRICT
 83  dmax = state.dmax;
 84//#endif
 85  wsize = state.wsize;
 86  whave = state.whave;
 87  wnext = state.wnext;
 88  s_window = state.window;
 89  hold = state.hold;
 90  bits = state.bits;
 91  lcode = state.lencode;
 92  dcode = state.distcode;
 93  lmask = (1 << state.lenbits) - 1;
 94  dmask = (1 << state.distbits) - 1;
 95
 96
 97  /* decode literals and length/distances until end-of-block or not enough
 98     input data or output space */
 99
100  top:
101  do {
102    if (bits < 15) {
103      hold += input[_in++] << bits;
104      bits += 8;
105      hold += input[_in++] << bits;
106      bits += 8;
107    }
108
109    here = lcode[hold & lmask];
110
111    dolen:
112    for (;;) { // Goto emulation
113      op = here >>> 24/*here.bits*/;
114      hold >>>= op;
115      bits -= op;
116      op = (here >>> 16) & 0xff/*here.op*/;
117      if (op === 0) {                          /* literal */
118        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
119        //        "inflate:         literal '%c'\n" :
120        //        "inflate:         literal 0x%02x\n", here.val));
121        output[_out++] = here & 0xffff/*here.val*/;
122      }
123      else if (op & 16) {                     /* length base */
124        len = here & 0xffff/*here.val*/;
125        op &= 15;                           /* number of extra bits */
126        if (op) {
127          if (bits < op) {
128            hold += input[_in++] << bits;
129            bits += 8;
130          }
131          len += hold & ((1 << op) - 1);
132          hold >>>= op;
133          bits -= op;
134        }
135        //Tracevv((stderr, "inflate:         length %u\n", len));
136        if (bits < 15) {
137          hold += input[_in++] << bits;
138          bits += 8;
139          hold += input[_in++] << bits;
140          bits += 8;
141        }
142        here = dcode[hold & dmask];
143
144        dodist:
145        for (;;) { // goto emulation
146          op = here >>> 24/*here.bits*/;
147          hold >>>= op;
148          bits -= op;
149          op = (here >>> 16) & 0xff/*here.op*/;
150
151          if (op & 16) {                      /* distance base */
152            dist = here & 0xffff/*here.val*/;
153            op &= 15;                       /* number of extra bits */
154            if (bits < op) {
155              hold += input[_in++] << bits;
156              bits += 8;
157              if (bits < op) {
158                hold += input[_in++] << bits;
159                bits += 8;
160              }
161            }
162            dist += hold & ((1 << op) - 1);
163//#ifdef INFLATE_STRICT
164            if (dist > dmax) {
165              strm.msg = 'invalid distance too far back';
166              state.mode = BAD;
167              break top;
168            }
169//#endif
170            hold >>>= op;
171            bits -= op;
172            //Tracevv((stderr, "inflate:         distance %u\n", dist));
173            op = _out - beg;                /* max distance in output */
174            if (dist > op) {                /* see if copy from window */
175              op = dist - op;               /* distance back in window */
176              if (op > whave) {
177                if (state.sane) {
178                  strm.msg = 'invalid distance too far back';
179                  state.mode = BAD;
180                  break top;
181                }
182
183// (!) This block is disabled in zlib defailts,
184// don't enable it for binary compatibility
185//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
186//                if (len <= op - whave) {
187//                  do {
188//                    output[_out++] = 0;
189//                  } while (--len);
190//                  continue top;
191//                }
192//                len -= op - whave;
193//                do {
194//                  output[_out++] = 0;
195//                } while (--op > whave);
196//                if (op === 0) {
197//                  from = _out - dist;
198//                  do {
199//                    output[_out++] = output[from++];
200//                  } while (--len);
201//                  continue top;
202//                }
203//#endif
204              }
205              from = 0; // window index
206              from_source = s_window;
207              if (wnext === 0) {           /* very common case */
208                from += wsize - op;
209                if (op < len) {         /* some from window */
210                  len -= op;
211                  do {
212                    output[_out++] = s_window[from++];
213                  } while (--op);
214                  from = _out - dist;  /* rest from output */
215                  from_source = output;
216                }
217              }
218              else if (wnext < op) {      /* wrap around window */
219                from += wsize + wnext - op;
220                op -= wnext;
221                if (op < len) {         /* some from end of window */
222                  len -= op;
223                  do {
224                    output[_out++] = s_window[from++];
225                  } while (--op);
226                  from = 0;
227                  if (wnext < len) {  /* some from start of window */
228                    op = wnext;
229                    len -= op;
230                    do {
231                      output[_out++] = s_window[from++];
232                    } while (--op);
233                    from = _out - dist;      /* rest from output */
234                    from_source = output;
235                  }
236                }
237              }
238              else {                      /* contiguous in window */
239                from += wnext - op;
240                if (op < len) {         /* some from window */
241                  len -= op;
242                  do {
243                    output[_out++] = s_window[from++];
244                  } while (--op);
245                  from = _out - dist;  /* rest from output */
246                  from_source = output;
247                }
248              }
249              while (len > 2) {
250                output[_out++] = from_source[from++];
251                output[_out++] = from_source[from++];
252                output[_out++] = from_source[from++];
253                len -= 3;
254              }
255              if (len) {
256                output[_out++] = from_source[from++];
257                if (len > 1) {
258                  output[_out++] = from_source[from++];
259                }
260              }
261            }
262            else {
263              from = _out - dist;          /* copy direct from output */
264              do {                        /* minimum length is three */
265                output[_out++] = output[from++];
266                output[_out++] = output[from++];
267                output[_out++] = output[from++];
268                len -= 3;
269              } while (len > 2);
270              if (len) {
271                output[_out++] = output[from++];
272                if (len > 1) {
273                  output[_out++] = output[from++];
274                }
275              }
276            }
277          }
278          else if ((op & 64) === 0) {          /* 2nd level distance code */
279            here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
280            continue dodist;
281          }
282          else {
283            strm.msg = 'invalid distance code';
284            state.mode = BAD;
285            break top;
286          }
287
288          break; // need to emulate goto via "continue"
289        }
290      }
291      else if ((op & 64) === 0) {              /* 2nd level length code */
292        here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
293        continue dolen;
294      }
295      else if (op & 32) {                     /* end-of-block */
296        //Tracevv((stderr, "inflate:         end of block\n"));
297        state.mode = TYPE;
298        break top;
299      }
300      else {
301        strm.msg = 'invalid literal/length code';
302        state.mode = BAD;
303        break top;
304      }
305
306      break; // need to emulate goto via "continue"
307    }
308  } while (_in < last && _out < end);
309
310  /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
311  len = bits >> 3;
312  _in -= len;
313  bits -= len << 3;
314  hold &= (1 << bits) - 1;
315
316  /* update state and return */
317  strm.next_in = _in;
318  strm.next_out = _out;
319  strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
320  strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
321  state.hold = hold;
322  state.bits = bits;
323  return;
324};