// File: /workspace/github_c_makefile_star2_O2/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 $0x4b8, %rsp            # imm = 0x4B8
movq %r9, %r13
movq %r8, %r14
movl %ecx, %ebp
movl %edx, %ebx
movq %rsi, %r15
movq %rdi, (%rsp)
movq %r8, %rdi
callq 0x35f5
movl 0x38(%r13), %ecx
cmpl $0x0, 0x34(%r13)
je 0x953f
cmpl $0x3, (%r14)
je 0x953d
cmpl $0x7, 0x4(%r14)
ja 0x953f
xorl %ecx, %ecx
testl %eax, %eax
je 0x95bb
cmpl $0x4, %ecx
ja 0x96cf
imull %eax, %ebx
addl $0x7, %ebx
addl $0x7, %eax
shrl $0x3, %ebx
shrl $0x3, %eax
movq %rax, 0x38(%rsp)
movl %ecx, %eax
leaq 0x1bdb(%rip), %rcx      # 0xb144
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %r15, %rax
leaq 0x1(%rbx), %r15
movl %ebp, %r12d
movq (%rsp), %r13
incq %r13
xorl %ebp, %ebp
xorl %edx, %edx
subq $0x1, %r12
jb 0x9bae
movq %rax, %r14
movb $0x0, -0x1(%r13)
movq %r13, %rdi
movq %rax, %rsi
movq %rbx, %rcx
movq 0x38(%rsp), %r8
xorl %r9d, %r9d
callq 0x9bc2
addq %r15, %r13
leaq (%r14,%rbx), %rax
movq %r14, %rdx
jmp 0x9587
pushq $0x1f
jmp 0x96d1
leaq 0x1(%rbx), %rax
movq %rax, 0x8(%rsp)
movl %ebp, %r12d
incq (%rsp)
xorl %ebp, %ebp
xorl %edx, %edx
cmpq %rbp, %r12
je 0x9bac
movq %r15, %r14
movq 0x40(%r13), %rax
movzbl (%rax,%rbp), %r9d
movq (%rsp), %r15
movb %r9b, -0x1(%r15)
movq %r15, %rdi
movq %r14, %rsi
movq %rbx, %rcx
movq 0x38(%rsp), %r8
callq 0x9bc2
incq %rbp
addq 0x8(%rsp), %r15
movq %r15, (%rsp)
leaq (%r14,%rbx), %r15
movq %r14, %rdx
jmp 0x95d6
xorl %r14d, %r14d
cmpq $0x5, %r14
je 0x96d7
movq %rbx, %rdi
callq 0x10f0
movq %rax, 0x50(%rsp,%r14,8)
incq %r14
testq %rax, %rax
jne 0x961e
jmp 0x96cb
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups 0x20(%r13), %xmm2
movaps %xmm0, 0xb0(%rsp)
movaps %xmm2, 0xd0(%rsp)
movaps %xmm1, 0xc0(%rsp)
movl $0x1, 0xb0(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0xc8(%rsp)
xorl %r14d, %r14d
cmpq $0x5, %r14
je 0x991a
movq %rbx, %rdi
callq 0x10f0
movq %rax, 0x80(%rsp,%r14,8)
incq %r14
testq %rax, %rax
jne 0x9682
jmp 0x96cb
xorl %r14d, %r14d
cmpq $0x5, %r14
je 0x9a6c
movq %rbx, %rdi
callq 0x10f0
movq %rax, 0xb0(%rsp,%r14,8)
incq %r14
testq %rax, %rax
jne 0x96a9
pushq $0x53
jmp 0x96d1
pushq $0x58
popq %rbp
jmp 0x9bae
leaq 0x1(%rbx), %rax
movq %rax, 0x20(%rsp)
cvtsi2ss %eax, %xmm6
movl %ebp, %eax
movq %rax, 0x40(%rsp)
movq (%rsp), %rax
incq %rax
movq %rax, 0x18(%rsp)
xorl %r13d, %r13d
xorps %xmm0, %xmm0
xorl %r12d, %r12d
xorl %ebp, %ebp
movq %r15, 0x30(%rsp)
movss %xmm6, 0x10(%rsp)
cmpq 0x40(%rsp), %r13
je 0x98ff
movq %r13, 0x28(%rsp)
imulq %rbx, %r13
addq %r15, %r13
xorl %r15d, %r15d
cmpq $0x5, %r15
je 0x98ab
movss %xmm0, 0x8(%rsp)
movq 0x50(%rsp,%r15,8), %r14
movzbl %r15b, %r9d
movq %r14, %rdi
movq %r13, %rsi
movq %rbp, %rdx
movq %rbx, %rcx
movq 0x38(%rsp), %r8
callq 0x9bc2
xorl %eax, %eax
cmpq $0x100, %rax            # imm = 0x100
je 0x976d
andl $0x0, 0xb0(%rsp,%rax,4)
incq %rax
jmp 0x9758
xorl %eax, %eax
movss 0x10(%rsp), %xmm6
movss 0x22c3(%rip), %xmm7     # 0xba40
movss 0x22be(%rip), %xmm8     # 0xba44
movss 0x22d1(%rip), %xmm9     # 0xba60
movss 0x22cc(%rip), %xmm10    # 0xba64
movss 0x22a7(%rip), %xmm11    # 0xba48
movss 0x22b2(%rip), %xmm12    # 0xba5c
movss 0x2299(%rip), %xmm13    # 0xba4c
movss 0x2294(%rip), %xmm14    # 0xba50
movss 0x228f(%rip), %xmm15    # 0xba54
cmpq %rax, %rbx
je 0x97db
movzbl (%r14,%rax), %ecx
incl 0xb0(%rsp,%rcx,4)
incq %rax
jmp 0x97c5
incl 0xb0(%rsp,%r15,4)
xorps %xmm0, %xmm0
xorl %eax, %eax
cmpq $0x100, %rax            # imm = 0x100
je 0x9884
movl 0xb0(%rsp,%rax,4), %ecx
testl %ecx, %ecx
je 0x9875
movl %ecx, %ecx
cvtsi2ss %rcx, %xmm1
divss %xmm6, %xmm1
movaps %xmm7, %xmm2
divss %xmm1, %xmm2
xorps %xmm3, %xmm3
ucomiss %xmm8, %xmm2
jbe 0x982f
addss %xmm9, %xmm3
mulss %xmm10, %xmm2
jmp 0x9814
addss %xmm7, %xmm3
mulss %xmm12, %xmm2
ucomiss %xmm11, %xmm2
ja 0x9826
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 0x21ed(%rip), %xmm2     # 0xba58
addss %xmm3, %xmm2
mulss %xmm2, %xmm1
jmp 0x9878
xorps %xmm1, %xmm1
addss %xmm1, %xmm0
incq %rax
jmp 0x97e8
testq %r15, %r15
sete %al
movss 0x8(%rsp), %xmm1
ucomiss %xmm0, %xmm1
seta %cl
orb %al, %cl
testb %cl, %cl
jne 0x989f
movaps %xmm1, %xmm0
cmovnel %r15d, %r12d
incq %r15
jmp 0x9727
movq 0x20(%rsp), %rax
imulq 0x28(%rsp), %rax
movq (%rsp), %rcx
movb %r12b, (%rcx,%rax)
movl %r12d, %eax
xorl %ecx, %ecx
movq 0x30(%rsp), %r15
movq 0x18(%rsp), %rsi
cmpq %rcx, %rbx
je 0x98e2
movq 0x50(%rsp,%rax,8), %rdx
movb (%rdx,%rcx), %dl
movb %dl, (%rsi,%rcx)
incq %rcx
jmp 0x98cd
movq 0x28(%rsp), %rax
incq %rax
addq 0x20(%rsp), %rsi
movq %rsi, 0x18(%rsp)
movq %r13, %rbp
movq %rax, %r13
jmp 0x970d
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0x9bac
movq 0x50(%rsp,%rbx,8), %rdi
callq 0x1030
incq %rbx
jmp 0x9901
movq %r15, 0x30(%rsp)
leaq 0x1(%rbx), %rsi
movl %ebp, %eax
movq %rax, 0x18(%rsp)
movq (%rsp), %rax
leaq 0x1(%rax), %rdi
xorl %r8d, %r8d
movq $0x0, 0x10(%rsp)
xorl %ebp, %ebp
xorl %r15d, %r15d
movq %rsi, 0x40(%rsp)
cmpq 0x18(%rsp), %r8
je 0x9a4e
movq %rdi, 0x28(%rsp)
movq %r8, 0x20(%rsp)
imulq %rbx, %r8
addq 0x30(%rsp), %r8
movq %r8, 0x8(%rsp)
xorl %r14d, %r14d
xorl %r12d, %r12d
cmpq $0x5, %r12
je 0x99fe
movq 0x80(%rsp,%r12,8), %r13
movzbl %r12b, %r9d
movq %r13, %rdi
movq 0x8(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq %rbx, %rcx
movq 0x38(%rsp), %r8
callq 0x9bc2
andq $0x0, 0x50(%rsp,%r12,8)
leaq (%rsp,%r14), %rsi
addq $0x50, %rsi
andq $0x0, 0x48(%rsp)
leaq 0x48(%rsp), %rdi
movq %r13, %rdx
movq %rbx, %rcx
leaq 0xb0(%rsp), %r8
callq 0x9db9
movq 0x48(%rsp), %rdi
callq 0x1030
testq %r14, %r14
sete %al
movq 0x50(%rsp,%r12,8), %rcx
cmpq %rbp, %rcx
setb %dl
orb %al, %dl
cmovneq %rcx, %rbp
cmovnel %r12d, %r15d
incq %r12
addq $0x8, %r14
jmp 0x9971
movq 0x40(%rsp), %rsi
movq %rsi, %rax
movq 0x20(%rsp), %r8
imulq %r8, %rax
movq (%rsp), %rcx
movb %r15b, (%rcx,%rax)
movl %r15d, %eax
xorl %ecx, %ecx
movq 0x28(%rsp), %rdi
cmpq %rcx, %rbx
je 0x9a39
movq 0x80(%rsp,%rax,8), %rdx
movb (%rdx,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
jmp 0x9a21
incq %r8
addq %rsi, %rdi
movq 0x8(%rsp), %rax
movq %rax, 0x10(%rsp)
jmp 0x9948
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0x9bac
movq 0x80(%rsp,%rbx,8), %rdi
callq 0x1030
incq %rbx
jmp 0x9a50
movq %r15, 0x30(%rsp)
leaq 0x1(%rbx), %rax
movq %rax, 0x10(%rsp)
movl %ebp, %eax
movq %rax, 0x18(%rsp)
movq (%rsp), %rax
leaq 0x1(%rax), %rsi
xorl %edi, %edi
xorl %r15d, %r15d
xorl %eax, %eax
movq $0x0, 0x8(%rsp)
cmpq 0x18(%rsp), %rdi
je 0x9b92
movq %rsi, 0x28(%rsp)
movq %rdi, 0x20(%rsp)
movq %rdi, %r13
imulq %rbx, %r13
addq 0x30(%rsp), %r13
xorl %ebp, %ebp
movzbl %al, %r12d
cmpq $0x5, %rbp
je 0x9b4b
movq 0xb0(%rsp,%rbp,8), %r14
movzbl %bpl, %r9d
movq %r14, %rdi
movq %r13, %rsi
movq 0x8(%rsp), %rdx
movq %rbx, %rcx
movq 0x38(%rsp), %r8
callq 0x9bc2
xorl %eax, %eax
xorl %ecx, %ecx
testq %rbp, %rbp
jne 0x9b21
cmpq %rcx, %rbx
je 0x9b26
movzbl (%r14,%rcx), %edx
addq %rdx, %rax
incq %rcx
jmp 0x9af7
movzbl (%r14,%rcx), %edx
movl %edx, %esi
xorl $0xff, %esi
testb %dl, %dl
cmovnsl %edx, %esi
addq %rsi, %rax
incq %rcx
cmpq %rcx, %rbx
jne 0x9b09
testq %rbp, %rbp
sete %cl
cmpq %r15, %rax
setb %dl
orb %cl, %dl
cmovneq %rax, %r15
movzbl %bpl, %eax
cmovnel %eax, %r12d
incq %rbp
movl %r12d, %eax
jmp 0x9abc
movq 0x10(%rsp), %rcx
movq 0x20(%rsp), %rdi
imulq %rdi, %rcx
movq (%rsp), %rdx
movb %r12b, (%rdx,%rcx)
xorl %ecx, %ecx
movq 0x28(%rsp), %rsi
cmpq %rcx, %rbx
je 0x9b80
movq 0xb0(%rsp,%r12,8), %rdx
movb (%rdx,%rcx), %dl
movb %dl, (%rsi,%rcx)
incq %rcx
jmp 0x9b68
incq %rdi
addq 0x10(%rsp), %rsi
movq %r13, 0x8(%rsp)
jmp 0x9a99
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0x9bac
movq 0xb0(%rsp,%rbx,8), %rdi
callq 0x1030
incq %rbx
jmp 0x9b94
xorl %ebp, %ebp
movl %ebp, %eax
addq $0x4b8, %rsp            # imm = 0x4B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq