#define TRACE
using System;
using System.Diagnostics;
using System.Text;

namespace Decal.Filters;

internal class zlib
{
	private byte[] mInData;

	private int mInIndex;

	private int mInCount;

	private int mInBuf;

	private int mInBufSize;

	private byte[] mOutData;

	private int mOutIndex;

	private int mOutCount;

	private short[] mDynLCodeTree;

	private short[] mDynDCodeTree;

	private static short[] mFixLCodeTree;

	private static short[] mFixDCodeTree;

	public static byte[] Inflate(byte[] CompressedData, int UncompressedSize)
	{
		byte[] array = (byte[])Array.CreateInstance(typeof(byte), UncompressedSize);
		new zlib(CompressedData, 0, CompressedData.Length, array, 0, UncompressedSize).Inflate();
		return array;
	}

	internal zlib(byte[] InData, int InIndex, int InCount, byte[] OutData, int OutIndex, int OutCount)
	{
		mInData = InData;
		mInIndex = InIndex;
		mInCount = InCount;
		mOutData = OutData;
		mOutIndex = OutIndex;
		mOutCount = OutCount;
	}

	internal bool Inflate()
	{
		byte b = Get.Byte(mInData, ref mInIndex);
		mInCount--;
		byte b2 = Get.Byte(mInData, ref mInIndex);
		mInCount--;
		int num = 0;
		if ((b2 & 0x20) != 0)
		{
			num = Get.DWord(mInData, ref mInIndex);
			mInCount -= 4;
		}
		if ((b & 0xF) != 8)
		{
			Trace.WriteLine(new StringBuilder(64).AppendFormat("zlib.Inflate() Warning: unknown compression method 0x{0:x1}", b & 0xF).ToString());
			return false;
		}
		if (b >> 4 != 7)
		{
			Trace.WriteLine("zlib.Inflate() Warning: window size other than 32K");
			return false;
		}
		if ((b2 & 0x20) != 0)
		{
			Trace.WriteLine(new StringBuilder(64).AppendFormat("zlib.Inflate() Warning: unknown DICTID 0x{0:x8}", num).ToString());
			return false;
		}
		int bits;
		do
		{
			bits = GetBits(1);
			switch (GetBits(2))
			{
			case 0:
			{
				GetBits(0);
				int bits2 = GetBits(16);
				int bits3 = GetBits(16);
				if (bits2 != (~bits3 & 0xFFFF))
				{
					Trace.WriteLine("zlib.Inflate() Warning: LEN != ~NLEN");
				}
				Buffer.BlockCopy(mInData, mInIndex, mOutData, mOutIndex, bits2);
				mInIndex += bits2;
				mOutIndex += bits2;
				break;
			}
			case 1:
				if ((mFixLCodeTree == null || mFixDCodeTree == null) && !InitFixedCodes())
				{
					return false;
				}
				if (!Decompress(mFixLCodeTree, mFixDCodeTree))
				{
					return false;
				}
				break;
			case 2:
				if (!InitDynamicCodes())
				{
					return false;
				}
				if (!Decompress(mDynLCodeTree, mDynDCodeTree))
				{
					return false;
				}
				break;
			case 3:
				Trace.WriteLine("zlib.Inflate() Warning: unhandled block type 3");
				return false;
			}
		}
		while (bits != 1);
		for (int i = 0; i < 4; i++)
		{
			GetBits(8);
		}
		return true;
	}

	private static bool InitFixedCodes()
	{
		int[] array = (int[])Array.CreateInstance(typeof(int), 288);
		int[] array2 = (int[])Array.CreateInstance(typeof(int), 32);
		int i;
		for (i = 0; i < 144; i++)
		{
			array[i] = 8;
		}
		for (; i < 256; i++)
		{
			array[i] = 9;
		}
		for (; i < 280; i++)
		{
			array[i] = 7;
		}
		for (; i < 288; i++)
		{
			array[i] = 8;
		}
		for (i = 0; i < 32; i++)
		{
			array2[i] = 5;
		}
		mFixLCodeTree = BuildCodeTree(array, 0, 288, 65536);
		mFixDCodeTree = BuildCodeTree(array2, 0, 32, 65536);
		return true;
	}

	private bool InitDynamicCodes()
	{
		int[] array = new int[19]
		{
			16, 17, 18, 0, 8, 7, 9, 6, 10, 5,
			11, 4, 12, 3, 13, 2, 14, 1, 15
		};
		int num = GetBits(5) + 257;
		int num2 = GetBits(5) + 1;
		int num3 = GetBits(4) + 4;
		int[] array2 = (int[])Array.CreateInstance(typeof(int), 19);
		for (int i = 0; i < num3; i++)
		{
			array2[array[i]] = GetBits(3);
		}
		short[] codeTree = BuildCodeTree(array2, 0, 19, 256);
		int num4 = num + num2;
		int[] array3 = (int[])Array.CreateInstance(typeof(int), num4);
		int num5 = 0;
		while (num5 < num4)
		{
			int code = GetCode(codeTree);
			if (code >= 0 && code < 16)
			{
				array3[num5++] = code;
				continue;
			}
			switch (code)
			{
			case 16:
			{
				int num7 = GetBits(2) + 3;
				while (num7-- > 0)
				{
					array3[num5] = array3[num5 - 1];
					num5++;
				}
				break;
			}
			case 17:
			{
				int num8 = GetBits(3) + 3;
				while (num8-- > 0)
				{
					array3[num5++] = 0;
				}
				break;
			}
			case 18:
			{
				int num6 = GetBits(7) + 11;
				while (num6-- > 0)
				{
					array3[num5++] = 0;
				}
				break;
			}
			default:
				Trace.WriteLine(new StringBuilder(64).AppendFormat("Deflate.InitDynamicCodes Warning: invalid code 0x{0:x4}", code).ToString());
				return false;
			}
		}
		mDynLCodeTree = BuildCodeTree(array3, 0, num, 65536);
		mDynDCodeTree = BuildCodeTree(array3, num, num2, 65536);
		return true;
	}

