// File: /workspace/github_c_makefile_star2_O2/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 $0x58, %rsp
movq %rcx, %rbx
movq %rdx, 0x50(%rsp)
movl %edi, %r12d
movq $0x1, (%rcx)
leaq 0x7f39(%rip), %rax      # 0xa320
movl (%rax), %r11d
cmpl $0x3, %r11d
jne 0x2419
leal -0xc(%rsi), %ecx
pushq $0xc
popq %rdx
pushq $0x1
popq %r15
cmpl $0x2a, %edx
ja 0x241d
cmpl %r12d, %ecx
jb 0x241d
movl %edx, (%rbx,%r15,8)
andl $0x0, 0x4(%rbx,%r15,8)
incq %r15
addl $0x2, %edx
addl $-0x2, %ecx
jmp 0x23fa
pushq $0x1
popq %r15
movq 0x40(%rax), %r14
movl %r12d, %edx
leaq (%r14,%rdx), %rcx
movq %rcx, 0x48(%rsp)
movzbl (%r14,%rdx), %ecx
xorl %edi, %edi
movl %r12d, %r8d
subl $0x8, %r8d
cmovbl %edi, %r8d
pushq $0x8
popq %rdi
cmovbl %r12d, %edi
negl %edi
cmpb %cl, (%r14,%r8)
je 0x245a
incq %r8
incl %edi
cmpq %rdx, %r8
jb 0x2448
jmp 0x246d
movl %r15d, %r8d
movl $0x1, (%rbx,%r8,8)
movl %edi, 0x4(%rbx,%r8,8)
incl %r15d
cmpl $0x3, %r11d
setne %dil
leal -0x2(%rsi), %ebp
cmpl %r12d, %ebp
setbe %r8b
orb %dil, %r8b
jne 0x24d5
leal 0x2(%r12), %edi
xorl %r9d, %r9d
movl %r12d, %r8d
subl $0x4f, %r8d
cmovbl %r9d, %r8d
pushq $0x4f
popq %r9
cmovbl %r12d, %r9d
negl %r9d
cmpb %cl, (%r14,%r8)
jne 0x24b6
leal 0x2(%r8), %r10d
movb (%r14,%r10), %r10b
cmpb (%r14,%rdi), %r10b
je 0x24c3
incq %r8
incl %r9d
cmpq %rdx, %r8
jb 0x24a2
jmp 0x24d5
movl %r15d, %edi
movl $0xfffffffd, (%rbx,%rdi,8) # imm = 0xFFFFFFFD
movl %r9d, 0x4(%rbx,%rdi,8)
incl %r15d
cmpl $0x3, %r11d
je 0x2513
cmpl $0x2, %r11d
je 0x24f6
cmpl $0x1, %r11d
jne 0x26dd
movl 0x1c(%rax), %eax
movl $0x1100, %r8d           # imm = 0x1100
jmp 0x24ff
movl 0x1c(%rax), %eax
movl $0x1000, %r8d           # imm = 0x1000
cmpl %r8d, %eax
cmovbl %eax, %r8d
movl $0x100, %eax            # imm = 0x100
movl $0xff, %r9d
jmp 0x252e
movl 0x1c(%rax), %eax
movl $0x10000, %r8d          # imm = 0x10000
cmpl %r8d, %eax
cmovbl %eax, %r8d
movl $0x300, %eax            # imm = 0x300
movl $0xeff, %r9d            # imm = 0xEFF
leal -0x1(%rsi), %edi
cmpl %r12d, %edi
jbe 0x26a7
movzbl 0x1(%rdx,%r14), %edx
shll $0xb, %ecx
leal (%rcx,%rdx,8), %ecx
leaq 0xf6d3(%rip), %rdx      # 0x11c20
movq (%rdx,%rcx), %rcx
testq %rcx, %rcx
je 0x26a7
movq %rcx, 0x18(%rsp)
movl (%rcx), %edi
movl %r12d, %ecx
subl %edi, %ecx
cmpl %eax, %ecx
ja 0x2585
cmpl %r8d, %ecx
ja 0x2585
movl %r15d, %eax
movl $0x2, (%rbx,%rax,8)
movl %edi, %edx
subl %r12d, %edx
movl %edx, 0x4(%rbx,%rax,8)
incl %r15d
cmpl %r12d, %ebp
jbe 0x26a7
cmpl %r8d, %ecx
ja 0x26a7
leal -0x1(%r12), %r13d
incl %esi
pushq $0x3
popq %rcx
xorl %eax, %eax
movl %r11d, 0xc(%rsp)
movq %rsi, 0x20(%rsp)
movl %r8d, 0x10(%rsp)
movq %r14, 0x30(%rsp)
movq %rbx, 0x28(%rsp)
movl %edi, %edx
addq %r14, %rdx
movq %rdx, 0x38(%rsp)
movl %edi, %r8d
subl %r12d, %r8d
movl %ecx, %ebp
subl %ecx, %esi
decl %edi
movq %rdi, 0x40(%rsp)
cmpl %r9d, %ebp
ja 0x26a2
cmpl %r12d, %esi
jbe 0x26a2
leal (%r13,%rbp), %ecx
testb $0x1, %al
je 0x2643
movq 0x50(%rsp), %rdx
movb (%rdx,%rcx), %al
leal (%rdi,%rbp), %ecx
cmpb (%rdx,%rcx), %al
jne 0x266a
movq 0x48(%rsp), %rdi
movl %esi, 0x14(%rsp)
movq 0x38(%rsp), %rsi
movq %rbp, %rdx
movq %r12, %rbx
movl %r9d, %r12d
movl %r8d, %r14d
callq 0x1080
movl 0x14(%rsp), %esi
movl %r14d, %r8d
movq 0x40(%rsp), %rdi
movl %r12d, %r9d
movq %rbx, %r12
movq 0x28(%rsp), %rbx
movq 0x30(%rsp), %r14
testl %eax, %eax
je 0x2650
jmp 0x266a
movb (%r14,%rcx), %al
leal (%rdi,%rbp), %ecx
cmpb (%r14,%rcx), %al
jne 0x266a
movl %r15d, %eax
movl %ebp, (%rbx,%rax,8)
movl %r8d, 0x4(%rbx,%rax,8)
incl %r15d
incq %rbp
decl %esi
xorl %eax, %eax
jmp 0x25d7
movq 0x18(%rsp), %rax
movq 0x8(%rax), %rax
testq %rax, %rax
je 0x26a2
movq %rax, 0x18(%rsp)
movl (%rax), %edi
movl %r12d, %edx
subl %edi, %edx
movb $0x1, %al
movl %ebp, %ecx
movl 0x10(%rsp), %r8d
cmpl %r8d, %edx
movl 0xc(%rsp), %r11d
movq 0x20(%rsp), %rsi
jbe 0x25bc
jmp 0x26a7
movl 0xc(%rsp), %r11d
cmpl $0x3, %r11d
movl $0xf11, %eax            # imm = 0xF11
movl $0x100, %ecx            # imm = 0x100
cmovel %eax, %ecx
cmpl %ecx, %r15d
ja 0x26d4
movl %r15d, %eax
andq $0x0, (%rbx,%rax,8)
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x2d9d(%rip), %rdi      # 0x5478
jmp 0x26e4
leaq 0x2df0(%rip), %rdi      # 0x54d4
callq 0x1110
pushq $0x1
popq %rdi
callq 0x10c0