// File: /workspace/github_c_makefile_star2_O3/Joy-Division[P]tools-mgs/lodepng/lodepng.c
// Function: filter
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;
  LodePNGFilterStrategy strategy = settings->filter_strategy;

  /*
  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_MINSUM and filter_palette_zero is true.

  If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed,
  but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum
  heuristic is used.
  */
  if(settings->filter_palette_zero &&
     (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO;

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

  if(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;
      out[outindex] = 0; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0);
      prevline = &in[inindex];
    }
  }
  else if(strategy == LFS_MINSUM)
  {
    /*adaptive filtering*/
    size_t sum[5];
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest = 0;
    unsigned char type, bestType = 0;

    for(type = 0; type != 5; ++type)
    {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 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], &in[y * linebytes], prevline, linebytes, bytewidth, type);

          /*calculate the sum of the result*/
          sum[type] = 0;
          if(type == 0)
          {
            for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type][x]);
          }
          else
          {
            for(x = 0; x != linebytes; ++x)
            {
              /*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.*/
              unsigned char s = attempt[type][x];
              sum[type] += s < 128 ? s : (255U - 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][x];
      }
    }

    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  }
  else if(strategy == LFS_ENTROPY)
  {
    float sum[5];
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    float smallest = 0;
    unsigned type, bestType = 0;
    unsigned count[256];

    for(type = 0; type != 5; ++type)
    {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 83; /*alloc fail*/
    }

    for(y = 0; y != h; ++y)
    {
      /*try the 5 filter types*/
      for(type = 0; type != 5; ++type)
      {
        filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
        for(x = 0; x != 256; ++x) count[x] = 0;
        for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]];
        ++count[type]; /*the filter type itself is part of the scanline*/
        sum[type] = 0;
        for(x = 0; x != 256; ++x)
        {
          float p = count[x] / (float)(linebytes + 1);
          sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p;
        }
        /*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][x];
    }

    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  }
  else if(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 char 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 if(strategy == 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];
    unsigned char* 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)
    {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 83; /*alloc fail*/
    }
    for(y = 0; y != h; ++y) /*try the 5 filter types*/
    {
      for(type = 0; type != 5; ++type)
      {
        unsigned testsize = linebytes;
        /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/

        filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
        size[type] = 0;
        dummy = 0;
        zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings);
        lodepng_free(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][x];
    }
    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  }
  else return 88; /* unknown filter strategy */

  return error;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x4c8, %rsp            # imm = 0x4C8
movl %ecx, %ebx
movq %rsi, %rbp
movq %rdi, %r12
xorl %r13d, %r13d
cmpl $0x6, %r8d
ja 0xc39f
movl %r8d, %eax
leaq 0x2769(%rip), %rcx      # 0xeb04
movl (%rcx,%rax,4), %r13d
imull %r9d, %r13d
testl %r13d, %r13d
je 0xc45b
movq 0x500(%rsp), %rdi
movl 0x38(%rdi), %ecx
xorl %esi, %esi
cmpl $0x8, %r9d
movl %ecx, %eax
cmovbl %esi, %eax
cmpl $0x3, %r8d
cmovel %esi, %eax
cmpl $0x0, 0x34(%rdi)
cmovel %ecx, %eax
cmpl $0x4, %eax
ja 0xca90
imull %r13d, %edx
addl $0x7, %edx
movl %edx, 0x10(%rsp)
movl %edx, %r15d
shrl $0x3, %r15d
addl $0x7, %r13d
shrl $0x3, %r13d
leaq 0x1e2a(%rip), %rcx      # 0xe224
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
movq %r12, 0x40(%rsp)
movq %rbp, 0x50(%rsp)
jmpq *%rax
testl %ebx, %ebx
je 0xca85
leaq 0x1(%r15), %rax
movl %ebx, %ecx
leaq 0x1(%r12), %rdx
xorl %esi, %esi
movq %rax, %rdi
imulq %rsi, %rdi
movb $0x0, (%r12,%rdi)
cmpl $0x8, 0x10(%rsp)
jb 0xc448
xorl %edi, %edi
movb (%rbp,%rdi), %r8b
movb %r8b, (%rdx,%rdi)
incq %rdi
cmpq %rdi, %r15
jne 0xc437
incq %rsi
addq %rax, %rdx
addq %r15, %rbp
cmpq %rcx, %rsi
jne 0xc422
jmp 0xca85
movl $0x1f, %eax
jmp 0xca95
testl %ebx, %ebx
je 0xca85
movq %r13, 0x18(%rsp)
leaq 0x1(%r15), %rax
movq %rax, 0x10(%rsp)
movq %rbp, %rax
movl %ebx, %ebp
incq %r12
xorl %ebx, %ebx
xorl %edx, %edx
movq %rax, %r14
movq 0x40(%rdi), %rax
movzbl (%rax,%rbx), %r9d
movb %r9b, -0x1(%r12)
movq %rdi, %r13
movq %r12, %rdi
movq %r14, %rsi
movq %r15, %rcx
movq 0x18(%rsp), %r8
callq 0xcaa7
movq %r13, %rdi
incq %rbx
addq 0x10(%rsp), %r12
leaq (%r14,%r15), %rax
movq %r14, %rdx
cmpq %rbx, %rbp
jne 0xc487
jmp 0xca85
xorl %r14d, %r14d
movq %r15, %rdi
callq 0x1100
movq %rax, 0x60(%rsp,%r14,8)
testq %rax, %rax
je 0xca89
incq %r14
cmpq $0x5, %r14
jne 0xc4cd
movq %r13, 0x18(%rsp)
testl %ebx, %ebx
je 0xc70e
leaq 0x1(%r15), %rax
movq %rax, 0x20(%rsp)
cvtsi2ss %eax, %xmm0
movss %xmm0, 0x38(%rsp)
movl %ebx, %eax
movq %rax, 0x48(%rsp)
leaq 0x1(%r12), %rsi
xorps %xmm0, %xmm0
xorl %edi, %edi
xorl %r13d, %r13d
xorl %ebp, %ebp
movq %rsi, 0x30(%rsp)
movq %r13, %rbx
movq %rdi, 0x28(%rsp)
movq %rdi, %r13
imulq %r15, %r13
addq 0x50(%rsp), %r13
xorl %r12d, %r12d
movaps %xmm0, %xmm1
movss %xmm1, 0x8(%rsp)
movq 0x60(%rsp,%r12,8), %r14
movzbl %r12b, %r9d
movq %r14, %rdi
movq %r13, %rsi
movq %rbx, %rdx
movq %r15, %rcx
movq 0x18(%rsp), %r8
callq 0xcaa7
movl $0x400, %edx            # imm = 0x400
leaq 0xc0(%rsp), %rdi
xorl %esi, %esi
callq 0x10b0
cmpl $0x8, 0x10(%rsp)
jb 0xc597
xorl %eax, %eax
movzbl (%r14,%rax), %ecx
incl 0xc0(%rsp,%rcx,4)
incq %rax
cmpl %eax, %r15d
jne 0xc583
incl 0xc0(%rsp,%r12,4)
xorps %xmm0, %xmm0
xorl %eax, %eax
movss 0x38(%rsp), %xmm6
movss 0x256e(%rip), %xmm7     # 0xeb20
movss 0x2569(%rip), %xmm8     # 0xeb24
movss 0x2564(%rip), %xmm9     # 0xeb28
movss 0x255f(%rip), %xmm10    # 0xeb2c
movss 0x255a(%rip), %xmm11    # 0xeb30
movss 0x2555(%rip), %xmm12    # 0xeb34
movss 0x2550(%rip), %xmm13    # 0xeb38
movss 0x254b(%rip), %xmm14    # 0xeb3c
movss 0x2546(%rip), %xmm15    # 0xeb40
movl 0xc0(%rsp,%rax,4), %ecx
xorps %xmm1, %xmm1
testl %ecx, %ecx
je 0xc67f
movl %ecx, %ecx
xorps %xmm1, %xmm1
cvtsi2ss %rcx, %xmm1
divss %xmm6, %xmm1
movaps %xmm7, %xmm2
divss %xmm1, %xmm2
xorps %xmm3, %xmm3
ucomiss %xmm8, %xmm2
jbe 0xc63b
addss %xmm9, %xmm3
mulss %xmm10, %xmm2
jmp 0xc620
addss %xmm7, %xmm3
mulss %xmm12, %xmm2
ucomiss %xmm11, %xmm2
ja 0xc632
movaps %xmm2, %xmm4
mulss %xmm2, %xmm4
mulss %xmm2, %xmm4
divss %xmm13, %xmm4
movaps %xmm2, %xmm5
mulss %xmm13, %xmm5
mulss %xmm5, %xmm2
mulss %xmm14, %xmm2
addss %xmm4, %xmm2
addss %xmm5, %xmm2
addss %xmm15, %xmm2
mulss 0x24cd(%rip), %xmm2     # 0xeb44
addss %xmm3, %xmm2
mulss %xmm2, %xmm1
addss %xmm1, %xmm0
incq %rax
cmpq $0x100, %rax            # imm = 0x100
jne 0xc5fa
testq %r12, %r12
sete %al
movss 0x8(%rsp), %xmm1
ucomiss %xmm0, %xmm1
seta %cl
orb %al, %cl
testb %cl, %cl
jne 0xc6ad
movaps %xmm1, %xmm0
cmovnel %r12d, %ebp
incq %r12
movaps %xmm0, %xmm1
cmpq $0x5, %r12
jne 0xc541
movq 0x20(%rsp), %rax
movq 0x28(%rsp), %rdi
imulq %rdi, %rax
movq 0x40(%rsp), %rcx
movb %bpl, (%rcx,%rax)
cmpl $0x8, 0x10(%rsp)
movq 0x30(%rsp), %rsi
jb 0xc6fb
movl %ebp, %eax
movq 0x60(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%rsi,%rcx)
incq %rcx
cmpl %ecx, %r15d
jne 0xc6ed
incq %rdi
addq 0x20(%rsp), %rsi
cmpq 0x48(%rsp), %rdi
jne 0xc522
xorl %ebx, %ebx
movq 0x60(%rsp,%rbx,8), %rdi
callq 0x1030
incq %rbx
cmpq $0x5, %rbx
jne 0xc710
jmp 0xca85
movups (%rdi), %xmm0
movups 0x10(%rdi), %xmm1
movups 0x20(%rdi), %xmm2
movaps %xmm0, 0xc0(%rsp)
movaps %xmm2, 0xe0(%rsp)
movaps %xmm1, 0xd0(%rsp)
movl $0x1, 0xc0(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0xd8(%rsp)
xorl %r14d, %r14d
movq %r15, %rdi
callq 0x1100
movq %rax, 0x90(%rsp,%r14,8)
testq %rax, %rax
je 0xca89
incq %r14
cmpq $0x5, %r14
jne 0xc764
movq %r13, 0x18(%rsp)
testl %ebx, %ebx
je 0xc8d3
leaq 0x1(%r15), %rsi
movl %ebx, %eax
movq %rax, 0x48(%rsp)
movq 0x40(%rsp), %rax
leaq 0x1(%rax), %rdi
xorl %r8d, %r8d
xorl %r12d, %r12d
xorl %r13d, %r13d
movq $0x0, 0x8(%rsp)
movq %rsi, 0x28(%rsp)
movq %rdi, 0x20(%rsp)
movq 0x8(%rsp), %rax
movq %rax, 0x38(%rsp)
movq %r8, 0x30(%rsp)
imulq %r15, %r8
addq %rbp, %r8
movq %r8, 0x8(%rsp)
xorl %ebp, %ebp
xorl %r14d, %r14d
movq 0x90(%rsp,%r14,8), %rbx
movzbl %r14b, %r9d
movq %rbx, %rdi
movq 0x8(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq %r15, %rcx
movq 0x18(%rsp), %r8
callq 0xcaa7
leaq (%rsp,%rbp), %rsi
addq $0x60, %rsi
xorl %eax, %eax
movq %rax, 0x60(%rsp,%r14,8)
movq %rax, 0x58(%rsp)
movq 0xd8(%rsp), %rax
leaq 0x58(%rsp), %rdi
movq %rbx, %rdx
movq %r15, %rcx
leaq 0xc0(%rsp), %r8
testq %rax, %rax
je 0xc841
callq *%rax
jmp 0xc846
callq 0x44b8
movq 0x58(%rsp), %rdi
callq 0x1030
testq %r14, %r14
sete %al
movq 0x60(%rsp,%r14,8), %rcx
cmpq %r13, %rcx
setb %dl
orb %al, %dl
cmovneq %rcx, %r13
cmovnel %r14d, %r12d
incq %r14
addq $0x8, %rbp
cmpq $0x5, %r14
jne 0xc7e3
movq 0x28(%rsp), %rsi
movq %rsi, %rax
movq 0x30(%rsp), %r8
imulq %r8, %rax
movq 0x40(%rsp), %rcx
movb %r12b, (%rcx,%rax)
cmpl $0x8, 0x10(%rsp)
movq 0x20(%rsp), %rdi
jb 0xc8bd
movl %r12d, %eax
movq 0x90(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
cmpl %ecx, %r15d
jne 0xc8af
incq %r8
addq %rsi, %rdi
cmpq 0x48(%rsp), %r8
movq 0x50(%rsp), %rbp
jne 0xc7be
xorl %ebx, %ebx
movq 0x90(%rsp,%rbx,8), %rdi
callq 0x1030
incq %rbx
cmpq $0x5, %rbx
jne 0xc8d5
jmp 0xca85
xorl %r14d, %r14d
movq %r15, %rdi
callq 0x1100
movq %rax, 0xc0(%rsp,%r14,8)
testq %rax, %rax
je 0xca89
incq %r14
cmpq $0x5, %r14
jne 0xc8f3
movq %r13, 0x18(%rsp)
testl %ebx, %ebx
je 0xca6d
leaq 0x1(%r15), %r8
movl %ebx, %eax
movq %rax, 0x28(%rsp)
leaq 0x1(%r12), %r9
xorl %r10d, %r10d
movq $0x0, 0x8(%rsp)
xorl %ecx, %ecx
xorl %eax, %eax
movq %r8, 0x30(%rsp)
movq %r9, 0x38(%rsp)
movq 0x8(%rsp), %r13
movq %r10, 0x20(%rsp)
imulq %r15, %r10
addq %rbp, %r10
movq %r10, 0x8(%rsp)
xorl %edx, %edx
movq %rax, %rbx
movl %ecx, %ebp
movq %rdx, %r12
movq 0xc0(%rsp,%rdx,8), %r14
movzbl %r12b, %r9d
movq %r14, %rdi
movq 0x8(%rsp), %rsi
movq %r13, %rdx
movq %r15, %rcx
movq 0x18(%rsp), %r8
callq 0xcaa7
testq %r12, %r12
je 0xc9c3
cmpl $0x8, 0x10(%rsp)
jae 0xc9a0
xorl %eax, %eax
jmp 0xc9ef
xorl %ecx, %ecx
xorl %eax, %eax
movzbl (%r14,%rcx), %edx
movl %edx, %esi
xorl $0xff, %esi
testb %dl, %dl
cmovnsl %edx, %esi
addq %rsi, %rax
incq %rcx
cmpl %ecx, %r15d
jne 0xc9a4
jmp 0xc9ea
movl $0x1, %edx
xorl %ecx, %ecx
movl $0x0, %eax
cmpl $0x8, 0x10(%rsp)
jb 0xc964
xorl %ecx, %ecx
xorl %eax, %eax
movzbl (%r14,%rcx), %edx
addq %rdx, %rax
incq %rcx
cmpl %ecx, %r15d
jne 0xc9da
testq %r12, %r12
je 0xca03
cmpq %rbx, %rax
cmovaeq %rbx, %rax
movzbl %r12b, %edx
movzbl %bpl, %ecx
cmovbl %edx, %ecx
jmp 0xca05
xorl %ecx, %ecx
incq %r12
movq %r12, %rdx
cmpq $0x5, %r12
jne 0xc964
movq 0x30(%rsp), %r8
movq %r8, %rdx
movq 0x20(%rsp), %r10
imulq %r10, %rdx
movq 0x40(%rsp), %rsi
movb %cl, (%rsi,%rdx)
cmpl $0x8, 0x10(%rsp)
movq 0x38(%rsp), %r9
jb 0xca57
movzbl %cl, %edx
movq 0xc0(%rsp,%rdx,8), %rdx
xorl %esi, %esi
movb (%rdx,%rsi), %dil
movb %dil, (%r9,%rsi)
incq %rsi
cmpl %esi, %r15d
jne 0xca47
incq %r10
addq %r8, %r9
cmpq 0x28(%rsp), %r10
movq 0x50(%rsp), %rbp
jne 0xc947
xorl %ebx, %ebx
movq 0xc0(%rsp,%rbx,8), %rdi
callq 0x1030
incq %rbx
cmpq $0x5, %rbx
jne 0xca6f
xorl %eax, %eax
jmp 0xca95
movl $0x53, %eax
jmp 0xca95
movl $0x58, %eax
addq $0x4c8, %rsp            # imm = 0x4C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq