// File: /workspace/github_cpp_makefile_star2_O1/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, %rbx
movq %rdx, %r12
movq %rdi, %r14
movq %rcx, %r15
cmpq $0x8, %rcx
jae 0x36f8
leaq 0xc(%rbx), %rbp
cmpq %rsi, %rbp
seta %al
cmpq $0x7fffffff, %rbx       # imm = 0x7FFFFFFF
setae %cl
orb %al, %cl
jne 0x3716
movl $0x2d787662, (%r14)     # imm = 0x2D787662
movl %r15d, 0x4(%r14)
leaq 0x8(%r14), %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x30c0
movl $0x24787662, 0x8(%r14,%rbx) # imm = 0x24787662
jmp 0x388c
movq %r8, %r13
cmpq $0xfff, %rbx            # imm = 0xFFF
ja 0x371d
movq %r12, (%rsp)
movb $0x1, %r12b
cmpq $0x11, %rsi
jae 0x3749
jmp 0x3798
xorl %ebp, %ebp
jmp 0x388c
movq %rsi, (%rsp)
movl $0xa7160, %edx          # imm = 0xA7160
movq %r13, %rdi
xorl %esi, %esi
callq 0x3080
movq %r13, %rdi
callq 0x3d70
testl %eax, %eax
je 0x37ad
movl $0x2, %ecx
movq %rbx, %r15
jmp 0x387f
leaq 0xc(%r14), %rdi
movq %rsi, %r15
addq $-0x10, %rsi
movq (%rsp), %rdx
movq %rbx, %rcx
movq %r13, %r8
callq 0x73fe
movq %r15, %rsi
movq %rax, %rbp
testq %rax, %rax
sete %al
cmpq %rbx, %rbp
setae %cl
orb %al, %cl
jne 0x3798
movl $0x6e787662, (%r14)     # imm = 0x6E787662
movl %ebx, 0x4(%r14)
movl %ebp, 0x8(%r14)
movl $0x24787662, 0xc(%r14,%rbp) # imm = 0x24787662
addq $0x10, %rbp
xorl %r12d, %r12d
movq %rbx, %r15
testb %r12b, %r12b
movq (%rsp), %r12
jne 0x36b8
jmp 0x388c
movq %r14, 0x28(%r13)
movq %r14, 0x30(%r13)
movq (%rsp), %rax
addq %r14, %rax
movq %rax, 0x38(%r13)
movq %r12, (%r13)
movq $0x0, 0x18(%r13)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmpq %rax, %rbx
jb 0x37f6
movq $0x40000, 0x8(%r13)     # imm = 0x40000
movq %r13, %rdi
callq 0x3e4e
movl $0x2, %ecx
testl %eax, %eax
je 0x37ff
xorl %eax, %eax
movq %rbx, %r15
jmp 0x385a
movq %rbx, 0x8(%r13)
movq %rbx, %r15
jmp 0x3862
leaq -0x40000(%rbx), %r15
cmpq $0x40000, %r15          # imm = 0x40000
jb 0x3840
movq $0x80000, 0x8(%r13)     # imm = 0x80000
movq %r13, %rdi
callq 0x3e4e
testl %eax, %eax
jne 0x3853
movl $0x40000, %esi          # imm = 0x40000
movq %r13, %rdi
callq 0x3dc8
addq $-0x40000, %r15         # imm = 0xFFFC0000
cmpq $0x3ffff, %r15          # imm = 0x3FFFF
ja 0x380f
movq %r15, %rax
orq $0x40000, %rax          # imm = 0x40000
movq %rax, 0x8(%r13)
xorl %ecx, %ecx
movb $0x1, %al
jmp 0x385a
xorl %eax, %eax
movl $0x2, %ecx
testb %al, %al
movq (%rsp), %rsi
je 0x3883
movq %r13, %rdi
callq 0x3e4e
testl %eax, %eax
jne 0x387a
movq %r13, %rdi
callq 0x429d
testl %eax, %eax
je 0x389e
movl $0x2, %ecx
movq (%rsp), %rsi
cmpl $0x2, %ecx
je 0x36b8
movq %rbp, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x28(%r13), %rbp
subq %r14, %rbp
movl $0x1, %ecx
jmp 0x387f