// File: /workspace/github_c_makefile_star2_O0/jsummers[P]deark/modules/nufx.c
// Function: decompress_lzw_2
static void decompress_lzw_2(deark *c, struct nufx_ctx *d,
	struct de_dfilter_in_params *dcmpri,
	struct de_dfilter_out_params *dcmpro, struct de_dfilter_results *dres)
{
	i64 pos = dcmpri->pos;
	i64 nbytes_to_copy;
	u8 volnum;
	u8 rlechar;
	u8 need_lzw_clear = 0;
	i64 output_bytes_remaining;
	dbuf *tmpdbuf_lzw = NULL;
	dbuf *tmpdbuf_rle = 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_lzw2";
	struct de_dfilter_ctx *dfctx = NULL;
	struct de_lzw_params delzwp;

	output_bytes_remaining = dcmpro->expected_len;

	tmpdbuf_lzw = dbuf_create_membuf(c, 4096, 0);
	tmpdbuf_rle = dbuf_create_membuf(c, 4096, 0);
	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));

	de_zeromem(&delzwp, sizeof(struct de_lzw_params));
	delzwp.fmt = DE_LZWFMT_SHRINKIT2;
	delzwp.max_code_size = 12;

	// The compressed data is chunked. There's an initial 2-byte header, then each
	// chunk has a 4-byte (if chunk uses LZW) or 2-byte (otherwise) header.

	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_dfilter_init_objects(c, NULL, dcmpro_lzw, dres_lzw);

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

		if(output_bytes_remaining<1) break;
		if(pos > dcmpri->pos + dcmpri->len) break;
		chkpos = pos;
		intermed_chunk_len = dbuf_getu16le_p(dcmpri->f, &pos); // if 4096, no RLE
		uses_lzw = (intermed_chunk_len & 0x8000)?1:0;
		intermed_chunk_len &= 0x1fff;
		uses_rle = (intermed_chunk_len != 4096);
		if(uses_lzw) {
			cmpr_len = dbuf_getu16le_p(dcmpri->f, &pos);
			cmpr_len -= 4; // Apparently, the length includes the chunk header
			if(cmpr_len<0) cmpr_len = 0;
		}
		else {
			cmpr_len = intermed_chunk_len;
		}

		de_dbg(c, "chunk at %"I64_FMT", intermed_len=%"I64_FMT", "
			"cmpr_len=%"I64_FMT", lzw=%u, rle=%u",
			chkpos, intermed_chunk_len, cmpr_len, (UI)uses_lzw, (UI)uses_rle);

		dbuf_empty(tmpdbuf_lzw);
		if(uses_lzw) {
			if(dfctx) {
				if(need_lzw_clear) {
					de_dfilter_command(dfctx, DE_DFILTER_COMMAND_SOFTRESET, 0);
				}
			}
			else {
				dcmpro_lzw->f = tmpdbuf_lzw;
				dcmpro_lzw->len_known = 0;
				dfctx = de_dfilter_create(c, dfilter_lzw_codec, (void*)&delzwp, dcmpro_lzw, dres_lzw);
			}
			need_lzw_clear = 0;

			de_dfilter_addslice(dfctx, dcmpri->f, pos, cmpr_len);
			de_dfilter_command(dfctx, DE_DFILTER_COMMAND_FINISH_BLOCK, 0);
			dbuf_flush(dcmpro_lzw->f);

			// Hack, to cause the error message to be available. TODO: Improve this.
			if(dfctx->finished_flag) {
				de_dfilter_finish(dfctx);
			}

			if(dres_lzw->errcode) {
				de_dfilter_transfer_error2(c, dres_lzw, dres, modname);
				goto done;
			}

			if(dcmpro_lzw->f->len != intermed_chunk_len) {
				de_dfilter_set_errorf(c, dres, modname, "LZW decompression failed "
					"(expected %"I64_FMT" bytes, got %"I64_FMT")",
					intermed_chunk_len, dcmpro_lzw->f->len);
				goto done;
			}
		}
		else {
			dbuf_copy(dcmpri->f, pos, intermed_chunk_len, tmpdbuf_lzw);
			if(dfctx) {
				// A non-LZW chunk following an LZW chunk: We'll have to reset the
				// LZW decompressor if/when we encounter another LZW chunk.
				need_lzw_clear = 1;
			}
		}
		pos += cmpr_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;
	}

done:
	de_dfilter_destroy(dfctx);
	dbuf_close(tmpdbuf_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 $0xd0, %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, -0x30(%rbp)
movb $0x0, -0x3b(%rbp)
movq $0x0, -0x50(%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)
leaq 0xe302f(%rip), %rax     # 0x1bb33d
movq %rax, -0x88(%rbp)
movq $0x0, -0x90(%rbp)
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x8(%rbp), %rdi
movl $0x1000, %esi           # imm = 0x1000
xorl %edx, %edx
callq 0x168020
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 $0x18, %esi
callq 0x15b780
movq %rax, -0x60(%rbp)
movq -0x8(%rbp), %rdi
movl $0x60, %esi
callq 0x15b780
movq %rax, -0x68(%rbp)
movq -0x8(%rbp), %rdi
movl $0x20, %esi
callq 0x15b780
movq %rax, -0x70(%rbp)
movq -0x8(%rbp), %rdi
movl $0x18, %esi
callq 0x15b780
movq %rax, -0x78(%rbp)
movq -0x8(%rbp), %rdi
movl $0x60, %esi
callq 0x15b780
movq %rax, -0x80(%rbp)
leaq -0xa4(%rbp), %rdi
xorl %esi, %esi
movl $0x14, %edx
callq 0x19140
movl $0xa, -0xa4(%rbp)
movl $0xc, -0x98(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rdi
leaq -0x30(%rbp), %rsi
callq 0x165170
movb %al, -0x39(%rbp)
movq -0x8(%rbp), %rdi
movzbl -0x39(%rbp), %edx
leaq 0xe2ea6(%rip), %rsi     # 0x1bb29d
movb $0x0, %al
callq 0x15b0d0
movq -0x18(%rbp), %rax
movq (%rax), %rdi
leaq -0x30(%rbp), %rsi
callq 0x165170
movb %al, -0x3a(%rbp)
movq -0x8(%rbp), %rdi
movzbl -0x3a(%rbp), %edx
leaq 0xe2e92(%rip), %rsi     # 0x1bb2b2
movb $0x0, %al
callq 0x15b0d0
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rdx
movq -0x68(%rbp), %rcx
xorl %eax, %eax
movl %eax, %esi
callq 0x1773f0
cmpq $0x1, -0x48(%rbp)
jge 0xd8448
jmp 0xd87fd
movq -0x30(%rbp), %rax
movq -0x18(%rbp), %rcx
movq 0x8(%rcx), %rcx
movq -0x18(%rbp), %rdx
addq 0x10(%rdx), %rcx
cmpq %rcx, %rax
jle 0xd8466
jmp 0xd87fd
movq -0x30(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rdi
leaq -0x30(%rbp), %rsi
callq 0x1652c0
movq %rax, -0xb8(%rbp)
movq -0xb8(%rbp), %rdx
andq $0x8000, %rdx           # imm = 0x8000
xorl %eax, %eax
movl $0x1, %ecx
cmpq $0x0, %rdx
cmovnel %ecx, %eax
movb %al, -0xc2(%rbp)
movq -0xb8(%rbp), %rax
andq $0x1fff, %rax           # imm = 0x1FFF
movq %rax, -0xb8(%rbp)
cmpq $0x1000, -0xb8(%rbp) # imm = 0x1000
setne %al
andb $0x1, %al
movzbl %al, %eax
movb %al, -0xc1(%rbp)
cmpb $0x0, -0xc2(%rbp)
je 0xd8520
movq -0x18(%rbp), %rax
movq (%rax), %rdi
leaq -0x30(%rbp), %rsi
callq 0x1652c0
movq %rax, -0xc0(%rbp)
movq -0xc0(%rbp), %rax
subq $0x4, %rax
movq %rax, -0xc0(%rbp)
cmpq $0x0, -0xc0(%rbp)
jge 0xd851e
movq $0x0, -0xc0(%rbp)
jmp 0xd852e
movq -0xb8(%rbp), %rax
movq %rax, -0xc0(%rbp)
movq -0x8(%rbp), %rdi
movq -0xb0(%rbp), %rdx
movq -0xb8(%rbp), %rcx
movq -0xc0(%rbp), %r8
movzbl -0xc2(%rbp), %r9d
movzbl -0xc1(%rbp), %eax
leaq 0xe2dea(%rip), %rsi     # 0x1bb347
movl %eax, (%rsp)
movb $0x0, %al
callq 0x15b0d0
movq -0x50(%rbp), %rdi
callq 0x169310
cmpb $0x0, -0xc2(%rbp)
je 0xd86a5
cmpq $0x0, -0x90(%rbp)
je 0xd85a2
cmpb $0x0, -0x3b(%rbp)
je 0xd85a0
movq -0x90(%rbp), %rdi
movl $0x1, %esi
xorl %edx, %edx
callq 0x177690
jmp 0xd85db
movq -0x50(%rbp), %rcx
movq -0x60(%rbp), %rax
movq %rcx, (%rax)
movq -0x60(%rbp), %rax
movb $0x0, 0x8(%rax)
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rcx
movq -0x68(%rbp), %r8
leaq 0xabe38(%rip), %rsi     # 0x184400
leaq -0xa4(%rbp), %rdx
callq 0x1775a0
movq %rax, -0x90(%rbp)
movb $0x0, -0x3b(%rbp)
movq -0x90(%rbp), %rdi
movq -0x18(%rbp), %rax
movq (%rax), %rsi
movq -0x30(%rbp), %rdx
movq -0xc0(%rbp), %rcx
callq 0x177770
movq -0x90(%rbp), %rdi
movl $0x3, %esi
xorl %edx, %edx
callq 0x177690
movq -0x60(%rbp), %rax
movq (%rax), %rdi
callq 0x167c30
movq -0x90(%rbp), %rax
cmpb $0x0, 0x20(%rax)
je 0xd8635
movq -0x90(%rbp), %rdi
callq 0x1776f0
movq -0x68(%rbp), %rax
cmpl $0x0, (%rax)
je 0xd865b
movq -0x8(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq -0x28(%rbp), %rdx
movq -0x88(%rbp), %rcx
callq 0x178c80
jmp 0xd87ff
movq -0x60(%rbp), %rax
movq (%rax), %rax
movq 0x18(%rax), %rax
cmpq -0xb8(%rbp), %rax
je 0xd86a3
movq -0x8(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x88(%rbp), %rdx
movq -0xb8(%rbp), %r8
movq -0x60(%rbp), %rax
movq (%rax), %rax
movq 0x18(%rax), %r9
leaq 0xe2ced(%rip), %rcx     # 0x1bb384
movb $0x0, %al
callq 0x177450
jmp 0xd87ff
jmp 0xd86d0
movq -0x18(%rbp), %rax
movq (%rax), %rdi
movq -0x30(%rbp), %rsi
movq -0xb8(%rbp), %rdx
movq -0x50(%rbp), %rcx
callq 0x166070
cmpq $0x0, -0x90(%rbp)
je 0xd86ce
movb $0x1, -0x3b(%rbp)
jmp 0xd86d0
movq -0xc0(%rbp), %rax
addq -0x30(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x58(%rbp), %rdi
callq 0x169310
cmpb $0x0, -0xc1(%rbp)
je 0xd878f
movq -0x8(%rbp), %rdi
movq -0x70(%rbp), %rsi
movq -0x78(%rbp), %rdx
movq -0x80(%rbp), %rcx
callq 0x1773f0
movq -0x50(%rbp), %rcx
movq -0x70(%rbp), %rax
movq %rcx, (%rax)
movq -0x70(%rbp), %rax
movq $0x0, 0x8(%rax)
movq -0x50(%rbp), %rax
movq 0x18(%rax), %rcx
movq -0x70(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x58(%rbp), %rcx
movq -0x78(%rbp), %rax
movq %rcx, (%rax)
movq -0x78(%rbp), %rax
movb $0x1, 0x8(%rax)
movq -0x78(%rbp), %rax
movq $0x1000, 0x10(%rax)     # imm = 0x1000
movq -0x8(%rbp), %rdi
movq -0x70(%rbp), %rsi
movq -0x78(%rbp), %rdx
movq -0x80(%rbp), %rcx
movzbl -0x3a(%rbp), %r8d
callq 0xd88c0
movq -0x80(%rbp), %rax
cmpl $0x0, (%rax)
je 0xd878d
movq -0x8(%rbp), %rdi
movq -0x80(%rbp), %rsi
movq -0x28(%rbp), %rdx
movq -0x88(%rbp), %rcx
callq 0x178c80
jmp 0xd87ff
jmp 0xd87a5
movq -0x50(%rbp), %rdi
movq -0x58(%rbp), %rcx
xorl %eax, %eax
movl %eax, %esi
movl $0x1000, %edx           # imm = 0x1000
callq 0x166070
movq -0x10(%rbp), %rax
movq 0x58(%rax), %rdi
movq -0x58(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
movl $0x1000, %ecx           # imm = 0x1000
callq 0x15f500
movq -0x48(%rbp), %rdi
movl $0x1000, %esi           # imm = 0x1000
callq 0x15ccf0
movq %rax, -0x38(%rbp)
movq -0x58(%rbp), %rdi
movq -0x38(%rbp), %rdx
movq -0x20(%rbp), %rax
movq (%rax), %rcx
xorl %eax, %eax
movl %eax, %esi
callq 0x166070
movq -0x38(%rbp), %rcx
movq -0x48(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x48(%rbp)
jmp 0xd843c
jmp 0xd87ff
movq -0x90(%rbp), %rdi
callq 0x177720
movq -0x50(%rbp), %rdi
callq 0x1676a0
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x15b820
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
addq $0xd0, %rsp
popq %rbp
retq
nop