// File: /workspace/github_cpp_makefile_star2_O2/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, -0x2c(%rbp)
testq %rdi, %rdi
je 0x3478
movq %rdi, 0x9d70(%rip)      # 0xd1e8
movq %rdx, -0x50(%rbp)
testq %rsi, %rsi
je 0x3488
movq %rsi, 0x9d68(%rip)      # 0xd1f0
leaq -0xd0(%rbp), %rdi
callq 0x3aac
pushq $0x1
popq %r12
movl $0x10000, %esi          # imm = 0x10000
movq %r12, %rdi
callq 0x3070
movq %rax, %r13
movl $0x10000, %edi          # imm = 0x10000
callq 0x3110
movq %rax, -0x60(%rbp)
movq %r13, -0x58(%rbp)
movq %r13, %rdi
callq 0x3367
movzbl (%r13), %edx
cmpl $0x30, %edx
jne 0x3a0f
movzbl 0x1(%r13), %edi
callq 0x32dc
leaq 0x9d17(%rip), %rcx      # 0xd1f8
cmpl $0x0, (%rcx)
jne 0x37ba
callq 0x3399
movq %rax, %r14
movq %rax, %rdi
leaq 0x4bb2(%rip), %rsi      # 0x80ae
callq 0x30b0
testl %eax, %eax
je 0x39e6
movl %eax, -0x30(%rbp)
movq %r14, %rdi
leaq 0x4b9d(%rip), %rsi      # 0x80b3
callq 0x30b0
testl %eax, %eax
jne 0x3a22
leaq 0x9cce(%rip), %rax      # 0xd1f8
cmpl $0x0, (%rax)
jne 0x37da
movq %r14, %rdi
callq 0x30d0
callq 0x3399
movq %rax, %r14
movq %rax, %rdi
leaq 0x4ba0(%rip), %rsi      # 0x80ed
callq 0x30b0
testl %eax, %eax
movq -0x50(%rbp), %r15
jne 0x3a3f
movq %r14, %rdi
callq 0x30d0
callq 0x3399
movq %r13, %rdi
callq 0x3367
cmpb $0x4, (%r13)
jne 0x3a5e
movzbl 0x1(%r13), %edi
callq 0x32dc
movq %rax, %r14
movq 0x9c56(%rip), %rdi      # 0xd1e8
callq 0x3160
movsbl %al, %edi
movl %eax, %ebx
shll $0x18, %ebx
movq 0x9c42(%rip), %rsi      # 0xd1e8
callq 0x3040
cmpl $0x62000000, %ebx       # imm = 0x62000000
jne 0x35f8
cmpb $0x0, -0x2c(%rbp)
je 0x37fa
movq 0x9c2c(%rip), %rdi      # 0xd1f0
movq 0x9c1d(%rip), %rsi      # 0xd1e8
movq %r14, %rdx
leaq -0x250(%rbp), %rcx
xorl %r8d, %r8d
callq 0x476b
testq %rax, %rax
je 0x3a7c
cmpl $0x0, -0x250(%rbp)
je 0x38c3
jmp 0x3a7c
movq 0x9be9(%rip), %rcx      # 0xd1e8
movl $0x180, %edx            # imm = 0x180
leaq -0x250(%rbp), %rdi
movq %r12, %rsi
callq 0x3130
cmpq $0x180, %rax            # imm = 0x180
jne 0x381b
movq -0x250(%rbp), %rdx
movabsq $0x73737a6c706d6f63, %rax # imm = 0x73737A6C706D6F63
cmpq %rax, %rdx
jne 0x3827
movl -0x244(%rbp), %eax
movl -0x240(%rbp), %r12d
bswapl %eax
movl %eax, -0x34(%rbp)
bswapl %r12d
leaq 0x9ba3(%rip), %rax      # 0xd1f8
cmpl $0x0, (%rax)
jne 0x3847
movl %r12d, %ebx
addq $-0x180, %r14           # imm = 0xFE80
cmpq %rbx, %r14
jb 0x386d
cmpb $0x0, -0x2c(%rbp)
pushq $0x1
popq %r12
je 0x3892
movl -0x34(%rbp), %eax
movq %rax, -0x70(%rbp)
movq $0x0, -0x48(%rbp)
xorl %r14d, %r14d
movq %rbx, -0x68(%rbp)
movq 0x9b4c(%rip), %rdi      # 0xd1e8
callq 0x3150
testl %eax, %eax
jne 0x38bf
movq %rbx, %rdx
subq %r14, %rdx
jbe 0x38bf
movl $0x10000, %ecx          # imm = 0x10000
leaq (%r14,%rcx), %rax
cmpq %rbx, %rax
cmovbeq %rcx, %rdx
movq 0x9b1c(%rip), %rcx      # 0xd1e8
movq %r13, %rdi
movq %r12, %rsi
callq 0x3130
testq %rax, %rax
je 0x38b3
movq %rax, %r15
addq %rax, %r14
xorl %ebx, %ebx
cmpq %rbx, %r15
movq -0x60(%rbp), %r12
jbe 0x3794
leaq (%rbx,%r13), %r8
movl %r15d, %r9d
subl %ebx, %r9d
leaq -0x3c(%rbp), %rax
movq %rax, (%rsp)
leaq -0xd0(%rbp), %rdi
movq %r12, %rsi
movl $0x10000, %edx          # imm = 0x10000
leaq -0x38(%rbp), %rcx
callq 0x3b66
pushq $0x1
popq %rsi
movl -0x38(%rbp), %edx
movq -0x48(%rbp), %rax
addq %rdx, %rax
cmpq -0x70(%rbp), %rax
jbe 0x373d
movl -0x34(%rbp), %eax
movl %eax, %edx
subl -0x48(%rbp), %edx
movl %edx, -0x38(%rbp)
movl -0x3c(%rbp), %r13d
movq 0x9aa8(%rip), %rcx      # 0xd1f0
movq %r12, %rdi
callq 0x31a0
movl -0x38(%rbp), %ecx
cmpq %rcx, %rax
jb 0x37a1
movq %rax, %r12
leaq 0x9a96(%rip), %rax      # 0xd1f8
cmpl $0x0, (%rax)
jne 0x3777
addq %r13, %rbx
addq %r12, -0x48(%rbp)
movq -0x58(%rbp), %r13
jmp 0x36e8
movq 0x985a(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
movl -0x3c(%rbp), %edx
leaq 0x4a99(%rip), %rsi      # 0x8224
xorl %eax, %eax
callq 0x3120
jmp 0x3767
pushq $0x1
popq %r12
movq -0x68(%rbp), %rbx
jmp 0x3695
leaq 0x4a76(%rip), %rdi      # 0x821e
callq 0x3090
pushq $0x1
popq %r12
movq -0x58(%rbp), %r13
jmp 0x39df
movq 0x9817(%rip), %rcx      # 0xcfd8
movq (%rcx), %rdi
leaq 0x48d0(%rip), %rsi      # 0x809b
movq %rax, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x34ea
movq 0x97f7(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
leaq 0x48ec(%rip), %rsi      # 0x80d7
movq %r14, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x3533
movq 0x97d7(%rip), %rax      # 0xcfd8
movq (%rax), %rcx
leaq 0x492c(%rip), %rdi      # 0x8137
pushq $0x17
popq %rsi
movq %r12, %rdx
callq 0x31a0
jmp 0x35bd
leaq 0x4823(%rip), %rdi      # 0x8045
jmp 0x39da
bswapq %rdx
movq 0x97a7(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
leaq 0x4938(%rip), %rsi      # 0x8173
xorl %eax, %eax
callq 0x3120
jmp 0x39df
movq 0x978a(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
leaq 0x4941(%rip), %rsi      # 0x8199
movl -0x34(%rbp), %edx
movl %r12d, %ecx
movq %r14, %r8
xorl %eax, %eax
callq 0x3120
jmp 0x365e
movq 0x9764(%rip), %rax      # 0xcfd8
movq (%rax), %rcx
leaq 0x4956(%rip), %rdi      # 0x81d4
pushq $0x33
popq %rsi
pushq $0x1
popq %r12
movq %r12, %rdx
callq 0x31a0
jmp 0x39df
movq 0x973f(%rip), %rax      # 0xcfd8
movq (%rax), %rcx
leaq 0x4894(%rip), %rdi      # 0x8137
pushq $0x17
popq %rsi
movq %r12, %rdx
callq 0x31a0
jmp 0x367f
leaq 0x494e(%rip), %rdi      # 0x8208
callq 0x3090
movq -0x50(%rbp), %r15
cmpb $0x0, -0x2c(%rbp)
je 0x3991
testq %r15, %r15
je 0x3913
movq 0x990f(%rip), %rcx      # 0xd1e8
movl $0x10000, %edx          # imm = 0x10000
movq %r13, %rdi
movq %r12, %rsi
callq 0x3130
testq %rax, %rax
je 0x3913
movq %rax, %r14
movq %r13, %rdi
movq %r12, %rsi
movq %rax, %rdx
movq %r15, %rcx
callq 0x31a0
cmpq %r14, %rax
je 0x38d2
leaq 0x493a(%rip), %rdi      # 0x8248
jmp 0x39da
leaq 0x98de(%rip), %rax      # 0xd1f8
cmpl $0x0, (%rax)
jne 0x39b2
leaq -0xd0(%rbp), %rdi
movq -0x60(%rbp), %rbx
movq %rbx, %rsi
movl $0x10000, %edx          # imm = 0x10000
leaq -0x250(%rbp), %rcx
callq 0x3f1c
movl -0x250(%rbp), %edx
movq 0x98a1(%rip), %rcx      # 0xd1f0
movq %rbx, %rdi
movq %r12, %rsi
callq 0x31a0
movl -0x250(%rbp), %edx
cmpq %rdx, %rax
jb 0x39d3
xorl %r15d, %r15d
leaq 0x9889(%rip), %rax      # 0xd1f8
cmpl $0x0, (%rax)
je 0x39e3
movq 0x965d(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
xorl %r15d, %r15d
leaq 0x48d9(%rip), %rsi      # 0x8261
xorl %eax, %eax
callq 0x3120
jmp 0x39e3
movq 0x9640(%rip), %rax      # 0xcfd8
movq (%rax), %rcx
leaq 0x489c(%rip), %rdi      # 0x823e
pushq $0x9
popq %rsi
movq %r12, %rdx
callq 0x31a0
jmp 0x38cd
movq 0x961f(%rip), %rax      # 0xcfd8
movq (%rax), %rcx
leaq 0x4890(%rip), %rdi      # 0x8253
pushq $0xd
popq %rsi
movq %r12, %rdx
callq 0x31a0
jmp 0x3923
leaq 0x4844(%rip), %rdi      # 0x821e
callq 0x3090
pushq $0x1
popq %r15
movl -0x30(%rbp), %eax
testl %eax, %eax
je 0x34ba
leaq -0xd0(%rbp), %rdi
callq 0x3b3e
movl %r15d, %eax
addq $0x238, %rsp            # imm = 0x238
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x95c2(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
leaq 0x465e(%rip), %rsi      # 0x807e
jmp 0x3a55
movq 0x95af(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
leaq 0x4685(%rip), %rsi      # 0x80b8
movq %r14, %rdx
xorl %eax, %eax
callq 0x3120
jmp 0x3a88
movq 0x9592(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
movzbl (%r13), %edx
leaq 0x469d(%rip), %rsi      # 0x80f2
xorl %eax, %eax
callq 0x3120
jmp 0x3a88
movq 0x9573(%rip), %rax      # 0xcfd8
movq (%rax), %rcx
leaq 0x46a8(%rip), %rdi      # 0x8117
pushq $0x1f
popq %rsi
pushq $0x1
popq %rdx
callq 0x31a0
jmp 0x3a88
leaq 0x46cc(%rip), %rdi      # 0x814f
callq 0x3090
pushq $0x1
popq %r15
jmp 0x39ee
jmp 0x3a95
jmp 0x3a95
movq %rax, %rbx
leaq -0xd0(%rbp), %rdi
callq 0x3b3e
movq %rbx, %rdi
callq 0x3190