// File: /workspace/github_c_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xb8, %rsp
movq %r9, 0x60(%rsp)
movq %r8, %r12
movq %rcx, %r13
movq %rsi, 0x98(%rsp)
movq %rdi, %rbx
movq 0x110(%rsp), %rbp
movq 0x108(%rsp), %r15
movq 0xf8(%rsp), %rax
movq 0xf0(%rsp), %r9
movq %r9, 0x10(%rsp)
movq %rdx, 0x38(%rsp)
movq 0x48(%rdx), %rcx
movq %rcx, 0x50(%rsp)
cmpl $0x0, 0x118(%rsp)
je 0x7803e
movq %rax, %r14
movq %rax, (%rsp)
leaq 0xa3ed1(%rip), %rsi     # 0x11befb
movq %rbx, %rdi
movl %r15d, %edx
movl %ebp, %ecx
movl %r12d, %r8d
xorl %eax, %eax
callq 0xde9f1
jmp 0x78058
movq %rax, %r14
leaq 0xa3ed7(%rip), %rsi     # 0x11bf1f
movq %rbx, %rdi
movl %r15d, %edx
movq %r9, %rcx
xorl %eax, %eax
callq 0xde9f1
cmpq $0x4, %r15
ja 0x7858b
pushq $0x16
popq %rax
movq 0x108(%rsp), %rcx
btq %rcx, %rax
jae 0x7858b
cmpq $0x4, %rbp
ja 0x7858b
btq %rbp, %rax
jae 0x7858b
cmpq $0x1, %rbp
setne %al
cmpb $0x0, 0x120(%rsp)
setne %cl
testb %cl, %al
jne 0x7858b
movq 0x108(%rsp), %rdx
cmpq $0x2, %rdx
movl $0x8000, %eax           # imm = 0x8000
movl $0x80000000, %ecx       # imm = 0x80000000
cmovel %eax, %ecx
cmpq $0x1, %rdx
movl $0x80, %eax
cmovnel %ecx, %eax
movl %eax, 0x6c(%rsp)
movq 0x38(%rsp), %rax
movq (%rax), %rcx
cmpq $0x1, %rbp
je 0x780e9
cmpq $0x2, %rbp
jne 0x780f0
pushq $0x10
popq %rsi
pushq $0xf
jmp 0x780f5
pushq $0x8
popq %rsi
pushq $0x7
jmp 0x780f5
pushq $0x20
popq %rsi
pushq $0x1f
popq %rax
addq %rcx, %rax
cqto
idivq %rsi
movq %rax, %rdi
movl $0x0, 0x28(%rsp)
cmpq $0x4, %rbp
jne 0x78133
cmpb $0x8, 0x10(%r13)
jne 0x78133
addq $0xf, %rcx
pushq $0x10
popq %rsi
movq %rcx, %rax
cqto
idivq %rsi
leaq (%rdi,%rdi), %rcx
cmpq %rax, %rcx
setne %al
movl %eax, 0x28(%rsp)
testq %rdi, %rdi
movl $0x0, %eax
movq %rdi, 0x90(%rsp)
cmovgq %rdi, %rax
movq $0x0, 0x70(%rsp)
xorl %r15d, %r15d
movq %rax, 0x20(%rsp)
movq %rbx, 0x30(%rsp)
movq %r12, 0xa0(%rsp)
movq %r13, 0x48(%rsp)
cmpq %rax, %r15
je 0x7858b
cmpl $0x3, (%rbx)
movq 0x10(%rsp), %rcx
jl 0x78196
movq %rbx, %rdi
leaq 0xa3db2(%rip), %rsi     # 0x11bf39
movl %r15d, %edx
xorl %eax, %eax
callq 0xdea83
movq 0x10(%rsp), %rcx
leaq 0x1(%r15), %rdi
movq 0x90(%rsp), %rdx
cmpq %rdx, %rdi
sete %al
testb %al, 0x28(%rsp)
movq %rbp, %r8
pushq $0x2
popq %rsi
cmovneq %rsi, %r8
movq 0x108(%rsp), %r9
movq %rsi, %rax
cmovneq %rsi, %r9
movl 0x6c(%rsp), %r10d
movl $0x8000, %esi           # imm = 0x8000
cmovnel %esi, %r10d
movl %r10d, 0x2c(%rsp)
cmpq 0x100(%rsp), %rcx
movq 0x60(%rsp), %r10
jge 0x78563
movq %rax, %rsi
movq %rdi, 0x80(%rsp)
movq %rdi, %rax
xorq %rdx, %rax
movq %r8, %rcx
xorq $0x4, %rcx
movq 0x38(%rsp), %rdx
movq 0x40(%rdx), %rdx
movq %r10, %rdi
movq %rdx, %rbx
testb $0x3, %dl
movq %r8, %rdx
cmovneq %rsi, %rdx
orq %rax, %rcx
movq %r8, 0x40(%rsp)
cmovneq %r8, %rdx
movq %rdx, 0x88(%rsp)
leaq 0x10(%rsp), %rsi
movq %r9, 0xb0(%rsp)
movq %r9, %rdx
callq 0x7859d
movq %rax, %r13
movq 0x30(%rsp), %rax
cmpl $0x3, (%rax)
jl 0x7826b
movq 0x30(%rsp), %rdi
leaq 0xa3ce9(%rip), %rsi     # 0x11bf47
movl %r15d, %edx
movq %r13, %rcx
xorl %eax, %eax
callq 0xdea83
imulq %r12, %rbx
testq %r13, %r13
movl $0x0, %eax
cmovleq %rax, %r13
addq 0x70(%rsp), %rbx
movq %rbx, 0x78(%rsp)
xorl %ecx, %ecx
movq $0x0, 0x18(%rsp)
movq 0x20(%rsp), %rax
movq 0x80(%rsp), %r15
movq 0x60(%rsp), %rbx
movq %r13, 0xa8(%rsp)
movq %rcx, 0x58(%rsp)
cmpq %r13, %rcx
je 0x78554
movq 0x100(%rsp), %rax
cmpq %rax, 0x10(%rsp)
jge 0x78563
movq %rbx, %rdi
leaq 0x10(%rsp), %r15
movq %r15, %rsi
movq %rbx, %r13
movq 0xb0(%rsp), %rbx
movq %rbx, %rdx
callq 0x7859d
testl %eax, %eax
je 0x7830f
movl %eax, %r12d
subl 0x2c(%rsp), %r12d
jae 0x78393
movl %eax, %eax
addq %rax, 0x18(%rsp)
movq 0x20(%rsp), %rax
movq %r13, %rbx
jmp 0x78527
movq %r13, %rdi
movq %r15, %rsi
movq %rbx, %rdx
callq 0x7859d
movq %rax, %r15
movq 0x18(%rsp), %rax
addq %r15, %rax
movq 0x38(%rsp), %rcx
cmpq 0x8(%rcx), %rax
jg 0x78563
movq %r13, %rbx
testq %r15, %r15
movq 0x48(%rsp), %r13
jle 0x7834c
movl $0x1, 0xc(%r13)
cmpl $0x0, 0x118(%rsp)
je 0x78483
movq %r14, %rax
cmpq 0x100(%rsp), %r14
jge 0x78563
movq %rax, %r14
movq %rbx, %rdi
leaq 0xc(%rsp), %rsi
movq %rax, %rdx
movq 0x40(%rsp), %r12
movq %r12, %rcx
callq 0xe3cb7
addq %r12, %r14
movq 0x48(%rsp), %r13
jmp 0x784a2
movq 0x18(%rsp), %rcx
addq %r12, %rcx
movq 0x38(%rsp), %rdx
cmpq 0x8(%rdx), %rcx
jg 0x78563
movq %r13, %rbx
cmpl 0x2c(%rsp), %eax
je 0x783bf
movq 0x48(%rsp), %rax
movl $0x1, 0xc(%rax)
movq 0x50(%rsp), %r15
imulq 0x18(%rsp), %r15
addq 0x78(%rsp), %r15
negq %r12
xorl %ebp, %ebp
movq 0x20(%rsp), %rax
cmpq %rbp, %r12
je 0x78522
cmpl $0x0, 0x118(%rsp)
je 0x78417
cmpq 0x100(%rsp), %r14
jge 0x78563
movq %rbx, %rdi
leaq 0xc(%rsp), %rsi
movq %r14, %rdx
movq 0x40(%rsp), %rbx
movq %rbx, %rcx
callq 0xe3cb7
addq %rbx, %r14
jmp 0x78436
movq 0x10(%rsp), %rdx
movq %rbx, %rdi
leaq 0xc(%rsp), %rsi
movq 0x40(%rsp), %rbx
movq %rbx, %rcx
callq 0xe3cb7
addq %rbx, 0x10(%rsp)
cmpb $0x0, 0x120(%rsp)
movq 0x48(%rsp), %rbx
je 0x78455
movq 0x20(%rbx), %rdi
movq %r15, %rsi
callq 0xe3eb4
xorb %al, 0xc(%rsp)
movq 0x20(%rbx), %rdi
movq %r15, %rsi
leaq 0xc(%rsp), %rdx
movq 0x88(%rsp), %rcx
callq 0xe5bfe
decq %rbp
addq 0x50(%rsp), %r15
movq 0x20(%rsp), %rax
movq %r13, %rbx
jmp 0x783d9
movq 0x10(%rsp), %rdx
movq %rbx, %rdi
leaq 0xc(%rsp), %rsi
movq 0x40(%rsp), %r12
movq %r12, %rcx
callq 0xe3cb7
addq %r12, 0x10(%rsp)
testq %r15, %r15
movl $0x0, %eax
cmovleq %rax, %r15
movq 0x50(%rsp), %r12
imulq 0x18(%rsp), %r12
addq 0x78(%rsp), %r12
negq %r15
xorl %ebp, %ebp
movq 0x20(%rsp), %rax
cmpq %rbp, %r15
je 0x78522
cmpb $0x0, 0x120(%rsp)
je 0x784ff
movb 0xc(%rsp), %bl
movq 0x20(%r13), %rdi
movq %r12, %rsi
callq 0xe3eb4
xorb %bl, %al
movq 0x60(%rsp), %rbx
movq 0x20(%r13), %rdi
movzbl %al, %edx
movq %r12, %rsi
callq 0xe5e13
jmp 0x78518
movq 0x20(%r13), %rdi
movq %r12, %rsi
leaq 0xc(%rsp), %rdx
movq 0x88(%rsp), %rcx
callq 0xe5bfe
decq %rbp
addq 0x50(%rsp), %r12
jmp 0x784c3
subq %rbp, 0x18(%rsp)
movq 0x58(%rsp), %rcx
incq %rcx
movq 0xa0(%rsp), %r12
movq 0x110(%rsp), %rbp
movq 0x80(%rsp), %r15
movq 0xa8(%rsp), %r13
jmp 0x782aa
addq %rbp, 0x70(%rsp)
movq 0x30(%rsp), %rbx
jmp 0x7816a
movq 0x98(%rsp), %rbx
cmpl $0x0, 0x1c(%rbx)
movq 0x30(%rsp), %rdi
jne 0x7858b
leaq 0xa39df(%rip), %rsi     # 0x11bf5c
xorl %eax, %eax
callq 0xdf2a5
movl $0x1, 0x1c(%rbx)
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq