// Generated by Sichem at 12/24/2021 8:28:15 PM

using Hebron.Runtime;

namespace StbImageBeef
{
	extension StbImage
	{
		public static int32 stbi__gif_header(stbi__context s, stbi__gif g, int32* comp, int32 is_info)
		{
			uint8 version = 0;
			if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
				return stbi__err("not GIF");
			version = stbi__get8(s);
			if (version != 55 && version != 57)
				return stbi__err("not GIF");
			if (stbi__get8(s) != 97)
				return stbi__err("not GIF");
			stbi__g_failure_reason = "";
			g.w = stbi__get16le(s);
			g.h = stbi__get16le(s);
			g.flags = stbi__get8(s);
			g.bgindex = stbi__get8(s);
			g.ratio = stbi__get8(s);
			g.transparent = -1;
			if (g.w > 1 << 24)
				return stbi__err("too large");
			if (g.h > 1 << 24)
				return stbi__err("too large");
			if (comp != null)
				*comp = 4;
			if (is_info != 0)
				return 1;
			if ((g.flags & 0x80) != 0)
				stbi__gif_parse_colortable(s, g.pal, 2 << (g.flags & 7), -1);
			return 1;
		}

		public static int32 stbi__gif_info(stbi__context s, int32* x, int32* y, int32* comp)
		{
			return stbi__gif_info_raw(s, x, y, comp);
		}

		public static int32 stbi__gif_info_raw(stbi__context s, int32* x, int32* y, int32* comp)
		{
			var g = new stbi__gif();
			if (g == null)
				return stbi__err("outofmem");
			if (stbi__gif_header(s, g, comp, 1) == 0)
			{
				stbi__rewind(s);
				return 0;
			}

			if (x != null)
				*x = g.w;
			if (y != null)
				*y = g.h;
			return 1;
		}

		public static void* stbi__gif_load(stbi__context s, int32* x, int32* y, int32* comp, int32 req_comp,
			stbi__result_info* ri)
		{
			uint8* u = null;
			var g = new stbi__gif();
			u = stbi__gif_load_next(s, g, comp, req_comp, null);

			if (u != null)
			{
				*x = g.w;
				*y = g.h;
				if (req_comp != 0 && req_comp != 4)
					u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
			}
			else if (g._out_ != null)
			{
				CRuntime.free(g._out_);
			}

			CRuntime.free(g.history);
			CRuntime.free(g.background);
			return u;
		}

