// File: /workspace/github_cpp_makefile_star2_O3/drummyfish[P]flowchart/src/lodepng.cpp
// Function: filter(unsigned char*, unsigned char const*, unsigned int, unsigned int, LodePNGColorMode const*, LodePNGEncoderSettings const*)
static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h,
                       const LodePNGColorMode* info, const LodePNGEncoderSettings* settings)
{
  /*
  For PNG filter method 0
  out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are
  the scanlines with 1 extra byte per scanline
  */

  unsigned bpp = lodepng_get_bpp(info);
  /*the width of a scanline in bytes, not including the filter type*/
  size_t linebytes = (w * bpp + 7) / 8;
  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
  size_t bytewidth = (bpp + 7) / 8;
  const unsigned char* prevline = 0;
  unsigned x, y;
  unsigned error = 0;
  /*
  There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard:
   *  If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e.
      use fixed filtering, with the filter None).
   * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is
     not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply
     all five filters and select the filter that produces the smallest sum of absolute values per row.
   This heuristic is used if filter strategy is LFS_HEURISTIC. Parts of it are used for filter strategies
   LFS_MINSUM and LFS_ZERO.
  */
  int heuristic_zero = info->colortype == LCT_PALETTE || info->bitdepth < 8;

  if(bpp == 0) return 31; /*error: invalid color type*/

  if((!heuristic_zero && settings->filter_strategy == LFS_HEURISTIC)||
      settings->filter_strategy == LFS_MINSUM)
  {
    /*adaptive filtering*/
    size_t sum[5];
    ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest = 0;
    unsigned type, bestType = 0;

    for(type = 0; type < 5; type++) ucvector_init(&attempt[type]);

    for(type = 0; type < 5; type++)
    {
      if(!ucvector_resize(&attempt[type], linebytes)) ERROR_BREAK(83 /*alloc fail*/);
    }

    if(!error)
    {
      for(y = 0; y < h; y++)
      {
        /*try the 5 filter types*/
        for(type = 0; type < 5; type++)
        {
          filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);

          /*calculate the sum of the result*/
          sum[type] = 0;
          /*note that not all pixels are checked to speed this up while still having probably the best choice*/
          for(x = 0; x < attempt[type].size; x+=3)
          {
            /*For differences, each byte should be treated as signed, values above 127 are negative
            (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there.
            This means filtertype 0 is almost never chosen, but that is justified.*/
            if(type == 0) sum[type] += (unsigned char)(attempt[type].data[x]);
            else
            {
              signed char s = (signed char)(attempt[type].data[x]);
              sum[type] += s < 0 ? -s : s;
            }
          }

          /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
          if(type == 0 || sum[type] < smallest)
          {
            bestType = type;
            smallest = sum[type];
          }
        }

        prevline = &in[y * linebytes];

        /*now fill the out values*/
        out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
        for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
      }
    }

    for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
  }
  else if((heuristic_zero && settings->filter_strategy == LFS_HEURISTIC)||
      settings->filter_strategy == LFS_ZERO)
  {
    for(y = 0; y < h; y++)
    {
      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
      size_t inindex = linebytes * y;
      const unsigned TYPE = 0;
      out[outindex] = TYPE; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, TYPE);
      prevline = &in[inindex];
    }
  }
  else if(settings->filter_strategy == LFS_PREDEFINED)
  {
    for(y = 0; y < h; y++)
    {
      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
      size_t inindex = linebytes * y;
      unsigned type = settings->predefined_filters[y];
      out[outindex] = type; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
      prevline = &in[inindex];
    }
  }
  else /*LFS_BRUTE_FORCE*/
  {
    /*brute force filter chooser.
    deflate the scanline after every filter attempt to see which one deflates best.
    This is very slow and gives only slightly smaller, sometimes even larger, result*/
    size_t size[5];
    ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest = 0;
    unsigned type = 0, bestType = 0;
    unsigned char* dummy;
    LodePNGCompressSettings zlibsettings = settings->zlibsettings;
    /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose,
    to simulate the true case where the tree is the same for the whole image. Sometimes it gives
    better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare
    cases better compression. It does make this a bit less slow, so it's worth doing this.*/
    zlibsettings.btype = 1;
    /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG
    images only, so disable it*/
    zlibsettings.custom_zlib = 0;
    zlibsettings.custom_deflate = 0;
    for(type = 0; type < 5; type++)
    {
      ucvector_init(&attempt[type]);
      ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/
    }
    for(y = 0; y < h; y++) /*try the 5 filter types*/
    {
      for(type = 0; type < 5; type++)
      {
        unsigned testsize = attempt[type].size;
        /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/

        filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
        size[type] = 0;
        dummy = 0;
        zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings);
        myfree(dummy);
        /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/
        if(type == 0 || size[type] < smallest)
        {
          bestType = type;
          smallest = size[type];
        }
      }
      prevline = &in[y * linebytes];
      out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
      for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
    }
    for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
  }

  return error;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x148, %rsp            # imm = 0x148
movl %ecx, %r13d
movl %edx, %r12d
movq %rdi, %rbp
xorl %eax, %eax
cmpl $0x6, %r8d
ja 0xd4fb
movl %r8d, %eax
leaq 0x5184(%rip), %rcx      # 0x1267c
movl (%rcx,%rax,4), %eax
movq 0x180(%rsp), %rdi
imull %r9d, %eax
imull %eax, %r12d
addl $0x7, %r12d
movl %r12d, %r14d
shrl $0x3, %r14d
leal 0x7(%rax), %r15d
shrl $0x3, %r15d
cmpl $0x3, %r8d
movq %rsi, 0x28(%rsp)
jne 0xd534
movb $0x1, %cl
testl %eax, %eax
jne 0xd54c
jmp 0xd740
testl %eax, %eax
je 0xd740
movb $0x1, %cl
cmpl $0x8, %r9d
jb 0xd54c
cmpl $0x0, 0x2c(%rdi)
je 0xd558
xorl %ecx, %ecx
movl 0x2c(%rdi), %eax
cmpl $0x2, %eax
jne 0xd74a
xorps %xmm0, %xmm0
movaps %xmm0, 0x100(%rsp)
movaps %xmm0, 0xf0(%rsp)
movaps %xmm0, 0xe0(%rsp)
movaps %xmm0, 0xd0(%rsp)
movaps %xmm0, 0xc0(%rsp)
movaps %xmm0, 0xb0(%rsp)
movaps %xmm0, 0xa0(%rsp)
movq $0x0, 0x110(%rsp)
xorl %ebx, %ebx
leaq (%rsp,%rbx), %rdi
addq $0xa0, %rdi
movq %r14, %rsi
callq 0xbc56
testl %eax, %eax
je 0xd81a
addq $0x18, %rbx
cmpq $0x78, %rbx
jne 0xd5a1
testl %r13d, %r13d
je 0xd739
movq %r15, 0x18(%rsp)
leaq 0x1(%r14), %rsi
cmpl $0x2, %r14d
movl $0x1, %edi
movq %r14, 0x20(%rsp)
cmovael %r14d, %edi
movl %r13d, %eax
movq %rax, 0x30(%rsp)
leaq 0x1(%rbp), %r8
xorl %r9d, %r9d
movq $0x0, (%rsp)
xorl %r14d, %r14d
xorl %r15d, %r15d
movq 0x28(%rsp), %rax
movq %rbp, 0x48(%rsp)
movl %r12d, 0x14(%rsp)
movq %rsi, 0x40(%rsp)
movq %rdi, 0x38(%rsp)
movq %r8, 0x8(%rsp)
movq (%rsp), %rbx
movq %r9, 0x50(%rsp)
imulq 0x20(%rsp), %r9
addq %rax, %r9
movq %r9, (%rsp)
xorl %r12d, %r12d
leaq (%r12,%r12,2), %r13
movq 0xa0(%rsp,%r13,8), %rbp
movzbl %r12b, %r9d
movq %rbp, %rdi
movq (%rsp), %rsi
movq %rbx, %rdx
movq 0x20(%rsp), %rcx
movq 0x18(%rsp), %r8
callq 0xda9c
movq 0xa8(%rsp,%r13,8), %rcx
testq %rcx, %rcx
je 0xd6ae
movl $0x3, %edx
xorl %eax, %eax
xorl %esi, %esi
movzbl (%rbp,%rsi), %esi
movl %esi, %edi
sarb $0x7, %dil
movl %esi, %r8d
xorb %dil, %r8b
subb %dil, %r8b
testq %r12, %r12
movzbl %r8b, %edi
cmovel %esi, %edi
movzbl %dil, %esi
addq %rsi, %rax
movl %edx, %esi
addl $0x3, %edx
cmpq %rsi, %rcx
ja 0xd67d
jmp 0xd6b0
xorl %eax, %eax
testq %r12, %r12
sete %cl
cmpq %r14, %rax
setb %dl
orb %cl, %dl
cmovnel %r12d, %r15d
cmovneq %rax, %r14
incq %r12
cmpq $0x5, %r12
jne 0xd63e
movq 0x40(%rsp), %rsi
movq %rsi, %rax
movq 0x50(%rsp), %r9
imulq %r9, %rax
movq 0x48(%rsp), %rbp
movb %r15b, (%rbp,%rax)
movl 0x14(%rsp), %r12d
cmpl $0x8, %r12d
movq 0x38(%rsp), %rdi
movq 0x8(%rsp), %r8
jb 0xd723
movl %r15d, %eax
leaq (%rax,%rax,2), %rax
movq 0xa0(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%r8,%rcx)
incq %rcx
cmpq %rcx, %rdi
jne 0xd714
incq %r9
addq %rsi, %r8
cmpq 0x30(%rsp), %r9
movq 0x28(%rsp), %rax
jne 0xd620
xorl %ebx, %ebx
jmp 0xd81f
movl $0x1f, %ebx
jmp 0xda88
testl %eax, %eax
sete %dl
testb %dl, %cl
jne 0xd7cc
cmpl $0x1, %eax
je 0xd7cc
cmpl $0x4, %eax
jne 0xd856
testl %r13d, %r13d
je 0xda86
leaq 0x1(%r14), %rax
movq %rax, (%rsp)
movl %r13d, %eax
movq %rax, 0x8(%rsp)
incq %rbp
xorl %ebx, %ebx
movq %r15, 0x18(%rsp)
xorl %r15d, %r15d
xorl %edx, %edx
movq %r14, %r12
movq %rsi, %r14
movq 0x30(%rdi), %rax
movzbl (%rax,%r15), %r9d
movb %r9b, -0x1(%rbp)
movq %rdi, %r13
movq %rbp, %rdi
movq %r12, %rcx
movq 0x18(%rsp), %r8
callq 0xda9c
movq %r13, %rdi
incq %r15
addq (%rsp), %rbp
leaq (%r14,%r12), %rsi
movq %r14, %rdx
cmpq %r15, 0x8(%rsp)
jne 0xd78c
jmp 0xda88
testl %r13d, %r13d
je 0xda86
leaq 0x1(%r14), %rax
movl %r13d, %ecx
leaq 0x1(%rbp), %rdx
xorl %r9d, %r9d
movq %rax, %rdi
imulq %r9, %rdi
movb $0x0, (%rbp,%rdi)
cmpl $0x8, %r12d
jb 0xd807
xorl %edi, %edi
movb (%rsi,%rdi), %r8b
movb %r8b, (%rdx,%rdi)
incq %rdi
cmpq %rdi, %r14
jne 0xd7f7
incq %r9
addq %rax, %rdx
addq %r14, %rsi
cmpq %rcx, %r9
jne 0xd7e3
jmp 0xda86
movl $0x53, %ebx
xorl %r14d, %r14d
xorps %xmm0, %xmm0
movups %xmm0, 0xa8(%rsp,%r14)
movq 0xa0(%rsp,%r14), %rdi
callq 0x2220
movq $0x0, 0xa0(%rsp,%r14)
addq $0x18, %r14
cmpq $0x78, %r14
jne 0xd822
jmp 0xda88
movq %r15, 0x18(%rsp)
movl %r12d, 0x14(%rsp)
movups (%rdi), %xmm0
movups 0x10(%rdi), %xmm1
movaps %xmm0, 0x70(%rsp)
movaps %xmm1, 0x80(%rsp)
movq 0x20(%rdi), %rax
movq %rax, 0x90(%rsp)
movl $0x1, 0x70(%rsp)
xorps %xmm0, %xmm0
movaps %xmm0, 0x80(%rsp)
xorl %ebx, %ebx
leaq (%rsp,%rbx), %rdi
addq $0xa0, %rdi
xorps %xmm0, %xmm0
movups %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
movq %r14, %rsi
callq 0xbc56
addq $0x18, %rbx
cmpq $0x78, %rbx
jne 0xd895
testl %r13d, %r13d
movq 0x28(%rsp), %rax
je 0xda56
leaq 0x1(%r14), %rsi
cmpl $0x2, %r14d
movl $0x1, %edi
cmovael %r14d, %edi
movl %r13d, %ecx
movq %rcx, 0x60(%rsp)
leaq 0x1(%rbp), %r8
xorl %r9d, %r9d
xorl %r12d, %r12d
xorl %r15d, %r15d
movq $0x0, 0x8(%rsp)
movq %rbp, 0x48(%rsp)
movq %r14, 0x20(%rsp)
movq %rsi, 0x30(%rsp)
movq %rdi, 0x68(%rsp)
movq %r8, 0x40(%rsp)
movq 0x8(%rsp), %rcx
movq %rcx, 0x50(%rsp)
movq %r9, 0x38(%rsp)
imulq %r14, %r9
addq %rax, %r9
movq %r9, 0x8(%rsp)
xorl %r13d, %r13d
leaq 0xa8(%rsp), %rbx
xorl %ebp, %ebp
movl (%rbx), %eax
movq %rax, (%rsp)
movq -0x8(%rbx), %r14
movzbl %bpl, %r9d
movq %r14, %rdi
movq 0x8(%rsp), %rsi
movq 0x50(%rsp), %rdx
movq 0x20(%rsp), %rcx
movq 0x18(%rsp), %r8
callq 0xda9c
leaq (%rsp,%r13), %rsi
addq $0x120, %rsi            # imm = 0x120
xorl %eax, %eax
movq %rax, 0x120(%rsp,%rbp,8)
movq %rax, 0x58(%rsp)
movq 0x80(%rsp), %rax
leaq 0x58(%rsp), %rdi
movq %r14, %rdx
testq %rax, %rax
je 0xd9a4
movq (%rsp), %rcx
leaq 0x70(%rsp), %r8
callq *%rax
jmp 0xd9b2
movq (%rsp), %rcx
leaq 0x70(%rsp), %r8
callq 0x5460
movq 0x58(%rsp), %rdi
callq 0x2220
testq %rbp, %rbp
sete %al
movq 0x120(%rsp,%rbp,8), %rcx
cmpq %r15, %rcx
setb %dl
orb %al, %dl
cmovneq %rcx, %r15
cmovnel %ebp, %r12d
incq %rbp
addq $0x18, %rbx
addq $0x8, %r13
cmpq $0x5, %rbp
jne 0xd93e
movq 0x30(%rsp), %rsi
movq %rsi, %rax
movq 0x38(%rsp), %r9
imulq %r9, %rax
movq 0x48(%rsp), %rbp
movb %r12b, (%rbp,%rax)
cmpl $0x8, 0x14(%rsp)
movq 0x68(%rsp), %rdi
movq 0x40(%rsp), %r8
jb 0xda3b
movl %r12d, %eax
leaq (%rax,%rax,2), %rax
movq 0xa0(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%r8,%rcx)
incq %rcx
cmpq %rcx, %rdi
jne 0xda2c
incq %r9
addq %rsi, %r8
cmpq 0x60(%rsp), %r9
movq 0x28(%rsp), %rax
movq 0x20(%rsp), %r14
jne 0xd911
xorl %ebx, %ebx
xorps %xmm0, %xmm0
movups %xmm0, 0xa8(%rsp,%rbx)
movq 0xa0(%rsp,%rbx), %rdi
callq 0x2220
movq $0x0, 0xa0(%rsp,%rbx)
addq $0x18, %rbx
cmpq $0x78, %rbx
jne 0xda58
xorl %ebx, %ebx
movl %ebx, %eax
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq