// File: /workspace/github_cpp_makefile_star2_O3/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)
testq %rdx, %rdx
je 0x8fbd
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
incw 0x10(%rsp,%rcx,2)
incq %rax
cmpq %rax, %r15
jne 0x8fab
movl $0x1, %ecx
xorl %r13d, %r13d
movq %r13, %rax
movw %ax, 0x30(%rsp,%rcx,2)
movl $0x10000, %edx          # imm = 0x10000
shrl %cl, %edx
movzwl 0x10(%rsp,%rcx,2), %r13d
imull %edx, %r13d
addq %rax, %r13
incq %rcx
cmpq $0x10, %rcx
jne 0x8fc5
cmpq $0x10000, %r13          # imm = 0x10000
movq %r8, 0x8(%rsp)
jne 0x919e
movl $0x400, %edx            # imm = 0x400
movq %r14, %rdi
movl $0xff, %esi
callq 0x3170
testq %r15, %r15
je 0x918d
movl $0x200, %esi            # imm = 0x200
xorl %edi, %edi
movl $0x5555, %r10d          # imm = 0x5555
pcmpeqd %xmm0, %xmm0
movzbl (%r12,%rdi), %eax
testl %eax, %eax
je 0x9151
movl $0x10000, %edx          # imm = 0x10000
movl %eax, %ecx
shrl %cl, %edx
movzwl 0x30(%rsp,%rax,2), %ecx
addl %ecx, %edx
rolw $0x8, %cx
movl %ecx, %r8d
shrl $0x4, %r8d
movl $0xf0f, %r9d            # imm = 0xF0F
andl %r9d, %r8d
andl %r9d, %ecx
shll $0x4, %ecx
orl %r8d, %ecx
movl %ecx, %r8d
movl $0x3333, %r9d           # imm = 0x3333
andl %r9d, %r8d
shrl $0x2, %ecx
andl %r9d, %ecx
leal (%rcx,%r8,4), %ecx
movl %ecx, %r8d
andl %r10d, %r8d
shrl %ecx
andl %r10d, %ecx
leal (%rcx,%r8,2), %r11d
movw %dx, 0x30(%rsp,%rax,2)
cmpb $0xa, %al
jb 0x90f7
movl $0x9, %edx
movl $0x1ff, %r8d            # imm = 0x1FF
xorl %ebp, %ebp
xorl %ebx, %ebx
movzwl %r11w, %r11d
andl %r11d, %r8d
movl %edx, %ecx
shrl %cl, %r11d
orl %ebx, %r8d
addl %edx, %ebp
movzwl (%r14,%r8,2), %ebx
cmpl $0xffff, %ebx           # imm = 0xFFFF
je 0x90c5
andl $0x7ff, %ebx            # imm = 0x7FF
jmp 0x90e3
movl %ebp, %ecx
shll $0xb, %ecx
movl %esi, %ebx
orl %esi, %ecx
orl $0x8000, %ecx           # imm = 0x8000
movw %cx, (%r14,%r8,2)
movdqu %xmm0, (%r14,%rsi,2)
addq $0x8, %rsi
subl %edx, %eax
movl $0x3, %edx
movl $0x7, %r8d
cmpl $0x3, %eax
jg 0x909f
jmp 0x9106
movl $0x1ff, %r8d            # imm = 0x1FF
movl $0x9, %edx
xorl %ebx, %ebx
xorl %ebp, %ebp
subl %eax, %edx
movzwl %r11w, %r11d
andl %r8d, %r11d
orl %ebx, %r11d
addl %eax, %ebp
shll $0xb, %ebp
orl %edi, %ebp
movl %ebp, %r8d
orl $0x80, %r8d
cmpq $0x100, %rdi            # imm = 0x100
cmovnel %ebp, %r8d
movl $0x1, %ebx
leal -0x1(%rbx), %ebp
movl %eax, %ecx
shll %cl, %ebp
movl %ebx, %r9d
movl %edx, %ecx
shrl %cl, %r9d
orl %r11d, %ebp
movw %r8w, (%r14,%rbp,2)
incl %ebx
testl %r9d, %r9d
je 0x9133
incq %rdi
cmpq %r15, %rdi
jne 0x9028
movb $0x1, %al
cmpq $0x10000, %r13          # imm = 0x10000
je 0x918f
testq %rsi, %rsi
movq 0x8(%rsp), %rdx
je 0x918f
xorl %ecx, %ecx
cmpw $-0x1, (%r14,%rcx,2)
jne 0x9181
movw %dx, (%r14,%rcx,2)
incq %rcx
movb $0x1, %al
cmpq %rcx, %rsi
jne 0x9174
jmp 0x918f
movb $0x1, %al
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jbe 0x91a4
xorl %eax, %eax
jmp 0x918f
xorl %eax, %eax
cmpq $0x13, %r8
je 0x918f
movzwl 0x12(%rsp), %ecx
shll $0xf, %ecx
cmpq %rcx, %r13
jne 0x918f
movl $0x400, %edx            # imm = 0x400
movq %r14, %rdi
movl $0xff, %esi
callq 0x3170
testq %r15, %r15
jne 0x9017
movl $0x200, %esi            # imm = 0x200
movq 0x8(%rsp), %rdx
jmp 0x9172