// File: /workspace/github_cpp_makefile_star2_O2/Alcaro[P]bridges/arlib/deflate-decomp.cpp
// Function: unpack_huffman_dfl(unsigned short*, unsigned char const*, unsigned long, unsigned long)
static bool unpack_huffman_dfl(uint16_t * out, const uint8_t * in, size_t in_len, size_t bad_symbol)
{
	uint16_t n_len[16] = {};
	for (size_t n=0;n<in_len;n++)
		n_len[in[n]]++;
	
	size_t used_bits = 0;
	uint16_t bits_start[16];
	for (size_t n=1;n<16;n++)
	{
		bits_start[n] = used_bits;
		used_bits += (0x10000>>n) * n_len[n];
	}
	
	// if everything defined as accepted by RFC 1951 is a valid DEFLATE bytestram and everything else is forbidden,
	//  then a huffman table containing two or more zeroes and nothing else is illegal
	//  "One distance code of zero bits means that there are no distance codes used at all (the data is all literals)."
	// if everything with a reasonable and unambiguous definition in 1951 is legal, then all incomplete huffman tables are legal,
	//  if the unused bit sequences never show up
	// zlib matches neither behavior; it accepts a huffman table containing multiple zeroes and nothing else,
	//  as well as one 1-bit symbol and the rest zeroes, but anything else is rejected
	// this one matches zlib
	// https://github.com/madler/zlib/blob/cacf7f1d4e3d44d871b605da3b647f07d718623f/inftrees.c#L130-L138
	// https://tools.ietf.org/html/rfc1951#page-13
	if (UNLIKELY(used_bits != 0x10000))
	{
		if (used_bits > 0x10000) return false; // no overfull tables
		if (used_bits != (size_t)(n_len[1]<<15)) return false; // only 1-bit and unrepresentable symbols
		if (bad_symbol == 19) return false; // huffman huffman table can't be incomplete
		// (zlib implements this check differently, but our results are the same)
		assert_reached();
	}
	// used_bits can be 0, 0x8000, or 0x10000
	
	size_t out_tree = 1<<HUFF_FAST_BITS;
	memset(out, 0xFF, sizeof(uint16_t)<<HUFF_FAST_BITS);
	
	for (size_t n=0;n<in_len;n++)
	{
		int n_bits = in[n];
		if (!n_bits) continue;
		uint16_t bits = bitreverse16(bits_start[n_bits]);
		bits_start[n_bits] += 0x10000 >> n_bits;
		
		uint32_t layer_start = 0;
		int layer_bits = HUFF_FAST_BITS;
		int layer_bits_mask = (1<<layer_bits)-1;
		int bits_used = 0;
		
		while (n_bits > layer_bits)
		{
			uint16_t& link = out[layer_start | (bits&layer_bits_mask)];
			
			bits >>= layer_bits;
			n_bits -= layer_bits;
			bits_used += layer_bits;
			
			if (link == 0xFFFF)
			{
				// create a new layer in the huffman table
#ifdef ARLIB_TEST
				assert(out_tree < inflator::huff_table_size_286);
#endif
				link = 0x8000 | (bits_used << 11) | out_tree;
				layer_start = out_tree;
				memset(out+out_tree, 0xFF, sizeof(uint16_t)<<HUFF_SLOW_BITS);
				out_tree += 1<<HUFF_SLOW_BITS;
			}
			else
			{
				// follow the existing node
#ifdef ARLIB_TEST
				assert(link & 0x8000);
#endif
				layer_start = link&0x7FF;
			}
			
			layer_bits = HUFF_SLOW_BITS;
			layer_bits_mask = (1<<layer_bits)-1;
		}
		
		for (int clones=0;clones<(1<<(layer_bits-n_bits));clones++)
		{
			uint16_t& leaf = out[layer_start | (clones<<n_bits) | (bits & layer_bits_mask)];
#ifdef ARLIB_TEST
			assert(leaf == 0xFFFF);
			assert(n_bits > 0);
			assert_eq(bits_used+n_bits, in[n]);
#endif
			leaf = 0x0000 | ((bits_used+n_bits) << 11) | n;
			if (n == 256) leaf |= 128; // remap EOF, saves an instruction in the symbol decoder fast path
		}
	}
	
	if (UNLIKELY(used_bits != 0x10000))
	{
		// used_bits can be 0, 0x8000, or 0x10000, and can't be the last one in this branch
		// if 0, erase all; if 0x8000, erase only odd indices, up to out_tree
		// I can't find any solution better than the obvious one - just wipe all slots that are 0xFFFF
		for (size_t i=0;i<out_tree;i++)
		{
			if (out[i] == 0xFFFF)
				out[i] = 0x0000 | (0 << 11) | bad_symbol;
		}
	}
	
	return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rcx, %r8
movq %rdx, %r15
movq %rsi, %r12
movq %rdi, %r14
pxor %xmm0, %xmm0
movdqa %xmm0, 0x20(%rsp)
movdqa %xmm0, 0x10(%rsp)
xorl %eax, %eax
cmpq %rax, %r15
je 0x758c
movzbl (%r12,%rax), %ecx
incw 0x10(%rsp,%rcx,2)
incq %rax
jmp 0x7578
pushq $0x1
popq %rcx
xorl %r13d, %r13d
cmpq $0x10, %rcx
je 0x75b5
movw %r13w, 0x30(%rsp,%rcx,2)
movl $0x10000, %eax          # imm = 0x10000
shrl %cl, %eax
movzwl 0x10(%rsp,%rcx,2), %edx
imull %eax, %edx
addq %rdx, %r13
incq %rcx
jmp 0x7592
cmpq $0x10000, %r13          # imm = 0x10000
jne 0x7747
movq %r8, (%rsp)
movl $0x400, %edx            # imm = 0x400
movq %r14, %rdi
movl $0xff, %esi
callq 0x3170
movl $0x200, %edi            # imm = 0x200
xorl %r8d, %r8d
pcmpeqd %xmm0, %xmm0
pushq $0x7
popq %rbx
pushq $0x3
popq %rbp
movq %r15, 0x8(%rsp)
cmpq %r15, %r8
je 0x772d
movzbl (%r12,%r8), %eax
testl %eax, %eax
je 0x7725
movq %r12, %r15
movl %eax, %edx
movzwl 0x30(%rsp,%rdx,2), %esi
movl $0x10000, %r9d          # imm = 0x10000
movl %eax, %ecx
shrl %cl, %r9d
addl %esi, %r9d
movl %esi, %ecx
rolw $0x8, %cx
movl %ecx, %esi
shrl $0x4, %esi
movl $0xf0f, %r10d           # imm = 0xF0F
andl %r10d, %esi
andl %r10d, %ecx
shll $0x4, %ecx
orl %esi, %ecx
movl %ecx, %esi
movl $0x3333, %r10d          # imm = 0x3333
andl %r10d, %esi
shrl $0x2, %ecx
andl %r10d, %ecx
leal (%rcx,%rsi,4), %ecx
movl %ecx, %esi
movl $0x5555, %r10d          # imm = 0x5555
andl %r10d, %esi
shrl %ecx
andl %r10d, %ecx
leal (%rcx,%rsi,2), %r12d
movw %r9w, 0x30(%rsp,%rdx,2)
movl $0x1ff, %r9d            # imm = 0x1FF
xorl %r10d, %r10d
pushq $0x9
popq %rdx
xorl %r11d, %r11d
movl %eax, %esi
movzwl %r12w, %r12d
subl %edx, %eax
jle 0x76d3
andl %r12d, %r9d
movl %edx, %ecx
shrl %cl, %r12d
orl %r10d, %r9d
addl %edx, %r11d
movzwl (%r14,%r9,2), %r10d
cmpl $0xffff, %r10d          # imm = 0xFFFF
je 0x76ac
andl $0x7ff, %r10d           # imm = 0x7FF
movl %eax, %esi
movl %ebp, %edx
movl %ebx, %r9d
jmp 0x7678
movl %r11d, %ecx
shll $0xb, %ecx
movl %edi, %r10d
orl %edi, %ecx
orl $0x8000, %ecx           # imm = 0x8000
movw %cx, (%r14,%r9,2)
movdqu %xmm0, (%r14,%rdi,2)
addq $0x8, %rdi
movl %ebp, %edx
movl %ebx, %r9d
jmp 0x7676
subl %esi, %edx
andl %r12d, %r9d
addl %esi, %r11d
shll $0xb, %r11d
orl %r8d, %r11d
movl %r11d, %eax
orl $0x80, %eax
cmpq $0x100, %r8             # imm = 0x100
cmovnel %r11d, %eax
xorl %r11d, %r11d
orl %r10d, %r9d
movq %r15, %r12
movq 0x8(%rsp), %r15
movl %r11d, %r10d
movl %edx, %ecx
shrl %cl, %r10d
testl %r10d, %r10d
jne 0x7725
movl %r11d, %r10d
movl %esi, %ecx
shll %cl, %r10d
orl %r9d, %r10d
movw %ax, (%r14,%r10,2)
incl %r11d
jmp 0x7703
incq %r8
jmp 0x75ef
movb $0x1, %al
cmpq $0x10000, %r13          # imm = 0x10000
jne 0x774d
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jbe 0x776a
xorl %eax, %eax
jmp 0x7738
xorl %ecx, %ecx
movq (%rsp), %rdx
cmpq %rcx, %rdi
je 0x7738
cmpw $-0x1, (%r14,%rcx,2)
jne 0x7765
movw %dx, (%r14,%rcx,2)
incq %rcx
jmp 0x7753
xorl %eax, %eax
cmpq $0x13, %r8
je 0x7738
movzwl 0x12(%rsp), %ecx
shll $0xf, %ecx
cmpq %rcx, %r13
je 0x75c2
jmp 0x7738
nop