// File: /workspace/github_c_makefile_star2_O0/mloar[P]charset/utf8.c
// Function: read_utf8
void read_utf8(charset_spec const *charset, long int input_chr,
	       charset_state *state,
	       void (*emit)(void *ctx, long int output), void *emitctx)
{
    UNUSEDARG(charset);

    /*
     * For reading UTF-8, the `state' word contains the character
     * being accumulated.  This is shifted left by six bits each
     * time a character is added, and there's a single '1' bit
     * in what would be bit 31 of the final character, which we
     * use to detect when it's complete.
     * 
     * As required, the state is zero when we are not in the middle
     * of a multibyte character at all.
     * 
     * For example, when reading E9 8D 8B, starting at state=0:
     * 
     *  - after E9, the state is 0x00080009
     *  - after 8D, the state is 0x0200024d
     *  - after 8B, the state conceptually becomes 0x8000934b, at
     *    which point we notice we've got as many characters as we
     *    were expecting, output U+934B, and reset the state to
     *    zero.
     *
     * If we detect an overlong sequence, we shift the marker bit
     * right one bit.  This is safe because an overlong sequence
     * can't encode a top-bit-set character.  Not that we worry
     * about what overlong sequences are trying to encode, but
     * it's nice to know that we could if we wanted to.
     *
     * Note that the maximum number of bits we might need to store
     * in the character value field is 25 (U+7FFFFFFF contains 31
     * bits, but we will never actually store its full value
     * because when we receive the last 6 bits in the final
     * continuation byte we will output it and revert the state to
     * zero). Hence we need 26 bits in total.
     */

    if (input_chr < 0x80) {
	/*
	 * Single-byte character. If the state is nonzero before
	 * coming here, output an error for an incomplete sequence.
	 * Then output the character.
	 */
	if (state->s0 != 0) {
	    emit(emitctx, ERROR);
	    state->s0 = 0;
	}
	emit(emitctx, input_chr);
    } else if (input_chr == 0xFE || input_chr == 0xFF) {
	/*
	 * FE and FF bytes should _never_ occur in UTF-8. They are
	 * automatic errors; if the state was nonzero to start
	 * with, output a further error for an incomplete sequence.
	 */
	if (state->s0 != 0) {
	    emit(emitctx, ERROR);
	    state->s0 = 0;
	}
	emit(emitctx, ERROR);
    } else if (input_chr >= 0x80 && input_chr < 0xC0) {
	/*
	 * Continuation byte. Output an error for an unexpected
	 * continuation byte, if the state is zero.
	 */
	if (state->s0 == 0) {
	    emit(emitctx, ERROR);
	} else {
	    unsigned long charval;

	    /*
	     * Otherwise, accumulate more of the character value.
	     */
	    charval = state->s0;
	    charval = (charval << 6) | (input_chr & 0x3F);

	    /*
	     * Detect overlong encodings.  We're looking for too many
	     * leading zeroes given our position in the character.  If
	     * we find an overlong encoding, clear the current marker
	     * bit and set the bit below it.  Overlong two-byte
	     * encodings are a special case, and are detected when we
	     * read their inital byte.
	     */
	    if ((charval & 0xffffffe0L) == 0x02000000L)
		charval ^= 0x03000000L;
	    else if ((charval & 0xfffffff0L) == 0x00080000L)
		charval ^= 0x000c0000L;
	    else if ((charval & 0xfffffff8L) == 0x00002000L)
		charval ^= 0x00003000L;
	    else if ((charval & 0xfffffffcL) == 0x00000080L)
		charval ^= 0x000000c0L;

	    /*
	     * Check the byte counts; if we have not reached the
	     * end of the character, update the state and return.
	     */
	    if (!(charval & 0xc0000000L)) {
		state->s0 = charval;
		return;
	    }

	    /*
	     * Clear the marker bit, or set it if it's clear,
	     * indicating an overlong sequence.
	     */
	    charval ^= 0x80000000L;

	    /*
	     * Now we know we've reached the end of the character.
	     * `charval' is the Unicode value. We should check for
	     * various invalid things, and then either output
	     * charval or an error. In all cases we reset the state
	     * to zero.
	     */
	    state->s0 = 0;

	    if (charval & 0x80000000L) {
		/* We got an overlong sequence. */
		emit(emitctx, ERROR);
	    } else if (charval >= 0xD800 && charval < 0xE000) {
		/*
		 * Surrogates (0xD800-0xDFFF) may never be encoded
		 * in UTF-8. A surrogate pair in Unicode should
		 * have been encoded as a single UTF-8 character
		 * occupying more than three bytes.
		 */
		emit(emitctx, ERROR);
	    } else if (charval == 0xFFFE || charval == 0xFFFF) {
		/*
		 * U+FFFE and U+FFFF are invalid Unicode characters
		 * and may never be encoded in UTF-8. (This is one
		 * reason why U+FFFF is our way of signalling an
		 * error to our `emit' function :-)
		 */
		emit(emitctx, ERROR);
	    } else {
		/*
		 * Oh, all right. We'll let this one off.
		 */
		emit(emitctx, charval);
	    }
	}

    } else {
	/*
	 * Lead byte. First output an error for an incomplete
	 * sequence, if the state is nonzero.
	 */
	if (state->s0 != 0)
	    emit(emitctx, ERROR);

	/*
	 * Now deal with the lead byte: work out the number of
	 * bytes we expect to see in this character, and extract
	 * the initial bits of it too.
	 */
	if (input_chr >= 0xC0 && input_chr < 0xC2) {
	    /* beginning of an overlong two-byte sequence */
	    state->s0 = 0x01000000L | (input_chr & 0x1F);
	} else if (input_chr >= 0xC2 && input_chr < 0xE0) {
	    state->s0 = 0x02000000L | (input_chr & 0x1F);
	} else if (input_chr >= 0xE0 && input_chr < 0xF0) {
	    state->s0 = 0x00080000L | (input_chr & 0x0F);
	} else if (input_chr >= 0xF0 && input_chr < 0xF8) {
	    state->s0 = 0x00002000L | (input_chr & 0x07);
	} else if (input_chr >= 0xF8 && input_chr < 0xFC) {
	    state->s0 = 0x00000080L | (input_chr & 0x03);
	} else if (input_chr >= 0xFC && input_chr < 0xFE) {
	    state->s0 = 0x00000002L | (input_chr & 0x01);
	}
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x30, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x8(%rbp)
cmpq $0x80, -0x10(%rbp)
jge 0xc1b5
movq -0x18(%rbp), %rax
cmpq $0x0, (%rax)
je 0xc1a2
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
movq -0x18(%rbp), %rax
movq $0x0, (%rax)
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq *%rax
jmp 0xc4f7
cmpq $0xfe, -0x10(%rbp)
je 0xc1c9
cmpq $0xff, -0x10(%rbp)
jne 0xc201
movq -0x18(%rbp), %rax
cmpq $0x0, (%rax)
je 0xc1ed
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
movq -0x18(%rbp), %rax
movq $0x0, (%rax)
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
jmp 0xc4f5
cmpq $0x80, -0x10(%rbp)
jl 0xc3c2
cmpq $0xc0, -0x10(%rbp)
jge 0xc3c2
movq -0x18(%rbp), %rax
cmpq $0x0, (%rax)
jne 0xc23b
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
jmp 0xc3bd
movq -0x18(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
shlq $0x6, %rax
movq -0x10(%rbp), %rcx
andq $0x3f, %rcx
orq %rcx, %rax
movq %rax, -0x30(%rbp)
movabsq $0xffffffe0, %rax       # imm = 0xFFFFFFE0
andq -0x30(%rbp), %rax
cmpq $0x2000000, %rax        # imm = 0x2000000
jne 0xc283
movq -0x30(%rbp), %rax
xorq $0x3000000, %rax        # imm = 0x3000000
movq %rax, -0x30(%rbp)
jmp 0xc2f9
movabsq $0xfffffff0, %rax       # imm = 0xFFFFFFF0
andq -0x30(%rbp), %rax
cmpq $0x80000, %rax          # imm = 0x80000
jne 0xc2a9
movq -0x30(%rbp), %rax
xorq $0xc0000, %rax          # imm = 0xC0000
movq %rax, -0x30(%rbp)
jmp 0xc2f7
movabsq $0xfffffff8, %rax       # imm = 0xFFFFFFF8
andq -0x30(%rbp), %rax
cmpq $0x2000, %rax           # imm = 0x2000
jne 0xc2cf
movq -0x30(%rbp), %rax
xorq $0x3000, %rax           # imm = 0x3000
movq %rax, -0x30(%rbp)
jmp 0xc2f5
movabsq $0xfffffffc, %rax       # imm = 0xFFFFFFFC
andq -0x30(%rbp), %rax
cmpq $0x80, %rax
jne 0xc2f3
movq -0x30(%rbp), %rax
xorq $0xc0, %rax
movq %rax, -0x30(%rbp)
jmp 0xc2f5
jmp 0xc2f7
jmp 0xc2f9
movabsq $0xc0000000, %rax       # imm = 0xC0000000
andq -0x30(%rbp), %rax
cmpq $0x0, %rax
jne 0xc31d
movq -0x30(%rbp), %rcx
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
jmp 0xc4f7
movabsq $0x80000000, %rax       # imm = 0x80000000
xorq -0x30(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rax
movq $0x0, (%rax)
movabsq $0x80000000, %rax       # imm = 0x80000000
andq -0x30(%rbp), %rax
cmpq $0x0, %rax
je 0xc35f
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
jmp 0xc3bb
cmpq $0xd800, -0x30(%rbp)    # imm = 0xD800
jb 0xc384
cmpq $0xe000, -0x30(%rbp)    # imm = 0xE000
jae 0xc384
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
jmp 0xc3b9
cmpq $0xfffe, -0x30(%rbp)    # imm = 0xFFFE
je 0xc398
cmpq $0xffff, -0x30(%rbp)    # imm = 0xFFFF
jne 0xc3a9
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
jmp 0xc3b7
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq *%rax
jmp 0xc3b9
jmp 0xc3bb
jmp 0xc3bd
jmp 0xc4f3
movq -0x18(%rbp), %rax
cmpq $0x0, (%rax)
je 0xc3db
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
cmpq $0xc0, -0x10(%rbp)
jl 0xc40a
cmpq $0xc2, -0x10(%rbp)
jge 0xc40a
movq -0x10(%rbp), %rcx
andq $0x1f, %rcx
orq $0x1000000, %rcx        # imm = 0x1000000
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
jmp 0xc4f1
cmpq $0xc2, -0x10(%rbp)
jl 0xc439
cmpq $0xe0, -0x10(%rbp)
jge 0xc439
movq -0x10(%rbp), %rcx
andq $0x1f, %rcx
orq $0x2000000, %rcx        # imm = 0x2000000
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
jmp 0xc4ef
cmpq $0xe0, -0x10(%rbp)
jl 0xc468
cmpq $0xf0, -0x10(%rbp)
jge 0xc468
movq -0x10(%rbp), %rcx
andq $0xf, %rcx
orq $0x80000, %rcx          # imm = 0x80000
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
jmp 0xc4ed
cmpq $0xf0, -0x10(%rbp)
jl 0xc494
cmpq $0xf8, -0x10(%rbp)
jge 0xc494
movq -0x10(%rbp), %rcx
andq $0x7, %rcx
orq $0x2000, %rcx           # imm = 0x2000
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
jmp 0xc4eb
cmpq $0xf8, -0x10(%rbp)
jl 0xc4c0
cmpq $0xfc, -0x10(%rbp)
jge 0xc4c0
movq -0x10(%rbp), %rcx
andq $0x3, %rcx
orq $0x80, %rcx
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
jmp 0xc4e9
cmpq $0xfc, -0x10(%rbp)
jl 0xc4e7
cmpq $0xfe, -0x10(%rbp)
jge 0xc4e7
movq -0x10(%rbp), %rcx
andq $0x1, %rcx
orq $0x2, %rcx
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
jmp 0xc4e9
jmp 0xc4eb
jmp 0xc4ed
jmp 0xc4ef
jmp 0xc4f1
jmp 0xc4f3
jmp 0xc4f5
jmp 0xc4f7
addq $0x30, %rsp
popq %rbp
retq
nopl (%rax)