// File: Lut99[P]RayTracer/src/lib/LodePNG.cpp
// Function: HuffmanTree_makeTable(HuffmanTree*)
static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
  static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/
  static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u;
  size_t i, numpresent, pointer, size; /*total table size*/
  unsigned* maxlens = (unsigned*)lodepng_malloc(headsize * sizeof(unsigned));
  if(!maxlens) return 83; /*alloc fail*/

  /* compute maxlens: max total bit length of symbols sharing prefix in the first table*/
  for(i = 0; i < headsize; ++i) maxlens[i] = 0;
  for(i = 0; i < tree->numcodes; i++) {
    unsigned symbol = tree->codes[i];
    unsigned l = tree->lengths[i];
    unsigned index;
    if(l <= FIRSTBITS) continue; /*symbols that fit in first table don't increase secondary table size*/
    /*get the FIRSTBITS MSBs, the MSBs of the symbol are encoded first. See later comment about the reversing*/
    index = reverseBits(symbol >> (l - FIRSTBITS), FIRSTBITS);
    maxlens[index] = LODEPNG_MAX(maxlens[index], l);
  }
  /* compute total table size: size of first table plus all secondary tables for symbols longer than FIRSTBITS */
  size = headsize;
  for(i = 0; i < headsize; ++i) {
    unsigned l = maxlens[i];
    if(l > FIRSTBITS) size += (unsigned long) (1u << (l - FIRSTBITS));
  }
  tree->table_len = (unsigned char*)lodepng_malloc(size * sizeof(*tree->table_len));
  tree->table_value = (unsigned short*)lodepng_malloc(size * sizeof(*tree->table_value));
  if(!tree->table_len || !tree->table_value) {
    lodepng_free(maxlens);
    /* freeing tree->table values is done at a higher scope */
    return 83; /*alloc fail*/
  }
  /*initialize with an invalid length to indicate unused entries*/
  for(i = 0; i < size; ++i) tree->table_len[i] = 16;

  /*fill in the first table for long symbols: max prefix size and pointer to secondary tables*/
  pointer = headsize;
  for(i = 0; i < headsize; ++i) {
    unsigned l = maxlens[i];
    if(l <= FIRSTBITS) continue;
    tree->table_len[i] = l;
    tree->table_value[i] = (unsigned short) pointer;
    pointer += (unsigned long) (1u << (l - FIRSTBITS));
  }
  lodepng_free(maxlens);

  /*fill in the first table for short symbols, or secondary table for long symbols*/
  numpresent = 0;
  for(i = 0; i < tree->numcodes; ++i) {
    unsigned l = tree->lengths[i];
    unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/
    /*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/
    unsigned reverse = reverseBits(symbol, l);
    if(l == 0) continue;
    numpresent++;

    if(l <= FIRSTBITS) {
      /*short symbol, fully in first table, replicated num times if l < FIRSTBITS*/
      unsigned num = 1u << (FIRSTBITS - l);
      unsigned j;
      for(j = 0; j < num; ++j) {
        /*bit reader will read the l bits of symbol first, the remaining FIRSTBITS - l bits go to the MSB's*/
        unsigned index = reverse | (j << l);
        if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/
        tree->table_len[index] = l;
        tree->table_value[index] = (unsigned short) i;
      }
    } else {
      /*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/
      /*the FIRSTBITS MSBs of the symbol are the first table index*/
      unsigned index = reverse & mask;
      unsigned maxlen = tree->table_len[index];
      /*log2 of secondary table length, should be >= l - FIRSTBITS*/
      unsigned tablelen = maxlen - FIRSTBITS;
      unsigned start = tree->table_value[index]; /*starting index in secondary table*/
      unsigned num = 1u << (tablelen - (l - FIRSTBITS)); /*amount of entries of this symbol in secondary table*/
      unsigned j;
      if(maxlen < l) return 55; /*invalid tree: long symbol shares prefix with short symbol*/
      for(j = 0; j < num; ++j) {
        unsigned reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */
        unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS)));
        tree->table_len[index2] = l;
        tree->table_value[index2] = (unsigned short) i;
      }
    }
  }

  if(numpresent < 2) {
    /* In case of exactly 1 symbol, in theory the huffman symbol needs 0 bits,
    but deflate uses 1 bit instead. In case of 0 symbols, no symbols can
    appear at all, but such huffman tree could still exist (e.g. if distance
    codes are never used). In both cases, not all symbols of the table will be
    filled in. Fill them in with an invalid symbol value so returning them from
    huffmanDecodeSymbol will cause error. */
    for(i = 0; i < size; ++i) {
      if(tree->table_len[i] == 16) {
        /* As length, use a value smaller than FIRSTBITS for the head table,
        and a value larger than FIRSTBITS for the secondary table, to ensure
        valid behavior for advanceBits when reading this symbol. */
        tree->table_len[i] = (i < headsize) ? 1 : (FIRSTBITS + 1);
        tree->table_value[i] = INVALIDSYMBOL;
      }
    }
  } else {
    /* A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.
    If that is not the case (due to too long length codes), the table will not
    have been fully used, and this is an error (not all bit combinations can be
    decoded): an oversubscribed huffman tree, indicated by error 55. */
    for(i = 0; i < size; ++i) {
      if(tree->table_len[i] == 16) return 55;
    }
  }

  return 0;
}

