// File: Lut99[P]RayTracer/src/lib/LodePNG.cpp
// Function: inflateHuffmanBlock(ucvector*, unsigned long*, LodePNGBitReader*, unsigned int)
static unsigned inflateHuffmanBlock(ucvector* out, size_t* pos, LodePNGBitReader* reader,
                                    unsigned btype) {
  unsigned error = 0;
  HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
  HuffmanTree tree_d; /*the huffman tree for distance codes*/

  HuffmanTree_init(&tree_ll);
  HuffmanTree_init(&tree_d);

  if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d);
  else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader);

  while(!error) /*decode all symbols until end reached, breaks at end code*/ {
    /*code_ll is literal, length or end code*/
    unsigned code_ll;
    ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */
    code_ll = huffmanDecodeSymbol(reader, &tree_ll);
    if(code_ll <= 255) /*literal symbol*/ {
      /*ucvector_push_back would do the same, but for some reason the two lines below run 10% faster*/
      if(!ucvector_resize(out, (*pos) + 1)) ERROR_BREAK(83 /*alloc fail*/);
      out->data[*pos] = (unsigned char)code_ll;
      ++(*pos);
    } else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ {
      unsigned code_d, distance;
      unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/
      size_t start, backward, length;

      /*part 1: get length base*/
      length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX];

      /*part 2: get extra bits and add the value of that to length*/
      numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
      if(numextrabits_l != 0) {
        /* bits already ensured above */
        length += readBits(reader, numextrabits_l);
      }

      /*part 3: get distance code*/
      ensureBits32(reader, 28); /* up to 15 for the huffman symbol, up to 13 for the extra bits */
      code_d = huffmanDecodeSymbol(reader, &tree_d);
      if(code_d > 29) {
        if(code_d <= 31) {
          ERROR_BREAK(18); /*error: invalid distance code (30-31 are never used)*/
        } else /* if(code_d == INVALIDSYMBOL) */{
          ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
        }
      }
      distance = DISTANCEBASE[code_d];

      /*part 4: get extra bits from distance*/
      numextrabits_d = DISTANCEEXTRA[code_d];
      if(numextrabits_d != 0) {
        /* bits already ensured above */
        distance += readBits(reader, numextrabits_d);
      }

      /*part 5: fill in all the out[n] values based on the length and dist*/
      start = (*pos);
      if(distance > start) ERROR_BREAK(52); /*too long backward distance*/
      backward = start - distance;

      if(!ucvector_resize(out, (*pos) + length)) ERROR_BREAK(83 /*alloc fail*/);
      if (distance < length) {
        size_t forward;
        lodepng_memcpy(out->data + *pos, out->data + backward, distance);
        *pos += distance;
        for(forward = distance; forward < length; ++forward) {
          out->data[(*pos)++] = out->data[backward++];
        }
      } else {
        lodepng_memcpy(out->data + *pos, out->data + backward, length);
        *pos += length;
      }
    } else if(code_ll == 256) {
      break; /*end code, break the loop*/
    } else /*if(code_ll == 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(51); /*error, bit pointer jumps past memory*/
    }
  }

  HuffmanTree_cleanup(&tree_ll);
  HuffmanTree_cleanup(&tree_d);

  return error;
}

// Assembly:
subq $0xa8, %rsp
movq %rdi, 0xa0(%rsp)
movq %rsi, 0x98(%rsp)
movq %rdx, 0x90(%rsp)
movl %ecx, 0x8c(%rsp)
movl $0x0, 0x88(%rsp)
leaq 0x60(%rsp), %rdi
callq 0x14bf60
leaq 0x38(%rsp), %rdi
callq 0x14bf60
cmpl $0x1, 0x8c(%rsp)
jne 0x14ba90
leaq 0x60(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x14bfa0
jmp 0x14baae
movq 0x90(%rsp), %rdx
leaq 0x60(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x14bfd0
movl %eax, 0x88(%rsp)
jmp 0x14bab0
cmpl $0x0, 0x88(%rsp)
setne %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x14bac6
jmp 0x14be2b
movq 0x90(%rsp), %rdi
movl $0x14, %esi
callq 0x13d3a0
movq 0x90(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x14c5e0
movl %eax, 0x34(%rsp)
cmpl $0xff, 0x34(%rsp)
ja 0x14bb5f
movq 0xa0(%rsp), %rdi
movq 0x98(%rsp), %rax
movq (%rax), %rsi
addq $0x1, %rsi
callq 0x14be50
cmpl $0x0, %eax
jne 0x14bb29
movl $0x53, 0x88(%rsp)
jmp 0x14be2b
movl 0x34(%rsp), %eax
movb %al, %dl
movq 0xa0(%rsp), %rax
movq (%rax), %rax
movq 0x98(%rsp), %rcx
movq (%rcx), %rcx
movb %dl, (%rax,%rcx)
movq 0x98(%rsp), %rax
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
jmp 0x14bdff
cmpl $0x101, 0x34(%rsp)      # imm = 0x101
jb 0x14bde4
cmpl $0x11d, 0x34(%rsp)      # imm = 0x11D
ja 0x14bde4
movl 0x34(%rsp), %eax
subl $0x101, %eax            # imm = 0x101
movl %eax, %eax
movl %eax, %ecx
leaq 0x2a861(%rip), %rax     # 0x1763f0
movl (%rax,%rcx,4), %eax
movq %rax, 0x8(%rsp)
movl 0x34(%rsp), %eax
subl $0x101, %eax            # imm = 0x101
movl %eax, %eax
movl %eax, %ecx
leaq 0x2a8c5(%rip), %rax     # 0x176470
movl (%rax,%rcx,4), %eax
movl %eax, 0x28(%rsp)
cmpl $0x0, 0x28(%rsp)
je 0x14bbd8
movq 0x90(%rsp), %rdi
movl 0x28(%rsp), %eax
movl %eax, %esi
callq 0x13d7c0
movl %eax, %eax
addq 0x8(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x90(%rsp), %rdi
movl $0x1c, %esi
callq 0x13d190
movq 0x90(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x14c5e0
movl %eax, 0x30(%rsp)
cmpl $0x1d, 0x30(%rsp)
jbe 0x14bc2e
cmpl $0x1f, 0x30(%rsp)
ja 0x14bc1e
movl $0x12, 0x88(%rsp)
jmp 0x14be2b
movl $0x10, 0x88(%rsp)
jmp 0x14be2b
movl 0x30(%rsp), %eax
movl %eax, %ecx
leaq 0x2a8b5(%rip), %rax     # 0x1764f0
movl (%rax,%rcx,4), %eax
movl %eax, 0x2c(%rsp)
movl 0x30(%rsp), %eax
movl %eax, %ecx
leaq 0x2a921(%rip), %rax     # 0x176570
movl (%rax,%rcx,4), %eax
movl %eax, 0x24(%rsp)
cmpl $0x0, 0x24(%rsp)
je 0x14bc78
movq 0x90(%rsp), %rdi
movl 0x24(%rsp), %eax
movl %eax, %esi
callq 0x13d7c0
addl 0x2c(%rsp), %eax
movl %eax, 0x2c(%rsp)
movq 0x98(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x18(%rsp)
movl 0x2c(%rsp), %eax
cmpq 0x18(%rsp), %rax
jbe 0x14bca3
movl $0x34, 0x88(%rsp)
jmp 0x14be2b
movq 0x18(%rsp), %rax
movl 0x2c(%rsp), %ecx
subq %rcx, %rax
movq %rax, 0x10(%rsp)
movq 0xa0(%rsp), %rdi
movq 0x98(%rsp), %rax
movq (%rax), %rsi
addq 0x8(%rsp), %rsi
callq 0x14be50
cmpl $0x0, %eax
jne 0x14bce6
movl $0x53, 0x88(%rsp)
jmp 0x14be2b
movl 0x2c(%rsp), %eax
cmpq 0x8(%rsp), %rax
jae 0x14bd9f
movq 0xa0(%rsp), %rax
movq (%rax), %rdi
movq 0x98(%rsp), %rax
addq (%rax), %rdi
movq 0xa0(%rsp), %rax
movq (%rax), %rsi
addq 0x10(%rsp), %rsi
movl 0x2c(%rsp), %eax
movl %eax, %edx
callq 0x14b830
movl 0x2c(%rsp), %eax
movl %eax, %ecx
movq 0x98(%rsp), %rax
addq (%rax), %rcx
movq %rcx, (%rax)
movl 0x2c(%rsp), %eax
movq %rax, (%rsp)
movq (%rsp), %rax
cmpq 0x8(%rsp), %rax
jae 0x14bd9d
movq 0xa0(%rsp), %rax
movq (%rax), %rax
movq 0x10(%rsp), %rcx
movq %rcx, %rdx
addq $0x1, %rdx
movq %rdx, 0x10(%rsp)
movb (%rax,%rcx), %dl
movq 0xa0(%rsp), %rax
movq (%rax), %rax
movq 0x98(%rsp), %rsi
movq (%rsi), %rcx
movq %rcx, %rdi
addq $0x1, %rdi
movq %rdi, (%rsi)
movb %dl, (%rax,%rcx)
movq (%rsp), %rax
addq $0x1, %rax
movq %rax, (%rsp)
jmp 0x14bd42
jmp 0x14bde2
movq 0xa0(%rsp), %rax
movq (%rax), %rdi
movq 0x98(%rsp), %rax
addq (%rax), %rdi
movq 0xa0(%rsp), %rax
movq (%rax), %rsi
addq 0x10(%rsp), %rsi
movq 0x8(%rsp), %rdx
callq 0x14b830
movq 0x8(%rsp), %rcx
movq 0x98(%rsp), %rax
addq (%rax), %rcx
movq %rcx, (%rax)
jmp 0x14bdfd
cmpl $0x100, 0x34(%rsp)      # imm = 0x100
jne 0x14bdf0
jmp 0x14be2b
movl $0x10, 0x88(%rsp)
jmp 0x14be2b
jmp 0x14bdff
movq 0x90(%rsp), %rax
movq 0x18(%rax), %rax
movq 0x90(%rsp), %rcx
cmpq 0x10(%rcx), %rax
jbe 0x14be26
movl $0x33, 0x88(%rsp)
jmp 0x14be2b
jmp 0x14bab0
leaq 0x60(%rsp), %rdi
callq 0x14c6d0
leaq 0x38(%rsp), %rdi
callq 0x14c6d0
movl 0x88(%rsp), %eax
addq $0xa8, %rsp
retq
nop