// File: /workspace/github_cpp_makefile_star2_O2/drummyfish[P]flowchart/src/lodepng.cpp
// Function: encodeLZ77(uivector*, Hash*, unsigned char const*, unsigned long, unsigned long, unsigned int)
static unsigned encodeLZ77(uivector* out, Hash* hash,
                           const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize)
{
  unsigned short numzeros = 0;
  int usezeros = windowsize >= 8192; /*for small window size, the 'max chain length' optimization does a better job*/
  unsigned pos, i, error = 0;

  if(!error)
  {
    unsigned offset; /*the offset represents the distance in LZ77 terminology*/
    unsigned length;
#ifdef LAZY_MATCHING
    unsigned lazy = 0;
    unsigned lazylength = 0, lazyoffset = 0;
#endif /*LAZY_MATCHING*/
    unsigned hashval;
    unsigned current_offset, current_length;
    const unsigned char *lastptr, *foreptr, *backptr;
    unsigned short hashpos, prevpos;

    for(pos = inpos; pos < insize; pos++)
    {
      size_t wpos = pos % windowsize; /*position for in 'circular' hash buffers*/

      hashval = getHash(in, insize, pos);
      updateHashChain(hash, pos, hashval, windowsize);

      if(usezeros && hashval == 0)
      {
        numzeros = countZeros(in, insize, pos);
        hash->zeros[wpos] = numzeros;
      }

      /*the length and offset found for the current position*/
      length = 0;
      offset = 0;

      prevpos = hash->head[hashval];
      hashpos = hash->chain[prevpos];

      lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH];

      /*search for the longest string*/
      if(hash->val[wpos] == (int)hashval)
      {
        /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/
        unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8;
        for(;;)
        {
          /*stop when went completely around the circular buffer*/
          if(prevpos < wpos && hashpos > prevpos && hashpos <= wpos) break;
          if(prevpos > wpos && (hashpos <= wpos || hashpos > prevpos)) break;
          if(maxchainlength-- == 0) break;

          current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize;
          if(current_offset > 0)
          {
            /*test the next characters*/
            foreptr = &in[pos];
            backptr = &in[pos - current_offset];

            /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/
            if(usezeros && hashval == 0 && hash->val[hashpos] == 0 /*hashval[hashpos] may be out of date*/)
            {
              unsigned short skip = hash->zeros[hashpos];
              if(skip > numzeros) skip = numzeros;
              backptr += skip;
              foreptr += skip;
            }

            /* multiple checks at once per array bounds check */
            while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/
            {
              ++backptr;
              ++foreptr;
            }
            current_length = (unsigned)(foreptr - &in[pos]);

            if(current_length > length)
            {
              length = current_length; /*the longest length*/
              offset = current_offset; /*the offset that is related to this longest length*/
              /*jump out once a length of max length is found (speed gain)*/
              if(current_length == MAX_SUPPORTED_DEFLATE_LENGTH) break;
            }
          }

          if(hashpos == hash->chain[hashpos]) break;

          prevpos = hashpos;
          hashpos = hash->chain[hashpos];
        }
      }

#ifdef LAZY_MATCHING
      if(!lazy && length >= 3 && length < MAX_SUPPORTED_DEFLATE_LENGTH)
      {
        lazy = 1;
        lazylength = length;
        lazyoffset = offset;
        continue;
      }
      if(lazy)
      {
        lazy = 0;
        if(pos == 0) ERROR_BREAK(81);
        if(length > lazylength + 1)
        {
          /*push the previous character as literal*/
          if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/);
        }
        else
        {
          length = lazylength;
          offset = lazyoffset;
          hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/
          pos--;
        }
      }
#endif /*LAZY_MATCHING*/

      if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/);


      /**encode it as length/distance pair or literal value**/
      if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/
      {
        if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
      }
      else
      {
        if(length == 3 && offset > 2048)
        {
          /*compensate for the fact that longer offsets have more extra bits, a
          length of only 3 may be not worth it then*/
          if(!uivector_push_back(out, in[pos + 0])) ERROR_BREAK(83 /*alloc fail*/);
          if(!uivector_push_back(out, in[pos + 1])) ERROR_BREAK(83 /*alloc fail*/);
          if(!uivector_push_back(out, in[pos + 2])) ERROR_BREAK(83 /*alloc fail*/);
        }
        else
        {
          addLengthDistance(out, length, offset);
        }
        for(i = 1; i < length; i++)
        {
          pos++;
          hashval = getHash(in, insize, pos);
          updateHashChain(hash, pos, hashval, windowsize);
          if(usezeros && hashval == 0)
          {
            hash->zeros[pos % windowsize] = countZeros(in, insize, pos);
          }
        }
      }

    } /*end of the loop through each character of input*/
  } /*end of "if(!error)"*/

  return error;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movq %r8, %rbp
movq %rcx, %r14
movq %rdx, %rbx
movq %rsi, %r13
movq %rdi, 0x30(%rsp)
movl %r9d, %eax
shrl $0x3, %eax
cmpl $0x2000, %r9d           # imm = 0x2000
movl %r9d, %ecx
movq %rcx, 0x50(%rsp)
movl %r9d, 0xc(%rsp)
cmovael %r9d, %eax
movl %eax, 0x48(%rsp)
xorl %ecx, %ecx
xorl %r12d, %r12d
movl $0x0, 0x28(%rsp)
movl $0x0, 0x2c(%rsp)
movq %r8, 0x38(%rsp)
movq %rdx, 0x10(%rsp)
movl %r14d, %r15d
cmpq %rbp, %r15
jae 0x9b9b
movl %ecx, 0x4c(%rsp)
movq %r12, 0x40(%rsp)
movq %r14, 0x20(%rsp)
movl %r14d, %eax
xorl %edx, %edx
divl 0xc(%rsp)
movl %edx, %r14d
movq %rbx, %rdi
movq %rbp, %rsi
movq %r15, %rdx
callq 0x9cde
movq 0x8(%r13), %r12
movl %eax, (%r12,%r14,4)
movq (%r13), %rdx
movl %eax, %r8d
movl (%rdx,%r8,4), %eax
cmpl $-0x1, %eax
je 0x97c1
movq 0x10(%r13), %rcx
movw %ax, (%rcx,%r14,2)
cmpl $0x2000, 0xc(%rsp)      # imm = 0x2000
setae %al
movq %rdx, 0x60(%rsp)
movl %r14d, (%rdx,%r8,4)
testq %r8, %r8
sete %cl
andb %al, %cl
movb %cl, 0x18(%rsp)
cmpb $0x1, %cl
jne 0x980d
movq %rbx, %rdi
movq %rbp, %rsi
movq %r15, %rdx
movq %r12, %rbx
movq %r8, %r12
callq 0x9d10
movq %r12, %r8
movq %rbx, %r12
movq 0x18(%r13), %rcx
movl %eax, 0x2c(%rsp)
movw %ax, (%rcx,%r14,2)
leaq 0x102(%r15), %rax
cmpq %rbp, %rax
cmovaeq %rbp, %rax
xorl %ebp, %ebp
movl $0x0, %ebx
movq %r8, 0x58(%rsp)
cmpl %r8d, (%r12,%r14,4)
jne 0x993a
movq 0x10(%rsp), %rsi
addq %rsi, %rax
movq 0x10(%r13), %rcx
movzwl %r14w, %edx
movzwl (%rcx,%rdx,2), %r9d
addq %rsi, %r15
xorl %edx, %edx
xorl %esi, %esi
movl %r14d, %edi
movl 0x48(%rsp), %r8d
movl %edi, %r11d
movl %r9d, %edi
movzwl %r11w, %r10d
movzwl %r9w, %r9d
cmpq %r14, %r10
jae 0x9877
cmpw %r11w, %di
jbe 0x9877
cmpl %r9d, %r14d
jae 0x9936
cmpl %r9d, %r14d
setae %r11b
cmpw %r10w, %di
seta %bl
cmpq %r14, %r10
jbe 0x9893
orb %bl, %r11b
jne 0x9936
subl $0x1, %r8d
jb 0x9936
movl %r9d, %r9d
movq %r14, %rbp
subq %r9, %rbp
movl $0x0, %r10d
cmovbl 0x50(%rsp), %r10d
addl %r10d, %ebp
je 0x9900
movq 0x20(%rsp), %r10
subl %ebp, %r10d
addq 0x10(%rsp), %r10
cmpb $0x0, 0x18(%rsp)
je 0x98d2
cmpl $0x0, (%r12,%r9,4)
je 0x9915
movq %r15, %rbx
cmpq %rax, %rbx
je 0x98ea
movb (%r10), %r11b
cmpb (%rbx), %r11b
jne 0x98ed
incq %r10
incq %rbx
jmp 0x98d5
movq %rax, %rbx
subq %r15, %rbx
cmpl %ebx, %esi
jae 0x9900
movl %ebp, %edx
movl %ebx, %esi
cmpl $0x102, %ebx            # imm = 0x102
je 0x993a
movzwl (%rcx,%r9,2), %r9d
movl %edx, %ebp
movl %esi, %ebx
cmpw %r9w, %di
jne 0x9855
jmp 0x993a
movq 0x18(%r13), %r11
movzwl (%r11,%r9,2), %r11d
movl 0x2c(%rsp), %ebx
cmpw %bx, %r11w
cmovael %ebx, %r11d
movzwl %r11w, %ebx
addq %rbx, %r10
addq %r15, %rbx
jmp 0x98d5
movl %edx, %ebp
movl %esi, %ebx
movl 0x4c(%rsp), %ecx
testl %ecx, %ecx
jne 0x996a
leal -0x3(%rbx), %eax
cmpl $0xff, %eax
jae 0x996a
movl %ebp, 0x28(%rsp)
movl %ebx, %r12d
pushq $0x1
popq %rcx
movq 0x38(%rsp), %rbp
movq 0x20(%rsp), %r14
movq 0x10(%rsp), %rbx
jmp 0x9b93
testl %ecx, %ecx
movq 0x20(%rsp), %r14
je 0x99aa
testl %r14d, %r14d
movq 0x40(%rsp), %r12
je 0x9ba7
leal 0x1(%r12), %eax
cmpl %eax, %ebx
jbe 0x99b1
leal -0x1(%r14), %eax
movq 0x10(%rsp), %rcx
movzbl (%rcx,%rax), %esi
movq 0x30(%rsp), %rdi
callq 0x91c5
testl %eax, %eax
jne 0x99cb
jmp 0x9b9f
movq 0x40(%rsp), %r12
jmp 0x99cb
movq 0x60(%rsp), %rax
movq 0x58(%rsp), %rcx
orl $-0x1, (%rax,%rcx,4)
decl %r14d
movl 0x28(%rsp), %eax
movl %eax, %ebp
movl %r12d, %ebx
cmpl $0x3, %ebx
jb 0x99da
cmpl 0xc(%rsp), %ebp
ja 0x9ba3
movl %r14d, %eax
cmpl $0x3, %ebx
jae 0x9a09
movq 0x10(%rsp), %rbx
movzbl (%rbx,%rax), %esi
movq 0x30(%rsp), %rdi
callq 0x91c5
xorl %ecx, %ecx
testl %eax, %eax
movq 0x38(%rsp), %rbp
jne 0x9b93
jmp 0x9b9f
jne 0x9a69
cmpl $0x801, %ebp            # imm = 0x801
jb 0x9a69
movq 0x10(%rsp), %r15
movzbl (%r15,%rax), %esi
movq 0x30(%rsp), %r12
movq %r12, %rdi
callq 0x91c5
testl %eax, %eax
je 0x9b9f
leal 0x1(%r14), %eax
movzbl (%r15,%rax), %esi
movq %r12, %rdi
callq 0x91c5
testl %eax, %eax
je 0x9b9f
leal 0x2(%r14), %eax
movzbl (%r15,%rax), %esi
movq %r12, %rdi
callq 0x91c5
testl %eax, %eax
jne 0x9af6
jmp 0x9b9f
movl %ebx, %edx
movl %ebp, %eax
movq %rax, 0x18(%rsp)
leaq 0x4727(%rip), %r12      # 0xe1a0
movq %r12, %rdi
pushq $0x1d
popq %rsi
callq 0x9d43
movq %r14, 0x20(%rsp)
movq %rax, %r14
movl %r14d, %eax
movl %ebx, %r15d
subl (%r12,%rax,4), %r15d
leaq 0x4803(%rip), %r12      # 0xe2a0
movq %r12, %rdi
pushq $0x1e
popq %rsi
movq 0x18(%rsp), %rdx
callq 0x9d43
movq %rax, 0x18(%rsp)
movl %eax, %ecx
subl (%r12,%rcx,4), %ebp
addl $0x101, %r14d           # imm = 0x101
movq 0x30(%rsp), %r12
movq %r12, %rdi
movl %r14d, %esi
movq 0x20(%rsp), %r14
callq 0x91c5
movq %r12, %rdi
movl %r15d, %esi
callq 0x91c5
movq %r12, %rdi
movq 0x18(%rsp), %rsi
callq 0x91c5
movq %r12, %rdi
movl %ebp, %esi
callq 0x91c5
pushq $0x1
popq %rax
movl %eax, %r15d
movq 0x38(%rsp), %rbp
cmpl %ebx, %r15d
jae 0x9b81
movq %r14, %r12
addl %r15d, %r14d
movq 0x10(%rsp), %rdi
movq %rbp, %rsi
movq %r14, %rdx
callq 0x9cde
movl %eax, %ecx
movq %r14, %rax
xorl %edx, %edx
divq 0x50(%rsp)
movq 0x8(%r13), %rax
movl %ecx, (%rax,%rdx,4)
movq (%r13), %rsi
movl %ecx, %eax
movl (%rsi,%rax,4), %ecx
cmpl $-0x1, %ecx
je 0x9b45
movq 0x10(%r13), %rdi
movw %cx, (%rdi,%rdx,2)
movl %edx, (%rsi,%rax,4)
cmpl $0x2000, 0xc(%rsp)      # imm = 0x2000
jb 0x9b79
testl %eax, %eax
jne 0x9b79
movq 0x10(%rsp), %rdi
movq %rbp, %rsi
movq %r14, %rdx
callq 0x9d10
movl %eax, %ecx
movq 0x18(%r13), %rsi
movl %r14d, %eax
xorl %edx, %edx
divl 0xc(%rsp)
movw %cx, (%rsi,%rdx,2)
incl %r15d
movq %r12, %r14
jmp 0x9b01
addl %r15d, %r14d
decl %r14d
xorl %ecx, %ecx
movq 0x10(%rsp), %rbx
movq 0x40(%rsp), %r12
incl %r14d
jmp 0x976c
xorl %eax, %eax
jmp 0x9baa
pushq $0x53
jmp 0x9ba9
pushq $0x56
jmp 0x9ba9
pushq $0x51
popq %rax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq