// File: lvandeve[P]lodepng/lodepng.cpp
// Function: inflateHuffmanBlock(ucvector*, LodePNGBitReader*, unsigned int, unsigned long)
static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader,
                                    unsigned btype, size_t max_output_size) {
  unsigned error = 0;
  HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
  HuffmanTree tree_d; /*the huffman tree for distance codes*/
  const size_t reserved_size = 260; /* must be at least 258 for max length, and a few extra for adding a few extra literals */
  int done = 0;

  if(!ucvector_reserve(out, out->size + reserved_size)) return 83; /*alloc fail*/

  HuffmanTree_init(&tree_ll);
  HuffmanTree_init(&tree_d);

  if(btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d);
  else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader);


  while(!error && !done) /*decode all symbols until end reached, breaks at end code*/ {
    /*code_ll is literal, length or end code*/
    unsigned code_ll;
    /* ensure enough bits for 2 huffman code reads (15 bits each): if the first is a literal, a second literal is read at once. This
    appears to be slightly faster, than ensuring 20 bits here for 1 huffman symbol and the potential 5 extra bits for the length symbol.*/
    ensureBits32(reader, 30);
    code_ll = huffmanDecodeSymbol(reader, &tree_ll);
    if(code_ll <= 255) {
      /*slightly faster code path if multiple literals in a row*/
      out->data[out->size++] = (unsigned char)code_ll;
      code_ll = huffmanDecodeSymbol(reader, &tree_ll);
    }
    if(code_ll <= 255) /*literal symbol*/ {
      out->data[out->size++] = (unsigned char)code_ll;
    } 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 */
        ensureBits25(reader, 5);
        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 = out->size;
      if(distance > start) ERROR_BREAK(52); /*too long backward distance*/
      backward = start - distance;

      out->size += length;
      if(distance < length) {
        size_t forward;
        lodepng_memcpy(out->data + start, out->data + backward, distance);
        start += distance;
        for(forward = distance; forward < length; ++forward) {
          out->data[start++] = out->data[backward++];
        }
      } else {
        lodepng_memcpy(out->data + start, out->data + backward, length);
      }
    } else if(code_ll == 256) {
      done = 1; /*end code, finish the loop*/
    } else /*if(code_ll == INVALIDSYMBOL)*/ {
      ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
    }
    if(out->allocsize - out->size < reserved_size) {
      if(!ucvector_reserve(out, out->size + reserved_size)) ERROR_BREAK(83); /*alloc fail*/
    }
    /*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*/
    }
    if(max_output_size && out->size > max_output_size) {
      ERROR_BREAK(109); /*error, larger than max size*/
    }
  }

  HuffmanTree_cleanup(&tree_ll);
  HuffmanTree_cleanup(&tree_d);

  return error;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xd0, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
movq %rcx, -0x28(%rbp)
movl $0x0, -0x2c(%rbp)
movq $0x104, -0x88(%rbp) # imm = 0x104
movl $0x0, -0x8c(%rbp)
movq -0x10(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
addq $0x104, %rsi            # imm = 0x104
callq 0x12ce0
cmpl $0x0, %eax
jne 0x127af
movl $0x53, -0x4(%rbp)
jmp 0x12bee
leaq -0x58(%rbp), %rdi
callq 0x12d70
leaq -0x80(%rbp), %rdi
callq 0x12d70
cmpl $0x1, -0x1c(%rbp)
jne 0x127d9
leaq -0x58(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0x12db0
movl %eax, -0x2c(%rbp)
jmp 0x127ed
movq -0x18(%rbp), %rdx
leaq -0x58(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0x12df0
movl %eax, -0x2c(%rbp)
jmp 0x127ef
xorl %eax, %eax
cmpl $0x0, -0x2c(%rbp)
movb %al, -0xc1(%rbp)
jne 0x1280f
cmpl $0x0, -0x8c(%rbp)
setne %al
xorb $-0x1, %al
movb %al, -0xc1(%rbp)
movb -0xc1(%rbp), %al
testb $0x1, %al
jne 0x1281e
jmp 0x12bd6
movq -0x18(%rbp), %rdi
movl $0x1e, %esi
callq 0x13340
movq -0x18(%rbp), %rdi
leaq -0x58(%rbp), %rsi
callq 0x13500
movl %eax, -0x90(%rbp)
cmpl $0xff, -0x90(%rbp)
ja 0x12883
movl -0x90(%rbp), %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq -0x10(%rbp), %rsi
movq 0x8(%rsi), %rcx
movq %rcx, %rdi
addq $0x1, %rdi
movq %rdi, 0x8(%rsi)
movb %dl, (%rax,%rcx)
movq -0x18(%rbp), %rdi
leaq -0x58(%rbp), %rsi
callq 0x13500
movl %eax, -0x90(%rbp)
cmpl $0xff, -0x90(%rbp)
ja 0x128b9
movl -0x90(%rbp), %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq -0x10(%rbp), %rsi
movq 0x8(%rsi), %rcx
movq %rcx, %rdi
addq $0x1, %rdi
movq %rdi, 0x8(%rsi)
movb %dl, (%rax,%rcx)
jmp 0x12b58
cmpl $0x101, -0x90(%rbp)     # imm = 0x101
jb 0x12b30
cmpl $0x11d, -0x90(%rbp)     # imm = 0x11D
ja 0x12b30
movl -0x90(%rbp), %eax
subl $0x101, %eax            # imm = 0x101
movl %eax, %eax
movl %eax, %ecx
leaq 0x9e991(%rip), %rax     # 0xb1280
movl (%rax,%rcx,4), %eax
movq %rax, -0xb8(%rbp)
movl -0x90(%rbp), %eax
subl $0x101, %eax            # imm = 0x101
movl %eax, %eax
movl %eax, %ecx
leaq 0x9e9f1(%rip), %rax     # 0xb1300
movl (%rax,%rcx,4), %eax
movl %eax, -0x9c(%rbp)
cmpl $0x0, -0x9c(%rbp)
je 0x12950
movq -0x18(%rbp), %rdi
movl $0x5, %esi
callq 0x135e0
movq -0x18(%rbp), %rdi
movl -0x9c(%rbp), %eax
movl %eax, %esi
callq 0x12590
movl %eax, %eax
addq -0xb8(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0x18(%rbp), %rdi
movl $0x1c, %esi
callq 0x13340
movq -0x18(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0x13500
movl %eax, -0x94(%rbp)
cmpl $0x1d, -0x94(%rbp)
jbe 0x1299b
cmpl $0x1f, -0x94(%rbp)
ja 0x1298f
movl $0x12, -0x2c(%rbp)
jmp 0x12bd6
movl $0x10, -0x2c(%rbp)
jmp 0x12bd6
movl -0x94(%rbp), %eax
movl %eax, %ecx
leaq 0x9e9d6(%rip), %rax     # 0xb1380
movl (%rax,%rcx,4), %eax
movl %eax, -0x98(%rbp)
movl -0x94(%rbp), %eax
movl %eax, %ecx
leaq 0x9ea3e(%rip), %rax     # 0xb1400
movl (%rax,%rcx,4), %eax
movl %eax, -0xa0(%rbp)
cmpl $0x0, -0xa0(%rbp)
je 0x129f1
movq -0x18(%rbp), %rdi
movl -0xa0(%rbp), %eax
movl %eax, %esi
callq 0x12590
addl -0x98(%rbp), %eax
movl %eax, -0x98(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0xa8(%rbp)
movl -0x98(%rbp), %eax
cmpq -0xa8(%rbp), %rax
jbe 0x12a1b
movl $0x34, -0x2c(%rbp)
jmp 0x12bd6
movq -0xa8(%rbp), %rax
movl -0x98(%rbp), %ecx
subq %rcx, %rax
movq %rax, -0xb0(%rbp)
movq -0xb8(%rbp), %rcx
movq -0x10(%rbp), %rax
addq 0x8(%rax), %rcx
movq %rcx, 0x8(%rax)
movl -0x98(%rbp), %eax
cmpq -0xb8(%rbp), %rax
jae 0x12b06
movq -0x10(%rbp), %rax
movq (%rax), %rdi
addq -0xa8(%rbp), %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rsi
addq -0xb0(%rbp), %rsi
movl -0x98(%rbp), %eax
movl %eax, %edx
callq 0x5820
movl -0x98(%rbp), %eax
addq -0xa8(%rbp), %rax
movq %rax, -0xa8(%rbp)
movl -0x98(%rbp), %eax
movq %rax, -0xc0(%rbp)
movq -0xc0(%rbp), %rax
cmpq -0xb8(%rbp), %rax
jae 0x12b04
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq -0xb0(%rbp), %rcx
movq %rcx, %rdx
addq $0x1, %rdx
movq %rdx, -0xb0(%rbp)
movb (%rax,%rcx), %dl
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq -0xa8(%rbp), %rcx
movq %rcx, %rsi
addq $0x1, %rsi
movq %rsi, -0xa8(%rbp)
movb %dl, (%rax,%rcx)
movq -0xc0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc0(%rbp)
jmp 0x12aa2
jmp 0x12b2e
movq -0x10(%rbp), %rax
movq (%rax), %rdi
addq -0xa8(%rbp), %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rsi
addq -0xb0(%rbp), %rsi
movq -0xb8(%rbp), %rdx
callq 0x5820
jmp 0x12b56
cmpl $0x100, -0x90(%rbp)     # imm = 0x100
jne 0x12b48
movl $0x1, -0x8c(%rbp)
jmp 0x12b54
movl $0x10, -0x2c(%rbp)
jmp 0x12bd6
jmp 0x12b56
jmp 0x12b58
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movq -0x10(%rbp), %rcx
subq 0x8(%rcx), %rax
cmpq $0x104, %rax            # imm = 0x104
jae 0x12b98
movq -0x10(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
addq $0x104, %rsi            # imm = 0x104
callq 0x12ce0
cmpl $0x0, %eax
jne 0x12b96
movl $0x53, -0x2c(%rbp)
jmp 0x12bd6
jmp 0x12b98
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x18(%rbp), %rcx
cmpq 0x10(%rcx), %rax
jbe 0x12bb3
movl $0x33, -0x2c(%rbp)
jmp 0x12bd6
cmpq $0x0, -0x28(%rbp)
je 0x12bd1
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
cmpq -0x28(%rbp), %rax
jbe 0x12bd1
movl $0x6d, -0x2c(%rbp)
jmp 0x12bd6
jmp 0x127ef
leaq -0x58(%rbp), %rdi
callq 0x13730
leaq -0x80(%rbp), %rdi
callq 0x13730
movl -0x2c(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0xd0, %rsp
popq %rbp
retq
nopw (%rax,%rax)