internal ZlibCompressionState Proc(InfBlocks s, ZStream z, ZlibCompressionState r) { int j; // temporary storage // int[] t; // temporary pointer int tindex; // temporary pointer int e; // extra bits or operation var b = 0; // bit buffer var k = 0; // bits in bit buffer var p = 0; // input data pointer int n; // bytes available there int q; // output window write pointer int m; // bytes to end of window or read pointer int f; // pointer to copy strings from // copy input/output information to locals (UPDATE macro restores) p = z.NextInIndex; n = z.AvailIn; b = s.Bitb; k = s.Bitk; q = s.Write; m = q < s.Read ? s.Read - q - 1 : s.End - q; // process input and output based on current state while (true) { switch (this.Mode) { // waiting for "i:"=input, "o:"=output, "x:"=nothing case START: // x: set up for LEN if (m >= 258 && n >= 10) { s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; r = Inflate_fast(this.Lbits, this.Dbits, this.Ltree, this.LtreeIndex, this.Dtree, this.DtreeIndex, s, z); p = z.NextInIndex; n = z.AvailIn; b = s.Bitb; k = s.Bitk; q = s.Write; m = q < s.Read ? s.Read - q - 1 : s.End - q; if (r != ZlibCompressionState.ZOK) { this.Mode = r == ZlibCompressionState.ZSTREAMEND ? WASH : BADCODE; break; } } this.Need = this.Lbits; this.Tree = this.Ltree; this.TreeIndex = this.LtreeIndex; this.Mode = LEN; goto case LEN; case LEN: // i: get length/literal/eob next j = this.Need; while (k < j) { if (n != 0) { r = ZlibCompressionState.ZOK; } else { s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); } n--; b |= (z.INextIn[p++] & 0xff) << k; k += 8; } tindex = (this.TreeIndex + (b & InflateMask[j])) * 3; b = SupportClass.URShift(b, this.Tree[tindex + 1]); k -= this.Tree[tindex + 1]; e = this.Tree[tindex]; if (e == 0) { // literal this.Lit = this.Tree[tindex + 2]; this.Mode = LIT; break; } if ((e & 16) != 0) { // length this.GetRenamed = e & 15; this.Len = this.Tree[tindex + 2]; this.Mode = LENEXT; break; } if ((e & 64) == 0) { // next table this.Need = e; this.TreeIndex = (tindex / 3) + this.Tree[tindex + 2]; break; } if ((e & 32) != 0) { // end of block this.Mode = WASH; break; } this.Mode = BADCODE; // invalid code z.Msg = "invalid literal/length code"; r = ZlibCompressionState.ZDATAERROR; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); case LENEXT: // i: getting length extra (have base) j = this.GetRenamed; while (k < j) { if (n != 0) { r = ZlibCompressionState.ZOK; } else { s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); } n--; b |= (z.INextIn[p++] & 0xff) << k; k += 8; } this.Len += b & InflateMask[j]; b >>= j; k -= j; this.Need = this.Dbits; this.Tree = this.Dtree; this.TreeIndex = this.DtreeIndex; this.Mode = DIST; goto case DIST; case DIST: // i: get distance next j = this.Need; while (k < j) { if (n != 0) { r = ZlibCompressionState.ZOK; } else { s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); } n--; b |= (z.INextIn[p++] & 0xff) << k; k += 8; } tindex = (this.TreeIndex + (b & InflateMask[j])) * 3; b >>= this.Tree[tindex + 1]; k -= this.Tree[tindex + 1]; e = this.Tree[tindex]; if ((e & 16) != 0) { // distance this.GetRenamed = e & 15; this.Dist = this.Tree[tindex + 2]; this.Mode = DISTEXT; break; } if ((e & 64) == 0) { // next table this.Need = e; this.TreeIndex = (tindex / 3) + this.Tree[tindex + 2]; break; } this.Mode = BADCODE; // invalid code z.Msg = "invalid distance code"; r = ZlibCompressionState.ZDATAERROR; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); case DISTEXT: // i: getting distance extra j = this.GetRenamed; while (k < j) { if (n != 0) { r = ZlibCompressionState.ZOK; } else { s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); } n--; b |= (z.INextIn[p++] & 0xff) << k; k += 8; } this.Dist += b & InflateMask[j]; b >>= j; k -= j; this.Mode = COPY; goto case COPY; case COPY: // o: copying bytes in window, waiting for space f = q - this.Dist; while (f < 0) { // modulo window size-"while" instead f += s.End; // of "if" handles invalid distances } while (this.Len != 0) { if (m == 0) { if (q == s.End && s.Read != 0) { q = 0; m = q < s.Read ? s.Read - q - 1 : s.End - q; } if (m == 0) { s.Write = q; r = s.Inflate_flush(z, r); q = s.Write; m = q < s.Read ? s.Read - q - 1 : s.End - q; if (q == s.End && s.Read != 0) { q = 0; m = q < s.Read ? s.Read - q - 1 : s.End - q; } if (m == 0) { s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); } } } s.Window[q++] = s.Window[f++]; m--; if (f == s.End) { f = 0; } this.Len--; } this.Mode = START; break; case LIT: // o: got literal, waiting for output space if (m == 0) { if (q == s.End && s.Read != 0) { q = 0; m = q < s.Read ? s.Read - q - 1 : s.End - q; } if (m == 0) { s.Write = q; r = s.Inflate_flush(z, r); q = s.Write; m = q < s.Read ? s.Read - q - 1 : s.End - q; if (q == s.End && s.Read != 0) { q = 0; m = q < s.Read ? s.Read - q - 1 : s.End - q; } if (m == 0) { s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); } } } r = ZlibCompressionState.ZOK; s.Window[q++] = (byte)this.Lit; m--; this.Mode = START; break; case WASH: // o: got eob, possibly more output if (k > 7) { // return unused byte, if any k -= 8; n++; p--; // can always return one } s.Write = q; r = s.Inflate_flush(z, r); q = s.Write; m = q < s.Read ? s.Read - q - 1 : s.End - q; if (s.Read != s.Write) { s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); } this.Mode = END; goto case END; case END: r = ZlibCompressionState.ZSTREAMEND; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); case BADCODE: // x: got error r = ZlibCompressionState.ZDATAERROR; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); default: r = ZlibCompressionState.ZSTREAMERROR; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(s.Inflate_flush(z, r)); } } }
// 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 static ZlibCompressionState Inflate_fast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InfBlocks s, ZStream z) { int t; // temporary pointer int[] tp; // temporary pointer int tp_index; // temporary pointer int e; // extra bits or operation int b; // bit buffer int k; // bits in bit buffer int p; // input data pointer int n; // bytes available there int q; // output window write pointer int m; // bytes to end of window or read pointer int ml; // mask for literal/length tree int md; // mask for distance tree int c; // bytes to copy int d; // distance back to copy from int r; // copy source pointer // load input, output, bit values p = z.NextInIndex; n = z.AvailIn; b = s.Bitb; k = s.Bitk; q = s.Write; m = q < s.Read ? s.Read - q - 1 : s.End - q; // initialize masks ml = InflateMask[bl]; md = InflateMask[bd]; // do until not enough input or output space for fast loop do { // assume called with m >= 258 && n >= 10 // get literal/length code while (k < 20) { // max bits for literal/length code n--; b |= (z.INextIn[p++] & 0xff) << k; k += 8; } t = b & ml; tp = tl; tp_index = tl_index; if ((e = tp[(tp_index + t) * 3]) == 0) { b >>= tp[((tp_index + t) * 3) + 1]; k -= tp[((tp_index + t) * 3) + 1]; s.Window[q++] = (byte)tp[((tp_index + t) * 3) + 2]; m--; continue; } do { b >>= tp[((tp_index + t) * 3) + 1]; k -= tp[((tp_index + t) * 3) + 1]; if ((e & 16) != 0) { e &= 15; c = tp[((tp_index + t) * 3) + 2] + (b & InflateMask[e]); b >>= e; k -= e; // decode distance base of block to copy while (k < 15) { // max bits for distance code n--; b |= (z.INextIn[p++] & 0xff) << k; k += 8; } t = b & md; tp = td; tp_index = td_index; e = tp[(tp_index + t) * 3]; do { b >>= tp[((tp_index + t) * 3) + 1]; k -= tp[((tp_index + t) * 3) + 1]; if ((e & 16) != 0) { // get extra bits to add to distance base e &= 15; while (k < e) { // get extra bits (up to 13) n--; b |= (z.INextIn[p++] & 0xff) << k; k += 8; } d = tp[((tp_index + t) * 3) + 2] + (b & InflateMask[e]); b >>= e; k -= e; // do the copy m -= c; if (q >= d) { // offset before dest // just copy r = q - d; if (q - r > 0 && (q - r) < 2) { s.Window[q++] = s.Window[r++]; c--; // minimum count is three, s.Window[q++] = s.Window[r++]; c--; // 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 r = q - d; 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 += b & InflateMask[e]; e = tp[(tp_index + t) * 3]; } else { z.Msg = "invalid distance code"; c = z.AvailIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= c << 3; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(ZlibCompressionState.ZDATAERROR); } }while (true); break; } if ((e & 64) == 0) { t += tp[((tp_index + t) * 3) + 2]; t += b & InflateMask[e]; if ((e = tp[(tp_index + t) * 3]) == 0) { b >>= tp[((tp_index + t) * 3) + 1]; k -= 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.AvailIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= c << 3; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(ZlibCompressionState.ZSTREAMEND); } else { z.Msg = "invalid literal/length code"; c = z.AvailIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= c << 3; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(ZlibCompressionState.ZDATAERROR); } }while (true); }while (m >= 258 && n >= 10); // not enough input or output--restore pointers and return c = z.AvailIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= c << 3; s.Bitb = b; s.Bitk = k; z.AvailIn = n; z.TotalIn += p - z.NextInIndex; z.NextInIndex = p; s.Write = q; return(ZlibCompressionState.ZOK); }