// File: /workspace/github_c_makefile_star2_O0/jsummers[P]deark/modules/nufx.c
// Function: decompress_lzw_1
static void decompress_lzw_1(deark *c, struct nufx_ctx *d,
	struct de_dfilter_in_params *dcmpri,
	struct de_dfilter_out_params *dcmpro, struct de_dfilter_results *dres)
{
	u32 lzwcrc_reported;
	u32 lzwcrc_calc;
	i64 pos = dcmpri->pos;
	i64 nbytes_to_copy;
	u8 volnum;
	u8 rlechar;
	i64 output_bytes_remaining;
	dbuf *tmpdbuf_lzw = NULL;
	dbuf *tmpdbuf_rle = NULL;
	struct de_dfilter_in_params *dcmpri_lzw = NULL;
	struct de_dfilter_out_params *dcmpro_lzw = NULL;
	struct de_dfilter_results *dres_lzw = NULL;
	struct de_dfilter_in_params *dcmpri_rle = NULL;
	struct de_dfilter_out_params *dcmpro_rle = NULL;
	struct de_dfilter_results *dres_rle = NULL;
	const char *modname = "nufx_lzw1";

	output_bytes_remaining = dcmpro->expected_len;
	tmpdbuf_lzw = dbuf_create_membuf(c, 4096, 0);
	tmpdbuf_rle = dbuf_create_membuf(c, 4096, 0);
	dcmpri_lzw = de_malloc(c, sizeof(struct de_dfilter_in_params));
	dcmpro_lzw = de_malloc(c, sizeof(struct de_dfilter_out_params));
	dres_lzw = de_malloc(c, sizeof(struct de_dfilter_results));
	dcmpri_rle = de_malloc(c, sizeof(struct de_dfilter_in_params));
	dcmpro_rle = de_malloc(c, sizeof(struct de_dfilter_out_params));
	dres_rle = de_malloc(c, sizeof(struct de_dfilter_results));

	// The compressed data is chunked. There's an initial 4-byte header, then each
	// chunk has a 3-byte header.
	// Every chunk should decompress to exactly 4096 bytes. (The last chunk is padded,
	// and the padding is included in the internal CRC computation).
	// A chunk may use LZW, RLE, both, or neither.
	// We can tell which methods are used, as well as the intermediate-decompressed size,
	// from the chunk header.
	// We need to do LZW decompression first (if applicable), then RLE decompression (if
	// applicable).
	// There's no easy way to figure out the size of a chunk of compressed data.
	// We can only do it after we do the LZW decompression, and see how much source data
	// was consumed (rounding up to the next whole byte) in order to produce the
	// intermediate number of bytes.
	// Our LZW decompressor tells us this info (though we'd rather not have to rely on it).

	lzwcrc_reported = (u32)de_getu16le_p(&pos);
	de_dbg(c, "lzwcodec crc (reported): 0x%04x", (UI)lzwcrc_reported);
	volnum = dbuf_getbyte_p(dcmpri->f, &pos);
	de_dbg(c, "lzwcodec vol num: %u", (UI)volnum);
	rlechar = dbuf_getbyte_p(dcmpri->f, &pos);
	de_dbg(c, "lzwcodec rle char: 0x%02x", (UI)rlechar);

	de_crcobj_reset(d->crco_for_lzw_codec);

