// File: /workspace/github_c_makefile_star2_O1/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 $0xd8, %rsp
movq %r9, %r14
movq %r8, %r12
movq %rcx, 0x38(%rsp)
movq %rsi, 0x90(%rsp)
movq %rdi, %rbx
movq 0x130(%rsp), %r13
movq 0x128(%rsp), %rax
movq 0x118(%rsp), %rcx
movq 0x110(%rsp), %r9
movq %r9, 0x20(%rsp)
movq %rdx, 0x48(%rsp)
movq 0x48(%rdx), %rdx
movq %rdx, 0x70(%rsp)
cmpl $0x0, 0x138(%rsp)
movq %rcx, 0x68(%rsp)
je 0x7ccdb
movq %rcx, (%rsp)
leaq 0xac247(%rip), %rsi     # 0x128f0b
movq %rbx, %rdi
movl %eax, %edx
movl %r13d, %ecx
movl %r12d, %r8d
movq %rax, %r15
xorl %eax, %eax
callq 0xe93cf
jmp 0x7ccf4
leaq 0xac24d(%rip), %rsi     # 0x128f2f
movq %rbx, %rdi
movl %eax, %edx
movq %r9, %rcx
movq %rax, %r15
xorl %eax, %eax
callq 0xe93cf
cmpq $0x4, %r15
ja 0x7d32d
movl $0x16, %eax
movq 0x128(%rsp), %rcx
btq %rcx, %rax
jae 0x7d32d
cmpq $0x4, %r13
ja 0x7d32d
btq %r13, %rax
jae 0x7d32d
cmpq $0x1, %r13
setne %al
cmpb $0x0, 0x140(%rsp)
setne %cl
testb %cl, %al
jne 0x7d32d
movq 0x128(%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, 0x8c(%rsp)
movq 0x48(%rsp), %rax
movq (%rax), %rax
cmpq $0x1, %r13
je 0x7cd8f
cmpq $0x2, %r13
jne 0x7cd9b
movl $0x10, %ecx
movl $0xf, %edx
jmp 0x7cda5
movl $0x8, %ecx
movl $0x7, %edx
jmp 0x7cda5
movl $0x20, %ecx
movl $0x1f, %edx
addq %rdx, %rax
cqto
idivq %rcx
cmpq $0x4, %r13
movq %rax, 0x60(%rsp)
jne 0x7ce02
movq 0x38(%rsp), %rcx
cmpb $0x8, 0x10(%rcx)
movl $0x0, %ecx
movq %rcx, 0x78(%rsp)
jne 0x7ce0b
movq 0x48(%rsp), %rax
movq (%rax), %rax
leaq 0xf(%rax), %rcx
addq $0x1e, %rax
testq %rcx, %rcx
cmovnsq %rcx, %rax
sarq $0x4, %rax
movq 0x60(%rsp), %rcx
addq %rcx, %rcx
cmpq %rax, %rcx
movq 0x60(%rsp), %rax
setne %cl
movq %rcx, 0x78(%rsp)
jmp 0x7ce0b
movq $0x0, 0x78(%rsp)
testq %rax, %rax
movl $0x0, %ecx
cmovgq %rax, %rcx
movq %rcx, 0xc0(%rsp)
movq $0x0, 0x98(%rsp)
movl $0x0, 0x14(%rsp)
xorl %r15d, %r15d
movq %rbx, 0xb0(%rsp)
movq %r14, 0xa0(%rsp)
movq %r12, 0xa8(%rsp)
cmpq 0xc0(%rsp), %r15
je 0x7d2f8
cmpl $0x3, (%rbx)
jl 0x7ce7f
movq 0x20(%rsp), %rcx
movq %rbx, %rdi
leaq 0xac0d9(%rip), %rsi     # 0x128f49
movl %r15d, %edx
xorl %eax, %eax
callq 0xe9461
movq 0x60(%rsp), %rax
leaq 0x1(%r15), %rsi
cmpq %rax, %rsi
movq %rax, %rcx
sete %al
testb %al, 0x78(%rsp)
movq %r13, %rax
movl $0x2, %edx
cmovneq %rdx, %rax
movq %rax, 0x50(%rsp)
movq 0x128(%rsp), %rbp
cmovneq %rdx, %rbp
movl 0x8c(%rsp), %edx
movl $0x8000, %eax           # imm = 0x8000
cmovnel %eax, %edx
movl %edx, 0x44(%rsp)
movq 0x120(%rsp), %rax
cmpq %rax, 0x20(%rsp)
movq %rsi, 0xc8(%rsp)
jge 0x7d29b
cmpq %rcx, %rsi
jne 0x7cf00
cmpq $0x4, 0x50(%rsp)
jne 0x7cf00
movl $0x2, %eax
movq %rax, 0x80(%rsp)
movq 0x48(%rsp), %rax
testb $0x3, 0x40(%rax)
jne 0x7cf0d
movq 0x50(%rsp), %rax
movq %rax, 0x80(%rsp)
movq 0x48(%rsp), %rax
movq 0x40(%rax), %rax
movq %r12, %r13
imulq %r12, %rax
movq %rax, 0x58(%rsp)
movq %r14, %rdi
leaq 0x20(%rsp), %rsi
movq %rbp, %rdx
callq 0x7d33f
movq %rax, %r12
cmpl $0x3, (%rbx)
jl 0x7cf51
movq %rbx, %rdi
leaq 0xac013(%rip), %rsi     # 0x128f57
movl %r15d, %edx
movq %r12, %rcx
xorl %eax, %eax
callq 0xe9461
testq %r12, %r12
jle 0x7d2a7
movq %r12, 0xd0(%rsp)
movq 0x58(%rsp), %rax
addq 0x98(%rsp), %rax
movq %rax, 0x58(%rsp)
movq $0x0, 0x30(%rsp)
xorl %r12d, %r12d
movq 0x68(%rsp), %rbx
leaq 0x20(%rsp), %r15
movq %rbp, 0x28(%rsp)
movq 0x130(%rsp), %r13
movl $0x2, 0x1c(%rsp)
movq 0x120(%rsp), %rax
cmpq %rax, 0x20(%rsp)
jge 0x7d05b
movq %r14, %rdi
movq %r15, %rsi
movq %rbp, %rdx
callq 0x7d33f
testl %eax, %eax
je 0x7cfe6
movl %eax, %ebp
subl 0x44(%rsp), %ebp
jae 0x7d06a
movl %eax, %eax
addq %rax, 0x30(%rsp)
movl $0x0, 0x1c(%rsp)
movb $0x1, %cl
jmp 0x7d25e
movq %r14, %rdi
movq %r15, %rsi
movq %rbp, %rdx
callq 0x7d33f
movq %rax, %rdx
movq 0x30(%rsp), %rax
addq %rdx, %rax
movq 0x48(%rsp), %rcx
cmpq 0x8(%rcx), %rax
jg 0x7d05b
movq %rdx, 0xb8(%rsp)
testq %rdx, %rdx
jle 0x7d023
movq 0x38(%rsp), %rax
movl $0x1, 0xc(%rax)
cmpl $0x0, 0x138(%rsp)
je 0x7d184
cmpq 0x120(%rsp), %rbx
jge 0x7d05b
movq %r14, %rdi
leaq 0x18(%rsp), %rsi
movq %rbx, %rdx
movq 0x50(%rsp), %rbp
movq %rbp, %rcx
callq 0xeeee8
addq %rbp, %rbx
jmp 0x7d1a3
xorl %ecx, %ecx
movl $0x1, 0x14(%rsp)
jmp 0x7d26b
movq 0x30(%rsp), %rcx
addq %rbp, %rcx
movq 0x48(%rsp), %rdx
cmpq 0x8(%rdx), %rcx
jle 0x7d08c
xorl %ecx, %ecx
movl $0x1, 0x14(%rsp)
jmp 0x7d25e
cmpl 0x44(%rsp), %eax
je 0x7d09e
movq 0x38(%rsp), %rcx
movl $0x1, 0xc(%rcx)
movb $0x1, %cl
cmpl 0x44(%rsp), %eax
jne 0x7d0b3
movl $0x0, 0x1c(%rsp)
jmp 0x7d25e
cmpq $0x1, %rbp
adcq $0x0, %rbp
movq 0x70(%rsp), %r15
imulq 0x30(%rsp), %r15
addq 0x58(%rsp), %r15
movq %r14, %r13
cmpl $0x0, 0x138(%rsp)
je 0x7d103
cmpq 0x120(%rsp), %rbx
jge 0x7d282
movq %r14, %rdi
leaq 0x18(%rsp), %rsi
movq %rbx, %rdx
movq 0x50(%rsp), %r14
movq %r14, %rcx
callq 0xeeee8
addq %r14, %rbx
jmp 0x7d122
movq 0x20(%rsp), %rdx
movq %r14, %rdi
leaq 0x18(%rsp), %rsi
movq 0x50(%rsp), %r14
movq %r14, %rcx
callq 0xeeee8
addq %r14, 0x20(%rsp)
cmpb $0x0, 0x140(%rsp)
je 0x7d141
movq 0x38(%rsp), %rax
movq 0x20(%rax), %rdi
movq %r15, %rsi
callq 0xef0d5
xorb %al, 0x18(%rsp)
movq 0x38(%rsp), %rax
movq 0x20(%rax), %rdi
movq %r15, %rsi
leaq 0x18(%rsp), %rdx
movq 0x80(%rsp), %rcx
callq 0xf11f9
incq 0x30(%rsp)
addq 0x70(%rsp), %r15
decq %rbp
movq %r13, %r14
movb $0x1, %cl
jne 0x7d0ce
movl $0x0, 0x1c(%rsp)
jmp 0x7d28c
movq 0x20(%rsp), %rdx
movq %r14, %rdi
leaq 0x18(%rsp), %rsi
movq 0x50(%rsp), %rbp
movq %rbp, %rcx
callq 0xeeee8
addq %rbp, 0x20(%rsp)
movl $0x0, 0x1c(%rsp)
movb $0x1, %cl
movq 0xb8(%rsp), %rax
testq %rax, %rax
jle 0x7d266
negq %rax
movq 0x70(%rsp), %rbp
imulq 0x30(%rsp), %rbp
addq 0x58(%rsp), %rbp
xorl %r14d, %r14d
movq %rax, %r13
movq %r12, 0x68(%rsp)
cmpb $0x0, 0x140(%rsp)
je 0x7d224
movq %r13, %r12
movq 0x38(%rsp), %r13
movq %rbx, %r15
movb 0x18(%rsp), %bl
movq 0x20(%r13), %rdi
movq %rbp, %rsi
callq 0xef0d5
xorb %bl, %al
movq %r15, %rbx
leaq 0x20(%rsp), %r15
movq 0x20(%r13), %rdi
movq %r12, %r13
movq 0x68(%rsp), %r12
movzbl %al, %edx
movq %rbp, %rsi
callq 0xf148e
jmp 0x7d242
movq 0x38(%rsp), %rax
movq 0x20(%rax), %rdi
movq %rbp, %rsi
leaq 0x18(%rsp), %rdx
movq 0x80(%rsp), %rcx
callq 0xf11f9
decq %r14
addq 0x70(%rsp), %rbp
cmpq %r14, %r13
movb $0x1, %cl
jne 0x7d1dc
subq %r14, 0x30(%rsp)
movq 0xa0(%rsp), %r14
movq 0x130(%rsp), %r13
movq 0x28(%rsp), %rbp
testb %cl, %cl
je 0x7d2be
incq %r12
cmpq 0xd0(%rsp), %r12
jne 0x7cf97
jmp 0x7d2b6
xorl %ecx, %ecx
movl $0x1, 0x14(%rsp)
movq 0x130(%rsp), %r13
leaq 0x20(%rsp), %r15
jmp 0x7d266
movl $0x1, 0x14(%rsp)
xorl %eax, %eax
jmp 0x7d2db
movb $0x1, %al
movq %r13, %r12
movq 0x130(%rsp), %r13
jmp 0x7d2db
movl $0x0, 0x1c(%rsp)
movq %rbx, 0x68(%rsp)
cmpl $0x0, 0x1c(%rsp)
sete %al
movq 0xb0(%rsp), %rbx
movq 0xa8(%rsp), %r12
addq %r13, 0x98(%rsp)
testb %al, %al
movq 0x60(%rsp), %rax
movq 0xc8(%rsp), %r15
jne 0x7ce4e
cmpl $0x0, 0x14(%rsp)
je 0x7d32d
movq 0x90(%rsp), %rax
cmpl $0x0, 0x1c(%rax)
jne 0x7d32d
leaq 0xabc58(%rip), %rsi     # 0x128f6c
movq %rbx, %rdi
xorl %eax, %eax
callq 0xe9df7
movq 0x90(%rsp), %rax
movl $0x1, 0x1c(%rax)
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq