// File: sbingner[P]kerneldec/lzfse/src/lzfse_decode.c
// Function: lzfse_decode_file_with_scratch
size_t lzfse_decode_file_with_scratch(FILE *dst_file, FILE *src_file, size_t src_size,
                                      int *error, void *__restrict scratch_buffer) {
  lzfse_decoder_state *s = (lzfse_decoder_state *)scratch_buffer;
  memset(s, 0x00, sizeof(*s));

  uint8_t *src_buf = malloc(DECODE_SRC_CHUNK_SIZE);
  if (src_buf == NULL) {
      if (error) *error = 1;
      return 0;
  }

  uint8_t *dst_buf = malloc(DECODE_DST_CHUNK_SIZE + LZFSE_ENCODE_MAX_D_VALUE);
  if (dst_buf == NULL) {
      if (error) *error = 1;
      return 0;
  }
  size_t dst_size = DECODE_DST_CHUNK_SIZE;

  int nr = fread(src_buf, 1, src_size?(src_size<DECODE_SRC_CHUNK_SIZE?src_size:DECODE_SRC_CHUNK_SIZE):DECODE_SRC_CHUNK_SIZE, src_file);
  if (nr < 0) {
      if (error) *error = 2;
      return 0;
  }
  src_size -= nr;

  // Initialize state
  s->src = src_buf;
  s->src_begin = src_buf;
  s->src_end = s->src + DECODE_SRC_CHUNK_SIZE;
  s->dst = dst_buf;
  s->dst_begin = dst_buf;
  s->dst_end = dst_buf + DECODE_DST_CHUNK_SIZE + LZFSE_ENCODE_MAX_D_VALUE;

  size_t written = 0;

  int status;
  while (s->end_of_stream == 0) {
      // Decode a block
      int status = lzfse_decode(s);
      if (error) *error = status;

      if (status == LZFSE_STATUS_ERROR) {
          return written;
      }

      int processed_data = 0;

      size_t dst_used = s->dst - s->dst_begin;
      if (dst_used > LZFSE_ENCODE_MAX_D_VALUE) {
          int num_to_write = dst_used - LZFSE_ENCODE_MAX_D_VALUE;
          processed_data = 1;
          int nw = fwrite(s->dst_begin, 1, num_to_write, dst_file);
          if (nw != num_to_write) {
              if (error) *error = 3;
              return written + (nw>0?nw:0);
          }
          written += num_to_write;
          memmove(s->dst_begin, s->dst_begin + num_to_write, LZFSE_ENCODE_MAX_D_VALUE);
          s->dst -= num_to_write;
      }

      size_t src_used = s->src - s->src_begin;
      size_t src_unused = s->src_end - s->src;
      if (src_used > 0) {
          processed_data = 1;
          memmove((uint8_t*)s->src_begin, s->src, src_unused);
          s->src = s->src_begin;
      }
      if (!processed_data) {
          if (error) *error = 4;
          fprintf(stderr, "lzfse not making progress, aborting.  Maybe we need larger buffers?\n");
          return written;
      }
      if (src_unused < DECODE_SRC_CHUNK_SIZE && src_size > 0) {
          size_t size_wanted = DECODE_SRC_CHUNK_SIZE - src_unused;
          size_t size_to_read = src_size?(src_size<size_wanted?src_size:size_wanted):size_wanted;
          nr = fread(src_buf + src_unused, 1, size_to_read, src_file);
          if (nr < 0) {
              if (error) *error = 2;
              return written;
          }
          src_size -= nr;
          s->src_end = s->src + src_unused + nr;
      }
  }

  size_t dst_used = s->dst - s->dst_begin;
  if (dst_used > 0) {
      int nw = fwrite(s->dst_begin, 1, dst_used, dst_file);
      if (nw != dst_used) {
          if (error) *error = 3;
          return written + (nw>0?nw:0);
      }
  }
  free(dst_buf);
  free(src_buf);

  return written; // bytes written
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
movq %r8, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rdi
xorl %esi, %esi
movl $0xb920, %edx           # imm = 0xB920
callq 0x3080
movl $0x40000, %edi          # imm = 0x40000
callq 0x30d0
movq %rax, -0x40(%rbp)
cmpq $0x0, -0x40(%rbp)
jne 0x3c9a
cmpq $0x0, -0x28(%rbp)
je 0x3c8d
movq -0x28(%rbp), %rax
movl $0x1, (%rax)
movq $0x0, -0x8(%rbp)
jmp 0x4197
movl $0x13fffb, %edi         # imm = 0x13FFFB
callq 0x30d0
movq %rax, -0x48(%rbp)
cmpq $0x0, -0x48(%rbp)
jne 0x3ccd
cmpq $0x0, -0x28(%rbp)
je 0x3cc0
movq -0x28(%rbp), %rax
movl $0x1, (%rax)
movq $0x0, -0x8(%rbp)
jmp 0x4197
movq $0x100000, -0x50(%rbp)  # imm = 0x100000
movq -0x40(%rbp), %rax
movq %rax, -0xb8(%rbp)
cmpq $0x0, -0x20(%rbp)
je 0x3d1c
cmpq $0x40000, -0x20(%rbp)   # imm = 0x40000
jae 0x3cfe
movq -0x20(%rbp), %rax
movq %rax, -0xc0(%rbp)
jmp 0x3d0c
movl $0x40000, %eax          # imm = 0x40000
movq %rax, -0xc0(%rbp)
jmp 0x3d0c
movq -0xc0(%rbp), %rax
movq %rax, -0xc8(%rbp)
jmp 0x3d2a
movl $0x40000, %eax          # imm = 0x40000
movq %rax, -0xc8(%rbp)
jmp 0x3d2a
movq -0xb8(%rbp), %rdi
movq -0xc8(%rbp), %rdx
movq -0x18(%rbp), %rcx
movl $0x1, %esi
callq 0x3040
movl %eax, -0x54(%rbp)
cmpl $0x0, -0x54(%rbp)
jge 0x3d6d
cmpq $0x0, -0x28(%rbp)
je 0x3d60
movq -0x28(%rbp), %rax
movl $0x2, (%rax)
movq $0x0, -0x8(%rbp)
jmp 0x4197
movslq -0x54(%rbp), %rcx
movq -0x20(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x20(%rbp)
movq -0x40(%rbp), %rcx
movq -0x38(%rbp), %rax
movq %rcx, (%rax)
movq -0x40(%rbp), %rcx
movq -0x38(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x38(%rbp), %rax
movq (%rax), %rcx
addq $0x40000, %rcx          # imm = 0x40000
movq -0x38(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x48(%rbp), %rcx
movq -0x38(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x48(%rbp), %rcx
movq -0x38(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x48(%rbp), %rcx
addq $0x100000, %rcx         # imm = 0x100000
addq $0x3fffb, %rcx          # imm = 0x3FFFB
movq -0x38(%rbp), %rax
movq %rcx, 0x28(%rax)
movq $0x0, -0x60(%rbp)
movq -0x38(%rbp), %rax
cmpl $0x0, 0x30(%rax)
jne 0x40ca
movq -0x38(%rbp), %rdi
callq 0x7870
movl %eax, -0x68(%rbp)
cmpq $0x0, -0x28(%rbp)
je 0x3e0d
movl -0x68(%rbp), %ecx
movq -0x28(%rbp), %rax
movl %ecx, (%rax)
cmpl $-0x3, -0x68(%rbp)
jne 0x3e20
movq -0x60(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x4197
movl $0x0, -0x6c(%rbp)
movq -0x38(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x38(%rbp), %rcx
movq 0x20(%rcx), %rcx
subq %rcx, %rax
movq %rax, -0x78(%rbp)
cmpq $0x3fffb, -0x78(%rbp)   # imm = 0x3FFFB
jbe 0x3f1f
movq -0x78(%rbp), %rax
subq $0x3fffb, %rax          # imm = 0x3FFFB
movl %eax, -0x7c(%rbp)
movl $0x1, -0x6c(%rbp)
movq -0x38(%rbp), %rax
movq 0x20(%rax), %rdi
movslq -0x7c(%rbp), %rdx
movq -0x10(%rbp), %rcx
movl $0x1, %esi
callq 0x3130
movl %eax, -0x80(%rbp)
movl -0x80(%rbp), %eax
cmpl -0x7c(%rbp), %eax
je 0x3ed8
cmpq $0x0, -0x28(%rbp)
je 0x3e96
movq -0x28(%rbp), %rax
movl $0x3, (%rax)
movq -0x60(%rbp), %rax
movq %rax, -0xd0(%rbp)
cmpl $0x0, -0x80(%rbp)
jle 0x3eb2
movl -0x80(%rbp), %eax
movl %eax, -0xd4(%rbp)
jmp 0x3ebc
xorl %eax, %eax
movl %eax, -0xd4(%rbp)
jmp 0x3ebc
movq -0xd0(%rbp), %rax
movl -0xd4(%rbp), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x8(%rbp)
jmp 0x4197
movslq -0x7c(%rbp), %rax
addq -0x60(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x38(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0x38(%rbp), %rax
movq 0x20(%rax), %rsi
movslq -0x7c(%rbp), %rax
addq %rax, %rsi
movl $0x3fffb, %edx          # imm = 0x3FFFB
callq 0x30f0
movl -0x7c(%rbp), %edx
movq -0x38(%rbp), %rax
movq 0x18(%rax), %rcx
movslq %edx, %rsi
xorl %edx, %edx
subq %rsi, %rdx
addq %rdx, %rcx
movq %rcx, 0x18(%rax)
movq -0x38(%rbp), %rax
movq (%rax), %rax
movq -0x38(%rbp), %rcx
movq 0x8(%rcx), %rcx
subq %rcx, %rax
movq %rax, -0x88(%rbp)
movq -0x38(%rbp), %rax
movq 0x10(%rax), %rax
movq -0x38(%rbp), %rcx
movq (%rcx), %rcx
subq %rcx, %rax
movq %rax, -0x90(%rbp)
cmpq $0x0, -0x88(%rbp)
jbe 0x3f8c
movl $0x1, -0x6c(%rbp)
movq -0x38(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x38(%rbp), %rax
movq (%rax), %rsi
movq -0x90(%rbp), %rdx
callq 0x30f0
movq -0x38(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x38(%rbp), %rax
movq %rcx, (%rax)
cmpl $0x0, -0x6c(%rbp)
jne 0x3fc8
cmpq $0x0, -0x28(%rbp)
je 0x3fa3
movq -0x28(%rbp), %rax
movl $0x4, (%rax)
movq 0xf04e(%rip), %rax      # 0x12ff8
movq (%rax), %rdi
leaq 0xc5cc(%rip), %rsi      # 0x10580
movb $0x0, %al
callq 0x30b0
movq -0x60(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x4197
cmpq $0x40000, -0x90(%rbp) # imm = 0x40000
jae 0x40c5
cmpq $0x0, -0x20(%rbp)
jbe 0x40c5
movl $0x40000, %eax          # imm = 0x40000
subq -0x90(%rbp), %rax
movq %rax, -0x98(%rbp)
cmpq $0x0, -0x20(%rbp)
je 0x4036
movq -0x20(%rbp), %rax
cmpq -0x98(%rbp), %rax
jae 0x4018
movq -0x20(%rbp), %rax
movq %rax, -0xe0(%rbp)
jmp 0x4026
movq -0x98(%rbp), %rax
movq %rax, -0xe0(%rbp)
movq -0xe0(%rbp), %rax
movq %rax, -0xe8(%rbp)
jmp 0x4044
movq -0x98(%rbp), %rax
movq %rax, -0xe8(%rbp)
movq -0xe8(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0x40(%rbp), %rdi
addq -0x90(%rbp), %rdi
movq -0xa0(%rbp), %rdx
movq -0x18(%rbp), %rcx
movl $0x1, %esi
callq 0x3040
movl %eax, -0x54(%rbp)
cmpl $0x0, -0x54(%rbp)
jge 0x4099
cmpq $0x0, -0x28(%rbp)
je 0x408c
movq -0x28(%rbp), %rax
movl $0x2, (%rax)
movq -0x60(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x4197
movslq -0x54(%rbp), %rcx
movq -0x20(%rbp), %rax
subq %rcx, %rax
movq %rax, -0x20(%rbp)
movq -0x38(%rbp), %rax
movq (%rax), %rcx
addq -0x90(%rbp), %rcx
movslq -0x54(%rbp), %rax
addq %rax, %rcx
movq -0x38(%rbp), %rax
movq %rcx, 0x10(%rax)
jmp 0x3de3
movq -0x38(%rbp), %rax
movq 0x18(%rax), %rax
movq -0x38(%rbp), %rcx
movq 0x20(%rcx), %rcx
subq %rcx, %rax
movq %rax, -0xa8(%rbp)
cmpq $0x0, -0xa8(%rbp)
jbe 0x417d
movq -0x38(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0xa8(%rbp), %rdx
movq -0x10(%rbp), %rcx
movl $0x1, %esi
callq 0x3130
movl %eax, -0xac(%rbp)
movslq -0xac(%rbp), %rax
cmpq -0xa8(%rbp), %rax
je 0x417b
cmpq $0x0, -0x28(%rbp)
je 0x4136
movq -0x28(%rbp), %rax
movl $0x3, (%rax)
movq -0x60(%rbp), %rax
movq %rax, -0xf0(%rbp)
cmpl $0x0, -0xac(%rbp)
jle 0x4158
movl -0xac(%rbp), %eax
movl %eax, -0xf4(%rbp)
jmp 0x4162
xorl %eax, %eax
movl %eax, -0xf4(%rbp)
jmp 0x4162
movq -0xf0(%rbp), %rax
movl -0xf4(%rbp), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x8(%rbp)
jmp 0x4197
jmp 0x417d
movq -0x48(%rbp), %rdi
callq 0x3030
movq -0x40(%rbp), %rdi
callq 0x3030
movq -0x60(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
nopw %cs:(%rax,%rax)