// File: /workspace/github_cpp_makefile_star2_O1/lvandeve[P]lodepng/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* color, const LodePNGEncoderSettings* settings) {
  /*
  For PNG filter method 0
  out must be a buffer with as size: h + (w * h * bpp + 7u) / 8u, because there are
  the scanlines with 1 extra byte per scanline
  */

  unsigned bpp = lodepng_get_bpp(color);
  /*the width of a scanline in bytes, not including the filter type*/
  size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u;

  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
  size_t bytewidth = (bpp + 7u) / 8u;
  const unsigned char* prevline = 0;
  unsigned x, y;
  unsigned error = 0;
  LodePNGFilterStrategy strategy = settings->filter_strategy;

  if(settings->filter_palette_zero && (color->colortype == LCT_PALETTE || color->bitdepth < 8)) {
    /*if the filter_palette_zero setting is enabled, override the filter strategy with
    zero for all scanlines for palette and less-than-8-bitdepth images*/
    strategy = LFS_ZERO;
  }

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

  if(strategy >= LFS_ZERO && strategy <= LFS_FOUR) {
    unsigned char type = (unsigned char)strategy;
    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] = type; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
      prevline = &in[inindex];
    }
  } else if(strategy == LFS_MINSUM) {
    /*adaptive filtering: independently for each row, try all five filter types and select the one that produces the
    smallest sum of absolute values per row.*/
    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]) error = 83; /*alloc fail*/
    }

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

          /*calculate the sum of the result*/
          if(type == 0) {
            for(x = 0; x != linebytes; ++x) sum += (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 += 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 < smallest) {
            bestType = type;
            smallest = sum;
          }
        }

        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) {
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t bestSum = 0;
    unsigned type, bestType = 0;
    unsigned count[256];

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

    if(!error) {
      for(y = 0; y != h; ++y) {
        /*try the 5 filter types*/
        for(type = 0; type != 5; ++type) {
          size_t sum = 0;
          filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
          lodepng_memset(count, 0, 256 * sizeof(*count));
          for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]];
          ++count[type]; /*the filter type itself is part of the scanline*/
          for(x = 0; x != 256; ++x) {
            sum += ilog2i(count[x]);
          }
          /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
          if(type == 0 || sum > bestSum) {
            bestType = type;
            bestSum = sum;
          }
        }

        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;
    lodepng_memcpy(&zlibsettings, &settings->zlibsettings, sizeof(LodePNGCompressSettings));
    /*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]) error = 83; /*alloc fail*/
    }
    if(!error) {
      for(y = 0; y != h; ++y) /*try the 5 filter types*/ {
        for(type = 0; type != 5; ++type) {
          unsigned testsize = (unsigned)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
movq %r9, %rbx
movl %ecx, %ebp
movl %edx, %r15d
movq %rsi, 0x30(%rsp)
movq %rdi, 0x10(%rsp)
movl (%r8), %r12d
movl 0x4(%r8), %r14d
movl %r12d, %edi
callq 0x5468
imull %r14d, %eax
movl 0x38(%rbx), %ecx
xorl %edx, %edx
cmpl $0x8, %r14d
movl %ecx, %esi
cmovbl %edx, %esi
cmpl $0x3, %r12d
cmovel %edx, %esi
cmpl $0x0, 0x34(%rbx)
cmovel %ecx, %esi
testl %eax, %eax
je 0x10310
movl %r15d, %ecx
shrl $0x3, %ecx
imulq %rax, %rcx
andl $0x7, %r15d
imull %eax, %r15d
addl $0x7, %r15d
shrl $0x3, %r15d
leaq (%rcx,%r15), %r13
leaq (%rcx,%r15), %rdx
incq %rdx
addl $0x7, %eax
shrl $0x3, %eax
movq %rax, 0x40(%rsp)
cmpl $0x4, %esi
ja 0x1031a
testl %ebp, %ebp
je 0x10309
movl %ebp, %r14d
movq %rdx, 0x20(%rsp)
movq 0x10(%rsp), %r12
incq %r12
movzbl %sil, %ebx
xorl %edx, %edx
movq 0x40(%rsp), %rbp
movq 0x30(%rsp), %rax
movq %rax, %r15
movb %bl, -0x1(%r12)
movq %r12, %rdi
movq %rax, %rsi
movq %r13, %rcx
movq %rbp, %r8
movl %ebx, %r9d
callq 0x108f6
addq 0x20(%rsp), %r12
leaq (%r15,%r13), %rax
movq %r15, %rdx
decq %r14
jne 0x102dc
xorl %eax, %eax
jmp 0x108e4
movl $0x1f, %eax
jmp 0x108e4
addl $-0x5, %esi
cmpl $0x3, %esi
ja 0x108df
leaq 0x61ec3(%rip), %rcx     # 0x721f0
movslq (%rcx,%rsi,4), %rax
addq %rcx, %rax
movq %rdx, 0x20(%rsp)
jmpq *%rax
xorl %ebx, %ebx
movl $0x53, %r14d
xorl %r15d, %r15d
movq %r13, %rdi
callq 0x22a0
movq %rax, 0xc0(%rsp,%rbx,8)
testq %rax, %rax
cmovel %r14d, %r15d
incq %rbx
cmpq $0x5, %rbx
jne 0x10346
movq %r15, 0x28(%rsp)
testl %r15d, %r15d
setne %al
testl %ebp, %ebp
sete %cl
orb %al, %cl
jne 0x104a7
movl %ebp, %eax
movq %rax, 0x18(%rsp)
xorl %r8d, %r8d
movq $0x0, 0x8(%rsp)
xorl %r14d, %r14d
xorl %ebp, %ebp
movq 0x8(%rsp), %r15
movq %r13, %rax
movq %r8, 0x38(%rsp)
imulq %r8, %rax
addq 0x30(%rsp), %rax
movq %rax, 0x8(%rsp)
xorl %r12d, %r12d
movq 0xc0(%rsp,%r12,8), %rbx
movzbl %r12b, %r9d
movq %rbx, %rdi
movq 0x8(%rsp), %rsi
movq %r15, %rdx
movq %r13, %rcx
movq 0x40(%rsp), %r8
callq 0x108f6
testq %r12, %r12
je 0x1040a
testq %r13, %r13
je 0x1042a
movl $0x1, %ecx
xorl %edx, %edx
xorl %eax, %eax
movzbl (%rbx,%rdx), %edx
movl %edx, %esi
xorl $0xff, %esi
testb %dl, %dl
cmovnsl %edx, %esi
addq %rsi, %rax
movl %ecx, %edx
incl %ecx
cmpq %rdx, %r13
jne 0x103eb
jmp 0x1042c
testq %r13, %r13
je 0x1042a
movl $0x1, %ecx
xorl %edx, %edx
xorl %eax, %eax
movzbl (%rbx,%rdx), %edx
addq %rdx, %rax
movl %ecx, %edx
incl %ecx
cmpq %rdx, %r13
jne 0x10418
jmp 0x1042c
xorl %eax, %eax
testq %r12, %r12
sete %cl
cmpq %rbp, %rax
setb %dl
orb %cl, %dl
cmovneq %rax, %rbp
movzbl %r14b, %r14d
cmovnel %r12d, %r14d
incq %r12
cmpq $0x5, %r12
jne 0x103b4
movq 0x20(%rsp), %rax
movq 0x38(%rsp), %r8
imulq %r8, %rax
movq 0x10(%rsp), %rcx
movb %r14b, (%rcx,%rax)
testq %r13, %r13
je 0x10499
addq 0x10(%rsp), %rax
movzbl %r14b, %ecx
movq 0xc0(%rsp,%rcx,8), %rcx
movl $0x1, %edx
xorl %esi, %esi
movb (%rcx,%rsi), %dil
movb %dil, 0x1(%rax,%rsi)
movl %edx, %esi
incl %edx
cmpq %rsi, %r13
jne 0x10487
incq %r8
cmpq 0x18(%rsp), %r8
jne 0x10396
xorl %ebx, %ebx
movq 0xc0(%rsp,%rbx,8), %rdi
callq 0x2290
incq %rbx
cmpq $0x5, %rbx
jne 0x104a9
jmp 0x108d8
movups (%rbx), %xmm0
movups 0x10(%rbx), %xmm1
movups 0x20(%rbx), %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 %ebx, %ebx
movl $0x53, %r14d
xorl %r15d, %r15d
movq %r13, %rdi
callq 0x22a0
movq %rax, 0x90(%rsp,%rbx,8)
testq %rax, %rax
cmovel %r14d, %r15d
incq %rbx
cmpq $0x5, %rbx
jne 0x10508
movq %r15, 0x28(%rsp)
testl %r15d, %r15d
setne %al
testl %ebp, %ebp
sete %cl
orb %al, %cl
jne 0x1065b
movl %r13d, %eax
movq %rax, 0x38(%rsp)
movl %ebp, %eax
movq %rax, 0x50(%rsp)
xorl %r8d, %r8d
movl $0x0, 0x18(%rsp)
xorl %r15d, %r15d
movq $0x0, 0x8(%rsp)
movq 0x8(%rsp), %rbx
movq %r13, %rax
movq %r8, 0x58(%rsp)
imulq %r8, %rax
addq 0x30(%rsp), %rax
movq %rax, 0x8(%rsp)
xorl %r14d, %r14d
xorl %r12d, %r12d
movq 0x90(%rsp,%r12,8), %rbp
movzbl %r12b, %r9d
movq %rbp, %rdi
movq 0x8(%rsp), %rsi
movq %rbx, %rdx
movq %r13, %rcx
movq 0x40(%rsp), %r8
callq 0x108f6
leaq (%rsp,%r14), %rsi
addq $0x60, %rsi
xorl %eax, %eax
movq %rax, 0x60(%rsp,%r12,8)
movq %rax, 0x48(%rsp)
leaq 0x48(%rsp), %rdi
movq %rbp, %rdx
movq 0x38(%rsp), %rcx
leaq 0xc0(%rsp), %r8
callq 0xd16b
movq 0x48(%rsp), %rdi
callq 0x2290
testq %r12, %r12
je 0x105ef
cmpq %r15, 0x60(%rsp,%r12,8)
jae 0x105f9
movq 0x60(%rsp,%r12,8), %r15
movl %r12d, 0x18(%rsp)
incq %r12
addq $0x8, %r14
cmpq $0x5, %r12
jne 0x10587
movq 0x20(%rsp), %rax
movq 0x58(%rsp), %r8
imulq %r8, %rax
movq 0x10(%rsp), %rcx
movl 0x18(%rsp), %edx
movb %dl, (%rcx,%rax)
testq %r13, %r13
je 0x1064d
addq %rcx, %rax
movl 0x18(%rsp), %ecx
movq 0x90(%rsp,%rcx,8), %rcx
movl $0x1, %edx
xorl %esi, %esi
movb (%rcx,%rsi), %dil
movb %dil, 0x1(%rax,%rsi)
movl %edx, %esi
incl %edx
cmpq %rsi, %r13
jne 0x1063b
incq %r8
cmpq 0x50(%rsp), %r8
jne 0x10566
xorl %ebx, %ebx
movq 0x90(%rsp,%rbx,8), %rdi
callq 0x2290
incq %rbx
cmpq $0x5, %rbx
jne 0x1065d
jmp 0x108d8
testl %ebp, %ebp
je 0x10309
movl %ebp, %eax
movq %rax, 0x8(%rsp)
movq 0x10(%rsp), %rbp
incq %rbp
xorl %r12d, %r12d
xorl %edx, %edx
movq 0x40(%rsp), %r14
movq 0x30(%rsp), %rax
movq %rax, %r15
movq 0x40(%rbx), %rax
movzbl (%rax,%r12), %r9d
movb %r9b, -0x1(%rbp)
movq %rbp, %rdi
movq %r15, %rsi
movq %r13, %rcx
movq %r14, %r8
callq 0x108f6
incq %r12
addq 0x20(%rsp), %rbp
leaq (%r15,%r13), %rax
movq %r15, %rdx
cmpq %r12, 0x8(%rsp)
jne 0x1069e
jmp 0x10309
xorl %ebx, %ebx
movl $0x53, %r14d
xorl %r15d, %r15d
movq %r13, %rdi
callq 0x22a0
movq %rax, 0x60(%rsp,%rbx,8)
testq %rax, %rax
cmovel %r14d, %r15d
incq %rbx
cmpq $0x5, %rbx
jne 0x106e5
movq %r15, 0x28(%rsp)
testl %r15d, %r15d
setne %al
testl %ebp, %ebp
sete %cl
orb %al, %cl
jne 0x108c3
movl %ebp, %eax
movq %rax, 0x18(%rsp)
xorl %r8d, %r8d
movq $0x0, 0x8(%rsp)
xorl %ebp, %ebp
xorl %r14d, %r14d
movq 0x8(%rsp), %r12
movq %r13, %rax
movq %r8, 0x38(%rsp)
imulq %r8, %rax
addq 0x30(%rsp), %rax
movq %rax, 0x8(%rsp)
xorl %r15d, %r15d
movq 0x60(%rsp,%r15,8), %rbx
movzbl %r15b, %r9d
movq %rbx, %rdi
movq 0x8(%rsp), %rsi
movq %r12, %rdx
movq %r13, %rcx
movq 0x40(%rsp), %r8
callq 0x108f6
movl $0x400, %edx            # imm = 0x400
leaq 0xc0(%rsp), %rdi
xorl %esi, %esi
callq 0x2140
testq %r13, %r13
je 0x107a5
movl $0x1, %eax
xorl %ecx, %ecx
movzbl (%rbx,%rcx), %ecx
incl 0xc0(%rsp,%rcx,4)
movl %eax, %ecx
incl %eax
cmpq %rcx, %r13
jne 0x10791
incl 0xc0(%rsp,%r15,4)
xorl %edx, %edx
xorl %eax, %eax
movl 0xc0(%rsp,%rdx,4), %esi
testq %rsi, %rsi
je 0x1083c
movl %esi, %ecx
shrl $0x10, %ecx
xorl %edi, %edi
cmpl $0x10000, %esi          # imm = 0x10000
setae %dil
cmovbq %rsi, %rcx
shll $0x4, %edi
leaq 0x8(%rdi), %r8
movl %ecx, %r9d
shrl $0x8, %r9d
cmpq $0x100, %rcx            # imm = 0x100
cmovbq %rcx, %r9
cmovbq %rdi, %r8
leaq 0x4(%r8), %rdi
movl %r9d, %r10d
shrl $0x4, %r10d
cmpq $0x10, %r9
cmovbq %r9, %r10
cmovbq %r8, %rdi
leaq 0x2(%rdi), %rcx
movl %r10d, %r8d
shrl $0x2, %r8d
cmpq $0x4, %r10
cmovbq %r10, %r8
cmovbq %rdi, %rcx
cmpl $0x2, %r8d
sbbq $-0x1, %rcx
movq $-0x1, %rdi
shlq %cl, %rdi
imulq %rsi, %rcx
addq %rsi, %rdi
leaq (%rcx,%rdi,2), %rcx
jmp 0x1083e
xorl %ecx, %ecx
addq %rcx, %rax
incq %rdx
cmpq $0x100, %rdx            # imm = 0x100
jne 0x107b1
testq %r15, %r15
sete %cl
cmpq %r14, %rax
seta %dl
orb %cl, %dl
cmovneq %rax, %r14
cmovnel %r15d, %ebp
incq %r15
cmpq $0x5, %r15
jne 0x10750
movq 0x20(%rsp), %rax
movq 0x38(%rsp), %r8
imulq %r8, %rax
movq 0x10(%rsp), %rcx
movb %bpl, (%rcx,%rax)
testq %r13, %r13
je 0x108b5
addq 0x10(%rsp), %rax
movl %ebp, %ecx
movq 0x60(%rsp,%rcx,8), %rcx
movl $0x1, %edx
xorl %esi, %esi
movb (%rcx,%rsi), %dil
movb %dil, 0x1(%rax,%rsi)
movl %edx, %esi
incl %edx
cmpq %rsi, %r13
jne 0x108a3
incq %r8
cmpq 0x18(%rsp), %r8
jne 0x10732
xorl %ebx, %ebx
movq 0x60(%rsp,%rbx,8), %rdi
callq 0x2290
incq %rbx
cmpq $0x5, %rbx
jne 0x108c5
movq 0x28(%rsp), %rax
jmp 0x108e4
movl $0x58, %eax
addq $0x4c8, %rsp            # imm = 0x4C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq