// File: /workspace/github_cpp_makefile_star2_O2/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, %r14
movq %r8, %r13
movl %ecx, %ebp
movl %edx, %r12d
movq %rsi, 0x20(%rsp)
movq %rdi, 0x18(%rsp)
movq %r8, %rdi
callq 0x4b00
movl %r12d, %ecx
shrl $0x3, %ecx
movl %eax, %edx
imulq %rcx, %rdx
andl $0x7, %r12d
imull %eax, %r12d
addl $0x7, %r12d
shrl $0x3, %r12d
leaq (%rdx,%r12), %r15
leaq (%rdx,%r12), %rcx
incq %rcx
movq %rcx, 0x38(%rsp)
leal 0x7(%rax), %ecx
shrl $0x3, %ecx
movq %rcx, 0x40(%rsp)
movl 0x38(%r14), %ecx
cmpl $0x0, 0x34(%r14)
pushq $0x1f
popq %r12
je 0xdec4
cmpl $0x3, (%r13)
je 0xdeb9
cmpl $0x8, 0x4(%r13)
jae 0xdec4
xorl %ecx, %ecx
testl %eax, %eax
jne 0xded1
jmp 0xe052
testl %eax, %eax
je 0xe052
cmpl $0x4, %ecx
ja 0xdf1b
movl %ebp, %ebx
movq 0x18(%rsp), %r12
incq %r12
movzbl %cl, %ebp
xorl %edx, %edx
movq 0x20(%rsp), %rax
subq $0x1, %rbx
jb 0xe04f
movq %rax, %r14
movb %bpl, -0x1(%r12)
movq %r12, %rdi
movq %rax, %rsi
movq %r15, %rcx
movq 0x40(%rsp), %r8
movl %ebp, %r9d
callq 0xe4d5
addq 0x38(%rsp), %r12
leaq (%r14,%r15), %rax
movq %r14, %rdx
jmp 0xdee5
addl $-0x5, %ecx
cmpl $0x3, %ecx
ja 0xe0eb
leaq 0x4e2de(%rip), %rax     # 0x5c20c
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
xorl %ebx, %ebx
pushq $0x53
popq %r14
xorl %r12d, %r12d
cmpq $0x5, %rbx
je 0xe08f
movq %r15, %rdi
callq 0x2280
movq %rax, 0xc0(%rsp,%rbx,8)
testq %rax, %rax
cmovel %r14d, %r12d
incq %rbx
jmp 0xdf40
leaq 0xc0(%rsp), %r13
pushq $0x30
popq %rdx
movq %r13, %rdi
movq %r14, %rsi
callq 0x4a08
movl $0x1, (%r13)
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%r13)
xorl %ebx, %ebx
pushq $0x53
popq %r14
movq $0x0, 0x8(%rsp)
movq 0x18(%rsp), %r12
cmpq $0x5, %rbx
je 0xdfcc
movq %r15, %rdi
callq 0x2280
movq %rax, 0x90(%rsp,%rbx,8)
testq %rax, %rax
movq 0x8(%rsp), %rax
cmovel %r14d, %eax
movq %rax, 0x8(%rsp)
incq %rbx
jmp 0xdfa0
cmpl $0x0, 0x8(%rsp)
movq 0x20(%rsp), %rax
je 0xe0f4
xorl %ebx, %ebx
movq 0x8(%rsp), %r12
cmpq $0x5, %rbx
je 0xe052
movq 0x90(%rsp,%rbx,8), %rdi
callq 0x2260
incq %rbx
jmp 0xdfe3
movl %ebp, %ebx
incq 0x18(%rsp)
xorl %r12d, %r12d
xorl %edx, %edx
movq 0x20(%rsp), %rax
cmpq %r12, %rbx
je 0xe04f
movq %rax, %r13
movq 0x40(%r14), %rax
movzbl (%rax,%r12), %r9d
movq 0x18(%rsp), %rbp
movb %r9b, -0x1(%rbp)
movq %rbp, %rdi
movq %r13, %rsi
movq %r15, %rcx
movq 0x40(%rsp), %r8
callq 0xe4d5
incq %r12
addq 0x38(%rsp), %rbp
movq %rbp, 0x18(%rsp)
leaq (%r15,%r13), %rax
movq %r13, %rdx
jmp 0xe00c
xorl %r12d, %r12d
movl %r12d, %eax
addq $0x4c8, %rsp            # imm = 0x4C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
xorl %ebx, %ebx
pushq $0x53
popq %r14
xorl %r12d, %r12d
cmpq $0x5, %rbx
je 0xe0b7
movq %r15, %rdi
callq 0x2280
movq %rax, 0x60(%rsp,%rbx,8)
testq %rax, %rax
cmovel %r14d, %r12d
incq %rbx
jmp 0xe070
movq %r12, 0x8(%rsp)
testl %r12d, %r12d
je 0xe219
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0xe0e1
movq 0xc0(%rsp,%rbx,8), %rdi
callq 0x2260
incq %rbx
jmp 0xe09f
movq %r12, 0x8(%rsp)
testl %r12d, %r12d
movq 0x20(%rsp), %rax
je 0xe323
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0xe0e1
movq 0x60(%rsp,%rbx,8), %rdi
callq 0x2260
incq %rbx
jmp 0xe0cc
movq 0x8(%rsp), %r12
jmp 0xe052
pushq $0x58
popq %r12
jmp 0xe052
movl %r15d, %ecx
movq %rcx, 0x30(%rsp)
movl %ebp, %ecx
movq %rcx, 0x58(%rsp)
xorl %edi, %edi
movq $0x0, 0x28(%rsp)
xorl %ebx, %ebx
xorl %r14d, %r14d
cmpq 0x58(%rsp), %rdi
je 0xdfdc
movq %r15, %rcx
movq %rdi, 0x48(%rsp)
imulq %rdi, %rcx
addq %rax, %rcx
movq %rcx, 0x10(%rsp)
xorl %r13d, %r13d
xorl %ebp, %ebp
cmpq $0x5, %rbp
je 0xe1cb
movq 0x90(%rsp,%rbp,8), %r12
movzbl %bpl, %r9d
movq %r12, %rdi
movq 0x10(%rsp), %rsi
movq 0x28(%rsp), %rdx
movq %r15, %rcx
movq 0x40(%rsp), %r8
callq 0xe4d5
andq $0x0, 0x60(%rsp,%rbp,8)
leaq (%rsp,%r13), %rsi
addq $0x60, %rsi
andq $0x0, 0x50(%rsp)
leaq 0x50(%rsp), %rdi
movq %r12, %rdx
movq 0x18(%rsp), %r12
movq 0x30(%rsp), %rcx
leaq 0xc0(%rsp), %r8
callq 0xb81a
movq 0x50(%rsp), %rdi
callq 0x2260
testq %r13, %r13
sete %al
movq 0x60(%rsp,%rbp,8), %rcx
cmpq %rbx, %rcx
setb %dl
orb %al, %dl
cmovneq %rcx, %rbx
cmovnel %ebp, %r14d
incq %rbp
addq $0x8, %r13
jmp 0xe137
movq 0x38(%rsp), %rcx
movq 0x48(%rsp), %rdi
imulq %rdi, %rcx
leaq (%r12,%rcx), %rax
movb %r14b, (%r12,%rcx)
movl %r14d, %ecx
xorl %edx, %edx
movl %edx, %edx
cmpq %rdx, %r15
je 0xe202
movq 0x90(%rsp,%rcx,8), %rsi
movb (%rsi,%rdx), %sil
movb %sil, 0x1(%rax,%rdx)
incl %edx
jmp 0xe1e6
incq %rdi
movq 0x10(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x20(%rsp), %rax
jmp 0xe113
movl %ebp, %eax
movq %rax, 0x30(%rsp)
xorl %edi, %edi
xorl %r12d, %r12d
xorl %eax, %eax
movq $0x0, 0x10(%rsp)
cmpq 0x30(%rsp), %rdi
je 0xe09d
movq %r15, %r14
movq %rdi, 0x28(%rsp)
imulq %rdi, %r14
addq 0x20(%rsp), %r14
xorl %ebp, %ebp
movzbl %al, %ebx
cmpq $0x5, %rbp
je 0xe2de
movq 0xc0(%rsp,%rbp,8), %r13
movzbl %bpl, %r9d
movq %r13, %rdi
movq %r14, %rsi
movq 0x10(%rsp), %rdx
movq %r15, %rcx
movq 0x40(%rsp), %r8
callq 0xe4d5
xorl %eax, %eax
xorl %ecx, %ecx
testq %rbp, %rbp
je 0xe2b4
movl %ecx, %ecx
cmpq %rcx, %r15
je 0xe2bb
movzbl (%r13,%rcx), %edx
movl %edx, %esi
xorl $0xff, %esi
testb %dl, %dl
cmovnsl %edx, %esi
addq %rsi, %rax
incl %ecx
jmp 0xe288
movzbl (%r13,%rcx), %edx
addq %rdx, %rax
incl %ecx
movl %ecx, %ecx
cmpq %rcx, %r15
jne 0xe2a9
testq %rbp, %rbp
sete %cl
cmpq %r12, %rax
setb %dl
orb %cl, %dl
cmovneq %rax, %r12
movzbl %bpl, %eax
cmovnel %eax, %ebx
incq %rbp
movl %ebx, %eax
jmp 0xe24e
movq 0x38(%rsp), %rdx
movq 0x28(%rsp), %rdi
imulq %rdi, %rdx
movq 0x18(%rsp), %rsi
leaq (%rsi,%rdx), %rcx
movb %bl, (%rsi,%rdx)
xorl %edx, %edx
movl %edx, %edx
cmpq %rdx, %r15
je 0xe316
movq 0xc0(%rsp,%rbx,8), %rsi
movb (%rsi,%rdx), %sil
movb %sil, 0x1(%rcx,%rdx)
incl %edx
jmp 0xe2fa
incq %rdi
movq %r14, 0x10(%rsp)
jmp 0xe230
movl %ebp, %ecx
movq %rcx, 0x48(%rsp)
xorl %edi, %edi
pushq $-0x1
popq %r12
xorl %r14d, %r14d
xorl %ebp, %ebp
movq $0x0, 0x28(%rsp)
cmpq 0x48(%rsp), %rdi
je 0xe0ca
movq %r15, %rcx
movq %rdi, 0x30(%rsp)
imulq %rdi, %rcx
addq %rax, %rcx
movq %rcx, 0x10(%rsp)
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0xe486
movq 0x60(%rsp,%rbx,8), %r13
movzbl %bl, %r9d
movq %r13, %rdi
movq 0x10(%rsp), %rsi
movq 0x28(%rsp), %rdx
movq %r15, %rcx
movq 0x40(%rsp), %r8
callq 0xe4d5
xorl %eax, %eax
cmpq $0x400, %rax            # imm = 0x400
je 0xe3a3
movb $0x0, 0xc0(%rsp,%rax)
incq %rax
jmp 0xe38e
xorl %eax, %eax
movl %eax, %eax
cmpq %rax, %r15
je 0xe3bd
movzbl (%r13,%rax), %ecx
incl 0xc0(%rsp,%rcx,4)
incl %eax
jmp 0xe3a5
incl 0xc0(%rsp,%rbx,4)
xorl %edx, %edx
xorl %eax, %eax
cmpq $0x100, %rdx            # imm = 0x100
je 0xe469
movl 0xc0(%rsp,%rdx,4), %esi
testq %rsi, %rsi
je 0xe45c
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 %r12, %rdi
shlq %cl, %rdi
imulq %rsi, %rcx
addq %rsi, %rdi
leaq (%rcx,%rdi,2), %rcx
jmp 0xe45e
xorl %ecx, %ecx
addq %rcx, %rax
incq %rdx
jmp 0xe3c8
testq %rbx, %rbx
sete %cl
cmpq %r14, %rax
seta %dl
orb %cl, %dl
cmovneq %rax, %r14
cmovnel %ebx, %ebp
incq %rbx
jmp 0xe35f
movq 0x38(%rsp), %rcx
movq 0x30(%rsp), %rdi
imulq %rdi, %rcx
movq 0x18(%rsp), %rdx
leaq (%rdx,%rcx), %rax
movb %bpl, (%rdx,%rcx)
movl %ebp, %ecx
xorl %edx, %edx
movl %edx, %edx
cmpq %rdx, %r15
je 0xe4be
movq 0x60(%rsp,%rcx,8), %rsi
movb (%rsi,%rdx), %sil
movb %sil, 0x1(%rax,%rdx)
incl %edx
jmp 0xe4a5
incq %rdi
movq 0x10(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x20(%rsp), %rax
jmp 0xe33e