// Assembly:
subq $0x98, %rsp
movq %rdi, 0x88(%rsp)
movl $0x800, %edi            # imm = 0x800
callq 0x13ce80
movq %rax, 0x60(%rsp)
cmpq $0x0, 0x60(%rsp)
jne 0x14cc16
movl $0x53, 0x94(%rsp)
jmp 0x14d2a6
movq $0x0, 0x80(%rsp)
cmpq $0x200, 0x80(%rsp) # imm = 0x200
jae 0x14cc5a
movq 0x60(%rsp), %rax
movq 0x80(%rsp), %rcx
movl $0x0, (%rax,%rcx,4)
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x14cc22
movq $0x0, 0x80(%rsp)
movq 0x80(%rsp), %rax
movq 0x88(%rsp), %rcx
movl 0x14(%rcx), %ecx
cmpq %rcx, %rax
jae 0x14cd30
movq 0x88(%rsp), %rax
movq (%rax), %rax
movq 0x80(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x5c(%rsp)
movq 0x88(%rsp), %rax
movq 0x8(%rax), %rax
movq 0x80(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x58(%rsp)
cmpl $0x9, 0x58(%rsp)
ja 0x14ccc0
jmp 0x14cd17
movl 0x5c(%rsp), %edi
movl 0x58(%rsp), %ecx
subl $0x9, %ecx
shrl %cl, %edi
movl $0x9, %esi
callq 0x14d2c0
movl %eax, 0x54(%rsp)
movq 0x60(%rsp), %rax
movl 0x54(%rsp), %ecx
movl (%rax,%rcx,4), %eax
cmpl 0x58(%rsp), %eax
jbe 0x14ccff
movq 0x60(%rsp), %rax
movl 0x54(%rsp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x10(%rsp)
jmp 0x14cd07
movl 0x58(%rsp), %eax
movl %eax, 0x10(%rsp)
movl 0x10(%rsp), %edx
movq 0x60(%rsp), %rax
movl 0x54(%rsp), %ecx
movl %edx, (%rax,%rcx,4)
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x14cc66
movq $0x200, 0x68(%rsp)      # imm = 0x200
movq $0x0, 0x80(%rsp)
cmpq $0x200, 0x80(%rsp) # imm = 0x200
jae 0x14cda0
movq 0x60(%rsp), %rax
movq 0x80(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x50(%rsp)
cmpl $0x9, 0x50(%rsp)
jbe 0x14cd88
movl 0x50(%rsp), %ecx
subl $0x9, %ecx
movl $0x1, %eax
shll %cl, %eax
movl %eax, %eax
addq 0x68(%rsp), %rax
movq %rax, 0x68(%rsp)
jmp 0x14cd8a
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x14cd45
movq 0x68(%rsp), %rdi
shlq $0x0, %rdi
callq 0x13ce80
movq %rax, %rcx
movq 0x88(%rsp), %rax
movq %rcx, 0x18(%rax)
movq 0x68(%rsp), %rdi
shlq %rdi
callq 0x13ce80
movq %rax, %rcx
movq 0x88(%rsp), %rax
movq %rcx, 0x20(%rax)
movq 0x88(%rsp), %rax
cmpq $0x0, 0x18(%rax)
je 0x14cdf7
movq 0x88(%rsp), %rax
cmpq $0x0, 0x20(%rax)
jne 0x14ce11
movq 0x60(%rsp), %rdi
callq 0x13e2d0
movl $0x53, 0x94(%rsp)
jmp 0x14d2a6
movq $0x0, 0x80(%rsp)
movq 0x80(%rsp), %rax
cmpq 0x68(%rsp), %rax
jae 0x14ce5a
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x80(%rsp), %rcx
movb $0x10, (%rax,%rcx)
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x14ce1d
movq $0x200, 0x70(%rsp)      # imm = 0x200
movq $0x0, 0x80(%rsp)
cmpq $0x200, 0x80(%rsp) # imm = 0x200
jae 0x14cf0e
movq 0x60(%rsp), %rax
movq 0x80(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x4c(%rsp)
cmpl $0x9, 0x4c(%rsp)
ja 0x14ce9e
jmp 0x14cef5
movl 0x4c(%rsp), %eax
movb %al, %dl
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x80(%rsp), %rcx
movb %dl, (%rax,%rcx)
movq 0x70(%rsp), %rax
movw %ax, %dx
movq 0x88(%rsp), %rax
movq 0x20(%rax), %rax
movq 0x80(%rsp), %rcx
movw %dx, (%rax,%rcx,2)
movl 0x4c(%rsp), %ecx
subl $0x9, %ecx
movl $0x1, %eax
shll %cl, %eax
movl %eax, %eax
addq 0x70(%rsp), %rax
movq %rax, 0x70(%rsp)
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x14ce6f
movq 0x60(%rsp), %rdi
callq 0x13e2d0
movq $0x0, 0x78(%rsp)
movq $0x0, 0x80(%rsp)
movq 0x80(%rsp), %rax
movq 0x88(%rsp), %rcx
movl 0x14(%rcx), %ecx
cmpq %rcx, %rax
jae 0x14d188
movq 0x88(%rsp), %rax
movq 0x8(%rax), %rax
movq 0x80(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x48(%rsp)
movq 0x88(%rsp), %rax
movq (%rax), %rax
movq 0x80(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, 0x44(%rsp)
movl 0x44(%rsp), %edi
movl 0x48(%rsp), %esi
callq 0x14d2c0
movl %eax, 0x40(%rsp)
cmpl $0x0, 0x48(%rsp)
jne 0x14cf9b
jmp 0x14d16f
movq 0x78(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x78(%rsp)
cmpl $0x9, 0x48(%rsp)
ja 0x14d06a
movl $0x9, %ecx
subl 0x48(%rsp), %ecx
movl $0x1, %eax
shll %cl, %eax
movl %eax, 0x3c(%rsp)
movl $0x0, 0x38(%rsp)
movl 0x38(%rsp), %eax
cmpl 0x3c(%rsp), %eax
jae 0x14d065
movl 0x40(%rsp), %eax
movl 0x38(%rsp), %edx
movl 0x48(%rsp), %ecx
shll %cl, %edx
movl %edx, %ecx
orl %ecx, %eax
movl %eax, 0x34(%rsp)
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movl 0x34(%rsp), %ecx
movzbl (%rax,%rcx), %eax
cmpl $0x10, %eax
je 0x14d01d
movl $0x37, 0x94(%rsp)
jmp 0x14d2a6
movl 0x48(%rsp), %eax
movb %al, %dl
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movl 0x34(%rsp), %ecx
movb %dl, (%rax,%rcx)
movq 0x80(%rsp), %rax
movw %ax, %dx
movq 0x88(%rsp), %rax
movq 0x20(%rax), %rax
movl 0x34(%rsp), %ecx
movw %dx, (%rax,%rcx,2)
movl 0x38(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x38(%rsp)
jmp 0x14cfd0
jmp 0x14d16d
movl 0x40(%rsp), %eax
andl $0x1ff, %eax            # imm = 0x1FF
movl %eax, 0x30(%rsp)
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movl 0x30(%rsp), %ecx
movzbl (%rax,%rcx), %eax
movl %eax, 0x2c(%rsp)
movl 0x2c(%rsp), %eax
subl $0x9, %eax
movl %eax, 0x28(%rsp)
movq 0x88(%rsp), %rax
movq 0x20(%rax), %rax
movl 0x30(%rsp), %ecx
movzwl (%rax,%rcx,2), %eax
movl %eax, 0x24(%rsp)
movl 0x28(%rsp), %ecx
movl 0x48(%rsp), %eax
subl $0x9, %eax
subl %eax, %ecx
movl $0x1, %eax
shll %cl, %eax
movl %eax, 0x20(%rsp)
movl 0x2c(%rsp), %eax
cmpl 0x48(%rsp), %eax
jae 0x14d0e4
movl $0x37, 0x94(%rsp)
jmp 0x14d2a6
movl $0x0, 0x1c(%rsp)
movl 0x1c(%rsp), %eax
cmpl 0x20(%rsp), %eax
jae 0x14d16b
movl 0x40(%rsp), %eax
shrl $0x9, %eax
movl %eax, 0x18(%rsp)
movl 0x24(%rsp), %eax
movl 0x18(%rsp), %ecx
movl %ecx, 0xc(%rsp)
movl 0x1c(%rsp), %edx
movl 0x48(%rsp), %ecx
subl $0x9, %ecx
shll %cl, %edx
movl 0xc(%rsp), %ecx
orl %edx, %ecx
addl %ecx, %eax
movl %eax, 0x14(%rsp)
movl 0x48(%rsp), %eax
movb %al, %dl
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movl 0x14(%rsp), %ecx
movb %dl, (%rax,%rcx)
movq 0x80(%rsp), %rax
movw %ax, %dx
movq 0x88(%rsp), %rax
movq 0x20(%rax), %rax
movl 0x14(%rsp), %ecx
movw %dx, (%rax,%rcx,2)
movl 0x1c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1c(%rsp)
jmp 0x14d0ec
jmp 0x14d16d
jmp 0x14d16f
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x14cf2d
cmpq $0x2, 0x78(%rsp)
jae 0x14d23c
movq $0x0, 0x80(%rsp)
movq 0x80(%rsp), %rax
cmpq 0x68(%rsp), %rax
jae 0x14d23a
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x80(%rsp), %rcx
movzbl (%rax,%rcx), %eax
cmpl $0x10, %eax
jne 0x14d21f
movq 0x80(%rsp), %rdx
movl $0xa, %eax
movl $0x1, %ecx
cmpq $0x200, %rdx            # imm = 0x200
cmovbl %ecx, %eax
movb %al, %dl
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x80(%rsp), %rcx
movb %dl, (%rax,%rcx)
movq 0x88(%rsp), %rax
movq 0x20(%rax), %rax
movq 0x80(%rsp), %rcx
movw $0xffff, (%rax,%rcx,2)  # imm = 0xFFFF
jmp 0x14d221
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x14d1a0
jmp 0x14d29b
movq $0x0, 0x80(%rsp)
movq 0x80(%rsp), %rax
cmpq 0x68(%rsp), %rax
jae 0x14d299
movq 0x88(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x80(%rsp), %rcx
movzbl (%rax,%rcx), %eax
cmpl $0x10, %eax
jne 0x14d281
movl $0x37, 0x94(%rsp)
jmp 0x14d2a6
jmp 0x14d283
movq 0x80(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x14d248
jmp 0x14d29b
movl $0x0, 0x94(%rsp)
movl 0x94(%rsp), %eax
addq $0x98, %rsp
retq
nopw %cs:(%rax,%rax)