// File: /workspace/github_cpp_makefile_star2_O3/sbingner[P]kerneldec/lzfse/src/lzfse_encode.c
// Function: lzfse_encode_buffer_with_scratch
size_t lzfse_encode_buffer_with_scratch(uint8_t *__restrict dst_buffer, 
                       size_t dst_size, const uint8_t *__restrict src_buffer,
                       size_t src_size, void *__restrict scratch_buffer) {
  const size_t original_size = src_size;

  // If input is really really small, go directly to uncompressed buffer
  // (because LZVN will refuse to encode it, and we will report a failure)
  if (src_size < LZVN_ENCODE_MIN_SRC_SIZE)
    goto try_uncompressed;

  // If input is too small, try encoding with LZVN
  if (src_size < LZFSE_ENCODE_LZVN_THRESHOLD) {
    // need header + end-of-stream marker
    size_t extra_size = 4 + sizeof(lzvn_compressed_block_header);
    if (dst_size <= extra_size)
      goto try_uncompressed; // DST is really too small, give up

    size_t sz = lzvn_encode_buffer(
        dst_buffer + sizeof(lzvn_compressed_block_header),
        dst_size - extra_size, src_buffer, src_size, scratch_buffer);
    if (sz == 0 || sz >= src_size)
      goto try_uncompressed; // failed, or no compression, fall back to
                             // uncompressed block

    // If we could encode, setup header and end-of-stream marker (we left room
    // for them, no need to test)
    lzvn_compressed_block_header header;
    header.magic = LZFSE_COMPRESSEDLZVN_BLOCK_MAGIC;
    header.n_raw_bytes = (uint32_t)src_size;
    header.n_payload_bytes = (uint32_t)sz;
    memcpy(dst_buffer, &header, sizeof(header));
    store4(dst_buffer + sizeof(lzvn_compressed_block_header) + sz,
           LZFSE_ENDOFSTREAM_BLOCK_MAGIC);

    return sz + extra_size;
  }

  // Try encoding with LZFSE
  {
    lzfse_encoder_state *state = scratch_buffer;
    memset(state, 0x00, sizeof *state);
    if (lzfse_encode_init(state) != LZFSE_STATUS_OK)
      goto try_uncompressed;
    state->dst = dst_buffer;
    state->dst_begin = dst_buffer;
    state->dst_end = &dst_buffer[dst_size];
    state->src = src_buffer;
    state->src_encode_i = 0;

    if (src_size >= 0xffffffffU) {
      //  lzfse only uses 32 bits for offsets internally, so if the input
      //  buffer is really huge, we need to process it in smaller chunks.
      //  Note that we switch over to this path for sizes much smaller
      //  2GB because it's actually faster to change algorithms well before
      //  it's necessary for correctness.
      //  The first chunk, we just process normally.
      const lzfse_offset encoder_block_size = 262144;
      state->src_end = encoder_block_size;
      if (lzfse_encode_base(state) != LZFSE_STATUS_OK)
        goto try_uncompressed;
      src_size -= encoder_block_size;
      while (src_size >= encoder_block_size) {
        //  All subsequent chunks require a translation to keep the offsets
        //  from getting too big.  Note that we are always going from
        //  encoder_block_size up to 2*encoder_block_size so that the
        //  offsets remain positive (as opposed to resetting to zero and
        //  having negative offsets).
        state->src_end = 2 * encoder_block_size;
        if (lzfse_encode_base(state) != LZFSE_STATUS_OK)
          goto try_uncompressed;
        lzfse_encode_translate(state, encoder_block_size);
        src_size -= encoder_block_size;
      }
      //  Set the end for the final chunk.
      state->src_end = encoder_block_size + (lzfse_offset)src_size;
    }
    //  If the source buffer is small enough to use 32-bit offsets, we simply
    //  encode the whole thing in a single chunk.
    else
      state->src_end = (lzfse_offset)src_size;
    //  This is either the trailing chunk (if the source file is huge), or
    //  the whole source file.
    if (lzfse_encode_base(state) != LZFSE_STATUS_OK)
      goto try_uncompressed;
    if (lzfse_encode_finish(state) != LZFSE_STATUS_OK)
      goto try_uncompressed;
    //  No error occured, return compressed size.
    return state->dst - dst_buffer;
  }

try_uncompressed:
  //  Compression failed for some reason.  If we can fit the data into the
  //  output buffer uncompressed, go ahead and do that instead.
  if (original_size + 12 <= dst_size && original_size < INT32_MAX) {
    uncompressed_block_header header = {.magic = LZFSE_UNCOMPRESSED_BLOCK_MAGIC,
                                        .n_raw_bytes = (uint32_t)src_size};
    uint8_t *dst_end = dst_buffer;
    memcpy(dst_end, &header, sizeof header);
    dst_end += sizeof header;
    memcpy(dst_end, src_buffer, original_size);
    dst_end += original_size;
    store4(dst_end, LZFSE_ENDOFSTREAM_BLOCK_MAGIC);
    dst_end += 4;
    return dst_end - dst_buffer;
  }

  //  Otherwise, there's nothing we can do, so return zero.
  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rcx, %r14
movq %rdx, %r15
movq %rsi, %r12
movq %rdi, %rbx
movq %rcx, %rbp
cmpq $0x8, %rcx
jb 0x372b
movq %r8, %r13
cmpq $0xfff, %r14            # imm = 0xFFF
ja 0x370d
movq %r14, %rbp
cmpq $0x11, %r12
jb 0x372b
leaq 0xc(%rbx), %rdi
leaq -0x10(%r12), %rsi
movq %r15, %rdx
movq %r14, %rcx
movq %r13, %r8
callq 0x7051
movq %rax, %r13
testq %rax, %rax
sete %al
cmpq %r14, %r13
setae %cl
orb %al, %cl
movq %r14, %rbp
jne 0x372b
movl $0x6e787662, (%rbx)     # imm = 0x6E787662
movl %r14d, 0x4(%rbx)
movl %r13d, 0x8(%rbx)
movl $0x24787662, 0xc(%rbx,%r13) # imm = 0x24787662
addq $0x10, %r13
jmp 0x37a9
movl $0xa7160, %edx          # imm = 0xA7160
movq %r13, %rdi
xorl %esi, %esi
callq 0x3080
movq %r13, %rdi
callq 0x3c8c
movq %r14, %rbp
testl %eax, %eax
je 0x3766
leaq 0xc(%r14), %r13
cmpq %r12, %r13
seta %al
cmpq $0x7fffffff, %r14       # imm = 0x7FFFFFFF
setae %cl
orb %al, %cl
jne 0x37a6
movl $0x2d787662, (%rbx)     # imm = 0x2D787662
movl %ebp, 0x4(%rbx)
leaq 0x8(%rbx), %rdi
movq %r15, %rsi
movq %r14, %rdx
callq 0x30c0
movl $0x24787662, 0x8(%rbx,%r14) # imm = 0x24787662
jmp 0x37a9
movq %rbx, 0x28(%r13)
movq %rbx, 0x30(%r13)
leaq (%rbx,%r12), %rax
movq %rax, 0x38(%r13)
movq %r15, (%r13)
movq $0x0, 0x18(%r13)
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
movq %r14, %rax
movq %r14, %rbp
cmpq %rcx, %r14
jb 0x3800
movq $0x40000, 0x8(%r13)     # imm = 0x40000
movq %r13, %rdi
callq 0x3e0a
testl %eax, %eax
je 0x37bb
xorl %r13d, %r13d
movq %r13, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r14, %rbp
movq $0x80000, 0x8(%r13)     # imm = 0x80000
movq %r13, %rdi
callq 0x3e0a
testl %eax, %eax
jne 0x3830
movl $0x40000, %esi          # imm = 0x40000
movq %r13, %rdi
callq 0x3cc8
leaq -0x40000(%rbp), %rax
addq $-0x80000, %rbp         # imm = 0xFFF80000
cmpq $0x3ffff, %rbp          # imm = 0x3FFFF
movq %rax, %rbp
ja 0x37be
leaq -0x40000(%rax), %rbp
movq %rax, 0x8(%r13)
movq %r13, %rdi
callq 0x3e0a
testl %eax, %eax
jne 0x372b
movq %r13, %rdi
callq 0x417e
testl %eax, %eax
jne 0x372b
movq 0x28(%r13), %r13
subq %rbx, %r13
jmp 0x37a9
addq $-0x40000, %rbp         # imm = 0xFFFC0000
jmp 0x372b