	private static short[] BuildCodeTree(int[] CodeLens, int Start, int Count, int CodeTreeLength)
	{
		short[] array = (short[])Array.CreateInstance(typeof(short), CodeTreeLength);
		int[] array2 = (int[])Array.CreateInstance(typeof(int), 16);
		int[] array3 = (int[])Array.CreateInstance(typeof(int), 16);
		for (int i = Start; i < Start + Count; i++)
		{
			array2[CodeLens[i]]++;
		}
		array2[0] = 0;
		int num = 0;
		for (int j = 1; j < 16; j++)
		{
			num = (array3[j] = num + array2[j - 1] << 1);
		}
		for (int k = 0; k < CodeTreeLength; k++)
		{
			array[k] = -1;
		}
		for (int l = 0; l < Count; l++)
		{
			int num2 = CodeLens[Start + l];
			if (num2 > 0)
			{
				int num3 = Reverse(array3[num2]++, num2);
				int num4 = 1;
				while (num2-- > 0)
				{
					num4 <<= 1;
					num4 += num3 & 1;
					num3 >>= 1;
				}
				array[num4] = (short)l;
			}
		}
		return array;
	}

	private bool Decompress(short[] LCodeTree, short[] DCodeTree)
	{
		int[,] array = new int[29, 2]
		{
			{ 0, 3 },
			{ 0, 4 },
			{ 0, 5 },
			{ 0, 6 },
			{ 0, 7 },
			{ 0, 8 },
			{ 0, 9 },
			{ 0, 10 },
			{ 1, 11 },
			{ 1, 13 },
			{ 1, 15 },
			{ 1, 17 },
			{ 2, 19 },
			{ 2, 23 },
			{ 2, 27 },
			{ 2, 31 },
			{ 3, 35 },
			{ 3, 43 },
			{ 3, 51 },
			{ 3, 59 },
			{ 4, 67 },
			{ 4, 83 },
			{ 4, 99 },
			{ 4, 115 },
			{ 5, 131 },
			{ 5, 163 },
			{ 5, 195 },
			{ 5, 227 },
			{ 0, 258 }
		};
		int[,] array2 = new int[30, 2]
		{
			{ 0, 1 },
			{ 0, 2 },
			{ 0, 3 },
			{ 0, 4 },
			{ 1, 5 },
			{ 1, 7 },
			{ 2, 9 },
			{ 2, 13 },
			{ 3, 17 },
			{ 3, 25 },
			{ 4, 33 },
			{ 4, 49 },
			{ 5, 65 },
			{ 5, 97 },
			{ 6, 129 },
			{ 6, 193 },
			{ 7, 257 },
			{ 7, 385 },
			{ 8, 513 },
			{ 8, 769 },
			{ 9, 1025 },
			{ 9, 1537 },
			{ 10, 2049 },
			{ 10, 3073 },
			{ 11, 4097 },
			{ 11, 6145 },
			{ 12, 8193 },
			{ 12, 12289 },
			{ 13, 16385 },
			{ 13, 24577 }
		};
		int code;
		while ((code = GetCode(LCodeTree)) != 256)
		{
			if (code >= 0 && code < 256)
			{
				mOutData[mOutIndex++] = (byte)code;
				mOutCount--;
				continue;
			}
			if (code > 256)
			{
				code -= 257;
				int numBits;
				int num = (((numBits = array[code, 0]) > 0) ? GetBits(numBits) : 0);
				num += array[code, 1];
				code = GetCode(DCodeTree);
				int num2 = (((numBits = array2[code, 0]) > 0) ? GetBits(numBits) : 0);
				num2 += array2[code, 1];
				while (num-- > 0)
				{
					mOutData[mOutIndex] = mOutData[mOutIndex - num2];
					mOutIndex++;
					mOutCount--;
				}
				continue;
			}
			Trace.WriteLine(new StringBuilder(64).AppendFormat("Deflate.Decompress Warning: invalid code 0x{0:x4}", code).ToString());
			return false;
		}
		return true;
	}

	private short GetCode(short[] CodeTree)
	{
		int num = CodeTree.Length;
		int num2 = 1;
		while (CodeTree[num2] == -1)
		{
			num2 <<= 1;
			num2 += GetBits(1);
			if (num2 >= num)
			{
				return -1;
			}
		}
		return CodeTree[num2];
	}

	private int GetBits(int NumBits)
	{
		int num;
		switch (NumBits)
		{
		default:
			return -1;
		case 0:
			num = mInBufSize & 7;
			mInBuf >>= num;
			mInBufSize -= num;
			return 0;
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
			break;
		}
		while (mInBufSize < NumBits)
		{
			int num2 = mInData[mInIndex++];
			mInCount--;
			mInBuf |= num2 << mInBufSize;
			mInBufSize += 8;
		}
		num = mInBuf & ((1 << NumBits) - 1);
		mInBuf >>= NumBits;
		mInBufSize -= NumBits;
		return num;
	}

	private static int Reverse(int Bits, int Length)
	{
		int num = 0;
		while (Length-- > 0)
		{
			num = (num << 1) | (Bits & 1);
			Bits >>= 1;
		}
		return num;
	}
}
