// File: /workspace/github_c_makefile_star2_O1/salextpuru[P]speccy-toochain/src/mhmt/mhmt-lz.c
// Function: make_lz_codes
void make_lz_codes(ULONG position, ULONG actual_len, UBYTE * hash, struct lzcode * codes)
{
    ULONG codepos;
    ULONG codelen,i;
    ULONG was_match;
    UBYTE curr_byte,next_byte;
    struct tb_chain * curr_tb;
    UWORD index;
    ULONG max_lookback,max_length,max_tbdisp;
    // copy-byte code is always present
    codes[0].length = 1;
    codes[0].disp   = 0;
    // start more filling of codes[] from that position
    codepos = 1;

    if( wrk.packtype==PK_HST ) { // for hrust only,
        // add 12,14,16,...,40,42 bytes copies, if possible
        for(codelen=12; codelen<=42; codelen+=2) {
            if( position <= (actual_len-codelen) ) {
                codes[codepos].length = codelen;
                codes[codepos].disp   = 0;
                codepos++;

            } else
                break;
        }
    }

    // check for one-byter (-1..-8)
    //
    curr_byte=wrk.indata[position];
    //
    i = (position>8) ? position-8 : 0;

    do {
        if( wrk.indata[i] == curr_byte ) {
            codes[codepos].length = 1;
            codes[codepos].disp   = -(LONG)(position-i);
            codepos++;
            break;
        }
    } while( (++i)<position );

    // for hrust, check 3-byte insertion code (-1..-79)
    if( (wrk.packtype==PK_HST) && (position < (actual_len-2)) ) {
        i = (position>79) ? position-79 : 0;

        do {
            if( (wrk.indata[i]==curr_byte) && (wrk.indata[i+2]==wrk.indata[position+2]) ) {
                codes[codepos].length = (-3);
                codes[codepos].disp   = -(LONG)(position-i);
                codepos++;
                break;
            }
        } while( (++i)<position );
    }

    switch( wrk.packtype ) { // set maximum lookback and length
    case PK_MLZ:
        max_lookback = (wrk.maxwin<4352) ? wrk.maxwin : 4352;
        max_length = 255;
        max_tbdisp = 256;
        break;

    case PK_HRM:
        max_lookback = (wrk.maxwin<4096) ? wrk.maxwin : 4096;
        max_length = 255;
        max_tbdisp = 256;
        break;

    case PK_HST:
        max_lookback = (wrk.maxwin<65536) ? wrk.maxwin : 65536;
        max_length = 3839;
        max_tbdisp = 768;
        break;

    default:
        printf("mhmt-lz.c:make_lz_codes() - wrong packer type!\n");
        exit(1);
    }

    // check for two-byter (-1..-max_tbdisp)
    //
    curr_tb = NULL;

    //
    if( position<(actual_len-1) ) { // don't try two-byter if we are at the byte before last one
        next_byte = wrk.indata[position+1];
        index=(curr_byte<<8) + next_byte;
        curr_tb = tb_entry[index];

        // there are two-byters!
        if( curr_tb ) {
            if( ((position-curr_tb->pos)<=max_tbdisp) && ((position-curr_tb->pos)<=max_lookback) ) {
                codes[codepos].length = 2;
                codes[codepos].disp   = -(LONG)(position - curr_tb->pos);
                codepos++;
            }
        }
    }

    // at last, check for lengths=3..max_length up to max_lookback
    if(  curr_tb  &&  ( (position-curr_tb->pos)<=max_lookback )  &&  ( position<(actual_len-2) )  ) { // if we can proceed at all
        was_match = 1; // there was match at codelen-1

        for( codelen=3; ( codelen<=max_length )&&( position<(actual_len-codelen+1) ); /*nothing*/ ) {
            if( was_match ) { // for codelen-1
                // codelen-1 bytes are matched, compare one more byte
                if( wrk.indata[position+codelen-1] == wrk.indata[curr_tb->pos+codelen-1] ) {
                    // add code to the table
                    codes[codepos].length = codelen;
                    codes[codepos].disp   = -(LONG)(position - curr_tb->pos);
                    codepos++;
                    codelen++; // next time do comparision of greater size

                } else { // last bytes do not match
MATCH_FAIL: // entrance for failed matches here: used 3-fold so we set "goto" here
                    // go for older twobyter
                    curr_tb = curr_tb->next;

                    // no more twobyters or they are too far - stop search at all
                    if( !curr_tb ) break;

                    if( (position - curr_tb->pos)>max_lookback ) break;

                    // mark there was no matches
                    was_match = 0;
                }

            } else { // there were no matches for previous codelen
                // next twobyter is already taken, but no comparision is done for codelen bytes
                // first we check if we need to do such comparision at all by seeing to the hashes of the ends of strings
                if( hash[position+codelen-1] == hash[curr_tb->pos+codelen-1] ) {
                    // hashes match, so try matching complete string
                    if( !memcmp( &wrk.indata[position], &wrk.indata[curr_tb->pos], codelen ) ) {
                        was_match = 1;
                        codes[codepos].length = codelen;
                        codes[codepos].disp   = -(LONG)(position - curr_tb->pos);
                        codepos++;
                        codelen++;

                    } else
                        // no match of whole string
                        goto MATCH_FAIL;

                } else
                    // no match of hashes
                    goto MATCH_FAIL;
            }
        }
    }

    // here we assume to have found all possible matches. check for codes[] table overflow:
    // there could be matches for length 1..3839, and there is copy-1-byte, 16 copymanybyters, 1 insertion match, total 3857 entries for hrust, 256 for megalz & hrum
    if(   codepos > ( (wrk.packtype==PK_HST) ? 3857 : 256 )   ) { // this should not happen!
        printf("mhmt-lz.c:make_lz_codes_hrust() encountered too many entries in codes[] table. Fatal error.\n");
        exit(1);
    }

    // mark end-of-records in codes[]
    codes[codepos].length = 0;
    codes[codepos].disp   = 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rcx, %r9
movq %rdx, %r11
movl %esi, %r8d
movl %edi, %r12d
movq $0x1, (%rcx)
leaq 0x8af8(%rip), %rcx      # 0xb320
movl (%rcx), %r10d
cmpl $0x3, %r10d
setne %al
leal -0xc(%r8), %edx
cmpl %edi, %edx
setb %dl
movl $0x1, %r13d
orb %al, %dl
jne 0x2876
leal -0xe(%r8), %edx
movl $0xc, %eax
movl $0x1, %r13d
movl %eax, (%r9,%r13,8)
movl $0x0, 0x4(%r9,%r13,8)
incq %r13
cmpl $0x28, %eax
ja 0x2876
addl $0x2, %eax
leal -0x2(%rdx), %esi
cmpl %r12d, %edx
movl %esi, %edx
jae 0x2854
movq 0x40(%rcx), %r14
movl %r12d, %eax
leaq (%r14,%rax), %rbp
movzbl (%r14,%rax), %edx
cmpl $0x8, %r12d
movl $0x8, %eax
cmovbl %r12d, %eax
negl %eax
leal (%r12,%rax), %esi
cmpb %dl, (%r14,%rsi)
je 0x28aa
incl %eax
movl %r12d, %esi
addl %eax, %esi
jb 0x2895
jmp 0x28bd
movl %r13d, %esi
movl $0x1, (%r9,%rsi,8)
movl %eax, 0x4(%r9,%rsi,8)
incl %r13d
cmpl $0x3, %r10d
setne %sil
leal -0x2(%r8), %eax
cmpl %r12d, %eax
setbe %dil
orb %sil, %dil
jne 0x292a
movq %r8, %rbx
leal 0x2(%r12), %edi
cmpl $0x4f, %r12d
movl $0x4f, %esi
cmovbl %r12d, %esi
negl %esi
leal (%r12,%rsi), %r8d
cmpb %dl, (%r14,%r8)
jne 0x2908
leal (%r12,%rsi), %r8d
addl $0x2, %r8d
movb (%r14,%r8), %r8b
cmpb (%r14,%rdi), %r8b
je 0x2914
incl %esi
movl %r12d, %r8d
addl %esi, %r8d
jb 0x28ec
jmp 0x2927
movl %r13d, %edi
movl $0xfffffffd, (%r9,%rdi,8) # imm = 0xFFFFFFFD
movl %esi, 0x4(%r9,%rdi,8)
incl %r13d
movq %rbx, %r8
cmpl $0x3, %r10d
je 0x2966
cmpl $0x2, %r10d
je 0x294a
cmpl $0x1, %r10d
jne 0x2b06
movl 0x1c(%rcx), %ecx
movl $0x1100, %edi           # imm = 0x1100
jmp 0x2952
movl 0x1c(%rcx), %ecx
movl $0x1000, %edi           # imm = 0x1000
cmpl %edi, %ecx
cmovbl %ecx, %edi
movl $0x100, %ecx            # imm = 0x100
movl $0xff, 0x4(%rsp)
jmp 0x2980
movl 0x1c(%rcx), %ecx
movl $0x10000, %edi          # imm = 0x10000
cmpl %edi, %ecx
cmovbl %ecx, %edi
movl $0x300, %ecx            # imm = 0x300
movl $0xeff, 0x4(%rsp)       # imm = 0xEFF
leal -0x1(%r8), %esi
cmpl %r12d, %esi
jbe 0x29d1
leal 0x1(%r12), %esi
movzbl (%r14,%rsi), %esi
shll $0xb, %edx
leal (%rdx,%rsi,8), %edx
leaq 0x10280(%rip), %rsi     # 0x12c20
movq (%rsi,%rdx), %r15
testq %r15, %r15
je 0x29d1
movl (%r15), %edx
movl %r12d, %esi
subl %edx, %esi
cmpl %ecx, %esi
ja 0x29d4
cmpl %edi, %esi
ja 0x29d4
movl %r13d, %ecx
movl $0x2, (%r9,%rcx,8)
subl %r12d, %edx
movl %edx, 0x4(%r9,%rcx,8)
incl %r13d
jmp 0x29d4
xorl %r15d, %r15d
movl 0x4(%rsp), %edx
testq %r15, %r15
je 0x2acd
cmpl %r12d, %eax
jbe 0x2acd
movl %r12d, %eax
subl (%r15), %eax
cmpl %edi, %eax
ja 0x2acd
movq %rbp, 0x18(%rsp)
incl %r8d
leal -0x1(%r12), %esi
movl $0x1, %eax
movl $0x3, %ebp
movq %r9, 0x30(%rsp)
movl %r10d, 0xc(%rsp)
movq %r11, 0x28(%rsp)
movq %r8, 0x20(%rsp)
movl %edi, 0x8(%rsp)
movq %rsi, 0x10(%rsp)
movl %r8d, %ecx
subl %ebp, %ecx
cmpl %r12d, %ecx
jbe 0x2acd
movl (%r15), %ebx
leal (%rbx,%rbp), %ecx
decl %ecx
testl %eax, %eax
je 0x2a6e
leal (%rsi,%rbp), %eax
movb (%r14,%rax), %al
cmpb (%r14,%rcx), %al
jne 0x2ab0
movl %r13d, %eax
movl %ebp, (%r9,%rax,8)
subl %r12d, %ebx
movl %ebx, 0x4(%r9,%rax,8)
incl %r13d
incl %ebp
movl $0x1, %eax
jmp 0x2ac5
leal (%rsi,%rbp), %eax
movb (%r11,%rax), %al
cmpb (%r11,%rcx), %al
jne 0x2ab0
leaq (%r14,%rbx), %rsi
movl %ebp, %edx
movq 0x18(%rsp), %rdi
callq 0x1090
movq 0x10(%rsp), %rsi
movl 0x4(%rsp), %edx
movl 0x8(%rsp), %edi
movq 0x20(%rsp), %r8
movq 0x28(%rsp), %r11
movl 0xc(%rsp), %r10d
movq 0x30(%rsp), %r9
testl %eax, %eax
je 0x2a53
movq 0x8(%r15), %r15
testq %r15, %r15
je 0x2acd
movl %r12d, %ecx
subl (%r15), %ecx
xorl %eax, %eax
cmpl %edi, %ecx
ja 0x2acd
cmpl %edx, %ebp
jbe 0x2a2c
cmpl $0x3, %r10d
movl $0xf11, %eax            # imm = 0xF11
movl $0x100, %ecx            # imm = 0x100
cmovel %eax, %ecx
cmpl %ecx, %r13d
ja 0x2afd
movl %r13d, %eax
movq $0x0, (%r9,%rax,8)
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3974(%rip), %rdi      # 0x6478
jmp 0x2b0d
leaq 0x39c7(%rip), %rdi      # 0x64d4
callq 0x1120
movl $0x1, %edi
callq 0x10d0