// File: /workspace/github_c_makefile_star2_O1/lmcilroy[P]lzm/lzmdecode.c
// Function: lzm_decode
unsigned int
lzm_decode(
    const struct lzm_state * const state,
    const unsigned char * const buffer_in,
    const unsigned int size_in,
    unsigned char * const buffer_out,
    unsigned int * const size_out)
{
	const unsigned char * const end = buffer_in + size_in;
	const unsigned char * const match_end = end - 5;
	const unsigned char *curr_in = (const unsigned char *) buffer_in;
	unsigned char *curr_out = (unsigned char *) buffer_out;
	const unsigned char * const out_limit = buffer_out + *size_out;
	const unsigned char *out_limit_fast_path;
	unsigned char *match;
	unsigned char *mend;
	unsigned long int c;
	unsigned int llen;
	unsigned int mlen;
	unsigned int off = 1;
	unsigned char op;

	(void)state;

	if (buffer_in == NULL || buffer_out == NULL)
		return EINVAL;

	out_limit_fast_path = (*size_out < (14 + 14 + MIN_MATCH)) ? NULL :
		out_limit - (14 + 14 + MIN_MATCH);

	while (likely(curr_in <= match_end)) {
		op = *curr_in++;
		llen = op >> 4;
		mlen = (op & 15) + MIN_MATCH;

		curr_in = decode_offset(curr_in, &off);

		if (likely(llen < 15 && (curr_in + 16) <= end &&
		    curr_out <= out_limit_fast_path)) {
			LOG("L %d\n", llen);
			memcpy(curr_out, curr_in, 16);
			curr_out += llen;
			curr_in += llen;
			if (unlikely(off > (curr_out - buffer_out)))
				return EIO;
			if (likely(mlen < (15 + MIN_MATCH) &&
			    likely(((off >= mlen) | (off >= 8))))) {
				LOG("M %d %d\n", mlen, off);
				match = curr_out - off;
				memcpy(curr_out, match, 8);
				memcpy(curr_out+8, match+8, 8);
				memcpy(curr_out+16, match+16, 2);
				curr_out += mlen;
				continue;
			}
			goto match;
		}

		if (likely(llen > 0)) {
			if (unlikely(llen == 15)) {
				if (unlikely(curr_in >= end - 15))
					return EIO;

				curr_in = decode_length(curr_in, &llen);
				llen += 15;
			}
			LOG("L %d\n", llen);
			if (unlikely((curr_in + llen) > end))
				return EIO;
			if (unlikely((curr_out + llen) > out_limit))
				return EOVERFLOW;
			memcpy(curr_out, curr_in, llen);
			curr_in += llen;
			curr_out += llen;
		}

		if (unlikely(off > (curr_out - buffer_out)))
			return EIO;

 match:
		if (unlikely(off == 0))
			break;

		if (likely(mlen < (15 + MIN_MATCH) && off >= mlen &&
		    (curr_out + (14 + MIN_MATCH)) <= out_limit)) {
			LOG("M %d %d\n", mlen, off);
			match = curr_out - off;
			memcpy(curr_out, match, 8);
			memcpy(curr_out+8, match+8, 8);
			memcpy(curr_out+16, match+16, 2);
			curr_out += mlen;
			continue;
		}

		if (likely(mlen == (15 + MIN_MATCH))) {
			if (unlikely(curr_in >= match_end))
				return EIO;

			curr_in = decode_length(curr_in, &mlen);
			mlen += 15 + MIN_MATCH;
		}

		LOG("M %d %d\n", mlen, off);
		if (unlikely((curr_out + mlen) > out_limit))
			return EOVERFLOW;

		match = curr_out - off;
		mend = curr_out + mlen;

		if (likely(mlen <= off)) {
			memcpy(curr_out, match, mlen);
			curr_out += mlen;
			continue;
		}

		if (off == 1) {
			c = *match;
			*curr_out++ = c;
			*curr_out++ = c;
			*curr_out++ = c;
			*curr_out++ = c;
			while (curr_out < mend)
				*curr_out++ = c;
			continue;
		}

		if (off == 2) {
			c = readmem16(match);
			writemem16(curr_out, c);
			curr_out += 2;
			writemem16(curr_out, c);
			curr_out += 2;
			while (curr_out < mend) {
				writemem16(curr_out, c);
				curr_out += 2;
				writemem16(curr_out, c);
				curr_out += 2;
			}
			curr_out = mend;
			continue;
		}

		if (off == 3) {
			unsigned char c1, c2, c3;
			c1 = *match;
			c2 = *(match+1);
			c3 = *(match+2);
			*curr_out++ = c1;
			*curr_out++ = c2;
			*curr_out++ = c3;
			*curr_out++ = c1;
			*curr_out++ = c2;
			*curr_out++ = c3;
			while (curr_out < mend) {
				*curr_out++ = c1;
				*curr_out++ = c2;
				*curr_out++ = c3;
			}
			curr_out = mend;
		}

		if (off == 4) {
			c = readmem32(match);
			writemem32(curr_out, c);
			curr_out += off;
			writemem32(curr_out, c);
			curr_out += off;
			while (curr_out < mend) {
				writemem32(curr_out, c);
				curr_out += off;
				writemem32(curr_out, c);
				curr_out += off;
			}
			curr_out = mend;
			continue;
		}

		if (off <= 8) {
			c = readmem64(match);
			writemem64(curr_out, c);
			curr_out += off;
			while (curr_out < mend) {
				writemem64(curr_out, c);
				curr_out += off;
			}
			curr_out = mend;
			continue;
		}

		memcpy(curr_out, match, 4);
		match += 4;
		curr_out += 4;
		while (curr_out < mend) {
			memcpy(curr_out, match, 8);
			match += 8;
			curr_out += 8;
		}
		curr_out = mend;
	}

	*size_out = curr_out - buffer_out;

	/* Finished without seeing end of stream? */
	if (off != 0)
		return EIO;

	return 0;
}

