// File: /workspace/github_cpp_makefile_star2_O1/sbingner[P]kerneldec/kerneldec.cpp
// Function: decompress_kernel
int decompress_kernel(FILE *inputfh, FILE* outputfh, FILE *kppfh, bool quiet)
{
    if (inputfh)
        _input = inputfh;
    if (outputfh)
        _output = outputfh;
#define CHUNK 0x10000

    lzssdecompress lzss;
    uint8_t *ibuf= (uint8_t*)malloc(CHUNK);
    uint8_t *obuf= (uint8_t*)malloc(CHUNK);
    bzero(ibuf, CHUNK);
    size_t nr;

next:
    read_asn1hdr(ibuf);
    if (*ibuf != 0x30) {
        fprintf(stderr, "Invalid input - not IM4P %x\n", *ibuf);
        return 1;
    }

    uint64_t len = read_asn1len(ibuf[1]);

    if (g_debug) fprintf(stderr, "file length: %lld\n", len);

    char *str = read_asn1str();

    if (strcasecmp(str, "IMG4") == 0) {
        // Encapsulated in IMG4
        goto next;
    }

    if (strcasecmp(str, "IM4P")) {
        fprintf(stderr, "Invalid input - not IM4P (%s)\n", str);
        return 1;
    }

    if (g_debug) fprintf(stderr, "Have an %s container\n", str);

    free(str);

    str = read_asn1str();

    if (strcasecmp(str, "krnl")) {
        fprintf(stderr, "Invalid input - not Kernel (0x%02x)\n", *ibuf);
        return 1;
    }

    free(str);

    str = read_asn1str();

    read_asn1hdr(ibuf);

    if (*ibuf != 0x04) {
        fprintf(stderr, "Invalid input - no kernel data\n");
        return 1;
    }

    uint64_t data_len = read_asn1len(ibuf[1]);

    // See if it might be LZFSE
    char peek = fgetc(_input);
    ungetc(peek, _input);

    if (peek == 0x62) {
        // LZFSE?
        if (!quiet) fprintf(stderr, "Writing kernelcache...\n");
        int error;
        size_t decoded = lzfse_decode_file(_output, _input, data_len, &error, NULL);
        if (decoded <= 0 || error) {
            perror("Unable to decode LZFSE kernel cache");
            return 1;
        }
    } else {
        // LZSS?
        struct lzss_hdr hdr;
        nr = fread(&hdr, 1, sizeof(struct lzss_hdr), _input);
        if (nr != sizeof(struct lzss_hdr)) {
            perror("read");
            return 1;
        }

        hdr.magic = be64toh(hdr.magic);
        if (hdr.magic != lzss_magic) {
            fprintf(stderr, "Invalid input - no lzss magic 0x%llx\n", hdr.magic);
            return 1;
        }

        hdr.size = be32toh(hdr.size);
        hdr.src_size = be32toh(hdr.src_size);
        if (g_debug) fprintf(stderr, "Found kernelcache size %u compressed: %u (asn1 size %lld)\n", hdr.size, hdr.src_size, data_len);
        if (hdr.src_size > data_len - sizeof(struct lzss_hdr)) {
            fprintf(stderr, "Invalid input - reports size larger than available\n");
            return 1;
        }

        uint64_t total_written=0;
        uint64_t total_read=0;
        if (!quiet) fprintf(stderr, "Writing kernelcache...\n");
        while (!feof(_input) && total_read < hdr.src_size)
        {
            if (total_read + CHUNK > hdr.src_size) {
                nr = fread(ibuf, 1, hdr.src_size - total_read, _input);
            } else {
                nr = fread(ibuf, 1, CHUNK, _input);
            }
            if (nr==0) {
                perror("input file short read");
                break;
            }

            total_read += nr;
            size_t srcp= 0;
            while (srcp<nr) {
                uint32_t dstused;
                uint32_t srcused;
                lzss.decompress(obuf, CHUNK, &dstused, ibuf+srcp, nr-srcp, &srcused);
                srcp+=srcused;
                if (total_written + dstused > hdr.size) {
                    dstused = hdr.size - total_written;
                }
                size_t nw= fwrite(obuf, 1, dstused, _output);
                if (nw<dstused) {
                    perror("write");
                    return 1;
                }
                total_written += nw;
                if (g_debug) fprintf(stderr, "decompress: 0x%x -> 0x%x\n", srcused, dstused);
            }
        }
    }
    if (!quiet) fprintf(stderr, "... done\n");
    if (kppfh != NULL) {
        while ((nr = fread(ibuf, 1, CHUNK, _input))) {
            if (fwrite(ibuf, 1, nr, kppfh) != nr) {
                perror("write kpp:");
                return 1;
            }
        }
    }
    if (g_debug) fprintf(stderr, "done reading\n");
    uint32_t dstused;
    lzss.flush(obuf, CHUNK, &dstused);
    size_t nw = fwrite(obuf, 1, dstused, _output);
    if (nw<dstused) {
        perror("write");
        return 1;
    }

    if (g_debug) fprintf(stderr, "flush: %d bytes\n", dstused);

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x248, %rsp            # imm = 0x248
movl %ecx, %r14d
movq %rdx, %r12
testq %rdi, %rdi
je 0x3709
movq %rdi, 0xaadf(%rip)      # 0xe1e8
testq %rsi, %rsi
je 0x3715
movq %rsi, 0xaadb(%rip)      # 0xe1f0
leaq -0xe0(%rbp), %rdi
callq 0x3d44
movl $0x10000, %edi          # imm = 0x10000
callq 0x3110
movq %rax, %r13
movl $0x10000, %edi          # imm = 0x10000
callq 0x3110
movq %rax, -0x48(%rbp)
movl $0x10000, %edx          # imm = 0x10000
movq %r13, %rdi
xorl %esi, %esi
callq 0x3050
movl %r14d, -0x5c(%rbp)
movq %r13, -0x50(%rbp)
movq %r12, -0x68(%rbp)
movq %r13, %rdi
callq 0x3624
movzbl (%r13), %edx
cmpl $0x30, %edx
jne 0x3ce6
movzbl 0x1(%r13), %edi
callq 0x35ac
leaq 0xaa7a(%rip), %rcx      # 0xe1f8
cmpl $0x0, (%rcx)
jne 0x3a9b
callq 0x364b
movq %rax, %rbx
movq %rax, %rdi
leaq 0x5915(%rip), %rsi      # 0x90ae
callq 0x30b0
movl %eax, -0x60(%rbp)
testl %eax, %eax
je 0x3cba
movq %rbx, %rdi
leaq 0x5900(%rip), %rsi      # 0x90b3
callq 0x30b0
testl %eax, %eax
jne 0x3abb
leaq 0xaa31(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
jne 0x3adb
movq %rbx, %rdi
callq 0x30d0
callq 0x364b
movq %rax, %rbx
movq %rax, %rdi
leaq 0x5903(%rip), %rsi      # 0x90ed
callq 0x30b0
testl %eax, %eax
jne 0x3afb
movq %rbx, %rdi
callq 0x30d0
callq 0x364b
movq %r13, %rdi
callq 0x3624
cmpb $0x4, (%r13)
jne 0x3b08
movzbl 0x1(%r13), %edi
callq 0x35ac
movq %rax, %r15
movq 0xa9bd(%rip), %rdi      # 0xe1e8
callq 0x3160
movsbl %al, %edi
movl %eax, %ebx
shll $0x18, %ebx
movq 0xa9a9(%rip), %rsi      # 0xe1e8
callq 0x3040
cmpl $0x62000000, %ebx       # imm = 0x62000000
jne 0x389a
testb %r14b, %r14b
je 0x3b12
movq 0xa994(%rip), %rdi      # 0xe1f0
movq 0xa985(%rip), %rsi      # 0xe1e8
movq %r15, %rdx
leaq -0x260(%rbp), %rcx
xorl %r8d, %r8d
callq 0x4aae
testq %rax, %rax
setne %al
cmpl $0x0, -0x260(%rbp)
sete %bl
andb %al, %bl
je 0x3b2a
testb %bl, %bl
jne 0x3bb8
jmp 0x3cba
movq 0xa947(%rip), %rcx      # 0xe1e8
movl $0x1, %esi
movl $0x180, %edx            # imm = 0x180
leaq -0x260(%rbp), %rdi
callq 0x3130
cmpq $0x180, %rax            # imm = 0x180
jne 0x3b1c
movq -0x260(%rbp), %rax
movq %rax, %rdx
bswapq %rdx
movq %rdx, -0x260(%rbp)
movabsq $0x73737a6c706d6f63, %rcx # imm = 0x73737A6C706D6F63
cmpq %rcx, %rax
movq -0x48(%rbp), %r12
jne 0x3b42
movl -0x254(%rbp), %eax
movl -0x250(%rbp), %ebx
bswapl %eax
movl %eax, -0x38(%rbp)
movl %eax, -0x254(%rbp)
bswapl %ebx
movl %ebx, -0x250(%rbp)
leaq 0xa8e4(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
jne 0x3b6a
movl %ebx, %ebx
addq $-0x180, %r15           # imm = 0xFE80
cmpq %rbx, %r15
jb 0x3b8f
testb %r14b, %r14b
je 0x3cc6
movl -0x38(%rbp), %eax
movq %rax, -0x80(%rbp)
movq $0x0, -0x58(%rbp)
xorl %r15d, %r15d
movq %rbx, -0x70(%rbp)
movq 0xa893(%rip), %rdi      # 0xe1e8
callq 0x3150
testl %eax, %eax
setne %al
movq %rbx, %rdx
subq %r15, %rdx
setbe %r14b
orb %al, %r14b
movl %r14d, -0x30(%rbp)
jne 0x3ba2
movl $0x10000, %ecx          # imm = 0x10000
leaq (%r15,%rcx), %rax
cmpq %rbx, %rax
cmovbeq %rcx, %rdx
movq 0xa85b(%rip), %rcx      # 0xe1e8
movl $0x1, %esi
movq -0x50(%rbp), %rdi
callq 0x3130
testq %rax, %rax
je 0x3cd0
movq %rax, %rcx
addq %rax, %r15
movq %r15, -0x78(%rbp)
xorl %r14d, %r14d
movq %r14, %r15
cmpq %r14, %rcx
jbe 0x3a85
movq -0x50(%rbp), %rax
leaq (%rax,%r15), %r8
movq %rcx, %r13
movl %ecx, %r9d
subl %r15d, %r9d
leaq -0x3c(%rbp), %rax
movq %rax, (%rsp)
leaq -0xe0(%rbp), %rdi
movq %r12, %rsi
movl $0x10000, %edx          # imm = 0x10000
leaq -0x34(%rbp), %rcx
callq 0x3e46
movl -0x34(%rbp), %eax
addq -0x58(%rbp), %rax
cmpq -0x80(%rbp), %rax
jbe 0x3a04
movl -0x38(%rbp), %eax
subl -0x58(%rbp), %eax
movl %eax, -0x34(%rbp)
movl -0x3c(%rbp), %r14d
movl -0x34(%rbp), %edx
movq 0xa7de(%rip), %rcx      # 0xe1f0
movl $0x1, %esi
movq %r12, %rdi
callq 0x31a0
movq %rax, %rbx
movl -0x34(%rbp), %r12d
cmpq %r12, %rax
jb 0x3a50
addq %rbx, -0x58(%rbp)
leaq 0xa7c2(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
jne 0x3a65
addq %r15, %r14
cmpq %r12, %rbx
movq -0x48(%rbp), %r12
movq %r13, %rcx
jae 0x39b1
jmp 0x3a85
leaq 0x57c7(%rip), %rdi      # 0x921e
callq 0x3090
movl $0x1, -0x2c(%rbp)
jmp 0x3a3b
movq 0xa56c(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
movl -0x3c(%rbp), %edx
leaq 0x57ab(%rip), %rsi      # 0x9224
movl %r12d, %ecx
xorl %eax, %eax
callq 0x3120
jmp 0x3a3b
cmpq %r15, %rcx
movq -0x70(%rbp), %rbx
movq -0x78(%rbp), %r15
jbe 0x394e
jmp 0x3ba2
movq 0xa536(%rip), %rcx      # 0xdfd8
movq (%rcx), %rdi
leaq 0x55ef(%rip), %rsi      # 0x909b
movq %rax, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x3787
movq 0xa516(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x55ec(%rip), %rsi      # 0x90b8
movq %rbx, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x3cb3
movq 0xa4f6(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x55eb(%rip), %rsi      # 0x90d7
movq %rbx, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x37d0
movq %r13, %rdi
callq 0x3258
jmp 0x3cb3
callq 0x327c
jmp 0x3cb3
callq 0x32e2
jmp 0x3855
leaq 0x5522(%rip), %rdi      # 0x9045
callq 0x3090
jmp 0x3b94
leaq 0x561e(%rip), %rdi      # 0x914f
callq 0x3090
movl $0x1, -0x2c(%rbp)
jmp 0x388d
movq 0xa48f(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
movl $0x0, -0x30(%rbp)
leaq 0x5619(%rip), %rsi      # 0x9173
xorl %eax, %eax
callq 0x3120
movl $0x1, -0x2c(%rbp)
jmp 0x3ba2
movq 0xa467(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x561e(%rip), %rsi      # 0x9199
movl -0x38(%rbp), %edx
movl %ebx, %ecx
movq %r15, %r8
xorl %eax, %eax
callq 0x3120
jmp 0x391d
callq 0x32c0
movl $0x1, -0x2c(%rbp)
movl $0x0, -0x30(%rbp)
cmpb $0x0, -0x30(%rbp)
movl -0x5c(%rbp), %r14d
movq -0x68(%rbp), %r12
movq -0x50(%rbp), %r13
je 0x3cba
testb %r14b, %r14b
je 0x3c93
testq %r12, %r12
je 0x3c0b
movq 0xa61b(%rip), %rcx      # 0xe1e8
movl $0x1, %esi
movl $0x10000, %edx          # imm = 0x10000
movq %r13, %rdi
callq 0x3130
testq %rax, %rax
je 0x3c0b
movq %rax, %rbx
movl $0x1, %esi
movq %r13, %rdi
movq %rax, %rdx
movq %r12, %rcx
callq 0x31a0
cmpq %rbx, %rax
je 0x3bc6
leaq 0x5642(%rip), %rdi      # 0x9248
jmp 0x3cae
leaq 0xa5e6(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
jne 0x3c9d
leaq -0xe0(%rbp), %rdi
movq -0x48(%rbp), %rbx
movq %rbx, %rsi
movl $0x10000, %edx          # imm = 0x10000
leaq -0x260(%rbp), %rcx
callq 0x41e0
movl -0x260(%rbp), %edx
movq 0xa5a9(%rip), %rcx      # 0xe1f0
movl $0x1, %esi
movq %rbx, %rdi
callq 0x31a0
movl -0x260(%rbp), %edx
cmpq %rdx, %rax
jb 0x3ca7
movl $0x0, -0x2c(%rbp)
leaq 0xa58b(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
je 0x3cba
movq 0xa35f(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
movl $0x0, -0x2c(%rbp)
leaq 0x55d7(%rip), %rsi      # 0x9261
xorl %eax, %eax
callq 0x3120
jmp 0x3cba
callq 0x3304
jmp 0x3bc1
callq 0x3326
jmp 0x3c1b
leaq 0x5570(%rip), %rdi      # 0x921e
callq 0x3090
movl $0x1, -0x2c(%rbp)
cmpl $0x0, -0x60(%rbp)
je 0x3757
jmp 0x3d05
callq 0x329e
jmp 0x3938
leaq 0x5531(%rip), %rdi      # 0x9208
callq 0x3090
movb $0x1, %al
movl %eax, -0x30(%rbp)
jmp 0x3ba2
movq 0xa2eb(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x5387(%rip), %rsi      # 0x907e
xorl %eax, %eax
callq 0x3120
movl $0x1, -0x2c(%rbp)
leaq -0xe0(%rbp), %rdi
callq 0x3e18
movl -0x2c(%rbp), %eax
addq $0x248, %rsp            # imm = 0x248
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x3d2a
jmp 0x3d2a
movq %rax, %rbx
leaq -0xe0(%rbp), %rdi
callq 0x3e18
movq %rbx, %rdi
callq 0x3190
nopl (%rax)