// Called with number of bytes left to write in window at least 258 // (the maximum string length) and number of input bytes available // at least ten. The ten bytes are six bytes for the longest length/ // distance pair plus four bytes for overloading the bit buffer. internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s) { int e; // extra bits or operation int c; // bytes to copy int nextIn = s._NextIn; // input data pointer int availIn = s._AvailIn; // bytes available there int bits = s.bitb; // bit buffer int bitsNum = s.bitk; // bits in bit buffer int q = s.writeAt; // output window write pointer int m = q < s.readAt ? s.readAt - q - 1 : s.end - q; // bytes to end of window or read pointer int ml = Constants.InflateMask[bl]; // mask for literal/length tree int md = Constants.InflateMask[bd]; // mask for distance tree // do until not enough input or output space for fast loop do { // assume called with m >= 258 && n >= 10 // get literal/length code while (bitsNum < 20) { // max bits for literal/length code availIn--; bits |= s.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } int t = bits & ml; // temporary pointer int[] tp = tl; // temporary pointer int tp_index = tl_index; // temporary pointer int tp_index_t_3 = (tp_index + t) * 3; if ((e = tp[tp_index_t_3]) == 0) { bits >>= tp[tp_index_t_3 + 1]; bitsNum -= tp[tp_index_t_3 + 1]; s.window[q++] = (byte)tp[tp_index_t_3 + 2]; m--; continue; } do { bits >>= tp[tp_index_t_3 + 1]; bitsNum -= tp[tp_index_t_3 + 1]; if ((e & 16) != 0) { e &= 15; c = tp[tp_index_t_3 + 2] + (bits & Constants.InflateMask[e]); bits >>= e; bitsNum -= e; // decode distance base of block to copy while (bitsNum < 15) { // max bits for distance code availIn--; bits |= s.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } t = bits & md; tp = td; tp_index = td_index; tp_index_t_3 = (tp_index + t) * 3; e = tp[tp_index_t_3]; do { bits >>= (tp[tp_index_t_3 + 1]); bitsNum -= (tp[tp_index_t_3 + 1]); if ((e & 16) != 0) { // get extra bits to add to distance base e &= 15; while (bitsNum < e) { // get extra bits (up to 13) availIn--; bits |= s.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } int d = tp[tp_index_t_3 + 2] + (bits & Constants.InflateMask[e]); // distance back to copy from bits >>= e; bitsNum -= e; // do the copy int r = q - d; // copy source pointer m -= c; if (q >= d) { // offset before dest, just copy if (q - r > 0 && 2 > (q - r)) { s.window[q++] = s.window[r++]; // minimum count is three, s.window[q++] = s.window[r++]; // so unroll loop a little } else { Array.Copy(s.window, r, s.window, q, 2); q += 2; r += 2; } c -= 2; } else { // else offset after destination do { r += s.end; // force pointer in window } while (r < 0); // covers invalid distances e = s.end - r; if (c > e) { // if source crosses, c -= e; // wrapped copy if (q - r > 0 && e > (q - r)) { do { s.window[q++] = s.window[r++]; } while (--e != 0); } else { Array.Copy(s.window, r, s.window, q, e); q += e; r += e; e = 0; } r = 0; // copy rest from start of window } } // copy all or what's left if (q - r > 0 && c > (q - r)) { do { s.window[q++] = s.window[r++]; } while (--c != 0); } else { Array.Copy(s.window, r, s.window, q, c); q += c; r += c; c = 0; } break; } else if ((e & 64) == 0) { t += tp[tp_index_t_3 + 2]; t += (bits & Constants.InflateMask[e]); tp_index_t_3 = (tp_index + t) * 3; e = tp[tp_index_t_3]; } else { throw new InvalidDataException("invalid distance code"); } } while (true); break; } if ((e & 64) == 0) { t += tp[tp_index_t_3 + 2]; t += (bits & Constants.InflateMask[e]); tp_index_t_3 = (tp_index + t) * 3; if ((e = tp[tp_index_t_3]) == 0) { bits >>= (tp[tp_index_t_3 + 1]); bitsNum -= (tp[tp_index_t_3 + 1]); s.window[q++] = (byte)tp[tp_index_t_3 + 2]; m--; break; } } else if ((e & 32) != 0) { c = s._AvailIn - availIn; c = (bitsNum >> 3) < c ? bitsNum >> 3 : c; availIn += c; nextIn -= c; bitsNum -= (c << 3); s.UpdateState(bits, bitsNum, availIn, nextIn, q); return(RCode.StreamEnd); } else { throw new InvalidDataException("invalid literal/length code"); } } while (true); } while (m >= 258 && availIn >= 10); // not enough input or output--restore pointers and return c = s._AvailIn - availIn; c = (bitsNum >> 3) < c ? bitsNum >> 3 : c; availIn += c; nextIn -= c; bitsNum -= (c << 3); s.UpdateState(bits, bitsNum, availIn, nextIn, q); return(RCode.Okay); }
internal int Process(InflateBlocks blocks, int r) { int tindex; // temporary pointer int e; // extra bits or operation ZlibCodec z = blocks.codec; int nextIn = z.NextIn;// input data pointer int availIn = z.AvailableBytesIn; // bytes available there int bits = blocks.bitb; // bit buffer int bitsNum = blocks.bitk; // bits in bit buffer int q = blocks.writeAt; // output window write pointer int m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; // bytes to end of window or read pointer // process input and output based on current state while (true) { switch (mode) { // waiting for "i:"=input, "o:"=output, "x:"=nothing case START: // x: set up for LEN if (m >= 258 && availIn >= 10) { blocks.UpdateState( bits, bitsNum, availIn, nextIn, q ); r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, z); nextIn = z.NextIn; availIn = z.AvailableBytesIn; bits = blocks.bitb; bitsNum = blocks.bitk; q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; if (r != RCode.Okay) { mode = (r == RCode.StreamEnd) ? WASH : BADCODE; break; } } need = lbits; tree = ltree; tree_index = ltree_index; mode = LEN; goto case LEN; case LEN: // i: get length/literal/eob next while (bitsNum < need) { if (availIn != 0) { r = RCode.Okay; } else { return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r ); } availIn--; bits |= z.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } tindex = (tree_index + (bits & Constants.InflateMask[need])) * 3; bits >>= (tree[tindex + 1]); bitsNum -= (tree[tindex + 1]); e = tree[tindex]; if (e == 0) { // literal lit = tree[tindex + 2]; mode = LIT; break; } if ((e & 16) != 0) { // length bitsToGet = e & 15; len = tree[tindex + 2]; mode = LENEXT; break; } if ((e & 64) == 0) { // next table need = e; tree_index = tindex / 3 + tree[tindex + 2]; break; } if ((e & 32) != 0) { // end of block mode = WASH; break; } throw new InvalidDataException( "invalid literal/length code" ); case LENEXT: // i: getting length extra (have base) while (bitsNum < bitsToGet) { if (availIn != 0) { r = RCode.Okay; } else { return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r ); } availIn--; bits |= z.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } len += (bits & Constants.InflateMask[bitsToGet]); bits >>= bitsToGet; bitsNum -= bitsToGet; need = dbits; tree = dtree; tree_index = dtree_index; mode = DIST; goto case DIST; case DIST: // i: get distance next while (bitsNum < need) { if (availIn != 0) { r = RCode.Okay; } else { return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r ); } availIn--; bits |= z.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } tindex = (tree_index + (bits & Constants.InflateMask[need])) * 3; bits >>= tree[tindex + 1]; bitsNum -= tree[tindex + 1]; e = tree[tindex]; if ((e & 0x10) != 0) { // distance bitsToGet = e & 15; dist = tree[tindex + 2]; mode = DISTEXT; break; } if ((e & 64) == 0) { // next table need = e; tree_index = tindex / 3 + tree[tindex + 2]; break; } throw new InvalidDataException( "invalid distance code" ); case DISTEXT: // i: getting distance extra while (bitsNum < bitsToGet) { if (availIn != 0) { r = RCode.Okay; } else { return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r ); } availIn--; bits |= z.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } dist += (bits & Constants.InflateMask[bitsToGet]); bits >>= bitsToGet; bitsNum -= bitsToGet; mode = COPY; goto case COPY; case COPY: // o: copying bytes in window, waiting for space int f = q - dist; // pointer to copy strings from while (f < 0) { // modulo window size-"while" instead f += blocks.end; // of "if" handles invalid distances } while (len != 0) { if (m == 0) { if (q == blocks.end && blocks.readAt != 0) { q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) { blocks.writeAt = q; r = blocks.Flush(r); q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; if (q == blocks.end && blocks.readAt != 0) { q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) { return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r ); } } } blocks.window[q++] = blocks.window[f++]; m--; if (f == blocks.end) f = 0; len--; } mode = START; break; case LIT: // o: got literal, waiting for output space if (m == 0) { if (q == blocks.end && blocks.readAt != 0) { q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) { blocks.writeAt = q; r = blocks.Flush(r); q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; if (q == blocks.end && blocks.readAt != 0) { q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) { return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r ); } } } r = RCode.Okay; blocks.window[q++] = (byte)lit; m--; mode = START; break; case WASH: // o: got eob, possibly more output if (bitsNum > 7) { // return unused byte, if any bitsNum -= 8; availIn++; nextIn--; // can always return one } blocks.writeAt = q; r = blocks.Flush(r); q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; if (blocks.readAt != blocks.writeAt) { return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r ); } mode = END; goto case END; case END: r = RCode.StreamEnd; return blocks.RanOutOfInput( bits, bitsNum, availIn, nextIn, q, r ); default: throw new InvalidDataException( "Encountered error: " + mode ); } } }
internal int Process(InflateBlocks blocks, int r) { int tindex; // temporary pointer int e; // extra bits or operation int nextIn = blocks._NextIn; // input data pointer int availIn = blocks._AvailIn; // bytes available there int bits = blocks.bitb; // bit buffer int bitsNum = blocks.bitk; // bits in bit buffer int q = blocks.writeAt; // output window write pointer int m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; // bytes to end of window or read pointer // process input and output based on current state while (true) { switch (mode) { // waiting for "i:"=input, "o:"=output, "x:"=nothing case START: // x: set up for LEN if (m >= 258 && availIn >= 10) { blocks.UpdateState(bits, bitsNum, availIn, nextIn, q); r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks); nextIn = blocks._NextIn; availIn = blocks._AvailIn; bits = blocks.bitb; bitsNum = blocks.bitk; q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; if (r != RCode.Okay) { mode = (r == RCode.StreamEnd) ? WASH : BADCODE; break; } } need = lbits; tree = ltree; tree_index = ltree_index; mode = LEN; goto case LEN; case LEN: // i: get length/literal/eob next while (bitsNum < need) { if (availIn != 0) { r = RCode.Okay; } else { return(blocks.RanOutOfInput(bits, bitsNum, availIn, nextIn, q, r)); } availIn--; bits |= blocks.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } tindex = (tree_index + (bits & Constants.InflateMask[need])) * 3; bits >>= (tree[tindex + 1]); bitsNum -= (tree[tindex + 1]); e = tree[tindex]; if (e == 0) { // literal lit = tree[tindex + 2]; mode = LIT; break; } if ((e & 16) != 0) { // length bitsToGet = e & 15; len = tree[tindex + 2]; mode = LENEXT; break; } if ((e & 64) == 0) { // next table need = e; tree_index = tindex / 3 + tree[tindex + 2]; break; } if ((e & 32) != 0) { // end of block mode = WASH; break; } throw new InvalidDataException("invalid literal/length code"); case LENEXT: // i: getting length extra (have base) while (bitsNum < bitsToGet) { if (availIn != 0) { r = RCode.Okay; } else { return(blocks.RanOutOfInput(bits, bitsNum, availIn, nextIn, q, r)); } availIn--; bits |= blocks.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } len += (bits & Constants.InflateMask[bitsToGet]); bits >>= bitsToGet; bitsNum -= bitsToGet; need = dbits; tree = dtree; tree_index = dtree_index; mode = DIST; goto case DIST; case DIST: // i: get distance next while (bitsNum < need) { if (availIn != 0) { r = RCode.Okay; } else { return(blocks.RanOutOfInput(bits, bitsNum, availIn, nextIn, q, r)); } availIn--; bits |= blocks.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } tindex = (tree_index + (bits & Constants.InflateMask[need])) * 3; bits >>= tree[tindex + 1]; bitsNum -= tree[tindex + 1]; e = tree[tindex]; if ((e & 0x10) != 0) { // distance bitsToGet = e & 15; dist = tree[tindex + 2]; mode = DISTEXT; break; } if ((e & 64) == 0) { // next table need = e; tree_index = tindex / 3 + tree[tindex + 2]; break; } throw new InvalidDataException("invalid distance code"); case DISTEXT: // i: getting distance extra while (bitsNum < bitsToGet) { if (availIn != 0) { r = RCode.Okay; } else { return(blocks.RanOutOfInput(bits, bitsNum, availIn, nextIn, q, r)); } availIn--; bits |= blocks.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } dist += (bits & Constants.InflateMask[bitsToGet]); bits >>= bitsToGet; bitsNum -= bitsToGet; mode = COPY; goto case COPY; case COPY: // o: copying bytes in window, waiting for space int f = q - dist; // pointer to copy strings from while (f < 0) { // modulo window size-"while" instead f += blocks.end; // of "if" handles invalid distances } while (len != 0) { if (m == 0) { if (q == blocks.end && blocks.readAt != 0) { q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) { blocks.writeAt = q; r = blocks.Flush(r); q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; if (q == blocks.end && blocks.readAt != 0) { q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) { return(blocks.RanOutOfInput(bits, bitsNum, availIn, nextIn, q, r)); } } } blocks.window[q++] = blocks.window[f++]; m--; if (f == blocks.end) { f = 0; } len--; } mode = START; break; case LIT: // o: got literal, waiting for output space if (m == 0) { if (q == blocks.end && blocks.readAt != 0) { q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) { blocks.writeAt = q; r = blocks.Flush(r); q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; if (q == blocks.end && blocks.readAt != 0) { q = 0; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; } if (m == 0) { return(blocks.RanOutOfInput(bits, bitsNum, availIn, nextIn, q, r)); } } } r = RCode.Okay; blocks.window[q++] = (byte)lit; m--; mode = START; break; case WASH: // o: got eob, possibly more output if (bitsNum > 7) { // return unused byte, if any bitsNum -= 8; availIn++; nextIn--; // can always return one } blocks.writeAt = q; r = blocks.Flush(r); q = blocks.writeAt; m = q < blocks.readAt ? blocks.readAt - q - 1 : blocks.end - q; if (blocks.readAt != blocks.writeAt) { return(blocks.RanOutOfInput(bits, bitsNum, availIn, nextIn, q, r)); } mode = END; goto case END; case END: r = RCode.StreamEnd; return(blocks.RanOutOfInput(bits, bitsNum, availIn, nextIn, q, r)); default: throw new InvalidDataException("Encountered error: " + mode); } } }
// Called with number of bytes left to write in window at least 258 // (the maximum string length) and number of input bytes available // at least ten. The ten bytes are six bytes for the longest length/ // distance pair plus four bytes for overloading the bit buffer. internal int InflateFast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InflateBlocks s, ZlibCodec z) { int e; // extra bits or operation int c; // bytes to copy int nextIn = z.NextIn; // input data pointer int availIn = z.AvailableBytesIn; // bytes available there int bits = s.bitb; // bit buffer int bitsNum = s.bitk; // bits in bit buffer int q = s.writeAt; // output window write pointer int m = q < s.readAt ? s.readAt - q - 1 : s.end - q; // bytes to end of window or read pointer int ml = Constants.InflateMask[bl]; // mask for literal/length tree int md = Constants.InflateMask[bd]; // mask for distance tree // do until not enough input or output space for fast loop do { // assume called with m >= 258 && n >= 10 // get literal/length code while (bitsNum < 20) { // max bits for literal/length code availIn--; bits |= z.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } int t = bits & ml; // temporary pointer int[] tp = tl;// temporary pointer int tp_index = tl_index;// temporary pointer int tp_index_t_3 = (tp_index + t) * 3; if ((e = tp[tp_index_t_3]) == 0) { bits >>= tp[tp_index_t_3 + 1]; bitsNum -= tp[tp_index_t_3 + 1]; s.window[q++] = (byte)tp[tp_index_t_3 + 2]; m--; continue; } do { bits >>= tp[tp_index_t_3 + 1]; bitsNum -= tp[tp_index_t_3 + 1]; if ((e & 16) != 0) { e &= 15; c = tp[tp_index_t_3 + 2] + (bits & Constants.InflateMask[e]); bits >>= e; bitsNum -= e; // decode distance base of block to copy while (bitsNum < 15) { // max bits for distance code availIn--; bits |= z.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } t = bits & md; tp = td; tp_index = td_index; tp_index_t_3 = (tp_index + t) * 3; e = tp[tp_index_t_3]; do { bits >>= (tp[tp_index_t_3 + 1]); bitsNum -= (tp[tp_index_t_3 + 1]); if ((e & 16) != 0) { // get extra bits to add to distance base e &= 15; while (bitsNum < e) { // get extra bits (up to 13) availIn--; bits |= z.InputBuffer[nextIn++] << bitsNum; bitsNum += 8; } int d = tp[tp_index_t_3 + 2] + (bits & Constants.InflateMask[e]); // distance back to copy from bits >>= e; bitsNum -= e; // do the copy int r = q - d; // copy source pointer m -= c; if (q >= d) { // offset before dest, just copy if (q - r > 0 && 2 > (q - r)) { s.window[q++] = s.window[r++]; // minimum count is three, s.window[q++] = s.window[r++]; // so unroll loop a little } else { Array.Copy(s.window, r, s.window, q, 2); q += 2; r += 2; } c -= 2; } else { // else offset after destination do { r += s.end; // force pointer in window } while (r < 0); // covers invalid distances e = s.end - r; if (c > e) { // if source crosses, c -= e; // wrapped copy if (q - r > 0 && e > (q - r)) { do { s.window[q++] = s.window[r++]; } while (--e != 0); } else { Array.Copy(s.window, r, s.window, q, e); q += e; r += e; e = 0; } r = 0; // copy rest from start of window } } // copy all or what's left if( q - r > 0 && c > ( q - r ) ) { do { s.window[q++] = s.window[r++]; } while ( --c != 0 ); } else { Array.Copy( s.window, r, s.window, q, c ); q += c; r += c; c = 0; } break; } else if ( ( e & 64 ) == 0 ) { t += tp[tp_index_t_3 + 2]; t += (bits & Constants.InflateMask[e]); tp_index_t_3 = (tp_index + t) * 3; e = tp[tp_index_t_3]; } else { throw new InvalidDataException( "invalid distance code" ); } } while (true); break; } if ( ( e & 64 ) == 0 ) { t += tp[tp_index_t_3 + 2]; t += (bits & Constants.InflateMask[e]); tp_index_t_3 = (tp_index + t) * 3; if ((e = tp[tp_index_t_3]) == 0) { bits >>= (tp[tp_index_t_3 + 1]); bitsNum -= (tp[tp_index_t_3 + 1]); s.window[q++] = (byte)tp[tp_index_t_3 + 2]; m--; break; } } else if ( ( e & 32 ) != 0 ) { c = z.AvailableBytesIn - availIn; c = (bitsNum >> 3) < c ? bitsNum >> 3 : c; availIn += c; nextIn -= c; bitsNum -= (c << 3); s.UpdateState( bits, bitsNum, availIn, nextIn, q ); return RCode.StreamEnd; } else { throw new InvalidDataException( "invalid literal/length code" ); } } while (true); } while (m >= 258 && availIn >= 10); // not enough input or output--restore pointers and return c = z.AvailableBytesIn - availIn; c = (bitsNum >> 3) < c ? bitsNum >> 3 : c; availIn += c; nextIn -= c; bitsNum -= (c << 3); s.UpdateState( bits, bitsNum, availIn, nextIn, q ); return RCode.Okay; }