using System;

namespace ComponentAce.Compression.Libs.zlib
{
    internal sealed class InfCodes
    {
    	private static readonly int[] inflate_mask = new int[17]
    	{
    		0, 1, 3, 7, 15, 31, 63, 127, 255, 511,
    		1023, 2047, 4095, 8191, 16383, 32767, 65535
    	};

    	private const int Z_OK = 0;

    	private const int Z_STREAM_END = 1;

    	private const int Z_NEED_DICT = 2;

    	private const int Z_ERRNO = -1;

    	private const int Z_STREAM_ERROR = -2;

    	private const int Z_DATA_ERROR = -3;

    	private const int Z_MEM_ERROR = -4;

    	private const int Z_BUF_ERROR = -5;

    	private const int Z_VERSION_ERROR = -6;

    	private const int START = 0;

    	private const int LEN = 1;

    	private const int LENEXT = 2;

    	private const int DIST = 3;

    	private const int DISTEXT = 4;

    	private const int COPY = 5;

    	private const int LIT = 6;

    	private const int WASH = 7;

    	private const int END = 8;

    	private const int BADCODE = 9;

    	internal int mode;

    	internal int len;

    	internal int[] tree;

    	internal int tree_index;

    	internal int need;

    	internal int lit;

    	internal int get_Renamed;

    	internal int dist;

    	internal byte lbits;

    	internal byte dbits;

    	internal int[] ltree;

    	internal int ltree_index;

    	internal int[] dtree;

    	internal int dtree_index;

    	internal InfCodes(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, ZStream z)
    	{
    		mode = 0;
    		lbits = (byte)bl;
    		dbits = (byte)bd;
    		ltree = tl;
    		ltree_index = tl_index;
    		dtree = td;
    		dtree_index = td_index;
    	}

    	internal InfCodes(int bl, int bd, int[] tl, int[] td, ZStream z)
    	{
    		mode = 0;
    		lbits = (byte)bl;
    		dbits = (byte)bd;
    		ltree = tl;
    		ltree_index = 0;
    		dtree = td;
    		dtree_index = 0;
    	}

