// File: /workspace/github_c_makefile_star2_O2/salextpuru[P]speccy-toochain/src/mhmt/mhmt-pack.c
// Function: pack
ULONG pack(void)
{
    ULONG (*get_lz_price)(ULONG position, struct lzcode * lzcode) = NULL; // generates correct bitlen (price) of code
    ULONG (*emit)(struct optchain * optch, ULONG actual_len) = NULL; // emits lzcode to the output bit/byte stream
    ULONG success=1;
    ULONG actual_len; // actual length of packing (to account for ZX headers containing last unpacked bytes)
    UBYTE * hash;
    struct optchain * optch=NULL;
    static struct lzcode codes[MAX_CODES_SIZE]; // generate codes here; static to ensure it's not on the stack
    UBYTE curr_byte, last_byte;
    UWORD index;
    ULONG position;

    // some preparations
    //
    if( wrk.packtype==PK_MLZ ) {
        get_lz_price  = &get_lz_price_megalz;
        emit          = &emit_megalz;

    } else if( wrk.packtype==PK_HRM ) {
        get_lz_price  = &get_lz_price_hrum;
        emit          = &emit_hrum;

    } else if( wrk.packtype==PK_HST ) {
        get_lz_price  = &get_lz_price_hrust;
        emit          = &emit_hrust;

    } else {
        printf("mhmt-pack.c:pack() - format unsupported!\n");
        return 0;
    }

    actual_len = wrk.inlen;

    if( wrk.zxheader ) {
        if( wrk.packtype==PK_HRM ) {
            actual_len -= 5;

        } else if( wrk.packtype==PK_HST ) {
            actual_len -= 6;

        } else {
            printf("mhmt-pack.c:pack() - there must be no zxheader for anything except hrust or hrum!\n");
            return 0;
        }
    }

    // initializations and preparations
    init_tb();
    hash = build_hash(wrk.indata, actual_len);

    if( !hash ) {
        printf("mhmt-pack.c:pack() - build_hash() failed!\n");
        success = 0;
    }

    if( success ) {
        optch = make_optch(actual_len);

        if( !optch ) {
            printf("mhmt-pack.c:pack() - can't make optchain array!\n");
            success = 0;
        }
    }

    // go packing!
    if( success ) {
        if( !wrk.greedy ) { // default optimal coding
            // go generating lzcodes byte-by-byte
            //
            curr_byte = wrk.indata[0];

            //
            for(position=1; position<actual_len; position++) {
                last_byte = curr_byte;
                curr_byte = wrk.indata[position];
                // add current two-byter to the chains
                index = (last_byte<<8) + curr_byte;

                if( !add_tb(index,position) ) {
                    printf("mhmt-pack.c:pack() - add_tb() failed!\n");
                    success = 0;
                    goto ERROR;
                }

                // search lzcodes for given position
                make_lz_codes(position, actual_len, hash, codes);
                // update optimal chain with lzcodes
                update_optch(position, codes, get_lz_price, optch);
            }

            // all input bytes scanned, chain built, so now reverse it (prepare for scanning in output generation part)
            reverse_optch(optch, actual_len);

        } else { // greedy coding
            printf("mhmt-pack.c:pack() - greedy coding not supported!\n");
            success = 0;
        }

        // data built, now emit packed file
        success = success && (*emit)(optch, actual_len);
    }

ERROR:
    free_optch(optch);
    destroy_hash(hash);
    return success;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
leaq 0x72fb(%rip), %r15      # 0xa320
movl (%r15), %eax
leal -0x1(%rax), %ecx
cmpl $0x3, %ecx
jae 0x3067
movl %ecx, %ecx
leaq 0x5ce7(%rip), %rdx      # 0x8d20
movq (%rdx,%rcx,8), %rbx
leaq 0x5cf4(%rip), %rdx      # 0x8d38
movq (%rdx,%rcx,8), %rcx
movq %rcx, 0x20(%rsp)
movl 0x48(%r15), %ebp
cmpl $0x0, 0xc(%r15)
je 0x307d
cmpl $0x3, %eax
je 0x307a
cmpl $0x2, %eax
jne 0x30c2
addl $-0x5, %ebp
jmp 0x307d
leaq 0x2d83(%rip), %rdi      # 0x5df1
callq 0x1110
xorl %ebp, %ebp
jmp 0x318c
addl $-0x6, %ebp
callq 0x3768
movq 0x40(%r15), %rdi
movl %ebp, %esi
callq 0x236c
movq %rax, 0x8(%rsp)
testq %rax, %rax
je 0x30b9
movl %ebp, %edi
callq 0x2ef0
testq %rax, %rax
je 0x30cb
movq %rax, %r14
cmpl $0x0, 0x4(%r15)
je 0x30df
leaq 0x2e38(%rip), %rdi      # 0x5eec
jmp 0x3173
leaq 0x2dac(%rip), %rdi      # 0x5e6c
jmp 0x30d2
leaq 0x2d51(%rip), %rdi      # 0x5e1a
jmp 0x306e
leaq 0x2dc4(%rip), %rdi      # 0x5e96
callq 0x1110
xorl %r14d, %r14d
jmp 0x3178
movq %rbx, 0x10(%rsp)
movq 0x40(%r15), %rax
movb (%rax), %al
movl %ebp, %ecx
movq %rcx, 0x18(%rsp)
pushq $0x1
popq %r12
cmpq 0x18(%rsp), %r12
jae 0x314f
movq 0x40(%r15), %rcx
movzbl (%rcx,%r12), %ebx
movzbl %al, %eax
shll $0x8, %eax
orl %ebx, %eax
movzwl %ax, %edi
movl %r12d, %esi
callq 0x37b5
testl %eax, %eax
je 0x316c
movl %r12d, %edi
movl %ebp, %esi
movq 0x8(%rsp), %rdx
leaq 0x7243(%rip), %r13      # 0xa370
movq %r13, %rcx
callq 0x23c0
movl %r12d, %edi
movq %r13, %rsi
movq 0x20(%rsp), %rdx
movq %r14, %rcx
callq 0x2f3a
incq %r12
movl %ebx, %eax
jmp 0x30f5
movq %r14, %rdi
movl %ebp, %esi
callq 0x2fd8
movq %r14, %rdi
movl %ebp, %esi
callq *0x10(%rsp)
xorl %ebp, %ebp
testl %eax, %eax
setne %bpl
jmp 0x317a
leaq 0x2d53(%rip), %rdi      # 0x5ec6
callq 0x1110
xorl %ebp, %ebp
movq %r14, %rdi
callq 0x2f35
movq 0x8(%rsp), %rdi
callq 0x23bb
movl %ebp, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nopl (%rax)