// File: phillip-h[P]fractal-gen/lodepng.cpp
// Function: inflateHuffmanBlock(ucvector*, unsigned char const*, unsigned long*, unsigned long*, unsigned long, unsigned int)
static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp,
                                    size_t* pos, size_t inlength, 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*/
  size_t inbitlength = inlength * 8;

  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, in, bp, inlength);

  while(!error) /*decode all symbols until end reached, breaks at end code*/
  {
    /*code_ll is literal, length or end code*/
    unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength);
    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, forward, 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((*bp + numextrabits_l) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/
      length += readBitsFromStream(bp, in, numextrabits_l);

      /*part 3: get distance code*/
      code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength);
      if(code_d > 29)
      {
        if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
        {
          /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
          (10=no endcode, 11=wrong jump outside of tree)*/
          error = (*bp) > inlength * 8 ? 10 : 11;
        }
        else error = 18; /*error: invalid distance code (30-31 are never used)*/
        break;
      }
      distance = DISTANCEBASE[code_d];

      /*part 4: get extra bits from distance*/
      numextrabits_d = DISTANCEEXTRA[code_d];
      if((*bp + numextrabits_d) > inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/
      distance += readBitsFromStream(bp, in, 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) {
        for(forward = 0; forward < length; ++forward)
        {
          out->data[(*pos)++] = out->data[backward++];
        }
      } else {
        memcpy(out->data + *pos, out->data + backward, length);
        *pos += length;
      }
    }
    else if(code_ll == 256)
    {
      break; /*end code, break the loop*/
    }
    else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
    {
      /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
      (10=no endcode, 11=wrong jump outside of tree)*/
      error = ((*bp) > inlength * 8) ? 10 : 11;
      break;
    }
  }

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

  return error;
}