	while(1) {
		i64 chkpos;
		i64 intermed_chunk_len; // size we expect after RLE decompression, before LZW decompression
		u8 uses_rle;
		u8 uses_lzw;

		if(output_bytes_remaining<1) break;
		if(pos+3 > dcmpri->pos + dcmpri->len) break;
		chkpos = pos;
		intermed_chunk_len = dbuf_getu16le_p(dcmpri->f, &pos); // if 4096, no RLE
		uses_rle = (intermed_chunk_len != 4096);
		uses_lzw = dbuf_getbyte_p(dcmpri->f, &pos); // if 0, no LZW
		de_dbg(c, "chunk at %"I64_FMT", intermed_len=%"I64_FMT", lzw=%u, rle=%u",
			chkpos, intermed_chunk_len, (UI)uses_lzw, (UI)uses_rle);

		dbuf_empty(tmpdbuf_lzw);
		if(uses_lzw) {
			de_dfilter_init_objects(c, dcmpri_lzw, dcmpro_lzw, dres_lzw);
			dcmpri_lzw->f = dcmpri->f;
			dcmpri_lzw->pos = pos;
			// ->len is just a maximum. We don't know the compressed data size yet.
			dcmpri_lzw->len = dcmpri->len + dcmpri->pos - pos;
			dcmpro_lzw->f = tmpdbuf_lzw;
			dcmpro_lzw->len_known = 1;
			dcmpro_lzw->expected_len = intermed_chunk_len;
			decompress_chunk_lzw1_lzw_layer(c, dcmpri_lzw, dcmpro_lzw, dres_lzw);
			if(dres_lzw->errcode) {
				de_dfilter_transfer_error2(c, dres_lzw, dres, modname);
				goto done;
			}
			if(!dres_lzw->bytes_consumed_valid) {
				de_dfilter_set_generic_error(c, dres, modname);
				goto done;
			}
			pos += dres_lzw->bytes_consumed;
		}
		else {
			dbuf_copy(dcmpri->f, pos, intermed_chunk_len, tmpdbuf_lzw);
			pos += intermed_chunk_len;
		}

		dbuf_empty(tmpdbuf_rle);
		if(uses_rle) {
			de_dfilter_init_objects(c, dcmpri_rle, dcmpro_rle, dres_rle);
			dcmpri_rle->f = tmpdbuf_lzw;
			dcmpri_rle->pos = 0;
			dcmpri_rle->len = tmpdbuf_lzw->len;
			dcmpro_rle->f = tmpdbuf_rle;
			dcmpro_rle->len_known = 1;
			dcmpro_rle->expected_len = 4096;
			decompress_chunk_rle_layer(c, dcmpri_rle, dcmpro_rle, dres_rle, rlechar);
			if(dres_rle->errcode) {
				de_dfilter_transfer_error2(c, dres_rle, dres, modname);
				goto done;
			}
		}
		else {
			dbuf_copy(tmpdbuf_lzw, 0, 4096, tmpdbuf_rle);
		}

		de_crcobj_addslice(d->crco_for_lzw_codec, tmpdbuf_rle, 0, 4096);

		nbytes_to_copy = de_min_int(output_bytes_remaining, 4096);
		dbuf_copy(tmpdbuf_rle, 0, nbytes_to_copy, dcmpro->f);
		output_bytes_remaining -= nbytes_to_copy;
	}

