// File: Lut99[P]RayTracer/src/lib/LodePNG.cpp
// Function: getTreeInflateDynamic(HuffmanTree*, HuffmanTree*, LodePNGBitReader*)
static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
                                      LodePNGBitReader* reader) {
  /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/
  unsigned error = 0;
  unsigned n, HLIT, HDIST, HCLEN, i;

  /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/
  unsigned* bitlen_ll = 0; /*lit,len code lengths*/
  unsigned* bitlen_d = 0; /*dist code lengths*/
  /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/
  unsigned* bitlen_cl = 0;
  HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/

  if(!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/

  /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
  HLIT =  readBits(reader, 5) + 257;
  /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/
  HDIST = readBits(reader, 5) + 1;
  /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/
  HCLEN = readBits(reader, 4) + 4;

  bitlen_cl = (unsigned*)lodepng_malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned));
  if(!bitlen_cl) return 83 /*alloc fail*/;

  HuffmanTree_init(&tree_cl);

  while(!error) {
    /*read the code length codes out of 3 * (amount of code length codes) bits*/
    if(lodepng_gtofl(reader->bp, HCLEN * 3, reader->bitsize)) {
      ERROR_BREAK(50); /*error: the bit pointer is or will go past the memory*/
    }
    for(i = 0; i != HCLEN; ++i) {
      ensureBits9(reader, 3); /*out of bounds already checked above */
      bitlen_cl[CLCL_ORDER[i]] = readBits(reader, 3);
    }
    for(i = HCLEN; i != NUM_CODE_LENGTH_CODES; ++i) {
      bitlen_cl[CLCL_ORDER[i]] = 0;
    }

    error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7);
    if(error) break;

    /*now we can use this tree to read the lengths for the tree that this function will return*/
    bitlen_ll = (unsigned*)lodepng_malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
    bitlen_d = (unsigned*)lodepng_malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
    if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/);
    for(i = 0; i != NUM_DEFLATE_CODE_SYMBOLS; ++i) bitlen_ll[i] = 0;
    for(i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen_d[i] = 0;

    /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/
    i = 0;
    while(i < HLIT + HDIST) {
      unsigned code;
      ensureBits25(reader, 22); /* up to 15 bits for huffman code, up to 7 extra bits below*/
      code = huffmanDecodeSymbol(reader, &tree_cl);
      if(code <= 15) /*a length code*/ {
        if(i < HLIT) bitlen_ll[i] = code;
        else bitlen_d[i - HLIT] = code;
        ++i;
      } else if(code == 16) /*repeat previous*/ {
        unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/
        unsigned value; /*set value to the previous code*/

        if(i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/

        replength += readBits(reader, 2);

        if(i < HLIT + 1) value = bitlen_ll[i - 1];
        else value = bitlen_d[i - HLIT - 1];
        /*repeat this value in the next lengths*/
        for(n = 0; n < replength; ++n) {
          if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/
          if(i < HLIT) bitlen_ll[i] = value;
          else bitlen_d[i - HLIT] = value;
          ++i;
        }
      } else if(code == 17) /*repeat "0" 3-10 times*/ {
        unsigned replength = 3; /*read in the bits that indicate repeat length*/
        replength += readBits(reader, 3);

        /*repeat this value in the next lengths*/
        for(n = 0; n < replength; ++n) {
          if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/

          if(i < HLIT) bitlen_ll[i] = 0;
          else bitlen_d[i - HLIT] = 0;
          ++i;
        }
      } else if(code == 18) /*repeat "0" 11-138 times*/ {
        unsigned replength = 11; /*read in the bits that indicate repeat length*/
        replength += readBits(reader, 7);

        /*repeat this value in the next lengths*/
        for(n = 0; n < replength; ++n) {
          if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/

          if(i < HLIT) bitlen_ll[i] = 0;
          else bitlen_d[i - HLIT] = 0;
          ++i;
        }
      } else /*if(code == INVALIDSYMBOL)*/ {
        ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
      }
      /*check if any of the ensureBits above went out of bounds*/
      if(reader->bp > reader->bitsize) {
        /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
        (10=no endcode, 11=wrong jump outside of tree)*/
        /* TODO: revise error codes 10,11,50: the above comment is no longer valid */
        ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
      }
    }
    if(error) break;

    if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/

    /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/
    error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15);
    if(error) break;
    error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15);

    break; /*end of error-while*/
  }

  lodepng_free(bitlen_cl);
  lodepng_free(bitlen_ll);
  lodepng_free(bitlen_d);
  HuffmanTree_cleanup(&tree_cl);

  return error;
}

// Assembly:
subq $0x98, %rsp
movq %rdi, 0x88(%rsp)
movq %rsi, 0x80(%rsp)
movq %rdx, 0x78(%rsp)
movl $0x0, 0x74(%rsp)
movq $0x0, 0x58(%rsp)
movq $0x0, 0x50(%rsp)
movq $0x0, 0x48(%rsp)
movq 0x78(%rsp), %rdi
movl $0xe, %esi
callq 0x13d550
cmpl $0x0, %eax
jne 0x14c033
movl $0x31, 0x94(%rsp)
jmp 0x14c5d1
movq 0x78(%rsp), %rdi
movl $0x5, %esi
callq 0x13d7c0
addl $0x101, %eax            # imm = 0x101
movl %eax, 0x6c(%rsp)
movq 0x78(%rsp), %rdi
movl $0x5, %esi
callq 0x13d7c0
addl $0x1, %eax
movl %eax, 0x68(%rsp)
movq 0x78(%rsp), %rdi
movl $0x4, %esi
callq 0x13d7c0
addl $0x4, %eax
movl %eax, 0x64(%rsp)
movl $0x4c, %edi
callq 0x13ce80
movq %rax, 0x48(%rsp)
cmpq $0x0, 0x48(%rsp)
jne 0x14c09e
movl $0x53, 0x94(%rsp)
jmp 0x14c5d1
leaq 0x20(%rsp), %rdi
callq 0x14bf60
cmpl $0x0, 0x74(%rsp)
setne %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x14c0bb
jmp 0x14c59e
movq 0x78(%rsp), %rax
movq 0x18(%rax), %rdi
imull $0x3, 0x64(%rsp), %eax
movl %eax, %eax
movl %eax, %esi
movq 0x78(%rsp), %rax
movq 0x10(%rax), %rdx
callq 0x14d320
cmpl $0x0, %eax
je 0x14c0ed
movl $0x32, 0x74(%rsp)
jmp 0x14c59e
movl $0x0, 0x60(%rsp)
movl 0x60(%rsp), %eax
cmpl 0x64(%rsp), %eax
je 0x14c144
movq 0x78(%rsp), %rdi
movl $0x3, %esi
callq 0x13d6b0
movq 0x78(%rsp), %rdi
movl $0x3, %esi
callq 0x13d7c0
movl %eax, %edx
movq 0x48(%rsp), %rax
movl 0x60(%rsp), %ecx
movl %ecx, %esi
leaq 0x2a4bf(%rip), %rcx     # 0x1765f0
movl (%rcx,%rsi,4), %ecx
movl %edx, (%rax,%rcx,4)
movl 0x60(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x60(%rsp)
jmp 0x14c0f5
movl 0x64(%rsp), %eax
movl %eax, 0x60(%rsp)
cmpl $0x13, 0x60(%rsp)
je 0x14c17c
movq 0x48(%rsp), %rax
movl 0x60(%rsp), %ecx
movl %ecx, %edx
leaq 0x2a48b(%rip), %rcx     # 0x1765f0
movl (%rcx,%rdx,4), %ecx
movl $0x0, (%rax,%rcx,4)
movl 0x60(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x60(%rsp)
jmp 0x14c14c
movq 0x48(%rsp), %rsi
leaq 0x20(%rsp), %rdi
movl $0x13, %edx
movl $0x7, %ecx
callq 0x14c8e0
movl %eax, 0x74(%rsp)
cmpl $0x0, 0x74(%rsp)
je 0x14c1a5
jmp 0x14c59e
movl $0x480, %edi            # imm = 0x480
callq 0x13ce80
movq %rax, 0x58(%rsp)
movl $0x80, %edi
callq 0x13ce80
movq %rax, 0x50(%rsp)
cmpq $0x0, 0x58(%rsp)
je 0x14c1d3
cmpq $0x0, 0x50(%rsp)
jne 0x14c1e0
movl $0x53, 0x74(%rsp)
jmp 0x14c59e
movl $0x0, 0x60(%rsp)
cmpl $0x120, 0x60(%rsp)      # imm = 0x120
je 0x14c20f
movq 0x58(%rsp), %rax
movl 0x60(%rsp), %ecx
movl $0x0, (%rax,%rcx,4)
movl 0x60(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x60(%rsp)
jmp 0x14c1e8
movl $0x0, 0x60(%rsp)
cmpl $0x20, 0x60(%rsp)
je 0x14c23b
movq 0x50(%rsp), %rax
movl 0x60(%rsp), %ecx
movl $0x0, (%rax,%rcx,4)
movl 0x60(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x60(%rsp)
jmp 0x14c217
movl $0x0, 0x60(%rsp)
movl 0x60(%rsp), %eax
movl 0x6c(%rsp), %ecx
addl 0x68(%rsp), %ecx
cmpl %ecx, %eax
jae 0x14c534
movq 0x78(%rsp), %rdi
movl $0x16, %esi
callq 0x13d3a0
movq 0x78(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x14c5e0
movl %eax, 0x1c(%rsp)
cmpl $0xf, 0x1c(%rsp)
ja 0x14c2c2
movl 0x60(%rsp), %eax
cmpl 0x6c(%rsp), %eax
jae 0x14c29c
movl 0x1c(%rsp), %edx
movq 0x58(%rsp), %rax
movl 0x60(%rsp), %ecx
movl %edx, (%rax,%rcx,4)
jmp 0x14c2b2
movl 0x1c(%rsp), %edx
movq 0x50(%rsp), %rax
movl 0x60(%rsp), %ecx
subl 0x6c(%rsp), %ecx
movl %ecx, %ecx
movl %edx, (%rax,%rcx,4)
movl 0x60(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x60(%rsp)
jmp 0x14c511
cmpl $0x10, 0x1c(%rsp)
jne 0x14c3ba
movl $0x3, 0x18(%rsp)
cmpl $0x0, 0x60(%rsp)
jne 0x14c2e9
movl $0x36, 0x74(%rsp)
jmp 0x14c534
movq 0x78(%rsp), %rdi
movl $0x2, %esi
callq 0x13d7c0
addl 0x18(%rsp), %eax
movl %eax, 0x18(%rsp)
movl 0x60(%rsp), %eax
movl 0x6c(%rsp), %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
jae 0x14c326
movq 0x58(%rsp), %rax
movl 0x60(%rsp), %ecx
subl $0x1, %ecx
movl %ecx, %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x14(%rsp)
jmp 0x14c33f
movq 0x50(%rsp), %rax
movl 0x60(%rsp), %ecx
subl 0x6c(%rsp), %ecx
subl $0x1, %ecx
movl %ecx, %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x14(%rsp)
movl $0x0, 0x70(%rsp)
movl 0x70(%rsp), %eax
cmpl 0x18(%rsp), %eax
jae 0x14c3b5
movl 0x60(%rsp), %eax
movl 0x6c(%rsp), %ecx
addl 0x68(%rsp), %ecx
cmpl %ecx, %eax
jb 0x14c36b
movl $0xd, 0x74(%rsp)
jmp 0x14c3b5
movl 0x60(%rsp), %eax
cmpl 0x6c(%rsp), %eax
jae 0x14c387
movl 0x14(%rsp), %edx
movq 0x58(%rsp), %rax
movl 0x60(%rsp), %ecx
movl %edx, (%rax,%rcx,4)
jmp 0x14c39d
movl 0x14(%rsp), %edx
movq 0x50(%rsp), %rax
movl 0x60(%rsp), %ecx
subl 0x6c(%rsp), %ecx
movl %ecx, %ecx
movl %edx, (%rax,%rcx,4)
movl 0x60(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x60(%rsp)
movl 0x70(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x70(%rsp)
jmp 0x14c347
jmp 0x14c50f
cmpl $0x11, 0x1c(%rsp)
jne 0x14c45f
movl $0x3, 0x10(%rsp)
movq 0x78(%rsp), %rdi
movl $0x3, %esi
callq 0x13d7c0
addl 0x10(%rsp), %eax
movl %eax, 0x10(%rsp)
movl $0x0, 0x70(%rsp)
movl 0x70(%rsp), %eax
cmpl 0x10(%rsp), %eax
jae 0x14c45a
movl 0x60(%rsp), %eax
movl 0x6c(%rsp), %ecx
addl 0x68(%rsp), %ecx
cmpl %ecx, %eax
jb 0x14c410
movl $0xe, 0x74(%rsp)
jmp 0x14c45a
movl 0x60(%rsp), %eax
cmpl 0x6c(%rsp), %eax
jae 0x14c42c
movq 0x58(%rsp), %rax
movl 0x60(%rsp), %ecx
movl $0x0, (%rax,%rcx,4)
jmp 0x14c442
movq 0x50(%rsp), %rax
movl 0x60(%rsp), %ecx
subl 0x6c(%rsp), %ecx
movl %ecx, %ecx
movl $0x0, (%rax,%rcx,4)
movl 0x60(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x60(%rsp)
movl 0x70(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x70(%rsp)
jmp 0x14c3ec
jmp 0x14c50d
cmpl $0x12, 0x1c(%rsp)
jne 0x14c501
movl $0xb, 0xc(%rsp)
movq 0x78(%rsp), %rdi
movl $0x7, %esi
callq 0x13d7c0
addl 0xc(%rsp), %eax
movl %eax, 0xc(%rsp)
movl $0x0, 0x70(%rsp)
movl 0x70(%rsp), %eax
cmpl 0xc(%rsp), %eax
jae 0x14c4ff
movl 0x60(%rsp), %eax
movl 0x6c(%rsp), %ecx
addl 0x68(%rsp), %ecx
cmpl %ecx, %eax
jb 0x14c4b5
movl $0xf, 0x74(%rsp)
jmp 0x14c4ff
movl 0x60(%rsp), %eax
cmpl 0x6c(%rsp), %eax
jae 0x14c4d1
movq 0x58(%rsp), %rax
movl 0x60(%rsp), %ecx
movl $0x0, (%rax,%rcx,4)
jmp 0x14c4e7
movq 0x50(%rsp), %rax
movl 0x60(%rsp), %ecx
subl 0x6c(%rsp), %ecx
movl %ecx, %ecx
movl $0x0, (%rax,%rcx,4)
movl 0x60(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x60(%rsp)
movl 0x70(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x70(%rsp)
jmp 0x14c491
jmp 0x14c50b
movl $0x10, 0x74(%rsp)
jmp 0x14c534
jmp 0x14c50d
jmp 0x14c50f
jmp 0x14c511
movq 0x78(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x78(%rsp), %rcx
cmpq 0x10(%rcx), %rax
jbe 0x14c52f
movl $0x32, 0x74(%rsp)
jmp 0x14c534
jmp 0x14c243
cmpl $0x0, 0x74(%rsp)
je 0x14c53d
jmp 0x14c59e
movq 0x58(%rsp), %rax
cmpl $0x0, 0x400(%rax)
jne 0x14c555
movl $0x40, 0x74(%rsp)
jmp 0x14c59e
movq 0x88(%rsp), %rdi
movq 0x58(%rsp), %rsi
movl $0x120, %edx            # imm = 0x120
movl $0xf, %ecx
callq 0x14c8e0
movl %eax, 0x74(%rsp)
cmpl $0x0, 0x74(%rsp)
je 0x14c57e
jmp 0x14c59e
movq 0x80(%rsp), %rdi
movq 0x50(%rsp), %rsi
movl $0x20, %edx
movl $0xf, %ecx
callq 0x14c8e0
movl %eax, 0x74(%rsp)
movq 0x48(%rsp), %rdi
callq 0x13e2d0
movq 0x58(%rsp), %rdi
callq 0x13e2d0
movq 0x50(%rsp), %rdi
callq 0x13e2d0
leaq 0x20(%rsp), %rdi
callq 0x14c6d0
movl 0x74(%rsp), %eax
movl %eax, 0x94(%rsp)
movl 0x94(%rsp), %eax
addq $0x98, %rsp
retq