// Assembly:
subq $0xb8, %rsp
movq %rdi, 0xb0(%rsp)
movq %rsi, 0xa8(%rsp)
movq %rdx, 0xa0(%rsp)
movq %rcx, 0x98(%rsp)
movq %r8, 0x90(%rsp)
movl %r9d, 0x8c(%rsp)
movl $0x0, 0x88(%rsp)
movq 0x90(%rsp), %rax
shlq $0x3, %rax
movq %rax, 0x40(%rsp)
leaq 0x68(%rsp), %rdi
callq 0x12420
leaq 0x48(%rsp), %rdi
callq 0x12420
cmpl $0x1, 0x8c(%rsp)
jne 0x11f12
leaq 0x68(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x12450
jmp 0x11f4c
cmpl $0x2, 0x8c(%rsp)
jne 0x11f4a
movq 0xa8(%rsp), %rdx
movq 0xa0(%rsp), %rcx
movq 0x90(%rsp), %r8
leaq 0x68(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x12480
movl %eax, 0x88(%rsp)
jmp 0x11f4c
jmp 0x11f4e
cmpl $0x0, 0x88(%rsp)
setne %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x11f64
jmp 0x122ea
movq 0xa8(%rsp), %rdi
movq 0xa0(%rsp), %rsi
movq 0x40(%rsp), %rcx
leaq 0x68(%rsp), %rdx
callq 0x12b60
movl %eax, 0x3c(%rsp)
cmpl $0xff, 0x3c(%rsp)
ja 0x11ff8
movq 0xb0(%rsp), %rdi
movq 0x98(%rsp), %rax
movq (%rax), %rsi
addq $0x1, %rsi
callq 0x12310
cmpl $0x0, %eax
jne 0x11fc2
movl $0x53, 0x88(%rsp)
jmp 0x122ea
movl 0x3c(%rsp), %eax
movb %al, %dl
movq 0xb0(%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 0x122e5
cmpl $0x101, 0x3c(%rsp)      # imm = 0x101
jb 0x122a7
cmpl $0x11d, 0x3c(%rsp)      # imm = 0x11D
ja 0x122a7
movl 0x3c(%rsp), %eax
subl $0x101, %eax            # imm = 0x101
movl %eax, %eax
movl %eax, %ecx
leaq 0xa558(%rip), %rax      # 0x1c580
movl (%rax,%rcx,4), %eax
movq %rax, 0x8(%rsp)
movl 0x3c(%rsp), %eax
subl $0x101, %eax            # imm = 0x101
movl %eax, %eax
movl %eax, %ecx
leaq 0xa5bc(%rip), %rax      # 0x1c600
movl (%rax,%rcx,4), %eax
movl %eax, 0x30(%rsp)
movq 0xa0(%rsp), %rax
movq (%rax), %rax
movl 0x30(%rsp), %ecx
addq %rcx, %rax
cmpq 0x40(%rsp), %rax
jbe 0x12074
movl $0x33, 0x88(%rsp)
jmp 0x122ea
movq 0xa0(%rsp), %rdi
movq 0xa8(%rsp), %rsi
movl 0x30(%rsp), %eax
movl %eax, %edx
callq 0x12c40
movl %eax, %eax
addq 0x8(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0xa8(%rsp), %rdi
movq 0xa0(%rsp), %rsi
movq 0x40(%rsp), %rcx
leaq 0x48(%rsp), %rdx
callq 0x12b60
movl %eax, 0x38(%rsp)
cmpl $0x1d, 0x38(%rsp)
jbe 0x1210c
cmpl $-0x1, 0x3c(%rsp)
jne 0x120fc
movq 0xa0(%rsp), %rax
movq (%rax), %rdx
movq 0x90(%rsp), %rsi
shlq $0x3, %rsi
movl $0xb, %eax
movl $0xa, %ecx
cmpq %rsi, %rdx
cmoval %ecx, %eax
movl %eax, 0x88(%rsp)
jmp 0x12107
movl $0x12, 0x88(%rsp)
jmp 0x122ea
movl 0x38(%rsp), %eax
movl %eax, %ecx
leaq 0xa567(%rip), %rax      # 0x1c680
movl (%rax,%rcx,4), %eax
movl %eax, 0x34(%rsp)
movl 0x38(%rsp), %eax
movl %eax, %ecx
leaq 0xa5d3(%rip), %rax      # 0x1c700
movl (%rax,%rcx,4), %eax
movl %eax, 0x2c(%rsp)
movq 0xa0(%rsp), %rax
movq (%rax), %rax
movl 0x2c(%rsp), %ecx
addq %rcx, %rax
cmpq 0x40(%rsp), %rax
jbe 0x1215d
movl $0x33, 0x88(%rsp)
jmp 0x122ea
movq 0xa0(%rsp), %rdi
movq 0xa8(%rsp), %rsi
movl 0x2c(%rsp), %eax
movl %eax, %edx
callq 0x12c40
addl 0x34(%rsp), %eax
movl %eax, 0x34(%rsp)
movq 0x98(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x20(%rsp)
movl 0x34(%rsp), %eax
cmpq 0x20(%rsp), %rax
jbe 0x121ab
movl $0x34, 0x88(%rsp)
jmp 0x122ea
movq 0x20(%rsp), %rax
movl 0x34(%rsp), %ecx
subq %rcx, %rax
movq %rax, 0x10(%rsp)
movq 0xb0(%rsp), %rdi
movq 0x98(%rsp), %rax
movq (%rax), %rsi
addq 0x8(%rsp), %rsi
callq 0x12310
cmpl $0x0, %eax
jne 0x121ee
movl $0x53, 0x88(%rsp)
jmp 0x122ea
movl 0x34(%rsp), %eax
cmpq 0x8(%rsp), %rax
jae 0x12262
movq $0x0, 0x18(%rsp)
movq 0x18(%rsp), %rax
cmpq 0x8(%rsp), %rax
jae 0x12260
movq 0xb0(%rsp), %rax
movq (%rax), %rax
movq 0x10(%rsp), %rcx
movq %rcx, %rdx
addq $0x1, %rdx
movq %rdx, 0x10(%rsp)
movb (%rax,%rcx), %dl
movq 0xb0(%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 0x18(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x18(%rsp)
jmp 0x12202
jmp 0x122a5
movq 0xb0(%rsp), %rax
movq (%rax), %rdi
movq 0x98(%rsp), %rax
addq (%rax), %rdi
movq 0xb0(%rsp), %rax
movq (%rax), %rsi
addq 0x10(%rsp), %rsi
movq 0x8(%rsp), %rdx
callq 0x3170
movq 0x8(%rsp), %rcx
movq 0x98(%rsp), %rax
addq (%rax), %rcx
movq %rcx, (%rax)
jmp 0x122e3
cmpl $0x100, 0x3c(%rsp)      # imm = 0x100
jne 0x122b3
jmp 0x122ea
movq 0xa0(%rsp), %rax
movq (%rax), %rdx
movq 0x90(%rsp), %rsi
shlq $0x3, %rsi
movl $0xb, %eax
movl $0xa, %ecx
cmpq %rsi, %rdx
cmoval %ecx, %eax
movl %eax, 0x88(%rsp)
jmp 0x122ea
jmp 0x122e5
jmp 0x11f4e
leaq 0x68(%rsp), %rdi
callq 0x12cc0
leaq 0x48(%rsp), %rdi
callq 0x12cc0
movl 0x88(%rsp), %eax
addq $0xb8, %rsp
retq
nopl (%rax)