		public static uint8* stbi__gif_load_next(stbi__context s, stbi__gif g, int32* comp, int32 req_comp, uint8* two_back)
		{
			int32 dispose = 0;
			int32 first_frame = 0;
			int32 pi = 0;
			int32 pcount = 0;
			first_frame = 0;
			if (g._out_ == null)
			{
				if (stbi__gif_header(s, g, comp, 0) == 0)
					return null;
				if (stbi__mad3sizes_valid(4, g.w, g.h, 0) == 0)
					return (uint8*)(stbi__err("too large") != 0 ? null : null);
				pcount = g.w * g.h;
				g._out_ = (uint8*)stbi__malloc(4 * pcount);
				g.background = (uint8*)stbi__malloc(4 * pcount);
				g.history = (uint8*)stbi__malloc((uint64)pcount);
				if (g._out_ == null || g.background == null || g.history == null)
					return (uint8*)(stbi__err("outofmem") != 0 ? null : null);
				CRuntime.memset(g._out_, 0x00, 4 * pcount);
				CRuntime.memset(g.background, 0x00, 4 * pcount);
				CRuntime.memset(g.history, 0x00, (uint64)pcount);
				first_frame = 1;
			}
			else
			{
				dispose = (g.eflags & 0x1C) >> 2;
				pcount = g.w * g.h;
				if (dispose == 3 && two_back == null) dispose = 2;

				if (dispose == 3)
				{
					for (pi = 0; pi < pcount; ++pi)
						if (g.history[pi] != 0)
							CRuntime.memcpy(&g._out_[pi * 4], &two_back[pi * 4], (uint64)4);
				}
				else if (dispose == 2)
				{
					for (pi = 0; pi < pcount; ++pi)
						if (g.history[pi] != 0)
							CRuntime.memcpy(&g._out_[pi * 4], &g.background[pi * 4], (uint64)4);
				}

				CRuntime.memcpy(g.background, g._out_, 4 * g.w * g.h);
			}

			CRuntime.memset(g.history, 0x00, (uint64)(g.w * g.h));
			for (; ; )
			{
				int32 tag = stbi__get8(s);
				switch (tag)
				{
					case 0x2C:
						{
							int32 x = 0;
							int32 y = 0;
							int32 w = 0;
							int32 h = 0;
							uint8* o;
							x = stbi__get16le(s);
							y = stbi__get16le(s);
							w = stbi__get16le(s);
							h = stbi__get16le(s);
							if (x + w > g.w || y + h > g.h)
								return (uint8*)(stbi__err("bad Image Descriptor") != 0 ? null : null);
							g.line_size = g.w * 4;
							g.start_x = x * 4;
							g.start_y = y * g.line_size;
							g.max_x = g.start_x + w * 4;
							g.max_y = g.start_y + h * g.line_size;
							g.cur_x = g.start_x;
							g.cur_y = g.start_y;
							if (w == 0)
								g.cur_y = g.max_y;
							g.lflags = stbi__get8(s);
							if ((g.lflags & 0x40) != 0)
							{
								g.step = 8 * g.line_size;
								g.parse = 3;
							}
							else
							{
								g.step = g.line_size;
								g.parse = 0;
							}

							if ((g.lflags & 0x80) != 0)
							{
								stbi__gif_parse_colortable(s, g.lpal, 2 << (g.lflags & 7),
									(g.eflags & 0x01) != 0 ? g.transparent : -1);
								g.color_table = (uint8*)g.lpal;
							}
							else if ((g.flags & 0x80) != 0)
							{
								g.color_table = (uint8*)g.pal;
							}
							else
							{
								return (uint8*)(stbi__err("missing color table") != 0 ? null : null);
							}

							o = stbi__process_gif_raster(s, g);
							if (o == null)
								return null;
							pcount = g.w * g.h;
							if (first_frame != 0 && g.bgindex > 0)
								for (pi = 0; pi < pcount; ++pi)
									if (g.history[pi] == 0)
									{
										g.pal[g.bgindex][3] = 255;
										CRuntime.memcpy(&g._out_[pi * 4], &g.pal[g.bgindex], (uint64)4);
									}

							return o;
						}

					case 0x21:
						{
							int32 len = 0;
							int32 ext = stbi__get8(s);
							if (ext == 0xF9)
							{
								len = stbi__get8(s);
								if (len == 4)
								{
									g.eflags = stbi__get8(s);
									g.delay = 10 * stbi__get16le(s);
									if (g.transparent >= 0) g.pal[g.transparent][3] = 255;

									if ((g.eflags & 0x01) != 0)
									{
										g.transparent = stbi__get8(s);
										if (g.transparent >= 0) g.pal[g.transparent][3] = 0;
									}
									else
									{
										stbi__skip(s, 1);
										g.transparent = -1;
									}
								}
								else
								{
									stbi__skip(s, len);
									break;
								}
							}

							while ((len = stbi__get8(s)) != 0) stbi__skip(s, len);

							break;
						}

					case 0x3B:
						return null;
					default:
						return (uint8*)(stbi__err("unknown code") != 0 ? null : null);
				}
			}
		}

		public static void stbi__gif_parse_colortable(stbi__context s, uint8** pal, int32 num_entries, int32 transp)
		{
			int32 i = 0;
			for (i = 0; i < num_entries; ++i)
			{
				pal[i][2] = stbi__get8(s);
				pal[i][1] = stbi__get8(s);
				pal[i][0] = stbi__get8(s);
				pal[i][3] = (uint8)(transp == i ? 0 : 255);
			}
		}

		public static int32 stbi__gif_test(stbi__context s)
		{
			var r = stbi__gif_test_raw(s);
			stbi__rewind(s);
			return r;
		}

