// File: /workspace/github_c_makefile_star2_O0/jsummers[P]deark/modules/ilbm.c
// Function: decompress_plane_vdelta
static void decompress_plane_vdelta(deark *c, lctx *d, struct imgbody_info *ibi,
	struct frame_ctx *frctx, i64 plane_idx,
	dbuf *inf, i64 codepos1, i64 datapos1, i64 endpos,
	i64 code_size, i64 dataelem_size, int separate_data_stream, u8 xor_mode)
{
	i64 pos = codepos1; // If !separate_data_stream, this is for code and data
	i64 datapos = datapos1;
	i64 num_columns;
	i64 col;
	i64 dststride = ibi->frame_buffer_rowspan;
	UI unc_threshold;
	u8 last_col_quirk = 0;
	int baddata_flag = 0;

	if(separate_data_stream) {
		de_dbg2(c, "vdelta(%d,%d) plane %d at (%"I64_FMT",%"I64_FMT")", (int)code_size,
			(int)dataelem_size, (int)plane_idx, codepos1, datapos1);
	}
	else {
		de_dbg2(c, "vdelta(%d) plane at (%"I64_FMT")", (int)code_size, codepos1);
	}
	if(code_size!=1 && code_size!=2 && code_size!=4) goto done;
	if(dataelem_size!=1 && dataelem_size!=2 && dataelem_size!=4) goto done;
	if(xor_mode && dataelem_size!=1) goto done;

	if(code_size==1) {
		unc_threshold = 0x80;
	}
	else if(code_size==2) {
		unc_threshold = 0x8000;
	}
	else {
		unc_threshold = 0x80000000U;
	}

	if(dataelem_size==1) {
		num_columns = (ibi->width+7)/8;
	}
	else if(dataelem_size==2) {
		num_columns = (ibi->width+15)/16;
	}
	else {
		num_columns = (ibi->width+31)/32;
	}

	if(frctx->op==8 && dataelem_size==4) {
		i64 num_columns_if_size2;

		num_columns_if_size2 = (ibi->width+15)/16;
		if(num_columns*2 != num_columns_if_size2) {
			// A dumb quirk of ANIM-8: The last column may use "word" mode,
			// even when when all other columns use "long" mode.
			last_col_quirk = 1;
		}
	}

	for(col=0; col<num_columns; col++) {
		i64 opcount;
		i64 opidx;
		i64 elem_bytes_to_write;
		i64 ypos = 0;
		i64 col_start_dstpos;
		i64 dataelem_size_thiscol;
		i64 code_size_thiscol;
		UI unc_threshold_thiscol;
		u8 is_last_col;

		if(c->debug_level>=3) {
			de_dbg3(c, "col %u at %"I64_FMT, (UI)col, pos);
		}

		is_last_col = (col+1 == num_columns);
		code_size_thiscol = code_size;
		dataelem_size_thiscol = dataelem_size;
		unc_threshold_thiscol = unc_threshold;
		if(is_last_col && last_col_quirk) {
			code_size_thiscol = 2;
			dataelem_size_thiscol = 2;
			unc_threshold_thiscol = 0x8000;
		}

		if(pos>=endpos) {
			baddata_flag = 1;
			goto done;
		}

		// Defend against writing beyond the right edge of this plane
		if(is_last_col && (dataelem_size_thiscol==4) && (ibi->bytes_per_row_per_plane%4)) {
			elem_bytes_to_write = 2;
		}
		else {
			elem_bytes_to_write = dataelem_size_thiscol;
		}

		col_start_dstpos = plane_idx * ibi->bytes_per_row_per_plane + dataelem_size*col;

		opcount = get_elem_as_int_p(inf, &pos, code_size_thiscol);
		if(c->debug_level>=3) {
			de_dbg3(c, "col %d op count: %"I64_FMT, (int)col, opcount);
		}

		for(opidx=0; opidx<opcount; opidx++) {
			i64 dstpos;
			i64 count;
			i64 k;
			UI op;
			u8 valbuf[4];

			if(pos>=endpos) {
				baddata_flag = 1;
				goto done;
			}
			op = (UI)get_elem_as_int_p(inf, &pos, code_size_thiscol);

			if(op==0) { // RLE
				count = get_elem_as_int_p(inf, &pos, code_size_thiscol);
				if(ypos+count > ibi->height) {
					// TODO: Should we tolerate this, and set count = 0?
					baddata_flag = 1;
					goto done;
				}

				if(count>0) {
					frctx->change_flag = 1;
				}

				if(separate_data_stream) {
					if(datapos>=endpos) {
						baddata_flag = 1;
						goto done;
					}
					dbuf_read(inf, valbuf, datapos, dataelem_size_thiscol);
					datapos += dataelem_size_thiscol;
				}
				else {
					dbuf_read(inf, valbuf, pos, dataelem_size_thiscol);
					pos += dataelem_size_thiscol;
				}

				for(k=0; k<count; k++) {
					dstpos = col_start_dstpos + ypos*dststride;
					if(xor_mode) {
						u8 val;

						val = valbuf[0] ^ dbuf_getbyte(frctx->frame_buffer, dstpos);
						dbuf_writebyte_at(frctx->frame_buffer, dstpos, val);
					}
					else {
						dbuf_write_at(frctx->frame_buffer, dstpos, valbuf, elem_bytes_to_write);
					}
					ypos++;
				}
			}
			else if(op < unc_threshold_thiscol) { // skip
				ypos += (i64)op;
			}
			else { // uncompressed run
				count = (i64)(op - unc_threshold_thiscol);
				if(ypos+count > ibi->height) {
					baddata_flag = 1;
					goto done;
				}

				if(count>0) {
					frctx->change_flag = 1;
				}

				for(k=0; k<count; k++) {
					if(separate_data_stream) {
						if(datapos>=endpos) {
							baddata_flag = 1;
							goto done;
						}
						dbuf_read(inf, valbuf, datapos, dataelem_size_thiscol);
						datapos += dataelem_size_thiscol;
					}
					else {
						dbuf_read(inf, valbuf, pos, dataelem_size_thiscol);
						pos += dataelem_size_thiscol;
					}

					dstpos = col_start_dstpos + ypos*dststride;
					if(xor_mode) {
						valbuf[0] ^= dbuf_getbyte(frctx->frame_buffer, dstpos);
					}
					dbuf_write_at(frctx->frame_buffer, dstpos, valbuf, elem_bytes_to_write);
					ypos++;
				}
			}
		}
	}

done:
	if(baddata_flag && !d->errflag) {
		de_err(c, "Delta decompression failed");
		d->errflag = 1;
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movb 0x40(%rbp), %al
movl 0x38(%rbp), %eax
movq 0x30(%rbp), %rax
movq 0x28(%rbp), %rax
movq 0x20(%rbp), %rax
movq 0x18(%rbp), %rax
movq 0x10(%rbp), %rax
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq %r9, -0x30(%rbp)
movq 0x10(%rbp), %rax
movq %rax, -0x38(%rbp)
movq 0x18(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rax
movq 0x48(%rax), %rax
movq %rax, -0x58(%rbp)
movb $0x0, -0x5d(%rbp)
movl $0x0, -0x64(%rbp)
cmpl $0x0, 0x38(%rbp)
je 0xb53ed
movq -0x8(%rbp), %rdi
movq 0x28(%rbp), %rax
movl %eax, %edx
movq 0x30(%rbp), %rax
movl %eax, %ecx
movq -0x28(%rbp), %rax
movl %eax, %r8d
movq 0x10(%rbp), %r9
movq 0x18(%rbp), %rax
leaq 0xff689(%rip), %rsi     # 0x1b4a69
movq %rax, (%rsp)
movb $0x0, %al
callq 0x15b350
jmp 0xb5409
movq -0x8(%rbp), %rdi
movq 0x28(%rbp), %rax
movl %eax, %edx
movq 0x10(%rbp), %rcx
leaq 0xff68b(%rip), %rsi     # 0x1b4a8d
movb $0x0, %al
callq 0x15b350
cmpq $0x1, 0x28(%rbp)
je 0xb5423
cmpq $0x2, 0x28(%rbp)
je 0xb5423
cmpq $0x4, 0x28(%rbp)
je 0xb5423
jmp 0xb5a4c
cmpq $0x1, 0x30(%rbp)
je 0xb543d
cmpq $0x2, 0x30(%rbp)
je 0xb543d
cmpq $0x4, 0x30(%rbp)
je 0xb543d
jmp 0xb5a4c
movzbl 0x40(%rbp), %eax
cmpl $0x0, %eax
je 0xb5452
cmpq $0x1, 0x30(%rbp)
je 0xb5452
jmp 0xb5a4c
cmpq $0x1, 0x28(%rbp)
jne 0xb5462
movl $0x80, -0x5c(%rbp)
jmp 0xb547b
cmpq $0x2, 0x28(%rbp)
jne 0xb5472
movl $0x8000, -0x5c(%rbp)    # imm = 0x8000
jmp 0xb5479
movl $0x80000000, -0x5c(%rbp) # imm = 0x80000000
jmp 0xb547b
cmpq $0x1, 0x30(%rbp)
jne 0xb549d
movq -0x18(%rbp), %rax
movq (%rax), %rax
addq $0x7, %rax
movl $0x8, %ecx
cqto
idivq %rcx
movq %rax, -0x48(%rbp)
jmp 0xb54da
cmpq $0x2, 0x30(%rbp)
jne 0xb54bf
movq -0x18(%rbp), %rax
movq (%rax), %rax
addq $0xf, %rax
movl $0x10, %ecx
cqto
idivq %rcx
movq %rax, -0x48(%rbp)
jmp 0xb54d8
movq -0x18(%rbp), %rax
movq (%rax), %rax
addq $0x1f, %rax
movl $0x20, %ecx
cqto
idivq %rcx
movq %rax, -0x48(%rbp)
jmp 0xb54da
movq -0x20(%rbp), %rax
movzbl 0x10(%rax), %eax
cmpl $0x8, %eax
jne 0xb551a
cmpq $0x4, 0x30(%rbp)
jne 0xb551a
movq -0x18(%rbp), %rax
movq (%rax), %rax
addq $0xf, %rax
movl $0x10, %ecx
cqto
idivq %rcx
movq %rax, -0x70(%rbp)
movq -0x48(%rbp), %rax
shlq %rax
cmpq -0x70(%rbp), %rax
je 0xb5518
movb $0x1, -0x5d(%rbp)
jmp 0xb551a
movq $0x0, -0x50(%rbp)
movq -0x50(%rbp), %rax
cmpq -0x48(%rbp), %rax
jge 0xb5a4a
movq $0x0, -0x90(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x3, (%rax)
jl 0xb5560
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rax
movl %eax, %edx
movq -0x38(%rbp), %rcx
leaq 0xff54e(%rip), %rsi     # 0x1b4aa7
movb $0x0, %al
callq 0x15b400
movq -0x50(%rbp), %rax
addq $0x1, %rax
cmpq -0x48(%rbp), %rax
sete %al
andb $0x1, %al
movzbl %al, %eax
movb %al, -0xad(%rbp)
movq 0x28(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq 0x30(%rbp), %rax
movq %rax, -0xa0(%rbp)
movl -0x5c(%rbp), %eax
movl %eax, -0xac(%rbp)
movzbl -0xad(%rbp), %eax
cmpl $0x0, %eax
je 0xb55ce
movzbl -0x5d(%rbp), %eax
cmpl $0x0, %eax
je 0xb55ce
movq $0x2, -0xa8(%rbp)
movq $0x2, -0xa0(%rbp)
movl $0x8000, -0xac(%rbp)    # imm = 0x8000
movq -0x38(%rbp), %rax
cmpq 0x20(%rbp), %rax
jl 0xb55e4
movl $0x1, -0x64(%rbp)
jmp 0xb5a4c
movzbl -0xad(%rbp), %eax
cmpl $0x0, %eax
je 0xb561f
cmpq $0x4, -0xa0(%rbp)
jne 0xb561f
movq -0x18(%rbp), %rax
movq 0x40(%rax), %rax
movl $0x4, %ecx
cqto
idivq %rcx
cmpq $0x0, %rdx
je 0xb561f
movq $0x2, -0x88(%rbp)
jmp 0xb562d
movq -0xa0(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x28(%rbp), %rax
movq -0x18(%rbp), %rcx
imulq 0x40(%rcx), %rax
movq 0x30(%rbp), %rcx
imulq -0x50(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0x98(%rbp)
movq -0x30(%rbp), %rdi
movq -0xa8(%rbp), %rdx
leaq -0x38(%rbp), %rsi
callq 0xb5a90
movq %rax, -0x78(%rbp)
movq -0x8(%rbp), %rax
cmpl $0x3, (%rax)
jl 0xb568a
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rax
movl %eax, %edx
movq -0x78(%rbp), %rcx
leaq 0xff432(%rip), %rsi     # 0x1b4ab5
movb $0x0, %al
callq 0x15b400
movq $0x0, -0x80(%rbp)
movq -0x80(%rbp), %rax
cmpq -0x78(%rbp), %rax
jge 0xb5a37
movq -0x38(%rbp), %rax
cmpq 0x20(%rbp), %rax
jl 0xb56b6
movl $0x1, -0x64(%rbp)
jmp 0xb5a4c
movq -0x30(%rbp), %rdi
movq -0xa8(%rbp), %rdx
leaq -0x38(%rbp), %rsi
callq 0xb5a90
movl %eax, -0xcc(%rbp)
cmpl $0x0, -0xcc(%rbp)
jne 0xb5886
movq -0x30(%rbp), %rdi
movq -0xa8(%rbp), %rdx
leaq -0x38(%rbp), %rsi
callq 0xb5a90
movq %rax, -0xc0(%rbp)
movq -0x90(%rbp), %rax
addq -0xc0(%rbp), %rax
movq -0x18(%rbp), %rcx
cmpq 0x8(%rcx), %rax
jle 0xb571c
movl $0x1, -0x64(%rbp)
jmp 0xb5a4c
cmpq $0x0, -0xc0(%rbp)
jle 0xb5731
movq -0x20(%rbp), %rax
movl $0x1, 0xc(%rax)
cmpl $0x0, 0x38(%rbp)
je 0xb5779
movq -0x40(%rbp), %rax
cmpq 0x20(%rbp), %rax
jl 0xb574d
movl $0x1, -0x64(%rbp)
jmp 0xb5a4c
movq -0x30(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
movq -0x40(%rbp), %rdx
movq -0xa0(%rbp), %rcx
callq 0x164d10
movq -0xa0(%rbp), %rax
addq -0x40(%rbp), %rax
movq %rax, -0x40(%rbp)
jmp 0xb57a3
movq -0x30(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
movq -0x38(%rbp), %rdx
movq -0xa0(%rbp), %rcx
callq 0x164d10
movq -0xa0(%rbp), %rax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movq $0x0, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
cmpq -0xc0(%rbp), %rax
jge 0xb5881
movq -0x98(%rbp), %rax
movq -0x90(%rbp), %rcx
imulq -0x58(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0xb8(%rbp)
cmpb $0x0, 0x40(%rbp)
je 0xb5836
movzbl -0xd0(%rbp), %eax
movl %eax, -0xd8(%rbp)
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0xb8(%rbp), %rsi
callq 0x165060
movb %al, %cl
movl -0xd8(%rbp), %eax
movzbl %cl, %ecx
xorl %ecx, %eax
movb %al, -0xd1(%rbp)
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0xb8(%rbp), %rsi
movzbl -0xd1(%rbp), %edx
callq 0x168790
jmp 0xb5858
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0xb8(%rbp), %rsi
leaq -0xd0(%rbp), %rdx
movq -0x88(%rbp), %rcx
callq 0x1683f0
movq -0x90(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x90(%rbp)
movq -0xc8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc8(%rbp)
jmp 0xb57ae
jmp 0xb5a24
movl -0xcc(%rbp), %eax
cmpl -0xac(%rbp), %eax
jae 0xb58ad
movl -0xcc(%rbp), %eax
addq -0x90(%rbp), %rax
movq %rax, -0x90(%rbp)
jmp 0xb5a22
movl -0xcc(%rbp), %eax
subl -0xac(%rbp), %eax
movl %eax, %eax
movq %rax, -0xc0(%rbp)
movq -0x90(%rbp), %rax
addq -0xc0(%rbp), %rax
movq -0x18(%rbp), %rcx
cmpq 0x8(%rcx), %rax
jle 0xb58e6
movl $0x1, -0x64(%rbp)
jmp 0xb5a4c
cmpq $0x0, -0xc0(%rbp)
jle 0xb58fb
movq -0x20(%rbp), %rax
movl $0x1, 0xc(%rax)
movq $0x0, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
cmpq -0xc0(%rbp), %rax
jge 0xb5a20
cmpl $0x0, 0x38(%rbp)
je 0xb5962
movq -0x40(%rbp), %rax
cmpq 0x20(%rbp), %rax
jl 0xb5936
movl $0x1, -0x64(%rbp)
jmp 0xb5a4c
movq -0x30(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
movq -0x40(%rbp), %rdx
movq -0xa0(%rbp), %rcx
callq 0x164d10
movq -0xa0(%rbp), %rax
addq -0x40(%rbp), %rax
movq %rax, -0x40(%rbp)
jmp 0xb598c
movq -0x30(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
movq -0x38(%rbp), %rdx
movq -0xa0(%rbp), %rcx
callq 0x164d10
movq -0xa0(%rbp), %rax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x98(%rbp), %rax
movq -0x90(%rbp), %rcx
imulq -0x58(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0xb8(%rbp)
cmpb $0x0, 0x40(%rbp)
je 0xb59d5
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0xb8(%rbp), %rsi
callq 0x165060
movzbl %al, %ecx
movzbl -0xd0(%rbp), %eax
xorl %ecx, %eax
movb %al, -0xd0(%rbp)
movq -0x20(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0xb8(%rbp), %rsi
leaq -0xd0(%rbp), %rdx
movq -0x88(%rbp), %rcx
callq 0x1683f0
movq -0x90(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x90(%rbp)
movq -0xc8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc8(%rbp)
jmp 0xb5906
jmp 0xb5a22
jmp 0xb5a24
jmp 0xb5a26
movq -0x80(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x80(%rbp)
jmp 0xb5692
jmp 0xb5a39
movq -0x50(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x50(%rbp)
jmp 0xb5522
jmp 0xb5a4c
cmpl $0x0, -0x64(%rbp)
je 0xb5a79
movq -0x10(%rbp), %rax
cmpl $0x0, 0x1c(%rax)
jne 0xb5a79
movq -0x8(%rbp), %rdi
leaq 0xff063(%rip), %rsi     # 0x1b4aca
movb $0x0, %al
callq 0x15bfb0
movq -0x10(%rbp), %rax
movl $0x1, 0x1c(%rax)
addq $0xe0, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)