// File: /workspace/github_cpp_makefile_star2_O3/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 $0x238, %rsp            # imm = 0x238
movl %ecx, %r12d
testq %rdi, %rdi
je 0x3706
movq %rdi, 0xaae2(%rip)      # 0xe1e8
movq %rdx, -0x58(%rbp)
testq %rsi, %rsi
je 0x3716
movq %rsi, 0xaada(%rip)      # 0xe1f0
leaq -0xd0(%rbp), %rdi
callq 0x3ce4
movl $0x1, %edi
movl $0x10000, %esi          # imm = 0x10000
callq 0x3070
movq %rax, %r13
movl $0x10000, %edi          # imm = 0x10000
callq 0x3110
movl %r12d, -0x38(%rbp)
movq %r13, -0x50(%rbp)
movq %rax, -0x48(%rbp)
movq %r13, %rdi
callq 0x3624
movzbl (%r13), %edx
cmpl $0x30, %edx
jne 0x3c4b
movzbl 0x1(%r13), %edi
callq 0x35ac
leaq 0xaa87(%rip), %rcx      # 0xe1f8
cmpl $0x0, (%rcx)
jne 0x3b64
callq 0x364b
movq %rax, %r15
movq %rax, %rdi
leaq 0x5922(%rip), %rsi      # 0x90ae
callq 0x30b0
testl %eax, %eax
je 0x3c26
movl %eax, -0x2c(%rbp)
movq %r15, %rdi
leaq 0x590d(%rip), %rsi      # 0x90b3
callq 0x30b0
testl %eax, %eax
jne 0x3c65
leaq 0xaa3e(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
jne 0x3b84
movq %r15, %rdi
callq 0x30d0
callq 0x364b
movq %rax, %rbx
movq %rax, %rdi
leaq 0x5910(%rip), %rsi      # 0x90ed
callq 0x30b0
testl %eax, %eax
jne 0x3c82
movq %rbx, %rdi
callq 0x30d0
callq 0x364b
movq %r13, %rdi
callq 0x3624
cmpb $0x4, (%r13)
jne 0x3c8c
movzbl 0x1(%r13), %edi
callq 0x35ac
movq %rax, %r15
movq 0xa9ca(%rip), %rdi      # 0xe1e8
callq 0x3160
movsbl %al, %edi
movl %eax, %ebx
shll $0x18, %ebx
movq 0xa9b6(%rip), %rsi      # 0xe1e8
callq 0x3040
cmpl $0x62000000, %ebx       # imm = 0x62000000
jne 0x3887
testb %r12b, %r12b
je 0x3bc1
movq 0xa9a1(%rip), %rdi      # 0xe1f0
movq 0xa992(%rip), %rsi      # 0xe1e8
movq %r15, %rdx
leaq -0x250(%rbp), %rcx
xorl %r8d, %r8d
callq 0x498e
testq %rax, %rax
movq -0x58(%rbp), %r14
je 0x3c93
cmpl $0x0, -0x250(%rbp)
je 0x3a6d
jmp 0x3c93
movq 0xa95a(%rip), %rcx      # 0xe1e8
movl $0x1, %esi
movl $0x180, %edx            # imm = 0x180
leaq -0x250(%rbp), %rdi
callq 0x3130
cmpq $0x180, %rax            # imm = 0x180
jne 0x3bcb
movq -0x250(%rbp), %rax
movq %rax, %rdx
bswapq %rdx
movq %rdx, -0x250(%rbp)
movabsq $0x73737a6c706d6f63, %rcx # imm = 0x73737A6C706D6F63
cmpq %rcx, %rax
jne 0x3bd9
movl -0x244(%rbp), %eax
movl -0x240(%rbp), %r14d
bswapl %eax
movl %eax, -0x30(%rbp)
movl %r14d, %ebx
bswapl %ebx
leaq 0xa903(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
jne 0x3bf3
movl %ebx, %eax
addq $-0x180, %r15           # imm = 0xFE80
cmpq %rax, %r15
jb 0x3c18
movq %rax, %r15
testb %r12b, %r12b
movq -0x48(%rbp), %rbx
je 0x3c30
movq 0xa8c1(%rip), %rdi      # 0xe1e8
callq 0x3150
testl %eax, %eax
sete %al
testl %r14d, %r14d
setne %cl
andb %al, %cl
cmpb $0x1, %cl
jne 0x3a65
movl -0x30(%rbp), %eax
movq %rax, -0x70(%rbp)
xorl %esi, %esi
xorl %r12d, %r12d
movq %r15, -0x60(%rbp)
movl $0x10000, %ecx          # imm = 0x10000
leaq (%rsi,%rcx), %rax
movq %r15, %rdx
subq %rsi, %rdx
cmpq %r15, %rax
cmovbeq %rcx, %rdx
movq 0xa879(%rip), %rcx      # 0xe1e8
movq %rsi, %r14
movl $0x1, %esi
movq %r13, %rdi
callq 0x3130
testq %rax, %rax
je 0x3c3a
movq %rax, %r15
addq %rax, %r14
movq %r14, -0x68(%rbp)
xorl %r13d, %r13d
movq -0x50(%rbp), %rax
leaq (%rax,%r13), %r8
movl %r15d, %r9d
subl %r13d, %r9d
leaq -0x3c(%rbp), %rax
movq %rax, (%rsp)
leaq -0xd0(%rbp), %rdi
movq %rbx, %rsi
movl $0x10000, %edx          # imm = 0x10000
leaq -0x34(%rbp), %rcx
callq 0x3de6
movl -0x34(%rbp), %edx
leaq (%r12,%rdx), %rax
cmpq -0x70(%rbp), %rax
jbe 0x39db
movl -0x30(%rbp), %eax
movl %eax, %edx
subl %r12d, %edx
movl %edx, -0x34(%rbp)
movl -0x3c(%rbp), %r14d
movq 0xa80a(%rip), %rcx      # 0xe1f0
movl $0x1, %esi
movq %rbx, %rdi
callq 0x31a0
movl -0x34(%rbp), %ecx
cmpq %rcx, %rax
jb 0x3b4b
movq %rax, %rbx
leaq 0xa7ef(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
jne 0x3a23
addq %r14, %r13
addq %rbx, %r12
cmpq %r15, %r13
movq -0x48(%rbp), %rbx
jb 0x3995
jmp 0x3a40
movq 0xa5ae(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
movl -0x3c(%rbp), %edx
leaq 0x57ed(%rip), %rsi      # 0x9224
xorl %eax, %eax
callq 0x3120
jmp 0x3a0e
movq 0xa7a1(%rip), %rdi      # 0xe1e8
callq 0x3150
testl %eax, %eax
movq -0x50(%rbp), %r13
movq -0x60(%rbp), %r15
movq -0x68(%rbp), %rsi
jne 0x3a65
cmpq %r15, %rsi
jb 0x3952
movl -0x38(%rbp), %r12d
movq -0x58(%rbp), %r14
testb %r12b, %r12b
je 0x3ba4
testq %r14, %r14
je 0x3ac0
movq 0xa766(%rip), %rcx      # 0xe1e8
movl $0x1, %esi
movl $0x10000, %edx          # imm = 0x10000
movq %r13, %rdi
callq 0x3130
testq %rax, %rax
je 0x3ac0
movq %rax, %rbx
movl $0x1, %esi
movq %r13, %rdi
movq %rax, %rdx
movq %r14, %rcx
callq 0x31a0
cmpq %rbx, %rax
je 0x3a7b
leaq 0x578d(%rip), %rdi      # 0x9248
jmp 0x3bd2
leaq 0xa731(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
jne 0x3bae
leaq -0xd0(%rbp), %rdi
movq -0x48(%rbp), %rbx
movq %rbx, %rsi
movl $0x10000, %edx          # imm = 0x10000
leaq -0x250(%rbp), %rcx
callq 0x4192
movl -0x250(%rbp), %edx
movq 0xa6f4(%rip), %rcx      # 0xe1f0
movl $0x1, %esi
movq %rbx, %rdi
callq 0x31a0
movl -0x250(%rbp), %edx
cmpq %rdx, %rax
jb 0x3bb8
xorl %r14d, %r14d
leaq 0xa6d6(%rip), %rax      # 0xe1f8
cmpl $0x0, (%rax)
je 0x3c23
movq 0xa4a6(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
xorl %r14d, %r14d
leaq 0x5722(%rip), %rsi      # 0x9261
xorl %eax, %eax
callq 0x3120
jmp 0x3c23
leaq 0x56cc(%rip), %rdi      # 0x921e
callq 0x3090
movl -0x38(%rbp), %r12d
movq -0x50(%rbp), %r13
jmp 0x3c1d
movq 0xa46d(%rip), %rcx      # 0xdfd8
movq (%rcx), %rdi
leaq 0x5526(%rip), %rsi      # 0x909b
movq %rax, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x377a
movq 0xa44d(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x5542(%rip), %rsi      # 0x90d7
movq %r15, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x37c3
callq 0x3304
jmp 0x3a76
callq 0x3326
jmp 0x3ad0
leaq 0x565f(%rip), %rdi      # 0x921e
jmp 0x3bd2
callq 0x32e2
jmp 0x3848
leaq 0x5473(%rip), %rdi      # 0x9045
callq 0x3090
jmp 0x3c1d
movq 0xa3f8(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x5589(%rip), %rsi      # 0x9173
xorl %eax, %eax
callq 0x3120
jmp 0x3c1d
movq 0xa3de(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x5595(%rip), %rsi      # 0x9199
movl -0x30(%rbp), %edx
movl %ebx, %ecx
movq %r15, %r8
xorl %eax, %eax
callq 0x3120
jmp 0x38fe
callq 0x32c0
movl $0x1, %r14d
movl -0x2c(%rbp), %eax
testl %eax, %eax
je 0x374a
jmp 0x3ca5
callq 0x329e
jmp 0x3920
leaq 0x55c7(%rip), %rdi      # 0x9208
callq 0x3090
jmp 0x3a65
movq 0xa386(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x5422(%rip), %rsi      # 0x907e
xorl %eax, %eax
callq 0x3120
jmp 0x3c9f
movq 0xa36c(%rip), %rax      # 0xdfd8
movq (%rax), %rdi
leaq 0x5442(%rip), %rsi      # 0x90b8
movq %r15, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x3c9f
movq %r13, %rdi
callq 0x3258
jmp 0x3c9f
callq 0x327c
jmp 0x3c9f
leaq 0x54b5(%rip), %rdi      # 0x914f
callq 0x3090
movl $0x1, %r14d
leaq -0xd0(%rbp), %rdi
callq 0x3db8
movl %r14d, %eax
addq $0x238, %rsp            # imm = 0x238
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x3cca
jmp 0x3cca
movq %rax, %rbx
leaq -0xd0(%rbp), %rdi
callq 0x3db8
movq %rbx, %rdi
callq 0x3190
nopl (%rax)