	lzwcrc_calc = de_crcobj_getval(d->crco_for_lzw_codec);
	de_dbg(c, "lzwcodec crc (calculated): 0x%04x", (UI)lzwcrc_calc);
	if(lzwcrc_calc != lzwcrc_reported) {
		de_dfilter_set_errorf(c, dres, modname, "Codec internal CRC check failed");
		goto done;
	}

done:
	dbuf_close(tmpdbuf_lzw);
	de_free(c, dcmpri_lzw);
	de_free(c, dcmpro_lzw);
	de_free(c, dres_lzw);
	de_free(c, dcmpri_rle);
	de_free(c, dcmpro_rle);
	de_free(c, dres_rle);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb0, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x38(%rbp)
movq $0x0, -0x58(%rbp)
movq $0x0, -0x60(%rbp)
movq $0x0, -0x68(%rbp)
movq $0x0, -0x70(%rbp)
movq $0x0, -0x78(%rbp)
movq $0x0, -0x80(%rbp)
movq $0x0, -0x88(%rbp)
movq $0x0, -0x90(%rbp)
leaq 0xe34cb(%rip), %rax     # 0x1bb273
movq %rax, -0x98(%rbp)
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x50(%rbp)
movq -0x8(%rbp), %rdi
movl $0x1000, %esi           # imm = 0x1000
xorl %edx, %edx
callq 0x168020
movq %rax, -0x58(%rbp)
movq -0x8(%rbp), %rdi
movl $0x1000, %esi           # imm = 0x1000
xorl %edx, %edx
callq 0x168020
movq %rax, -0x60(%rbp)
movq -0x8(%rbp), %rdi
movl $0x20, %esi
callq 0x15b780
movq %rax, -0x68(%rbp)
movq -0x8(%rbp), %rdi
movl $0x18, %esi
callq 0x15b780
movq %rax, -0x70(%rbp)
movq -0x8(%rbp), %rdi
movl $0x60, %esi
callq 0x15b780
movq %rax, -0x78(%rbp)
movq -0x8(%rbp), %rdi
movl $0x20, %esi
callq 0x15b780
movq %rax, -0x80(%rbp)
movq -0x8(%rbp), %rdi
movl $0x18, %esi
callq 0x15b780
movq %rax, -0x88(%rbp)
movq -0x8(%rbp), %rdi
movl $0x60, %esi
callq 0x15b780
movq %rax, -0x90(%rbp)
movq -0x8(%rbp), %rax
movq 0x18(%rax), %rdi
leaq -0x38(%rbp), %rsi
callq 0x1652c0
movl %eax, -0x2c(%rbp)
movq -0x8(%rbp), %rdi
movl -0x2c(%rbp), %edx
leaq 0xe3406(%rip), %rsi     # 0x1bb27d
movb $0x0, %al
callq 0x15b0d0
movq -0x18(%rbp), %rax
movq (%rax), %rdi
leaq -0x38(%rbp), %rsi
callq 0x165170
movb %al, -0x41(%rbp)
movq -0x8(%rbp), %rdi
movzbl -0x41(%rbp), %edx
leaq 0xe33fd(%rip), %rsi     # 0x1bb29d
movb $0x0, %al
callq 0x15b0d0
movq -0x18(%rbp), %rax
movq (%rax), %rdi
leaq -0x38(%rbp), %rsi
callq 0x165170
movb %al, -0x42(%rbp)
movq -0x8(%rbp), %rdi
movzbl -0x42(%rbp), %edx
leaq 0xe33e9(%rip), %rsi     # 0x1bb2b2
movb $0x0, %al
callq 0x15b0d0
movq -0x10(%rbp), %rax
movq 0x58(%rax), %rdi
callq 0x15f250
cmpq $0x1, -0x50(%rbp)
jge 0xd7ee9
jmp 0xd81e5
movq -0x38(%rbp), %rax
addq $0x3, %rax
movq -0x18(%rbp), %rcx
movq 0x8(%rcx), %rcx
movq -0x18(%rbp), %rdx
addq 0x10(%rdx), %rcx
cmpq %rcx, %rax
jle 0xd7f0b
jmp 0xd81e5
movq -0x38(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rdi
leaq -0x38(%rbp), %rsi
callq 0x1652c0
movq %rax, -0xa8(%rbp)
cmpq $0x1000, -0xa8(%rbp) # imm = 0x1000
setne %al
andb $0x1, %al
movzbl %al, %eax
movb %al, -0xa9(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rdi
leaq -0x38(%rbp), %rsi
callq 0x165170
movb %al, -0xaa(%rbp)
movq -0x8(%rbp), %rdi
movq -0xa0(%rbp), %rdx
movq -0xa8(%rbp), %rcx
movzbl -0xaa(%rbp), %r8d
movzbl -0xa9(%rbp), %r9d
leaq 0xe3347(%rip), %rsi     # 0x1bb2cc
movb $0x0, %al
callq 0x15b0d0
movq -0x58(%rbp), %rdi
callq 0x169310
cmpb $0x0, -0xaa(%rbp)
je 0xd807f
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq -0x70(%rbp), %rdx
movq -0x78(%rbp), %rcx
callq 0x1773f0
movq -0x18(%rbp), %rax
movq (%rax), %rcx
movq -0x68(%rbp), %rax
movq %rcx, (%rax)
movq -0x38(%rbp), %rcx
movq -0x68(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x18(%rbp), %rax
movq 0x10(%rax), %rcx
movq -0x18(%rbp), %rax
addq 0x8(%rax), %rcx
subq -0x38(%rbp), %rcx
movq -0x68(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x58(%rbp), %rcx
movq -0x70(%rbp), %rax
movq %rcx, (%rax)
movq -0x70(%rbp), %rax
movb $0x1, 0x8(%rax)
movq -0xa8(%rbp), %rcx
movq -0x70(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq -0x70(%rbp), %rdx
movq -0x78(%rbp), %rcx
callq 0xd8860
movq -0x78(%rbp), %rax
cmpl $0x0, (%rax)
je 0xd804a
movq -0x8(%rbp), %rdi
movq -0x78(%rbp), %rsi
movq -0x28(%rbp), %rdx
movq -0x98(%rbp), %rcx
callq 0x178c80
jmp 0xd8233
movq -0x78(%rbp), %rax
cmpb $0x0, 0x4(%rax)
jne 0xd806d
movq -0x8(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x98(%rbp), %rdx
callq 0x177560
jmp 0xd8233
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
jmp 0xd80a9
movq -0x18(%rbp), %rax
movq (%rax), %rdi
movq -0x38(%rbp), %rsi
movq -0xa8(%rbp), %rdx
movq -0x58(%rbp), %rcx
callq 0x166070
movq -0xa8(%rbp), %rax
addq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x60(%rbp), %rdi
callq 0x169310
cmpb $0x0, -0xa9(%rbp)
je 0xd8177
movq -0x8(%rbp), %rdi
movq -0x80(%rbp), %rsi
movq -0x88(%rbp), %rdx
movq -0x90(%rbp), %rcx
callq 0x1773f0
movq -0x58(%rbp), %rcx
movq -0x80(%rbp), %rax
movq %rcx, (%rax)
movq -0x80(%rbp), %rax
movq $0x0, 0x8(%rax)
movq -0x58(%rbp), %rax
movq 0x18(%rax), %rcx
movq -0x80(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x60(%rbp), %rcx
movq -0x88(%rbp), %rax
movq %rcx, (%rax)
movq -0x88(%rbp), %rax
movb $0x1, 0x8(%rax)
movq -0x88(%rbp), %rax
movq $0x1000, 0x10(%rax)     # imm = 0x1000
movq -0x8(%rbp), %rdi
movq -0x80(%rbp), %rsi
movq -0x88(%rbp), %rdx
movq -0x90(%rbp), %rcx
movzbl -0x42(%rbp), %r8d
callq 0xd88c0
movq -0x90(%rbp), %rax
cmpl $0x0, (%rax)
je 0xd8175
movq -0x8(%rbp), %rdi
movq -0x90(%rbp), %rsi
movq -0x28(%rbp), %rdx
movq -0x98(%rbp), %rcx
callq 0x178c80
jmp 0xd8233
jmp 0xd818d
movq -0x58(%rbp), %rdi
movq -0x60(%rbp), %rcx
xorl %eax, %eax
movl %eax, %esi
movl $0x1000, %edx           # imm = 0x1000
callq 0x166070
movq -0x10(%rbp), %rax
movq 0x58(%rax), %rdi
movq -0x60(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
movl $0x1000, %ecx           # imm = 0x1000
callq 0x15f500
movq -0x50(%rbp), %rdi
movl $0x1000, %esi           # imm = 0x1000
callq 0x15ccf0
movq %rax, -0x40(%rbp)
movq -0x60(%rbp), %rdi
movq -0x40(%rbp), %rdx
movq -0x20(%rbp), %rax
movq (%rax), %rcx
xorl %eax, %eax
movl %eax, %esi
callq 0x166070
movq -0x40(%rbp), %rcx
movq -0x50(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x50(%rbp)
jmp 0xd7edd
movq -0x10(%rbp), %rax
movq 0x58(%rax), %rdi
callq 0x15f340
movl %eax, -0x30(%rbp)
movq -0x8(%rbp), %rdi
movl -0x30(%rbp), %edx
leaq 0xe30f8(%rip), %rsi     # 0x1bb2fb
movb $0x0, %al
callq 0x15b0d0
movl -0x30(%rbp), %eax
cmpl -0x2c(%rbp), %eax
je 0xd8231
movq -0x8(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x98(%rbp), %rdx
leaq 0xe30f5(%rip), %rcx     # 0x1bb31d
movb $0x0, %al
callq 0x177450
jmp 0xd8233
jmp 0xd8233
movq -0x58(%rbp), %rdi
callq 0x1676a0
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
callq 0x15b820
movq -0x8(%rbp), %rdi
movq -0x70(%rbp), %rsi
callq 0x15b820
movq -0x8(%rbp), %rdi
movq -0x78(%rbp), %rsi
callq 0x15b820
movq -0x8(%rbp), %rdi
movq -0x80(%rbp), %rsi
callq 0x15b820
movq -0x8(%rbp), %rdi
movq -0x88(%rbp), %rsi
callq 0x15b820
movq -0x8(%rbp), %rdi
movq -0x90(%rbp), %rsi
callq 0x15b820
addq $0xb0, %rsp
popq %rbp
retq
nopl (%rax)