    	internal int proc(InfBlocks s, ZStream z, int r)
    	{
    		int num = 0;
    		int num2 = 0;
    		int num3 = 0;
    		num3 = z.next_in_index;
    		int num4 = z.avail_in;
    		num = s.bitb;
    		num2 = s.bitk;
    		int num5 = s.write;
    		int num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    		while (true)
    		{
    			switch (mode)
    			{
    			case 0:
    				if (num6 >= 258 && num4 >= 10)
    				{
    					s.bitb = num;
    					s.bitk = num2;
    					z.avail_in = num4;
    					z.total_in += num3 - z.next_in_index;
    					z.next_in_index = num3;
    					s.write = num5;
    					r = inflate_fast(lbits, dbits, ltree, ltree_index, dtree, dtree_index, s, z);
    					num3 = z.next_in_index;
    					num4 = z.avail_in;
    					num = s.bitb;
    					num2 = s.bitk;
    					num5 = s.write;
    					num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    					if (r != 0)
    					{
    						mode = ((r == 1) ? 7 : 9);
    						break;
    					}
    				}
    				need = lbits;
    				tree = ltree;
    				tree_index = ltree_index;
    				mode = 1;
    				goto case 1;
    			case 1:
    			{
    				int num7;
    				for (num7 = need; num2 < num7; num2 += 8)
    				{
    					if (num4 != 0)
    					{
    						r = 0;
    						num4--;
    						num |= (z.next_in[num3++] & 0xFF) << num2;
    						continue;
    					}
    					s.bitb = num;
    					s.bitk = num2;
    					z.avail_in = num4;
    					z.total_in += num3 - z.next_in_index;
    					z.next_in_index = num3;
    					s.write = num5;
    					return s.inflate_flush(z, r);
    				}
    				int num8 = (tree_index + (num & inflate_mask[num7])) * 3;
    				num = SupportClass.URShift(num, tree[num8 + 1]);
    				num2 -= tree[num8 + 1];
    				int num9 = tree[num8];
    				if (num9 == 0)
    				{
    					lit = tree[num8 + 2];
    					mode = 6;
    					break;
    				}
    				if (((uint)num9 & 0x10u) != 0)
    				{
    					get_Renamed = num9 & 0xF;
    					len = tree[num8 + 2];
    					mode = 2;
    					break;
    				}
    				if ((num9 & 0x40) == 0)
    				{
    					need = num9;
    					tree_index = num8 / 3 + tree[num8 + 2];
    					break;
    				}
    				if (((uint)num9 & 0x20u) != 0)
    				{
    					mode = 7;
    					break;
    				}
    				mode = 9;
    				z.msg = "invalid literal/length code";
    				r = -3;
    				s.bitb = num;
    				s.bitk = num2;
    				z.avail_in = num4;
    				z.total_in += num3 - z.next_in_index;
    				z.next_in_index = num3;
    				s.write = num5;
    				return s.inflate_flush(z, r);
    			}
    			case 2:
    			{
    				int num7;
    				for (num7 = get_Renamed; num2 < num7; num2 += 8)
    				{
    					if (num4 != 0)
    					{
    						r = 0;
    						num4--;
    						num |= (z.next_in[num3++] & 0xFF) << num2;
    						continue;
    					}
    					s.bitb = num;
    					s.bitk = num2;
    					z.avail_in = num4;
    					z.total_in += num3 - z.next_in_index;
    					z.next_in_index = num3;
    					s.write = num5;
    					return s.inflate_flush(z, r);
    				}
    				len += num & inflate_mask[num7];
    				num >>= num7;
    				num2 -= num7;
    				need = dbits;
    				tree = dtree;
    				tree_index = dtree_index;
    				mode = 3;
    				goto case 3;
    			}
    			case 3:
    			{
    				int num7;
    				for (num7 = need; num2 < num7; num2 += 8)
    				{
    					if (num4 != 0)
    					{
    						r = 0;
    						num4--;
    						num |= (z.next_in[num3++] & 0xFF) << num2;
    						continue;
    					}
    					s.bitb = num;
    					s.bitk = num2;
    					z.avail_in = num4;
    					z.total_in += num3 - z.next_in_index;
    					z.next_in_index = num3;
    					s.write = num5;
    					return s.inflate_flush(z, r);
    				}
    				int num8 = (tree_index + (num & inflate_mask[num7])) * 3;
    				num >>= tree[num8 + 1];
    				num2 -= tree[num8 + 1];
    				int num9 = tree[num8];
    				if (((uint)num9 & 0x10u) != 0)
    				{
    					get_Renamed = num9 & 0xF;
    					dist = tree[num8 + 2];
    					mode = 4;
    					break;
    				}
    				if ((num9 & 0x40) == 0)
    				{
    					need = num9;
    					tree_index = num8 / 3 + tree[num8 + 2];
    					break;
    				}
    				mode = 9;
    				z.msg = "invalid distance code";
    				r = -3;
    				s.bitb = num;
    				s.bitk = num2;
    				z.avail_in = num4;
    				z.total_in += num3 - z.next_in_index;
    				z.next_in_index = num3;
    				s.write = num5;
    				return s.inflate_flush(z, r);
    			}
    			case 4:
    			{
    				int num7;
    				for (num7 = get_Renamed; num2 < num7; num2 += 8)
    				{
    					if (num4 != 0)
    					{
    						r = 0;
    						num4--;
    						num |= (z.next_in[num3++] & 0xFF) << num2;
    						continue;
    					}
    					s.bitb = num;
    					s.bitk = num2;
    					z.avail_in = num4;
    					z.total_in += num3 - z.next_in_index;
    					z.next_in_index = num3;
    					s.write = num5;
    					return s.inflate_flush(z, r);
    				}
    				dist += num & inflate_mask[num7];
    				num >>= num7;
    				num2 -= num7;
    				mode = 5;
    				goto case 5;
    			}
    			case 5:
    			{
    				int i;
    				for (i = num5 - dist; i < 0; i += s.end)
    				{
    				}
    				while (len != 0)
    				{
    					if (num6 == 0)
    					{
    						if (num5 == s.end && s.read != 0)
    						{
    							num5 = 0;
    							num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    						}
    						if (num6 == 0)
    						{
    							s.write = num5;
    							r = s.inflate_flush(z, r);
    							num5 = s.write;
    							num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    							if (num5 == s.end && s.read != 0)
    							{
    								num5 = 0;
    								num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    							}
    							if (num6 == 0)
    							{
    								s.bitb = num;
    								s.bitk = num2;
    								z.avail_in = num4;
    								z.total_in += num3 - z.next_in_index;
    								z.next_in_index = num3;
    								s.write = num5;
    								return s.inflate_flush(z, r);
    							}
    						}
    					}
    					s.window[num5++] = s.window[i++];
    					num6--;
    					if (i == s.end)
    					{
    						i = 0;
    					}
    					len--;
    				}
    				mode = 0;
    				break;
    			}
    			case 6:
    				if (num6 == 0)
    				{
    					if (num5 == s.end && s.read != 0)
    					{
    						num5 = 0;
    						num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    					}
    					if (num6 == 0)
    					{
    						s.write = num5;
    						r = s.inflate_flush(z, r);
    						num5 = s.write;
    						num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    						if (num5 == s.end && s.read != 0)
    						{
    							num5 = 0;
    							num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    						}
    						if (num6 == 0)
    						{
    							s.bitb = num;
    							s.bitk = num2;
    							z.avail_in = num4;
    							z.total_in += num3 - z.next_in_index;
    							z.next_in_index = num3;
    							s.write = num5;
    							return s.inflate_flush(z, r);
    						}
    					}
    				}
    				r = 0;
    				s.window[num5++] = (byte)lit;
    				num6--;
    				mode = 0;
    				break;
    			case 7:
    				if (num2 > 7)
    				{
    					num2 -= 8;
    					num4++;
    					num3--;
    				}
    				s.write = num5;
    				r = s.inflate_flush(z, r);
    				num5 = s.write;
    				num6 = ((num5 < s.read) ? (s.read - num5 - 1) : (s.end - num5));
    				if (s.read != s.write)
    				{
    					s.bitb = num;
    					s.bitk = num2;
    					z.avail_in = num4;
    					z.total_in += num3 - z.next_in_index;
    					z.next_in_index = num3;
    					s.write = num5;
    					return s.inflate_flush(z, r);
    				}
    				mode = 8;
    				goto case 8;
    			case 8:
    				r = 1;
    				s.bitb = num;
    				s.bitk = num2;
    				z.avail_in = num4;
    				z.total_in += num3 - z.next_in_index;
    				z.next_in_index = num3;
    				s.write = num5;
    				return s.inflate_flush(z, r);
    			case 9:
    				r = -3;
    				s.bitb = num;
    				s.bitk = num2;
    				z.avail_in = num4;
    				z.total_in += num3 - z.next_in_index;
    				z.next_in_index = num3;
    				s.write = num5;
    				return s.inflate_flush(z, r);
    			default:
    				r = -2;
    				s.bitb = num;
    				s.bitk = num2;
    				z.avail_in = num4;
    				z.total_in += num3 - z.next_in_index;
    				z.next_in_index = num3;
    				s.write = num5;
    				return s.inflate_flush(z, r);
    			}
    		}
    	}

    	internal void free(ZStream z)
    	{
    	}

    	internal int inflate_fast(int bl, int bd, int[] tl, int tl_index, int[] td, int td_index, InfBlocks s, ZStream z)
    	{
    		int next_in_index = z.next_in_index;
    		int num = z.avail_in;
    		int num2 = s.bitb;
    		int num3 = s.bitk;
    		int num4 = s.write;
    		int num5 = ((num4 < s.read) ? (s.read - num4 - 1) : (s.end - num4));
    		int num6 = inflate_mask[bl];
    		int num7 = inflate_mask[bd];
    		int num11;
    		while (true)
    		{
    			if (num3 < 20)
    			{
    				num--;
    				num2 |= (z.next_in[next_in_index++] & 0xFF) << num3;
    				num3 += 8;
    				continue;
    			}
    			int num8 = num2 & num6;
    			int[] array = tl;
    			int num9 = tl_index;
    			int num10;
    			if ((num10 = array[(num9 + num8) * 3]) == 0)
    			{
    				num2 >>= array[(num9 + num8) * 3 + 1];
    				num3 -= array[(num9 + num8) * 3 + 1];
    				s.window[num4++] = (byte)array[(num9 + num8) * 3 + 2];
    				num5--;
    			}
    			else
    			{
    				while (true)
    				{
    					num2 >>= array[(num9 + num8) * 3 + 1];
    					num3 -= array[(num9 + num8) * 3 + 1];
    					if (((uint)num10 & 0x10u) != 0)
    					{
    						num10 &= 0xF;
    						num11 = array[(num9 + num8) * 3 + 2] + (num2 & inflate_mask[num10]);
    						num2 >>= num10;
    						for (num3 -= num10; num3 < 15; num3 += 8)
    						{
    							num--;
    							num2 |= (z.next_in[next_in_index++] & 0xFF) << num3;
    						}
    						num8 = num2 & num7;
    						array = td;
    						num9 = td_index;
    						num10 = array[(num9 + num8) * 3];
    						while (true)
    						{
    							num2 >>= array[(num9 + num8) * 3 + 1];
    							num3 -= array[(num9 + num8) * 3 + 1];
    							if (((uint)num10 & 0x10u) != 0)
    							{
    								break;
    							}
    							if ((num10 & 0x40) == 0)
    							{
    								num8 += array[(num9 + num8) * 3 + 2];
    								num8 += num2 & inflate_mask[num10];
    								num10 = array[(num9 + num8) * 3];
    								continue;
    							}
    							z.msg = "invalid distance code";
    							num11 = z.avail_in - num;
    							num11 = ((num3 >> 3 < num11) ? (num3 >> 3) : num11);
    							num += num11;
    							next_in_index -= num11;
    							num3 -= num11 << 3;
    							s.bitb = num2;
    							s.bitk = num3;
    							z.avail_in = num;
    							z.total_in += next_in_index - z.next_in_index;
    							z.next_in_index = next_in_index;
    							s.write = num4;
    							return -3;
    						}
    						for (num10 &= 0xF; num3 < num10; num3 += 8)
    						{
    							num--;
    							num2 |= (z.next_in[next_in_index++] & 0xFF) << num3;
    						}
    						int num12 = array[(num9 + num8) * 3 + 2] + (num2 & inflate_mask[num10]);
    						num2 >>= num10;
    						num3 -= num10;
    						num5 -= num11;
    						int num13;
    						if (num4 >= num12)
    						{
    							num13 = num4 - num12;
    							if (num4 - num13 > 0 && 2 > num4 - num13)
    							{
    								s.window[num4++] = s.window[num13++];
    								num11--;
    								s.window[num4++] = s.window[num13++];
    								num11--;
    							}
    							else
    							{
    								Array.Copy(s.window, num13, s.window, num4, 2);
    								num4 += 2;
    								num13 += 2;
    								num11 -= 2;
    							}
    						}
    						else
    						{
    							num13 = num4 - num12;
    							do
    							{
    								num13 += s.end;
    							}
    							while (num13 < 0);
    							num10 = s.end - num13;
    							if (num11 > num10)
    							{
    								num11 -= num10;
    								if (num4 - num13 > 0 && num10 > num4 - num13)
    								{
    									do
    									{
    										s.window[num4++] = s.window[num13++];
    									}
    									while (--num10 != 0);
    								}
    								else
    								{
    									Array.Copy(s.window, num13, s.window, num4, num10);
    									num4 += num10;
    									num13 += num10;
    									num10 = 0;
    								}
    								num13 = 0;
    							}
    						}
    						if (num4 - num13 > 0 && num11 > num4 - num13)
    						{
    							do
    							{
    								s.window[num4++] = s.window[num13++];
    							}
    							while (--num11 != 0);
    							break;
    						}
    						Array.Copy(s.window, num13, s.window, num4, num11);
    						num4 += num11;
    						num13 += num11;
    						num11 = 0;
    						break;
    					}
    					if ((num10 & 0x40) == 0)
    					{
    						num8 += array[(num9 + num8) * 3 + 2];
    						num8 += num2 & inflate_mask[num10];
    						if ((num10 = array[(num9 + num8) * 3]) == 0)
    						{
    							num2 >>= array[(num9 + num8) * 3 + 1];
    							num3 -= array[(num9 + num8) * 3 + 1];
    							s.window[num4++] = (byte)array[(num9 + num8) * 3 + 2];
    							num5--;
    							break;
    						}
    						continue;
    					}
    					if (((uint)num10 & 0x20u) != 0)
    					{
    						num11 = z.avail_in - num;
    						num11 = ((num3 >> 3 < num11) ? (num3 >> 3) : num11);
    						num += num11;
    						next_in_index -= num11;
    						num3 -= num11 << 3;
    						s.bitb = num2;
    						s.bitk = num3;
    						z.avail_in = num;
    						z.total_in += next_in_index - z.next_in_index;
    						z.next_in_index = next_in_index;
    						s.write = num4;
    						return 1;
    					}
    					z.msg = "invalid literal/length code";
    					num11 = z.avail_in - num;
    					num11 = ((num3 >> 3 < num11) ? (num3 >> 3) : num11);
    					num += num11;
    					next_in_index -= num11;
    					num3 -= num11 << 3;
    					s.bitb = num2;
    					s.bitk = num3;
    					z.avail_in = num;
    					z.total_in += next_in_index - z.next_in_index;
    					z.next_in_index = next_in_index;
    					s.write = num4;
    					return -3;
    				}
    			}
    			if (num5 < 258 || num < 10)
    			{
    				break;
    			}
    		}
    		num11 = z.avail_in - num;
    		num11 = ((num3 >> 3 < num11) ? (num3 >> 3) : num11);
    		num += num11;
    		next_in_index -= num11;
    		num3 -= num11 << 3;
    		s.bitb = num2;
    		s.bitk = num3;
    		z.avail_in = num;
    		z.total_in += next_in_index - z.next_in_index;
    		z.next_in_index = next_in_index;
    		s.write = num4;
    		return 0;
    	}
    }
}