// File: /workspace/github_c_makefile_star2_O1/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 0x7d37(%rip), %r14      # 0xb320
movl (%r14), %eax
leal -0x1(%rax), %ecx
cmpl $0x3, %ecx
jae 0x362b
movl %ecx, %ecx
leaq 0x6723(%rip), %rdx      # 0x9d20
movq (%rdx,%rcx,8), %r13
leaq 0x6730(%rip), %rdx      # 0x9d38
movq (%rdx,%rcx,8), %rcx
movq %rcx, 0x20(%rsp)
movl 0x48(%r14), %ebx
cmpl $0x0, 0xc(%r14)
je 0x3641
cmpl $0x3, %eax
je 0x363e
cmpl $0x2, %eax
jne 0x3679
addl $-0x5, %ebx
jmp 0x3641
leaq 0x37fb(%rip), %rdi      # 0x6e2d
callq 0x1120
xorl %ebp, %ebp
jmp 0x3786
addl $-0x6, %ebx
movl %ebx, %r15d
callq 0x3e18
movq 0x40(%r14), %rdi
movl %ebx, %esi
callq 0x2798
movq %rax, %rbx
testq %rax, %rax
je 0x3670
movl %r15d, %edi
callq 0x33a8
testq %rax, %rax
je 0x3682
movq %rax, %r12
xorl %eax, %eax
jmp 0x3693
leaq 0x3831(%rip), %rdi      # 0x6ea8
jmp 0x3689
leaq 0x37d6(%rip), %rdi      # 0x6e56
jmp 0x3632
leaq 0x3849(%rip), %rdi      # 0x6ed2
callq 0x1120
movb $0x1, %al
xorl %r12d, %r12d
testb %al, %al
je 0x369e
xorl %ebp, %ebp
jmp 0x3776
movl 0x4(%r14), %eax
movl %eax, 0x14(%rsp)
testl %eax, %eax
je 0x36bb
leaq 0x3877(%rip), %rdi      # 0x6f28
callq 0x1120
jmp 0x3759
movq %rbx, 0x8(%rsp)
movq %r13, 0x18(%rsp)
cmpl $0x2, %r15d
jb 0x3744
movq 0x40(%r14), %rax
movb (%rax), %al
movl $0x1, %r13d
movq 0x40(%r14), %rcx
movzbl (%rcx,%r13), %ebx
movzbl %al, %eax
shll $0x8, %eax
orl %ebx, %eax
movzwl %ax, %edi
movl %r13d, %esi
callq 0x3e68
testl %eax, %eax
je 0x3797
movl %r13d, %edi
movl %r15d, %esi
movq 0x8(%rsp), %rdx
movq %r15, %rbp
movq %r12, %r15
movq %r14, %r12
leaq 0x7c5a(%rip), %r14      # 0xb370
movq %r14, %rcx
callq 0x2800
movl %r13d, %edi
movq %r14, %rsi
movq %r12, %r14
movq %r15, %r12
movq %rbp, %r15
movq 0x20(%rsp), %rdx
movq %r12, %rcx
callq 0x34eb
incq %r13
movl %ebx, %eax
cmpq %r13, %rbp
jne 0x36d7
movq %r12, %rdi
movl %r15d, %esi
callq 0x3599
movq 0x18(%rsp), %r13
movq 0x8(%rsp), %rbx
cmpl $0x0, 0x14(%rsp)
movl $0x0, %ebp
jne 0x3776
movq %r12, %rdi
movl %r15d, %esi
callq *%r13
xorl %ebp, %ebp
testl %eax, %eax
setne %bpl
movq %r12, %rdi
callq 0x34e1
movq %rbx, %rdi
callq 0x27f4
movl %ebp, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3764(%rip), %rdi      # 0x6f02
callq 0x1120
movq 0x8(%rsp), %rbx
jmp 0x3697
nopl (%rax)