// Assembly:
movq %rcx, %r9
testq %rsi, %rsi
sete %al
testq %rcx, %rcx
sete %cl
orb %al, %cl
je 0x277f
pushq $0x16
popq %rax
retq
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movl %edx, %r10d
leaq (%rsi,%r10), %r11
addq $-0x5, %r11
movl (%r8), %eax
movq %rax, %rcx
addq %r9, %rcx
movq %rcx, 0x10(%rsp)
addq $-0x20, %rcx
xorl %ebp, %ebp
cmpl $0x20, %eax
cmovaeq %rcx, %rbp
cmpq %rsi, %r11
jb 0x2c17
movq %r8, 0x20(%rsp)
addq %rsi, %r10
leaq -0xf(%r10), %rax
movq %rax, 0x18(%rsp)
leaq 0x40ac(%rip), %r8       # 0x6880
movq %r9, %rdi
movq %r11, (%rsp)
movq %r9, 0x28(%rsp)
movzbl (%rsi), %ebx
movl %ebx, %eax
shrl $0x4, %eax
andl $0xf, %ebx
movl 0x1(%rsi), %r14d
bsfl %r14d, %edx
leal 0x1(%rdx), %ecx
andl (%r8,%rcx,4), %r14d
shrq %cl, %r14
leaq 0x4(%rbx), %r15
leaq (%rdx,%rsi), %r12
addq $0x2, %r12
movl %r14d, %r13d
cmpl $0xf, %eax
je 0x289a
leaq (%rdx,%rsi), %rcx
addq $0x12, %rcx
cmpq %r10, %rcx
ja 0x289a
cmpq %rbp, %rdi
ja 0x289a
movups (%r12), %xmm0
movups %xmm0, (%rdi)
addq %rax, %rdi
movq %rdi, %rcx
subq %r9, %rcx
cmpq %r13, %rcx
jl 0x2c12
addq %rax, %r12
cmpl $0xf, %ebx
je 0x2903
cmpl %r15d, %r14d
setb %al
cmpl $0x8, %r14d
setb %cl
testb %cl, %al
jne 0x2903
movq %rdi, %rax
subq %r13, %rax
movq (%rax), %rcx
movq %rcx, (%rdi)
movq 0x8(%rax), %rax
movq %rax, 0x8(%rdi)
negq %r13
movzwl 0x10(%rdi,%r13), %eax
movw %ax, 0x10(%rdi)
addq %rdi, %r15
movq %r12, %rsi
movq %r15, %rdi
cmpq %r11, %r12
jbe 0x27e0
jmp 0x2c22
testl %eax, %eax
je 0x29ab
cmpl $0xf, %eax
je 0x29b3
movl %eax, %edx
leaq (%r12,%rdx), %rcx
cmpq %r10, %rcx
ja 0x2c12
leaq (%rdi,%rdx), %rax
cmpq 0x10(%rsp), %rax
ja 0x2c47
movq %r12, %rsi
movq %r10, %r12
movq %rax, 0x8(%rsp)
movq %rcx, 0x30(%rsp)
callq 0x11c0
movq 0x8(%rsp), %rax
movq (%rsp), %r11
movq %r12, %r10
movq 0x28(%rsp), %r9
movq %rax, %rdi
movq 0x30(%rsp), %r12
subq %r9, %rax
cmpq %r13, %rax
jl 0x2c12
testl %r14d, %r14d
je 0x2c1f
cmpl $0xf, %ebx
je 0x294f
cmpl %r15d, %r14d
jb 0x294f
leaq 0x12(%rdi), %rax
cmpq 0x10(%rsp), %rax
ja 0x294f
movq %rdi, %rax
subq %r13, %rax
movq (%rax), %rcx
movq %rcx, (%rdi)
movq 0x8(%rax), %rcx
movq %rcx, 0x8(%rdi)
movzwl 0x10(%rax), %eax
movw %ax, 0x10(%rdi)
movl %r15d, %r15d
addq %rdi, %r15
leaq 0x3f36(%rip), %r8       # 0x6880
jmp 0x2886
cmpl $0x13, %r15d
jne 0x2977
cmpq %r11, %r12
jae 0x2c12
movzbl (%r12), %r15d
cmpl $0xfc, %r15d
jae 0x2a3f
incq %r12
addl $0x13, %r15d
movl %r15d, %edx
leaq (%rdi,%rdx), %r15
cmpq 0x10(%rsp), %r15
ja 0x2c47
movq %r10, %r13
movq %r9, %rbx
movq %rdi, %rsi
subq %r14, %rsi
cmpl %r14d, %edx
ja 0x29d9
callq 0x11c0
movq %rbx, %r9
movq %r13, %r10
movq (%rsp), %r11
jmp 0x2943
movq %rdi, %rax
jmp 0x28f7
cmpq 0x18(%rsp), %r12
jae 0x2c12
movzbl (%r12), %eax
cmpl $0xfc, %eax
jae 0x2b23
incq %r12
addl $0xf, %eax
jmp 0x28ab
movq %rdx, %r9
cmpl $0x3, %r14d
je 0x2a5b
cmpl $0x2, %r14d
je 0x2a9b
cmpl $0x1, %r14d
jne 0x2ac8
movb (%rsi), %al
movb %al, (%rdi)
movb %al, 0x1(%rdi)
movb %al, 0x2(%rdi)
leaq 0x4(%rdi), %r15
movb %al, 0x3(%rdi)
cmpl $0x5, %r9d
jb 0x299f
movq %r9, %rdx
addq %rdi, %rdx
leaq 0x5(%rdi), %rcx
cmpq %rcx, %rdx
cmovbeq %rcx, %rdx
movq %rdx, 0x8(%rsp)
subq %rdi, %rdx
addq $-0x4, %rdx
movzbl %al, %esi
movq %r15, %rdi
callq 0x1120
movq 0x8(%rsp), %r15
jmp 0x299f
jne 0x2b66
movzbl 0x1(%r12), %r15d
addl $0xfc, %r15d
addq $0x2, %r12
jmp 0x2973
movb (%rsi), %cl
movb 0x1(%rsi), %dl
movb 0x2(%rsi), %r8b
movb %cl, (%rdi)
movb %dl, 0x1(%rdi)
movb %r8b, 0x2(%rdi)
movb %cl, 0x3(%rdi)
movb %dl, 0x4(%rdi)
movb %r8b, 0x5(%rdi)
movq %r15, %rax
cmpl $0x7, %r9d
jb 0x2acb
addq $0x6, %rdi
movb %cl, (%rdi)
movb %dl, 0x1(%rdi)
movb %r8b, 0x2(%rdi)
addq $0x3, %rdi
cmpq %r15, %rdi
jb 0x2a84
movq %r15, %rax
jmp 0x2acb
movzwl (%rsi), %eax
movw %ax, (%rdi)
movw %ax, 0x2(%rdi)
cmpl $0x5, %r9d
jb 0x299f
addq $0x4, %rdi
movw %ax, (%rdi)
movw %ax, 0x2(%rdi)
addq $0x4, %rdi
cmpq %r15, %rdi
jb 0x2ab3
jmp 0x299f
movq %rdi, %rax
cmpl $0x4, %r14d
jne 0x2b0a
movl (%rsi), %ecx
movl %ecx, (%rax)
leaq (%rax,%r14), %rdx
movl %ecx, (%rax,%r14)
addq %r14, %rdx
cmpq %r15, %rdx
jae 0x299f
leaq (%r14,%r14,2), %rdx
movq %r14, %rsi
addq %r14, %rsi
movl %ecx, (%rax,%rsi)
movl %ecx, (%rax,%rdx)
addq %rsi, %rax
leaq (%rax,%rsi), %rdi
cmpq %r15, %rdi
jb 0x2af3
jmp 0x299f
cmpl $0x8, %r14d
ja 0x2b39
movq (%rsi), %rcx
movq %rcx, (%rax)
addq %r14, %rax
cmpq %r15, %rax
jb 0x2b13
jmp 0x299f
jne 0x2b85
movzbl 0x1(%r12), %eax
addl $0xfc, %eax
addq $0x2, %r12
jmp 0x29d1
movl (%rsi), %ecx
movl %ecx, (%rax)
addq $0x4, %rax
cmpq %r15, %rax
jae 0x299f
addq $0x4, %rsi
movq (%rsi), %rcx
movq %rcx, (%rax)
addq $0x8, %rsi
addq $0x8, %rax
cmpq %r15, %rax
jb 0x2b4e
jmp 0x299f
cmpl $0xfd, %r15d
jne 0x2ba0
movzwl 0x1(%r12), %r15d
addl $0xfd, %r15d
addq $0x3, %r12
jmp 0x2973
cmpl $0xfd, %eax
jne 0x2bc6
movzwl 0x1(%r12), %eax
addl $0xfd, %eax
addq $0x3, %r12
jmp 0x29d1
cmpl $0xfe, %r15d
jne 0x2be7
movl 0x1(%r12), %r15d
movl $0xffffff, %eax         # imm = 0xFFFFFF
andl %eax, %r15d
addl $0xfe, %r15d
addq $0x4, %r12
jmp 0x2973
cmpl $0xfe, %eax
jne 0x2bfd
movl 0x1(%r12), %eax
movl $0xffffff, %ecx         # imm = 0xFFFFFF
andl %ecx, %eax
addl $0xfe, %eax
addq $0x4, %r12
jmp 0x29d1
movl 0x1(%r12), %r15d
movl $0xff, %eax
addl %eax, %r15d
addq $0x5, %r12
jmp 0x2973
movl 0x1(%r12), %eax
movl $0xff, %ecx
addl %ecx, %eax
addq $0x5, %r12
jmp 0x29d1
pushq $0x5
popq %rax
jmp 0x2c38
pushq $0x5
popq %rax
movq %r9, %r15
jmp 0x2c32
movq %rdi, %r15
xorl %eax, %eax
testl %r14d, %r14d
setne %al
leal (%rax,%rax,4), %eax
movq 0x20(%rsp), %r8
subl %r9d, %r15d
movl %r15d, (%r8)
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
pushq $0x4b
jmp 0x2c14
nopl (%rax,%rax)