Encoder and Decoder for ZLIB (IETF RFC1950 and RFC1951).
This class compresses and decompresses data according to the Deflate algorithm documented in RFC1950 and RFC1951.
        internal int Process(InflateBlocks blocks, ZlibCodec z, int r)
        {
            int j; // temporary storage
            int tindex; // temporary pointer
            int e; // extra bits or operation
            int b = 0; // bit buffer
            int k = 0; // bits in bit buffer
            int 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.NextIn; n = z.AvailableBytesIn; b = blocks.bitb; k = blocks.bitk;
            q = blocks.write; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;

            // 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 && n >= 10)
                        {

                            blocks.bitb = b; blocks.bitk = k;
                            z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                            blocks.write = q;
                            r = InflateFast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, blocks, z);

                            p = z.NextIn; n = z.AvailableBytesIn; b = blocks.bitb; k = blocks.bitk;
                            q = blocks.write; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;

                            if (r != ZlibConstants.Z_OK)
                            {
                                mode = (r == ZlibConstants.Z_STREAM_END) ? WASH : BADCODE;
                                break;
                            }
                        }
                        need = lbits;
                        tree = ltree;
                        tree_index = ltree_index;

                        mode = LEN;
                        goto case LEN;

                    case LEN:  // i: get length/literal/eob next
                        j = need;

                        while (k < (j))
                        {
                            if (n != 0)
                                r = ZlibConstants.Z_OK;
                            else
                            {

                                blocks.bitb = b; blocks.bitk = k;
                                z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                blocks.write = q;
                                return blocks.Flush(z, r);
                            }
                            n--;
                            b |= (z.InputBuffer[p++] & 0xff) << k;
                            k += 8;
                        }

                        tindex = (tree_index + (b & inflate_mask[j])) * 3;

                        b = SharedUtils.URShift(b, (tree[tindex + 1]));
                        k -= (tree[tindex + 1]);

                        e = tree[tindex];

                        if (e == 0)
                        {
                            // literal
                            lit = tree[tindex + 2];
                            mode = LIT;
                            break;
                        }
                        if ((e & 16) != 0)
                        {
                            // length
                            get_Renamed = 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;
                        }
                        mode = BADCODE; // invalid code
                        z.Message = "invalid literal/length code";
                        r = ZlibConstants.Z_DATA_ERROR;

                        blocks.bitb = b; blocks.bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        blocks.write = q;
                        return blocks.Flush(z, r);


                    case LENEXT:  // i: getting length extra (have base)
                        j = get_Renamed;

                        while (k < (j))
                        {
                            if (n != 0)
                                r = ZlibConstants.Z_OK;
                            else
                            {

                                blocks.bitb = b; blocks.bitk = k;
                                z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                blocks.write = q;
                                return blocks.Flush(z, r);
                            }
                            n--; b |= (z.InputBuffer[p++] & 0xff) << k;
                            k += 8;
                        }

                        len += (b & inflate_mask[j]);

                        b >>= j;
                        k -= j;

                        need = dbits;
                        tree = dtree;
                        tree_index = dtree_index;
                        mode = DIST;
                        goto case DIST;

                    case DIST:  // i: get distance next
                        j = need;

                        while (k < (j))
                        {
                            if (n != 0)
                                r = ZlibConstants.Z_OK;
                            else
                            {

                                blocks.bitb = b; blocks.bitk = k;
                                z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                blocks.write = q;
                                return blocks.Flush(z, r);
                            }
                            n--; b |= (z.InputBuffer[p++] & 0xff) << k;
                            k += 8;
                        }

                        tindex = (tree_index + (b & inflate_mask[j])) * 3;

                        b >>= tree[tindex + 1];
                        k -= tree[tindex + 1];

                        e = (tree[tindex]);
                        if ((e & 16) != 0)
                        {
                            // distance
                            get_Renamed = 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;
                        }
                        mode = BADCODE; // invalid code
                        z.Message = "invalid distance code";
                        r = ZlibConstants.Z_DATA_ERROR;

                        blocks.bitb = b; blocks.bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        blocks.write = q;
                        return blocks.Flush(z, r);


                    case DISTEXT:  // i: getting distance extra
                        j = get_Renamed;

                        while (k < (j))
                        {
                            if (n != 0)
                                r = ZlibConstants.Z_OK;
                            else
                            {

                                blocks.bitb = b; blocks.bitk = k;
                                z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                blocks.write = q;
                                return blocks.Flush(z, r);
                            }
                            n--; b |= (z.InputBuffer[p++] & 0xff) << k;
                            k += 8;
                        }

                        dist += (b & inflate_mask[j]);

                        b >>= j;
                        k -= j;

                        mode = COPY;
                        goto case COPY;

                    case COPY:  // o: copying bytes in window, waiting for space
                        f = q - dist;
                        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.read != 0)
                                {
                                    q = 0; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;
                                }
                                if (m == 0)
                                {
                                    blocks.write = q; r = blocks.Flush(z, r);
                                    q = blocks.write; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;

                                    if (q == blocks.end && blocks.read != 0)
                                    {
                                        q = 0; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;
                                    }

                                    if (m == 0)
                                    {
                                        blocks.bitb = b; blocks.bitk = k;
                                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                        blocks.write = q;
                                        return blocks.Flush(z, 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.read != 0)
                            {
                                q = 0; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;
                            }
                            if (m == 0)
                            {
                                blocks.write = q; r = blocks.Flush(z, r);
                                q = blocks.write; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;

                                if (q == blocks.end && blocks.read != 0)
                                {
                                    q = 0; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;
                                }
                                if (m == 0)
                                {
                                    blocks.bitb = b; blocks.bitk = k;
                                    z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                    blocks.write = q;
                                    return blocks.Flush(z, r);
                                }
                            }
                        }
                        r = ZlibConstants.Z_OK;

                        blocks.window[q++] = (byte)lit; m--;

                        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
                        }

                        blocks.write = q; r = blocks.Flush(z, r);
                        q = blocks.write; m = q < blocks.read ? blocks.read - q - 1 : blocks.end - q;

                        if (blocks.read != blocks.write)
                        {
                            blocks.bitb = b; blocks.bitk = k;
                            z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                            blocks.write = q;
                            return blocks.Flush(z, r);
                        }
                        mode = END;
                        goto case END;

                    case END:
                        r = ZlibConstants.Z_STREAM_END;
                        blocks.bitb = b; blocks.bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        blocks.write = q;
                        return blocks.Flush(z, r);


                    case BADCODE:  // x: got error

                        r = ZlibConstants.Z_DATA_ERROR;

                        blocks.bitb = b; blocks.bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        blocks.write = q;
                        return blocks.Flush(z, r);


                    default:
                        r = ZlibConstants.Z_STREAM_ERROR;

                        blocks.bitb = b; blocks.bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        blocks.write = q;
                        return blocks.Flush(z, r);

                }
            }
        }
 internal InflateBlocks(ZlibCodec z, System.Object checkfn, int w)
 {
     hufts = new int[MANY * 3];
     window = new byte[w];
     end = w;
     this.checkfn = checkfn;
     mode = TYPE;
     Reset(z, null);
 }
        // copy as much as possible from the sliding window to the output area
        internal int Flush(ZlibCodec z, int r)
        {
            int n;
            int p;
            int q;

            // local copies of source and destination pointers
            p = z.NextOut;
            q = read;

            // compute number of bytes to copy as far as end of window
            n = (int)((q <= write ? write : end) - q);
            if (n > z.AvailableBytesOut)
                n = z.AvailableBytesOut;
            if (n != 0 && r == ZlibConstants.Z_BUF_ERROR)
                r = ZlibConstants.Z_OK;

            // update counters
            z.AvailableBytesOut -= n;
            z.TotalBytesOut += n;

            // update check information
            if (checkfn != null)
                z._Adler32 = check = Adler.Adler32(check, window, q, n);

            // copy as far as end of window
            Array.Copy(window, q, z.OutputBuffer, p, n);
            p += n;
            q += n;

            // see if more to copy at beginning of window
            if (q == end)
            {
                // wrap pointers
                q = 0;
                if (write == end)
                    write = 0;

                // compute bytes to copy
                n = write - q;
                if (n > z.AvailableBytesOut)
                    n = z.AvailableBytesOut;
                if (n != 0 && r == ZlibConstants.Z_BUF_ERROR)
                    r = ZlibConstants.Z_OK;

                // update counters
                z.AvailableBytesOut -= n;
                z.TotalBytesOut += n;

                // update check information
                if (checkfn != null)
                    z._Adler32 = check = Adler.Adler32(check, window, q, n);

                // copy
                Array.Copy(window, q, z.OutputBuffer, p, n);
                p += n;
                q += n;
            }

            // update pointers
            z.NextOut = p;
            read = q;

            // done
            return r;
        }
 internal void Init(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, ZlibCodec z)
 {
     mode = START;
     lbits = (byte)bl;
     dbits = (byte)bd;
     ltree = tl;
     ltree_index = tl_index;
     dtree = td;
     dtree_index = td_index;
     tree = null;
 }
		internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z)
		{
			bl[0] = fixed_bl;
			bd[0] = fixed_bd;
			tl[0] = fixed_tl;
			td[0] = fixed_td;
			return Z_OK;
		}
        // 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 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

            int tp_index_t_3; // (tp_index+t)*3

            // load input, output, bit values
            p = z.NextIn; n = z.AvailableBytesIn; b = s.bitb; k = s.bitk;
            q = s.write; m = q < s.read ? s.read - q - 1 : s.end - q;

            // initialize masks
            ml = inflate_mask[bl];
            md = inflate_mask[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.InputBuffer[p++] & 0xff) << k; k += 8;
                }

                t = b & ml;
                tp = tl;
                tp_index = tl_index;
                tp_index_t_3 = (tp_index + t) * 3;
                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] + ((int)b & inflate_mask[e]);

                        b >>= e; k -= e;

                        // decode distance base of block to copy
                        while (k < (15))
                        {
                            // max bits for distance code
                            n--;
                            b |= (z.InputBuffer[p++] & 0xff) << k; k += 8;
                        }

                        t = b & md;
                        tp = td;
                        tp_index = td_index;
                        tp_index_t_3 = (tp_index + t) * 3;
                        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.InputBuffer[p++] & 0xff) << k; k += 8;
                                }

                                d = tp[tp_index_t_3 + 2] + (b & inflate_mask[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 && 2 > (q - r))
                                    {
                                        s.window[q++] = s.window[r++]; // minimum count is three,
                                        s.window[q++] = s.window[r++]; // so unroll loop a little
                                        c -= 2;
                                    }
                                    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 & inflate_mask[e]);
                                tp_index_t_3 = (tp_index + t) * 3;
                                e = tp[tp_index_t_3];
                            }
                            else
                            {
                                z.Message = "invalid distance code";

                                c = z.AvailableBytesIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= (c << 3);

                                s.bitb = b; s.bitk = k;
                                z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                s.write = q;

                                return ZlibConstants.Z_DATA_ERROR;
                            }
                        }
                        while (true);
                        break;
                    }

                    if ((e & 64) == 0)
                    {
                        t += tp[tp_index_t_3 + 2];
                        t += (b & inflate_mask[e]);
                        tp_index_t_3 = (tp_index + t) * 3;
                        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.AvailableBytesIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= (c << 3);

                        s.bitb = b; s.bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        s.write = q;

                        return ZlibConstants.Z_STREAM_END;
                    }
                    else
                    {
                        z.Message = "invalid literal/length code";

                        c = z.AvailableBytesIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= (c << 3);

                        s.bitb = b; s.bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        s.write = q;

                        return ZlibConstants.Z_DATA_ERROR;
                    }
                }
                while (true);
            }
            while (m >= 258 && n >= 10);

            // not enough input or output--restore pointers and return
            c = z.AvailableBytesIn - n; c = (k >> 3) < c ? k >> 3 : c; n += c; p -= c; k -= (c << 3);

            s.bitb = b; s.bitk = k;
            z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
            s.write = q;

            return ZlibConstants.Z_OK;
        }
        internal int SetDictionary(ZlibCodec z, byte[] dictionary)
        {
            int index = 0;
            int length = dictionary.Length;
            if (z == null || z.istate == null || z.istate.mode != DICT0)
                throw new ZlibException("Stream error.");

            if (Adler.Adler32(1L, dictionary, 0, dictionary.Length) != z._Adler32)
            {
                return ZlibConstants.Z_DATA_ERROR;
            }

            z._Adler32 = Adler.Adler32(0, null, 0, 0);

            if (length >= (1 << z.istate.wbits))
            {
                length = (1 << z.istate.wbits) - 1;
                index = dictionary.Length - length;
            }
            z.istate.blocks.SetDictionary(dictionary, index, length);
            z.istate.mode = BLOCKS;
            return ZlibConstants.Z_OK;
        }
		internal int inflate_trees_bits(int[] c, int[] bb, int[] tb, int[] hp, ZlibCodec z)
		{
			int result;
			initWorkArea(19);
			hn[0] = 0;
			result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
			
			if (result == Z_DATA_ERROR)
			{
				z.Message = "oversubscribed dynamic bit lengths tree";
			}
			else if (result == Z_BUF_ERROR || bb[0] == 0)
			{
				z.Message = "incomplete dynamic bit lengths tree";
				result = Z_DATA_ERROR;
			}
			return result;
		}
        internal int Initialize(ZlibCodec z, int w)
        {
            z.Message = null;
            blocks = null;

            // handle undocumented nowrap option (no zlib header or check)
            //nowrap = 0;
            //if (w < 0)
            //{
            //    w = - w;
            //    nowrap = 1;
            //}

            // set window size
            if (w < 8 || w > 15)
            {
                End(z);
                throw new ZlibException("Bad window size.");

                //return ZlibConstants.Z_STREAM_ERROR;
            }
            wbits = w;

            z.istate.blocks = new InflateBlocks(z,
                z.istate.HandleRfc1950HeaderBytes ? this : null,
                1 << w);

            // reset state
            Reset(z);
            return ZlibConstants.Z_OK;
        }
        internal int Inflate(ZlibCodec z, int f)
        {
            int r;
            int b;

            if (z == null)
                throw new ZlibException("Codec is null. ");
            if (z.istate == null)
                throw new ZlibException("InflateManager is null. ");
            if (z.InputBuffer == null)
                throw new ZlibException("InputBuffer is null. ");

            //return ZlibConstants.Z_STREAM_ERROR;

            f = (f == ZlibConstants.Z_FINISH)
                ? ZlibConstants.Z_BUF_ERROR
                : ZlibConstants.Z_OK;
            r = ZlibConstants.Z_BUF_ERROR;
            while (true)
            {
                switch (z.istate.mode)
                {
                    case METHOD:
                        if (z.AvailableBytesIn == 0)
                            return r;

                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        
                        if (((z.istate.method = z.InputBuffer[z.NextIn++]) & 0xf) != Z_DEFLATED)
                        {
                            z.istate.mode = BAD;
                            z.Message = String.Format("unknown compression method (0x{0:X2})", z.istate.method);
                            z.istate.marker = 5; // can't try inflateSync
                            break;
                        }
                        if ((z.istate.method >> 4) + 8 > z.istate.wbits)
                        {
                            z.istate.mode = BAD;
                            z.Message = String.Format("invalid window size ({0})", (z.istate.method >> 4) + 8);
                            z.istate.marker = 5; // can't try inflateSync
                            break;
                        }
                        z.istate.mode = FLAG;
                        goto case FLAG;

                    case FLAG:

                        if (z.AvailableBytesIn == 0) return r; 
                        
                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        b = (z.InputBuffer[z.NextIn++]) & 0xff;

                        if ((((z.istate.method << 8) + b) % 31) != 0)
                        {
                            z.istate.mode = BAD;
                            z.Message = "incorrect header check";
                            z.istate.marker = 5; // can't try inflateSync
                            break;
                        }

                        if ((b & PRESET_DICT) == 0)
                        {
                            z.istate.mode = BLOCKS;
                            break;
                        }
                        z.istate.mode = DICT4;
                        goto case DICT4;

                    case DICT4:

                        if (z.AvailableBytesIn == 0) return r;

                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        z.istate.need = ((z.InputBuffer[z.NextIn++] & 0xff) << 24) & unchecked((int)0xff000000L);
                        z.istate.mode = DICT3;
                        goto case DICT3;

                    case DICT3:

                        if (z.AvailableBytesIn == 0) return r;

                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        z.istate.need += (((z.InputBuffer[z.NextIn++] & 0xff) << 16) & 0xff0000L);
                        z.istate.mode = DICT2;
                        goto case DICT2;

                    case DICT2:

                        if (z.AvailableBytesIn == 0) return r;

                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        z.istate.need += (((z.InputBuffer[z.NextIn++] & 0xff) << 8) & 0xff00L);
                        z.istate.mode = DICT1;
                        goto case DICT1;

                    case DICT1:

                        if (z.AvailableBytesIn == 0) return r;

                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        z.istate.need += (z.InputBuffer[z.NextIn++] & 0xffL);
                        z._Adler32 = z.istate.need;
                        z.istate.mode = DICT0;
                        return ZlibConstants.Z_NEED_DICT;

                    case DICT0:
                        z.istate.mode = BAD;
                        z.Message = "need dictionary";
                        z.istate.marker = 0; // can try inflateSync
                        return ZlibConstants.Z_STREAM_ERROR;

                    case BLOCKS:

                        r = z.istate.blocks.Process(z, r);
                        if (r == ZlibConstants.Z_DATA_ERROR)
                        {
                            z.istate.mode = BAD;
                            z.istate.marker = 0; // can try inflateSync
                            break;
                        }
                        if (r == ZlibConstants.Z_OK) r = f;

                        if (r != ZlibConstants.Z_STREAM_END) return r;

                        r = f;
                        z.istate.blocks.Reset(z, z.istate.was);
                        if (!z.istate.HandleRfc1950HeaderBytes)
                        {
                            z.istate.mode = DONE;
                            break;
                        }
                        z.istate.mode = CHECK4;
                        goto case CHECK4;

                    case CHECK4:

                        if (z.AvailableBytesIn == 0) return r;

                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        z.istate.need = ((z.InputBuffer[z.NextIn++] & 0xff) << 24) & unchecked((int)0xff000000L);
                        z.istate.mode = CHECK3;
                        goto case CHECK3;

                    case CHECK3:

                        if (z.AvailableBytesIn == 0) return r;

                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        z.istate.need += (((z.InputBuffer[z.NextIn++] & 0xff) << 16) & 0xff0000L);
                        z.istate.mode = CHECK2;
                        goto case CHECK2;

                    case CHECK2:

                        if (z.AvailableBytesIn == 0) return r;
                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        z.istate.need += (((z.InputBuffer[z.NextIn++] & 0xff) << 8) & 0xff00L);
                        z.istate.mode = CHECK1;
                        goto case CHECK1;

                    case CHECK1:

                        if (z.AvailableBytesIn == 0) return r;

                        r = f;

                        z.AvailableBytesIn--; z.TotalBytesIn++;
                        z.istate.need += (z.InputBuffer[z.NextIn++] & 0xffL);

                        if (((int)(z.istate.was[0])) != ((int)(z.istate.need)))
                        {
                            z.istate.mode = BAD;
                            z.Message = "incorrect data check";
                            z.istate.marker = 5; // can't try inflateSync
                            break;
                        }

                        z.istate.mode = DONE;
                        goto case DONE;

                    case DONE:
                        return ZlibConstants.Z_STREAM_END;

                    case BAD:
                        throw new ZlibException(String.Format("Bad state ({0})", z.Message));
                    //return ZlibConstants.Z_DATA_ERROR;

                    default:
                        throw new ZlibException("Stream error.");
                    //return ZlibConstants.Z_STREAM_ERROR;

                }
            }
        }
 internal int End(ZlibCodec z)
 {
     if (blocks != null)
         blocks.Free(z);
     blocks = null;
     //    ZFREE(z, z->state);
     return ZlibConstants.Z_OK;
 }
        internal int Reset(ZlibCodec z)
        {
            if (z == null)
                throw new ZlibException("Codec is null.");

            if (z.istate == null)
                throw new ZlibException("InflateManager is null.");

            z.TotalBytesIn = z.TotalBytesOut = 0;
            z.Message = null;
            z.istate.mode = z.istate.HandleRfc1950HeaderBytes ? METHOD : BLOCKS;
            z.istate.blocks.Reset(z, null);
            return ZlibConstants.Z_OK;
        }
        internal int Process(ZlibCodec z, int r)
        {
            int t; // temporary storage
            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

            // copy input/output information to locals (UPDATE macro restores)
            {
                p = z.NextIn; n = z.AvailableBytesIn; b = bitb; k = bitk;
            }
            {
                q = write; m = (int)(q < read ? read - q - 1 : end - q);
            }

            // process input based on current state
            while (true)
            {
                switch (mode)
                {

                    case TYPE:

                        while (k < (3))
                        {
                            if (n != 0)
                            {
                                r = ZlibConstants.Z_OK;
                            }
                            else
                            {
                                bitb = b; bitk = k;
                                z.AvailableBytesIn = n;
                                z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                write = q;
                                return Flush(z, r);
                            }
                            ;
                            n--;
                            b |= (z.InputBuffer[p++] & 0xff) << k;
                            k += 8;
                        }
                        t = (int)(b & 7);
                        last = t & 1;

                        switch (SharedUtils.URShift(t, 1))
                        {

                            case 0:  // stored 
                                {
                                    b = SharedUtils.URShift(b, (3)); k -= (3);
                                }
                                t = k & 7; // go to byte boundary
                                {
                                    b = SharedUtils.URShift(b, (t)); k -= (t);
                                }
                                mode = LENS; // get length of stored block
                                break;

                            case 1:  // fixed
                                {
                                    int[] bl = new int[1];
                                    int[] bd = new int[1];
                                    int[][] tl = new int[1][];
                                    int[][] td = new int[1][];

                                    InfTree.inflate_trees_fixed(bl, bd, tl, td, z);
                                    codes.Init(bl[0], bd[0], tl[0], 0, td[0], 0, z);
                                }
                                {
                                    b = SharedUtils.URShift(b, (3)); k -= (3);
                                }

                                mode = CODES;
                                break;

                            case 2:  // dynamic
                                {
                                    b = SharedUtils.URShift(b, (3)); k -= (3);
                                }

                                mode = TABLE;
                                break;

                            case 3:  // illegal
                                {
                                    b = SharedUtils.URShift(b, (3)); k -= (3);
                                }
                                mode = BAD;
                                z.Message = "invalid block type";
                                r = ZlibConstants.Z_DATA_ERROR;

                                bitb = b; bitk = k;
                                z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                write = q;
                                return Flush(z, r);
                        }
                        break;

                    case LENS:

                        while (k < (32))
                        {
                            if (n != 0)
                            {
                                r = ZlibConstants.Z_OK;
                            }
                            else
                            {
                                bitb = b; bitk = k;
                                z.AvailableBytesIn = n;
                                z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                write = q;
                                return Flush(z, r);
                            }
                            ;
                            n--;
                            b |= (z.InputBuffer[p++] & 0xff) << k;
                            k += 8;
                        }

                        if (((SharedUtils.URShift((~b), 16)) & 0xffff) != (b & 0xffff))
                        {
                            mode = BAD;
                            z.Message = "invalid stored block lengths";
                            r = ZlibConstants.Z_DATA_ERROR;

                            bitb = b; bitk = k;
                            z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                            write = q;
                            return Flush(z, r);
                        }
                        left = (b & 0xffff);
                        b = k = 0; // dump bits
                        mode = left != 0 ? STORED : (last != 0 ? DRY : TYPE);
                        break;

                    case STORED:
                        if (n == 0)
                        {
                            bitb = b; bitk = k;
                            z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                            write = q;
                            return Flush(z, r);
                        }

                        if (m == 0)
                        {
                            if (q == end && read != 0)
                            {
                                q = 0; m = (int)(q < read ? read - q - 1 : end - q);
                            }
                            if (m == 0)
                            {
                                write = q;
                                r = Flush(z, r);
                                q = write; m = (int)(q < read ? read - q - 1 : end - q);
                                if (q == end && read != 0)
                                {
                                    q = 0; m = (int)(q < read ? read - q - 1 : end - q);
                                }
                                if (m == 0)
                                {
                                    bitb = b; bitk = k;
                                    z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                    write = q;
                                    return Flush(z, r);
                                }
                            }
                        }
                        r = ZlibConstants.Z_OK;

                        t = left;
                        if (t > n)
                            t = n;
                        if (t > m)
                            t = m;
                        Array.Copy(z.InputBuffer, p, window, q, t);
                        p += t; n -= t;
                        q += t; m -= t;
                        if ((left -= t) != 0)
                            break;
                        mode = last != 0 ? DRY : TYPE;
                        break;

                    case TABLE:

                        while (k < (14))
                        {
                            if (n != 0)
                            {
                                r = ZlibConstants.Z_OK;
                            }
                            else
                            {
                                bitb = b; bitk = k;
                                z.AvailableBytesIn = n;
                                z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                write = q;
                                return Flush(z, r);
                            }
                            ;
                            n--;
                            b |= (z.InputBuffer[p++] & 0xff) << k;
                            k += 8;
                        }

                        table = t = (b & 0x3fff);
                        if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
                        {
                            mode = BAD;
                            z.Message = "too many length or distance symbols";
                            r = ZlibConstants.Z_DATA_ERROR;

                            bitb = b; bitk = k;
                            z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                            write = q;
                            return Flush(z, r);
                        }
                        t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
                        if (blens == null || blens.Length < t)
                        {
                            blens = new int[t];
                        }
                        else
                        {
                            for (int i = 0; i < t; i++)
                            {
                                blens[i] = 0;
                            }
                        }
                        {
                            b = SharedUtils.URShift(b, (14)); k -= (14);
                        }

                        index = 0;
                        mode = BTREE;
                        goto case BTREE;

                    case BTREE:
                        while (index < 4 + (SharedUtils.URShift(table, 10)))
                        {
                            while (k < (3))
                            {
                                if (n != 0)
                                {
                                    r = ZlibConstants.Z_OK;
                                }
                                else
                                {
                                    bitb = b; bitk = k;
                                    z.AvailableBytesIn = n;
                                    z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                    write = q;
                                    return Flush(z, r);
                                }
                                ;
                                n--;
                                b |= (z.InputBuffer[p++] & 0xff) << k;
                                k += 8;
                            }

                            blens[border[index++]] = b & 7;

                            {
                                b = SharedUtils.URShift(b, (3)); k -= (3);
                            }
                        }

                        while (index < 19)
                        {
                            blens[border[index++]] = 0;
                        }

                        bb[0] = 7;
                        t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z);
                        if (t != ZlibConstants.Z_OK)
                        {
                            r = t;
                            if (r == ZlibConstants.Z_DATA_ERROR)
                            {
                                blens = null;
                                mode = BAD;
                            }

                            bitb = b; bitk = k;
                            z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                            write = q;
                            return Flush(z, r);
                        }

                        index = 0;
                        mode = DTREE;
                        goto case DTREE;

                    case DTREE:
                        while (true)
                        {
                            t = table;
                            if (!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)))
                            {
                                break;
                            }

                            int i, j, c;

                            t = bb[0];

                            while (k < (t))
                            {
                                if (n != 0)
                                {
                                    r = ZlibConstants.Z_OK;
                                }
                                else
                                {
                                    bitb = b; bitk = k;
                                    z.AvailableBytesIn = n;
                                    z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                    write = q;
                                    return Flush(z, r);
                                }
                                ;
                                n--;
                                b |= (z.InputBuffer[p++] & 0xff) << k;
                                k += 8;
                            }

                            if (tb[0] == -1)
                            {
                                //System.err.println("null...");
                            }

                            t = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 1];
                            c = hufts[(tb[0] + (b & inflate_mask[t])) * 3 + 2];

                            if (c < 16)
                            {
                                b = SharedUtils.URShift(b, (t)); k -= (t);
                                blens[index++] = c;
                            }
                            else
                            {
                                // c == 16..18
                                i = c == 18 ? 7 : c - 14;
                                j = c == 18 ? 11 : 3;

                                while (k < (t + i))
                                {
                                    if (n != 0)
                                    {
                                        r = ZlibConstants.Z_OK;
                                    }
                                    else
                                    {
                                        bitb = b; bitk = k;
                                        z.AvailableBytesIn = n;
                                        z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                        write = q;
                                        return Flush(z, r);
                                    }
                                    ;
                                    n--;
                                    b |= (z.InputBuffer[p++] & 0xff) << k;
                                    k += 8;
                                }

                                b = SharedUtils.URShift(b, (t)); k -= (t);

                                j += (b & inflate_mask[i]);

                                b = SharedUtils.URShift(b, (i)); k -= (i);

                                i = index;
                                t = table;
                                if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || (c == 16 && i < 1))
                                {
                                    blens = null;
                                    mode = BAD;
                                    z.Message = "invalid bit length repeat";
                                    r = ZlibConstants.Z_DATA_ERROR;

                                    bitb = b; bitk = k;
                                    z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                    write = q;
                                    return Flush(z, r);
                                }

                                c = c == 16 ? blens[i - 1] : 0;
                                do
                                {
                                    blens[i++] = c;
                                }
                                while (--j != 0);
                                index = i;
                            }
                        }

                        tb[0] = -1;
                        {
                            int[] bl = new int[] { 9 };  // must be <= 9 for lookahead assumptions
                            int[] bd = new int[] { 6 }; // must be <= 9 for lookahead assumptions							
                            int[] tl = new int[1];
                            int[] td = new int[1];

                            t = table;
                            t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), blens, bl, bd, tl, td, hufts, z);

                            if (t != ZlibConstants.Z_OK)
                            {
                                if (t == ZlibConstants.Z_DATA_ERROR)
                                {
                                    blens = null;
                                    mode = BAD;
                                }
                                r = t;

                                bitb = b; bitk = k;
                                z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                                write = q;
                                return Flush(z, r);
                            }
                            codes.Init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z);
                        }
                        mode = CODES;
                        goto case CODES;

                    case CODES:
                        bitb = b; bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        write = q;

                        if ((r = codes.Process(this, z, r)) != ZlibConstants.Z_STREAM_END)
                        {
                            return Flush(z, r);
                        }
                        r = ZlibConstants.Z_OK;
                        p = z.NextIn; n = z.AvailableBytesIn; b = bitb; k = bitk;
                        q = write; m = (int)(q < read ? read - q - 1 : end - q);

                        if (last == 0)
                        {
                            mode = TYPE;
                            break;
                        }
                        mode = DRY;
                        goto case DRY;

                    case DRY:
                        write = q;
                        r = Flush(z, r);
                        q = write; m = (int)(q < read ? read - q - 1 : end - q);
                        if (read != write)
                        {
                            bitb = b; bitk = k;
                            z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                            write = q;
                            return Flush(z, r);
                        }
                        mode = DONE;
                        goto case DONE;

                    case DONE:
                        r = ZlibConstants.Z_STREAM_END;

                        bitb = b; bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        write = q;
                        return Flush(z, r);

                    case BAD:
                        r = ZlibConstants.Z_DATA_ERROR;

                        bitb = b; bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        write = q;
                        return Flush(z, r);


                    default:
                        r = ZlibConstants.Z_STREAM_ERROR;

                        bitb = b; bitk = k;
                        z.AvailableBytesIn = n; z.TotalBytesIn += p - z.NextIn; z.NextIn = p;
                        write = q;
                        return Flush(z, r);

                }
            }
        }
        internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZlibCodec z)
        {
            int result;

            // build literal/length tree
            initWorkArea(288);
            hn[0]  = 0;
            result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
            if (result != Z_OK || bl[0] == 0)
            {
                if (result == Z_DATA_ERROR)
                {
                    z.Message = "oversubscribed literal/length tree";
                }
                else if (result != Z_MEM_ERROR)
                {
                    z.Message = "incomplete literal/length tree";
                    result    = Z_DATA_ERROR;
                }
                return(result);
            }

            // build distance tree
            initWorkArea(288);
            result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);

            if (result != Z_OK || (bd[0] == 0 && nl > 257))
            {
                if (result == Z_DATA_ERROR)
                {
                    z.Message = "oversubscribed distance tree";
                }
                else if (result == Z_BUF_ERROR)
                {
                    z.Message = "incomplete distance tree";
                    result    = Z_DATA_ERROR;
                }
                else if (result != Z_MEM_ERROR)
                {
                    z.Message = "empty distance tree with lengths";
                    result    = Z_DATA_ERROR;
                }
                return(result);
            }

            return(Z_OK);
        }
        internal int Sync(ZlibCodec z)
        {
            int n; // number of bytes to look at
            int p; // pointer to bytes
            int m; // number of marker bytes found in a row
            long r, w; // temporaries to save total_in and total_out

            // set up
            if (z == null || z.istate == null)
                return ZlibConstants.Z_STREAM_ERROR;
            if (z.istate.mode != BAD)
            {
                z.istate.mode = BAD;
                z.istate.marker = 0;
            }
            if ((n = z.AvailableBytesIn) == 0)
                return ZlibConstants.Z_BUF_ERROR;
            p = z.NextIn;
            m = z.istate.marker;

            // search
            while (n != 0 && m < 4)
            {
                if (z.InputBuffer[p] == mark[m])
                {
                    m++;
                }
                else if (z.InputBuffer[p] != 0)
                {
                    m = 0;
                }
                else
                {
                    m = 4 - m;
                }
                p++; n--;
            }

            // restore
            z.TotalBytesIn += p - z.NextIn;
            z.NextIn = p;
            z.AvailableBytesIn = n;
            z.istate.marker = m;

            // return no joy or set up to restart on a new block
            if (m != 4)
            {
                return ZlibConstants.Z_DATA_ERROR;
            }
            r = z.TotalBytesIn; w = z.TotalBytesOut;
            Reset(z);
            z.TotalBytesIn = r; z.TotalBytesOut = w;
            z.istate.mode = BLOCKS;
            return ZlibConstants.Z_OK;
        }
 internal static int inflate_trees_fixed(int[] bl, int[] bd, int[][] tl, int[][] td, ZlibCodec z)
 {
     bl[0] = fixed_bl;
     bd[0] = fixed_bd;
     tl[0] = fixed_tl;
     td[0] = fixed_td;
     return(Z_OK);
 }
 // Returns true if inflate is currently at the end of a block generated
 // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
 // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
 // but removes the length bytes of the resulting empty stored block. When
 // decompressing, PPP checks that at the end of input packet, inflate is
 // waiting for these length bytes.
 internal int SyncPoint(ZlibCodec z)
 {
     if (z == null || z.istate == null || z.istate.blocks == null)
         return ZlibConstants.Z_STREAM_ERROR;
     return z.istate.blocks.SyncPoint();
 }
		internal int inflate_trees_dynamic(int nl, int nd, int[] c, int[] bl, int[] bd, int[] tl, int[] td, int[] hp, ZlibCodec z)
		{
			int result;
			
			// build literal/length tree
			initWorkArea(288);
			hn[0] = 0;
			result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
			if (result != Z_OK || bl[0] == 0)
			{
				if (result == Z_DATA_ERROR)
				{
					z.Message = "oversubscribed literal/length tree";
				}
				else if (result != Z_MEM_ERROR)
				{
					z.Message = "incomplete literal/length tree";
					result = Z_DATA_ERROR;
				}
				return result;
			}
			
			// build distance tree
			initWorkArea(288);
			result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
			
			if (result != Z_OK || (bd[0] == 0 && nl > 257))
			{
				if (result == Z_DATA_ERROR)
				{
					z.Message = "oversubscribed distance tree";
				}
				else if (result == Z_BUF_ERROR)
				{
					z.Message = "incomplete distance tree";
					result = Z_DATA_ERROR;
				}
				else if (result != Z_MEM_ERROR)
				{
					z.Message = "empty distance tree with lengths";
					result = Z_DATA_ERROR;
				}
				return result;
			}
			
			return Z_OK;
		}
 internal void Free(ZlibCodec z)
 {
     Reset(z, null);
     window = null;
     hufts = null;
     //ZFREE(z, s);
 }
 private void end()
 {
     if (_z == null)
         return;
     if (_wantCompress)
     {
         //_z.EndDeflate();
     }
     else
     {
         _z.EndInflate();
     }
     _z = null;
 }
        internal void Reset(ZlibCodec z, long[] c)
        {
            if (c != null)
                c[0] = check;
            if (mode == BTREE || mode == DTREE)
            {
            }
            if (mode == CODES)
            {
            }
            mode = TYPE;
            bitk = 0;
            bitb = 0;
            read = write = 0;

            if (checkfn != null)
                z._Adler32 = check = Adler.Adler32(0L, null, 0, 0);
        }