		public static int32 stbi__gif_test_raw(stbi__context s)
		{
			int32 sz = 0;
			if (stbi__get8(s) != 71 || stbi__get8(s) != 73 || stbi__get8(s) != 70 || stbi__get8(s) != 56)
				return 0;
			sz = stbi__get8(s);
			if (sz != 57 && sz != 55)
				return 0;
			if (stbi__get8(s) != 97)
				return 0;
			return 1;
		}

		public static void* stbi__load_gif_main(stbi__context s, int32** delays, int32* x, int32* y, int32* z, int32* comp,
			int32 req_comp)
		{
			if (stbi__gif_test(s) != 0)
			{
				int32 layers = 0;
				uint8* u = null;
				uint8* _out_ = null;
				uint8* two_back = null;
				var g = new stbi__gif();
				int32 stride = 0;
				int32 out_size = 0;
				int32 delays_size = 0;
				if (delays != null) *delays = null;

				repeat
				{
					u = stbi__gif_load_next(s, g, comp, req_comp, two_back);
					if (u != null)
					{
						*x = g.w;
						*y = g.h;
						++layers;
						stride = g.w * g.h * 4;
						if (_out_ != null)
						{
							void* tmp = (uint8*)CRuntime.realloc(_out_, (uint64)(layers * stride));
							if (tmp == null) return stbi__load_gif_main_outofmem(g, _out_, delays);

							_out_ = (uint8*)tmp;
							out_size = layers * stride;

							if (delays != null)
							{
								var new_delays = (int32*)CRuntime.realloc(*delays, (uint64)(sizeof(int32) * layers));
								if (new_delays == null)
									return stbi__load_gif_main_outofmem(g, _out_, delays);
								*delays = new_delays;
								delays_size = layers * sizeof(int32);
							}
						}
						else
						{
							_out_ = (uint8*)stbi__malloc((uint64)(layers * stride));
							if (_out_ == null)
								return stbi__load_gif_main_outofmem(g, _out_, delays);
							out_size = layers * stride;
							if (delays != null)
							{
								*delays = (int32*)stbi__malloc((uint64)(layers * sizeof(int32)));
								if (*delays == null)
									return stbi__load_gif_main_outofmem(g, _out_, delays);
								delays_size = layers * sizeof(int32);
							}
						}

						CRuntime.memcpy(_out_ + (layers - 1) * stride, u, (uint64)stride);
						if (layers >= 2) two_back = _out_ - 2 * stride;

						if (delays != null) (*delays)[layers - 1U] = g.delay;
					}
				} while (u != null);

				CRuntime.free(g._out_);
				CRuntime.free(g.history);
				CRuntime.free(g.background);
				if (req_comp != 0 && req_comp != 4)
					_out_ = stbi__convert_format(_out_, 4, req_comp, layers * g.w, g.h);
				*z = layers;
				return _out_;
			}

			return (uint8*)(stbi__err("not GIF") != 0 ? null : null);
		}

		public static void* stbi__load_gif_main_outofmem(stbi__gif g, uint8* _out_, int32** delays)
		{
			CRuntime.free(g._out_);
			CRuntime.free(g.history);
			CRuntime.free(g.background);
			if (_out_ != null)
				CRuntime.free(_out_);
			if (delays != null && *delays != null)
				CRuntime.free(*delays);
			return (uint8*)(stbi__err("outofmem") != 0 ? null : null);
		}

		public static void stbi__out_gif_code(stbi__gif g, uint16 code)
		{
			uint8* p;
			uint8* c;
			int32 idx = 0;
			if (g.codes[code].prefix >= 0)
				stbi__out_gif_code(g, (uint16)g.codes[code].prefix);
			if (g.cur_y >= g.max_y)
				return;
			idx = g.cur_x + g.cur_y;
			p = &g._out_[idx];
			g.history[idx / 4] = 1;
			c = &g.color_table[g.codes[code].suffix * 4];
			if (c[3] > 128)
			{
				p[0] = c[2];
				p[1] = c[1];
				p[2] = c[0];
				p[3] = c[3];
			}

			g.cur_x += 4;
			if (g.cur_x >= g.max_x)
			{
				g.cur_x = g.start_x;
				g.cur_y += g.step;
				while (g.cur_y >= g.max_y && g.parse > 0)
				{
					g.step = (1 << g.parse) * g.line_size;
					g.cur_y = g.start_y + (g.step >> 1);
					--g.parse;
				}
			}
		}

		public static uint8* stbi__process_gif_raster(stbi__context s, stbi__gif g)
		{
			uint8 lzw_cs = 0;
			int32 len = 0;
			int32 init_code = 0;
			uint32 first = 0;
			int32 codesize = 0;
			int32 codemask = 0;
			int32 avail = 0;
			int32 oldcode = 0;
			int32 bits = 0;
			int32 valid_bits = 0;
			int32 clear = 0;
			stbi__gif_lzw* p;
			lzw_cs = stbi__get8(s);
			if (lzw_cs > 12)
				return null;
			clear = 1 << lzw_cs;
			first = 1;
			codesize = lzw_cs + 1;
			codemask = (1 << codesize) - 1;
			bits = 0;
			valid_bits = 0;
			for (init_code = 0; init_code < clear; init_code++)
			{
				g.codes[init_code].prefix = -1;
				g.codes[init_code].first = (uint8)init_code;
				g.codes[init_code].suffix = (uint8)init_code;
			}

			avail = clear + 2;
			oldcode = -1;
			len = 0;
			for (; ; )
				if (valid_bits < codesize)
				{
					if (len == 0)
					{
						len = stbi__get8(s);
						if (len == 0)
							return g._out_;
					}

					--len;
					bits |= stbi__get8(s) << valid_bits;
					valid_bits += 8;
				}
				else
				{
					var code = bits & codemask;
					bits >>= codesize;
					valid_bits -= codesize;
					if (code == clear)
					{
						codesize = lzw_cs + 1;
						codemask = (1 << codesize) - 1;
						avail = clear + 2;
						oldcode = -1;
						first = 0;
					}
					else if (code == clear + 1)
					{
						stbi__skip(s, len);
						while ((len = stbi__get8(s)) > 0) stbi__skip(s, len);

						return g._out_;
					}
					else if (code <= avail)
					{
						if (first != 0) return (uint8*)(stbi__err("no clear code") != 0 ? null : null);

						if (oldcode >= 0)
						{
							p = &g.codes[avail++];
							if (avail > 8192) return (uint8*)(stbi__err("too many codes") != 0 ? null : null);

							p.prefix = (int16)oldcode;
							p.first = g.codes[oldcode].first;
							p.suffix = code == avail ? p.first : g.codes[code].first;
						}
						else if (code == avail)
						{
							return (uint8*)(stbi__err("illegal code in raster") != 0 ? null : null);
						}

						stbi__out_gif_code(g, (uint16)code);
						if ((avail & codemask) == 0 && avail <= 0x0FFF)
						{
							codesize++;
							codemask = (1 << codesize) - 1;
						}

						oldcode = code;
					}
					else
					{
						return (uint8*)(stbi__err("illegal code in raster") != 0 ? null : null);
					}
				}
		}

		public class stbi__gif
		{
			public uint8* _out_;
			public uint8* background;
			public int32 bgindex;
			public stbi__gif_lzw* codes = (stbi__gif_lzw*)stbi__malloc(8192 * sizeof(stbi__gif_lzw));
			public uint8* color_table;
			public int32 cur_x;
			public int32 cur_y;
			public int32 delay;
			public int32 eflags;
			public int32 flags;
			public int32 h;
			public uint8* history;
			public int32 lflags;
			public int32 line_size;
			public uint8** lpal= (uint8**)stbi__malloc(256 * 4 * sizeof(uint8));
			public int32 max_x;
			public int32 max_y;
			public uint8** pal = (uint8**)stbi__malloc(256 * 4 * sizeof(uint8));
			public int32 parse;
			public int32 ratio;
			public int32 start_x;
			public int32 start_y;
			public int32 step;
			public int32 transparent;
			public int32 w;
		}

		public struct stbi__gif_lzw
		{
			public int16 prefix;
			public uint8 first;
			public uint8 suffix;
		}
	}
}