// File: /workspace/github_c_makefile_star2_O3/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 $0x18, %rsp
leaq 0x7d1f(%rip), %r15      # 0xb320
movl (%r15), %eax
leal -0x1(%rax), %ecx
cmpl $0x3, %ecx
jae 0x3643
movl %ecx, %ecx
leaq 0x670b(%rip), %rdx      # 0x9d20
movq (%rdx,%rcx,8), %r13
leaq 0x6718(%rip), %rdx      # 0x9d38
movq (%rdx,%rcx,8), %rcx
movq %rcx, 0x10(%rsp)
movl 0x48(%r15), %ebp
cmpl $0x0, 0xc(%r15)
je 0x3656
cmpl $0x3, %eax
je 0x3653
cmpl $0x2, %eax
jne 0x369f
addl $-0x5, %ebp
jmp 0x3656
leaq 0x37e3(%rip), %rdi      # 0x6e2d
callq 0x1120
xorl %ebp, %ebp
jmp 0x36c9
addl $-0x6, %ebp
callq 0x3e28
movq 0x40(%r15), %rdi
movl %ebp, %esi
callq 0x27e8
movq %rax, %rbx
testq %rax, %rax
je 0x3696
movl %ebp, %edi
movq %rdi, (%rsp)
callq 0x33c4
testq %rax, %rax
je 0x36a8
movq %rax, %r14
cmpl $0x0, 0x4(%r15)
je 0x36da
leaq 0x3899(%rip), %rdi      # 0x6f28
callq 0x1120
jmp 0x36b7
leaq 0x380b(%rip), %rdi      # 0x6ea8
jmp 0x36af
leaq 0x37b0(%rip), %rdi      # 0x6e56
jmp 0x364a
leaq 0x3823(%rip), %rdi      # 0x6ed2
callq 0x1120
xorl %r14d, %r14d
xorl %ebp, %ebp
movq %r14, %rdi
callq 0x34fb
movq %rbx, %rdi
callq 0x2837
movl %ebp, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r13, 0x8(%rsp)
cmpl $0x2, (%rsp)
jb 0x375d
movq 0x40(%r15), %rax
movb (%rax), %al
movl $0x1, %r13d
movq (%rsp), %r12
movq 0x40(%r15), %rcx
movzbl (%rcx,%r13), %ebp
movzbl %al, %eax
shll $0x8, %eax
orl %ebp, %eax
movzwl %ax, %edi
movl %r13d, %esi
callq 0x3e78
testl %eax, %eax
je 0x3783
movl %r13d, %edi
movl %r12d, %esi
movq %rbx, %rdx
movq %r14, %r15
movq %rbx, %r14
leaq 0x7c45(%rip), %rbx      # 0xb370
movq %rbx, %rcx
callq 0x2844
movl %r13d, %edi
movq %rbx, %rsi
movq %r14, %rbx
movq %r15, %r14
leaq 0x7bda(%rip), %r15      # 0xb320
movq 0x10(%rsp), %rdx
movq %r14, %rcx
callq 0x3505
incq %r13
movl %ebp, %eax
cmpq %r13, %r12
jne 0x36f5
movq %r14, %rdi
movq (%rsp), %r15
movl %r15d, %esi
callq 0x35b3
movq %r14, %rdi
movl %r15d, %esi
callq *0x8(%rsp)
xorl %ebp, %ebp
testl %eax, %eax
setne %bpl
jmp 0x36b9
leaq 0x3778(%rip), %rdi      # 0x6f02
jmp 0x368f
nop