// File: /workspace/github_cpp_makefile_star2_O2/Alcaro[P]bridges/arlib/image-png-decode.cpp
// Function: oimage::init_decode_png(arrayview<unsigned char>)
bool oimage::init_decode_png(arrayview<uint8_t> pngdata)
{
	struct pngchunk : public bytestream {
		uint32_t type;
		uint32_t len;
	};
	class pngreader : public bytestream {
	public:
		pngreader(arrayview<uint8_t> bytes) : bytestream(bytes) {}
		
		pngchunk chunk_raw()
		{
			pngchunk ret;
			ret.type = 0; // invalid value, looks like an unrecognized critical chunk and will propagate outwards
			
			if (remaining() < 12) return ret;
			ret.len = u32b();
			
			if (ret.len >= 0x80000000 || remaining()-8 < ret.len) return ret;
			
			uint32_t crc32_actual = crc32(peekbytes(4+ret.len));
			
			ret.type = u32b();
			ret.init(bytes(ret.len));
			
			uint32_t crc32_exp = u32b();
			if (crc32_actual != crc32_exp) ret.type = 0;
			
			return ret;
		}
		
		//Returns the next recognized or critical chunk. (Only tRNS is recognized.)
		pngchunk chunk()
		{
			while (true)
			{
				pngchunk ret = chunk_raw();
				if (ret.type == 0x74524E53) return ret; // tRNS
				if (!(ret.type&0x20000000)) return ret; // critical
			}
		}
	};
	
	
	pngreader reader(pngdata);
	
	if (reader.remaining() < 8 || !reader.signature("\x89PNG\r\n\x1A\n"))
	{
	fail: // putting this up here to avoid 99999 'jump to label foo crosses initialization of bar' errors
		this->storage = NULL; // forcibly deallocate - this can leave this->pixels as a dead pointer, but caller won't use that.
		return false;
	}
	
	pngchunk IHDR = reader.chunk_raw(); // no ancillary chunks allowed before IHDR
	if (IHDR.type != 0x49484452) goto fail; // IHDR must be the first chunk
	if (IHDR.len != 13) goto fail; // the IHDR chunk is always 13 bytes
	
	uint32_t width  = this->width  = IHDR.u32b();
	uint32_t height = this->height = IHDR.u32b();
	
	// Greyscale             - 0
	// Truecolour            - 2
	// Indexed-colour        - 3
	// Greyscale with alpha  - 4
	// Truecolour with alpha - 6
	
	uint8_t bits_per_sample = IHDR.u8();
	uint8_t color_type = IHDR.u8();
	uint8_t comp_meth = IHDR.u8();
	uint8_t filter_meth = IHDR.u8();
	uint8_t interlace_meth = IHDR.u8();
	
	if (width == 0 || height == 0 || width >= 0x80000000 || height >= 0x80000000) goto fail;
	if ((uint64_t)width * height >= 0x80000000 / sizeof(uint32_t)) goto fail; // ensure width*height doesn't overflow
	// huge images will still OOM, but at least they won't corrupt memory
	if (bits_per_sample >= 32 || color_type > 6 || comp_meth != 0 || filter_meth != 0 || interlace_meth > 1) goto fail;
	if (bits_per_sample > 8) goto fail; // bpp=16 is allowed by the png standard, but not by this program
	if (interlace_meth) goto fail; // TODO: implement this
	static const uint32_t bpp_allowed[7] = { 0x68808000, 0x00000000, 0x00808000, 0x68800000, 0x00808000, 0x00000000, 0x00808000 };
	if (!((bpp_allowed[color_type]<<bits_per_sample)&0x80000000)) goto fail; // clear bit - invalid bpp (this also rejects types 1 and 5)
	
	uint32_t palette[256];
	unsigned palettelen = 0;
	
	if (color_type == 3)
	{
		pngchunk PLTE = reader.chunk();
		if (PLTE.type != 0x504C5445) goto fail;
		
		if (PLTE.len == 0 || PLTE.len%3 || PLTE.len/3 > (1u<<bits_per_sample)) goto fail;
		palettelen = PLTE.len/3;
		for (unsigned i=0;i<palettelen;i++)
		{
			// this reads a byte it shouldn't, but it's either previous color or the chunk's type, so not UB
			palette[i] = 0xFF000000 | readu_be32(PLTE.bytes(3).ptr()-1);
		}
	}
	
	bool has_alpha = (color_type >= 4);
	bool has_bool_alpha = false;
	uint32_t transparent = 0; // if you see this value (after filtering), make it transparent
	                          // for rgb, this value is ARGB, A=0xFF
	
	pngchunk tRNS_IDAT = reader.chunk();
	if (tRNS_IDAT.type == 0x504C5445) // PLTE
	{
		if (color_type == 2 || color_type == 6) // it's allowed on those two types
			tRNS_IDAT = reader.chunk();
		//else fall through and let IEND handler whine
	}
	pngchunk IDAT;
	if (!has_alpha && tRNS_IDAT.type == 0x74524E53) // tRNS
	{
		pngchunk tRNS = tRNS_IDAT;
		has_alpha = true;
		
		if (color_type == 0)
		{
			if (tRNS.len != 2) goto fail;
			transparent = tRNS.u16b();
			if (transparent >= 1u<<bits_per_sample) goto fail;
			if (bits_per_sample == 8) transparent = 0xFF000000 + transparent*0x010101;
			has_bool_alpha = true;
		}
		if (color_type == 2)
		{
			if (tRNS.len != 6) goto fail;
			
			uint16_t r = tRNS.u16b();
			uint16_t g = tRNS.u16b();
			uint16_t b = tRNS.u16b();
			
			if ((r|g|b) >= 1<<bits_per_sample) goto fail;
			
			transparent = 0xFF000000 | r<<16 | g<<8 | b;
			has_bool_alpha = true;
		}
		if (color_type == 3)
		{
			if (tRNS.len == 0 || tRNS.len > palettelen) goto fail;
			
			has_bool_alpha = true;
			for (size_t i=0;i<tRNS.len;i++)
			{
				uint8_t newa = tRNS.u8();
				if (newa != 0x00 && newa != 0xFF) has_bool_alpha = false;
				palette[i] = (palette[i]&0x00FFFFFF) | (uint32_t)newa<<24; // extra cast because u8 << 24 is signed
			}
		}
		if (color_type == 4) goto fail;
		if (color_type == 6) goto fail;
		
		IDAT = reader.chunk();
	}
	else IDAT = tRNS_IDAT; // could be neither tRNS or IDAT, in which case the while loop won't enter, and the IEND checker will whine
	
	
	this->stride = sizeof(uint32_t) * width;
	
	int samples_per_px = (0x04021301 >> (color_type*4))&15;
	size_t bytes_per_line_raw = (bits_per_sample*samples_per_px*width + 7)/8;
	
	//+4 and +2 to let filters read outside the image, and to ensure there's enough
	// space to decode and convert the image to the desired output format
	//+7*u32 because the decoder overshoots on low bitdepths
	//unpacking (png -> uint32_t) needs one pixel of buffer, though compiler considerations say minimum one scanline
	//unfiltering needs another scanline of buffer, plus another one must exist in front
	//
	//however, there's another another issue - what scanline size?
	// output must be packed, raw is pngpack+1, unfiltering needs at least pngpack+4
	//the correct offsets are
	//scan_out = width * (3 or 4)
	//scan_packed = whatever+4
	//scan_filtered = whatever+1
	//start_out = 0
	//start_packed = end - height*scan_packed - scan_packed
	//start_filtered = end - height*scan_filtered
	//deinterleaving probably isn't doable in-place at all
	size_t nbytes = max(this->stride, bytes_per_line_raw+4) * (height+2) + sizeof(uint32_t)*7;
	this->storage = xmalloc(nbytes);
	
	this->pixels8 = (uint8_t*)this->storage;
	this->fmt = (has_alpha ? (has_bool_alpha ? ifmt_bargb8888 : ifmt_argb8888) : ifmt_xrgb8888);
	
	uint8_t* inflate_end = (uint8_t*)this->storage + nbytes;
	uint8_t* inflate_start = inflate_end - (bytes_per_line_raw+1)*height;
	
	inflator::zlibhead infl;
	infl.set_output_first(bytesw(inflate_start, inflate_end-inflate_start));
	inflator::ret_t infl_status = inflator::ret_more_input;
	
	while (IDAT.type == 0x49444154 && infl_status == inflator::ret_more_input)
	{
		infl.set_input(IDAT.bytes(IDAT.len), false);
		infl_status = infl.inflate();
		IDAT = reader.chunk_raw(); // all IDAT chunks must be consecutive
	}
	
	if (infl_status == inflator::ret_more_input)
	{
		infl.set_input(NULL, true);
		infl_status = infl.inflate();
	}
	if (infl_status != inflator::ret_done) goto fail;
	if (inflate_start+infl.output_in_last() != inflate_end) goto fail;
	
	pngchunk IEND = IDAT;
	if (IEND.type != 0x49454E44) IEND = reader.chunk(); // ancillary between IDAT and IEND is fine, just discard that
	if (IEND.type != 0x49454E44 || IEND.len != 0) goto fail;
	
	
	if (interlace_meth == 1)
	{
puts("unsupported: Adam7");
goto fail;
	}
	
//for(uint8_t*n=inflate_start;n<inflate_at;n++)printf("%.2X ",*n);
//puts("");
	
	size_t defilter_out_line = 4 + bytes_per_line_raw;
	uint8_t* defilter_start = inflate_end - height*defilter_out_line - defilter_out_line;
	
	if (inflate_start[0] >= 2)
		memset(defilter_start - defilter_out_line, 0, defilter_out_line); // y=-1 is all zeroes
	size_t filter_bpp = (bits_per_sample*samples_per_px + 7)/8;
	if (!image::png_defilter(defilter_start, defilter_out_line, inflate_start, filter_bpp, bytes_per_line_raw, height)) goto fail;
	
	defilter_start += 4; // skip the x=-1 = 0 padding
	
	if(0);
	else if (color_type == 0)
	{
		//treating gray as a palette makes things a fair bit simpler, especially with tRNS handling
		//doing it for bpp=8 means an 1KB table which is boring, but that one doesn't pack multiple pixels in a single byte,
		// so it's easy to put in the non-palette decoder (and there's no other sane way to handle gray+alpha)
		if (bits_per_sample == 1)
		{
			static const uint32_t gray_1bpp[] = { 0xFF000000, 0xFFFFFFFF };
			if (has_alpha) transparent = gray_1bpp[transparent];
			png_unpack_plte<1>(defilter_start, defilter_out_line, gray_1bpp, 2);
		}
		else if (bits_per_sample == 2)
		{
			static const uint32_t gray_2bpp[] = { 0xFF000000, 0xFF555555, 0xFFAAAAAA, 0xFFFFFFFF };
			if (has_alpha) transparent = gray_2bpp[transparent];
			png_unpack_plte<2>(defilter_start, defilter_out_line, gray_2bpp, 4);
		}
		else if (bits_per_sample == 4)
		{
			static const uint32_t gray_4bpp[] = { 0xFF000000, 0xFF111111, 0xFF222222, 0xFF333333,
			                                      0xFF444444, 0xFF555555, 0xFF666666, 0xFF777777,
			                                      0xFF888888, 0xFF999999, 0xFFAAAAAA, 0xFFBBBBBB,
			                                      0xFFCCCCCC, 0xFFDDDDDD, 0xFFEEEEEE, 0xFFFFFFFF };
			if (has_alpha) transparent = gray_4bpp[transparent];
			png_unpack_plte<4>(defilter_start, defilter_out_line, gray_4bpp, 16);
		}
		else /* bits_per_sample == 8 */ png_unpack_rgb<0>(defilter_start, defilter_out_line);
	}
	
	else if (color_type == 2 /* bits_per_sample == 8 */) png_unpack_rgb<2>(defilter_start, defilter_out_line);
	else if (color_type == 3)
	{
		if      (bits_per_sample == 1) { if (!png_unpack_plte<1>(defilter_start, defilter_out_line, palette, palettelen)) goto fail; }
		else if (bits_per_sample == 2) { if (!png_unpack_plte<2>(defilter_start, defilter_out_line, palette, palettelen)) goto fail; }
		else if (bits_per_sample == 4) { if (!png_unpack_plte<4>(defilter_start, defilter_out_line, palette, palettelen)) goto fail; }
		else /* bits_per_sample = 8 */ { if (!png_unpack_plte<8>(defilter_start, defilter_out_line, palette, palettelen)) goto fail; }
	}
	else if (color_type == 4 /* bits_per_sample == 8 */) png_unpack_rgb<4>(defilter_start, defilter_out_line);
	else  /* color_type == 6 && bits_per_sample == 8 */  png_unpack_rgb<6>(defilter_start, defilter_out_line);
	
	if (transparent >= 0xFF000000)
	{
		uint32_t* pixels = (uint32_t*)(uint8_t*)this->storage;
		for (size_t i=0;i<width*height;i++)
		{
			if (pixels[i] == transparent) pixels[i] &= 0x00FFFFFF;
		}
	}
	
	return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x17c8, %rsp           # imm = 0x17C8
movq %rdi, %rbx
movq %rsi, 0x60(%rsp)
leaq (%rsi,%rdx), %rax
movq %rax, 0x70(%rsp)
cmpq $0x8, %rdx
jb 0x919c
movq %rsi, %r14
leaq 0x4f8(%rsp), %rdi
movq %rsi, (%rdi)
movq $0x8, 0x8(%rdi)
leaq 0x1f81f(%rip), %rsi     # 0x288e0
pushq $0x8
popq %rdx
callq 0x4338
testb %al, %al
je 0x919c
addq $0x8, %r14
leaq 0x60(%rsp), %rsi
movq %r14, 0x8(%rsi)
leaq 0xc0(%rsp), %r14
movq %r14, %rdi
callq 0x98b2
cmpl $0x49484452, 0x18(%r14) # imm = 0x49484452
jne 0x919c
cmpl $0xd, 0xdc(%rsp)
jne 0x919c
movq 0xc8(%rsp), %rdx
movl (%rdx), %r12d
bswapl %r12d
movl %r12d, (%rbx)
movl 0x4(%rdx), %ebp
bswapl %ebp
movl %ebp, 0x4(%rbx)
movzbl 0x8(%rdx), %r15d
movb 0x9(%rdx), %r8b
movb 0xa(%rdx), %al
movb 0xb(%rdx), %cl
leaq 0xd(%rdx), %rsi
movq %rsi, 0xc8(%rsp)
testl %r12d, %r12d
setle %sil
testl %ebp, %ebp
setle %dil
orb %sil, %dil
jne 0x919c
movl %r12d, %esi
movl %ebp, %r13d
imulq %r13, %rsi
cmpq $0x1fffffff, %rsi       # imm = 0x1FFFFFFF
ja 0x919c
movb 0xc(%rdx), %dl
testb %dl, %dl
jne 0x919c
cmpb $0x8, %r15b
ja 0x919c
cmpb $0x1f, %r15b
ja 0x919c
cmpb $0x6, %r8b
ja 0x919c
orb %al, %cl
jne 0x919c
cmpb $0x1, %dl
ja 0x919c
movzbl %r8b, %edx
leaq 0x1f6c0(%rip), %rax     # 0x28850
movl (%rax,%rdx,4), %eax
movl %r15d, %ecx
shll %cl, %eax
testl %eax, %eax
js 0x91c2
addq $0x18, %rbx
xorl %r14d, %r14d
movq %rbx, %rdi
xorl %esi, %esi
callq 0x9d10
movl %r14d, %eax
addq $0x17c8, %rsp           # imm = 0x17C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rdx, 0x40(%rsp)
xorl %eax, %eax
cmpb $0x3, %r8b
movq %r8, 0x30(%rsp)
jne 0x924c
leaq 0x4f8(%rsp), %r14
leaq 0x60(%rsp), %rsi
movq %r14, %rdi
callq 0x994a
cmpl $0x504c5445, 0x18(%r14) # imm = 0x504C5445
jne 0x919c
pushq $0x1
popq %rsi
movl %r15d, %ecx
shll %cl, %esi
movl 0x514(%rsp), %ecx
pushq $0x3
popq %rdi
movl %ecx, %eax
xorl %edx, %edx
divl %edi
testl %ecx, %ecx
je 0x919c
testl %edx, %edx
jne 0x919c
cmpl %esi, %eax
ja 0x919c
movq 0x500(%rsp), %r9
movl %eax, %ecx
decq %r9
xorl %edx, %edx
movl $0xff, %esi
movq 0x30(%rsp), %r8
cmpq %rdx, %rcx
je 0x924c
movl (%r9), %edi
orl %esi, %edi
bswapl %edi
movl %edi, 0xf0(%rsp,%rdx,4)
incq %rdx
addq $0x3, %r9
jmp 0x9230
movl %eax, 0x2c(%rsp)
movq %r13, 0x58(%rsp)
movl %r15d, 0xc(%rsp)
cmpb $0x4, %r8b
setae 0xb(%rsp)
leaq 0xa0(%rsp), %r14
leaq 0x60(%rsp), %rsi
movq %r14, %rdi
callq 0x994a
movq 0x30(%rsp), %rsi
movl 0x18(%r14), %eax
cmpl $0x504c5445, %eax       # imm = 0x504C5445
setne %cl
movl %esi, %edx
andb $0x3, %dl
cmpb $0x2, %dl
setne %dl
orb %cl, %dl
jne 0x92b6
leaq 0xa0(%rsp), %r14
leaq 0x60(%rsp), %rsi
movq %r14, %rdi
callq 0x994a
movq 0x30(%rsp), %rsi
movl 0x18(%r14), %eax
movq 0xa8(%rsp), %r13
movq 0xb8(%rsp), %r15
pushq $0x5
popq %rcx
cmpb $0x3, %sil
ja 0x932e
cmpl $0x74524e53, %eax       # imm = 0x74524E53
jne 0x932e
cmpb $0x2, %sil
je 0x95ec
cmpl $0x0, 0x40(%rsp)
jne 0x9647
shrq $0x20, %r15
cmpl $0x2, %r15d
jne 0x919c
movzwl (%r13), %eax
rolw $0x8, %ax
movzwl %ax, %eax
movl %eax, %edx
movl 0xc(%rsp), %ecx
shrl %cl, %edx
testl %edx, %edx
jne 0x919c
imull $0x10101, %eax, %edi    # imm = 0x10101
addl $0xff000000, %edi       # imm = 0xFF000000
cmpl $0x8, 0xc(%rsp)
cmovnel %eax, %edi
jmp 0x9642
movl %ecx, 0x10(%rsp)
movl $0x0, 0x1c(%rsp)
leal (,%r12,4), %eax
leal (,%rsi,4), %ecx
movl $0x4021301, %edx        # imm = 0x4021301
shrl %cl, %edx
movl %eax, 0xc(%rbx)
andl $0x7, %edx
imull 0xc(%rsp), %edx
movl %edx, 0x4c(%rsp)
movl %edx, %r14d
imull %r12d, %r14d
addl $0x7, %r14d
shrl $0x3, %r14d
leaq 0x4(%r14), %rcx
cmpl %eax, %ecx
movq %rcx, 0x20(%rsp)
cmoval %ecx, %eax
leal 0x2(%rbp), %ecx
imull %eax, %ecx
movq %rcx, 0x38(%rsp)
leaq 0x1c(%rcx), %rdi
callq 0x11544
leaq 0x18(%rbx), %rdi
movq %rdi, 0x78(%rsp)
movq %rax, %rsi
callq 0x9d30
movq 0x18(%rbx), %rax
movq %rax, 0x10(%rbx)
cmpb $0x0, 0xb(%rsp)
pushq $0x6
popq %rcx
cmovnel 0x10(%rsp), %ecx
movl %ecx, 0x8(%rbx)
movq 0x38(%rsp), %rcx
addq %rcx, %rax
addq $0x1c, %rax
movq %r14, 0x50(%rsp)
notq %r14
imulq 0x58(%rsp), %r14
addq %rax, %r14
leaq 0x500(%rsp), %rcx
movl $0x1, -0x8(%rcx)
movb $0x0, 0x2(%rcx)
andq $0x0, 0x30(%rcx)
xorps %xmm0, %xmm0
movups %xmm0, 0x4(%rcx)
movups %xmm0, 0x10(%rcx)
movb $-0x2, (%rcx)
movq %rax, 0x10(%rsp)
subq %r14, %rax
leaq 0xe0(%rsp), %rsi
movq %r14, 0x38(%rsp)
movq %r14, (%rsi)
movq %rax, 0x8(%rsi)
leaq 0x4f8(%rsp), %rdi
callq 0x9d50
pushq $0x2
popq %r14
cmpl $0x49444154, %r15d      # imm = 0x49444154
jne 0x9485
cmpl $0x2, %r14d
jne 0x9485
shrq $0x20, %r15
leaq 0x500(%rsp), %rdi
movq %r13, %rsi
movq %r15, %rdx
xorl %ecx, %ecx
callq 0x7922
leaq 0x4f8(%rsp), %rdi
callq 0x18750
movl %eax, %r14d
leaq 0x80(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x98b2
movq 0x88(%rsp), %r13
movq 0x98(%rsp), %r15
jmp 0x9429
cmpl $0x2, %r14d
jne 0x94af
pushq $0x1
popq %rcx
leaq 0x500(%rsp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x7922
leaq 0x4f8(%rsp), %rdi
callq 0x18750
movl %eax, %r14d
testl %r14d, %r14d
movq 0x58(%rsp), %r13
jne 0x919c
movq 0x530(%rsp), %rax
subq 0x528(%rsp), %rax
addq 0x38(%rsp), %rax
cmpq 0x10(%rsp), %rax
jne 0x919c
cmpl $0x49454e44, %r15d      # imm = 0x49454E44
je 0x94ff
leaq 0x80(%rsp), %r14
leaq 0x60(%rsp), %rsi
movq %r14, %rdi
callq 0x994a
movq 0x18(%r14), %r15
cmpq $0x49454e44, %r15       # imm = 0x49454E44
jne 0x919c
movq 0x20(%rsp), %r14
movq %r14, %rax
imulq %r13, %rax
movq 0x10(%rsp), %r15
subq %rax, %r15
pushq $-0x4
popq %rdi
movq 0x50(%rsp), %r8
subq %r8, %rdi
addq %rdi, %r15
movq 0x38(%rsp), %rax
cmpb $0x2, (%rax)
jb 0x954a
addq %r15, %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x3170
movq 0x50(%rsp), %r8
movl 0x4c(%rsp), %ecx
addl $0x7, %ecx
shrl $0x3, %ecx
movq %r15, 0x10(%rsp)
movq %r15, %rdi
movq %r14, %rsi
movq 0x38(%rsp), %rdx
movq %r13, %r9
callq 0x997c
testb %al, %al
je 0x919c
addq $0x4, 0x10(%rsp)
cmpb $0x2, 0x30(%rsp)
je 0x96e3
cmpl $0x0, 0x40(%rsp)
jne 0x9731
cmpl $0x4, 0xc(%rsp)
je 0x97da
cmpl $0x2, 0xc(%rsp)
je 0x979f
cmpl $0x1, 0xc(%rsp)
jne 0x9815
cmpb $0x0, 0xb(%rsp)
je 0x95ca
leaq 0x1f2ad(%rip), %rax     # 0x2886c
movl 0x1c(%rsp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x1c(%rsp)
leaq 0x1f29b(%rip), %rcx     # 0x2886c
pushq $0x2
popq %r8
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0x9d78
jmp 0x96f5
shrq $0x20, %r15
cmpl $0x6, %r15d
jne 0x919c
movzwl (%r13), %eax
movzwl 0x2(%r13), %ecx
rolw $0x8, %ax
rolw $0x8, %cx
movzwl 0x4(%r13), %edx
rolw $0x8, %dx
movzwl %ax, %eax
movzwl %cx, %edi
movl %edi, %esi
orl %eax, %esi
movzwl %dx, %edx
orl %edx, %esi
movl 0xc(%rsp), %ecx
shrl %cl, %esi
testl %esi, %esi
jne 0x919c
shll $0x10, %eax
shll $0x8, %edi
orl %eax, %edi
orl %edx, %edi
orl $0xff000000, %edi       # imm = 0xFF000000
movb $0x1, %r14b
jmp 0x96a2
xorl %edi, %edi
movl $0x0, %r14d
cmpb $0x3, %sil
jne 0x9691
shrq $0x20, %r15
je 0x919c
cmpl %r15d, 0x2c(%rsp)
jb 0x919c
movb $0x1, %r14b
xorl %eax, %eax
cmpq %rax, %r15
je 0x9691
movb (%r13,%rax), %cl
leal 0x1(%rcx), %edx
cmpb $0x2, %dl
setb %dl
andb %dl, %r14b
movb %cl, 0xf3(%rsp,%rax,4)
incq %rax
jmp 0x966f
movq 0x40(%rsp), %rax
orl $0x2, %eax
cmpl $0x6, %eax
je 0x919c
movl %edi, 0x1c(%rsp)
leaq 0x4f8(%rsp), %r15
leaq 0x60(%rsp), %rsi
movq %r15, %rdi
callq 0x994a
movq 0x30(%rsp), %rsi
movq 0x8(%r15), %r13
movq 0x18(%r15), %r15
movzbl %r14b, %eax
andl $0x1, %eax
leal (%rax,%rax,2), %eax
addl $0x5, %eax
movl %eax, 0x10(%rsp)
movb $0x1, 0xb(%rsp)
jmp 0x933a
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0x9fe8
movl 0x1c(%rsp), %esi
cmpl $0xff000000, %esi       # imm = 0xFF000000
jb 0x9729
movq 0x78(%rsp), %rax
movq (%rax), %rax
imull %r12d, %ebp
movl %esi, %ecx
andl $0xffffff, %ecx         # imm = 0xFFFFFF
xorl %edx, %edx
cmpq %rdx, %rbp
je 0x9729
cmpl %esi, (%rax,%rdx,4)
jne 0x9724
movl %ecx, (%rax,%rdx,4)
incq %rdx
jmp 0x9717
movb $0x1, %r14b
jmp 0x91ad
cmpb $0x3, 0x30(%rsp)
jne 0x977d
cmpl $0x4, 0xc(%rsp)
je 0x9864
cmpl $0x2, 0xc(%rsp)
je 0x9843
cmpl $0x1, 0xc(%rsp)
jne 0x9885
leaq 0xf0(%rsp), %rcx
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
movl 0x2c(%rsp), %r8d
callq 0x9d78
jmp 0x98a4
cmpb $0x4, 0x30(%rsp)
jne 0x982c
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0xa08a
jmp 0x96f5
cmpb $0x0, 0xb(%rsp)
je 0x97b8
leaq 0x1f0d3(%rip), %rax     # 0x28880
movl 0x1c(%rsp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x1c(%rsp)
leaq 0x1f0c1(%rip), %rcx     # 0x28880
pushq $0x4
popq %r8
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0x9e32
jmp 0x96f5
cmpb $0x0, 0xb(%rsp)
je 0x97f3
leaq 0x1f0a8(%rip), %rax     # 0x28890
movl 0x1c(%rsp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x1c(%rsp)
leaq 0x1f096(%rip), %rcx     # 0x28890
pushq $0x10
popq %r8
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0x9f06
jmp 0x96f5
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0x9f9e
jmp 0x96f5
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
callq 0xa0da
jmp 0x96f5
leaq 0xf0(%rsp), %rcx
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
movl 0x2c(%rsp), %r8d
callq 0x9e32
jmp 0x98a4
leaq 0xf0(%rsp), %rcx
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
movl 0x2c(%rsp), %r8d
callq 0x9f06
jmp 0x98a4
leaq 0xf0(%rsp), %rcx
movq %rbx, %rdi
movq 0x10(%rsp), %rsi
movq 0x20(%rsp), %rdx
movl 0x2c(%rsp), %r8d
callq 0xa036
testb %al, %al
je 0x919c
jmp 0x96f5
nop