// File: /workspace/github_c_makefile_star2_O0/mloar[P]charset/utf16.c
// Function: read_utf16
static void read_utf16(charset_spec const *charset, long int input_chr,
		       charset_state *state,
		       void (*emit)(void *ctx, long int output),
		       void *emitctx)
{
    struct utf16 const *utf = (struct utf16 *)charset->data;
    long int hw;

    /*
     * State variable s1 handles the combining of bytes into
     * transport-endianness halfwords. It contains:
     * 
     *  - 0 if we're between halfwords
     *  - 0x100 plus the first byte if we're in mid-halfword
     * 
     * State variable s0 handles everything from there upwards. It
     * contains:
     * 
     * 	- Bottom 16 bits are set to a surrogate value if we've just
     * 	  seen one.
     * 	- Next two bits (17:16) indicate possible endiannesses. Bit
     * 	  17 is set if we might be BE; bit 16 if we might be LE. If
     * 	  they're both zero, it has to be because this is right at
     * 	  the start, so the first thing we do is set them to the
     * 	  correct initial state.
     * 	- The bit after that (18) is 1 iff we have already seen at
     * 	  least one halfword (meaning we should pass any further
     * 	  BOMs straight through).
     */

    /* Set up s0 if this is the start. */
    if (state->s0 == 0)
	state->s0 = utf->s0;

    /* Accumulate a transport-endianness halfword. */
    if (state->s1 == 0) {
	state->s1 = 0x100 | input_chr;
	return;
    }
    hw = ((state->s1 & 0xFF) << 8) + input_chr;
    state->s1 = 0;

    /* Process BOM and determine byte order. */
    if (!(state->s0 & 0x40000)) {
	state->s0 |= 0x40000;
	if (hw == 0xFEFF && (state->s0 & 0x20000)) {
	    /*
	     * Text starts with a big-endian BOM, and big-
	     * endianness is a possibility. So clear the
	     * little-endian bit (the BOM confirms our endianness),
	     * and return without emitting the BOM in Unicode.
	     */
	    state->s0 &= ~0x10000;
	    return;
	} else if (hw == 0xFFFE && (state->s0 & 0x10000)) {
	    /*
	     * Text starts with a little-endian BOM, and little-
	     * endianness is a possibility. So clear the big-endian
	     * bit (the BOM confirms our endianness), and return
	     * without emitting the BOM in Unicode.
	     */
	    state->s0 &= ~0x20000;
	    return;
	} else {
	    /*
	     * Text does not begin with a BOM. RFC 2781 states that
	     * in this case we must assume big-endianness if we
	     * haven't been told otherwise by the content type.
	     */
	    if ((state->s0 & 0x30000) == 0x30000)
		state->s0 &= ~0x10000; /* clear LE bit */
	}
    }

    /*
     * Byte-swap transport-endianness halfword if necessary. We may
     * now test individual endianness bits, since we can be sure
     * exactly one is set.
     */
    if (state->s0 & 0x10000)
	hw = ((hw >> 8) | (hw << 8)) & 0xFFFF;

    /*
     * Now that the endianness issue has been dealt with, what
     * reaches this point should be a stream of halfwords in
     * sensible numeric form. So now we process surrogates.
     */
    if (state->s0 & 0xFFFF) {
	/*
	 * We have already seen a high surrogate, so we expect a
	 * low surrogate. Whinge if we didn't get it.
	 */
	if (hw < 0xDC00 || hw >= 0xE000) {
	    emit(emitctx, ERROR);
	} else {
	    hw &= 0x3FF;
	    hw |= (state->s0 & 0x3FF) << 10;
	    emit(emitctx, hw + 0x10000);
	}
	state->s0 &= 0xFFFF0000;
    } else {
	/*
	 * Any low surrogate is an error.
	 */
	if (hw >= 0xDC00 && hw < 0xE000) {
	    emit(emitctx, ERROR);
	    return;
	}

	/*
	 * Any high surrogate is simply stored until we see the
	 * next halfword.
	 */
	if (hw >= 0xD800 && hw < 0xDC00) {
	    state->s0 |= hw;
	    return;
	}

	/*
	 * Anything else we simply output.
	 */
	emit(emitctx, hw);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %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 0x18(%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rax
cmpq $0x0, (%rax)
jne 0xb760
movq -0x30(%rbp), %rax
movslq (%rax), %rcx
movq -0x18(%rbp), %rax
movq %rcx, (%rax)
movq -0x18(%rbp), %rax
cmpq $0x0, 0x8(%rax)
jne 0xb783
movq -0x10(%rbp), %rcx
orq $0x100, %rcx            # imm = 0x100
movq -0x18(%rbp), %rax
movq %rcx, 0x8(%rax)
jmp 0xb974
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rax
andq $0xff, %rax
shlq $0x8, %rax
addq -0x10(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rax
movq $0x0, 0x8(%rax)
movq -0x18(%rbp), %rax
movq (%rax), %rax
andq $0x40000, %rax          # imm = 0x40000
cmpq $0x0, %rax
jne 0xb863
movq -0x18(%rbp), %rax
movq (%rax), %rcx
orq $0x40000, %rcx          # imm = 0x40000
movq %rcx, (%rax)
cmpq $0xfeff, -0x38(%rbp)    # imm = 0xFEFF
jne 0xb804
movq -0x18(%rbp), %rax
movq (%rax), %rax
andq $0x20000, %rax          # imm = 0x20000
cmpq $0x0, %rax
je 0xb804
movq -0x18(%rbp), %rax
movq (%rax), %rcx
andq $-0x10001, %rcx         # imm = 0xFFFEFFFF
movq %rcx, (%rax)
jmp 0xb974
cmpq $0xfffe, -0x38(%rbp)    # imm = 0xFFFE
jne 0xb837
movq -0x18(%rbp), %rax
movq (%rax), %rax
andq $0x10000, %rax          # imm = 0x10000
cmpq $0x0, %rax
je 0xb837
movq -0x18(%rbp), %rax
movq (%rax), %rcx
andq $-0x20001, %rcx         # imm = 0xFFFDFFFF
movq %rcx, (%rax)
jmp 0xb974
movq -0x18(%rbp), %rax
movq (%rax), %rax
andq $0x30000, %rax          # imm = 0x30000
cmpq $0x30000, %rax          # imm = 0x30000
jne 0xb85d
movq -0x18(%rbp), %rax
movq (%rax), %rcx
andq $-0x10001, %rcx         # imm = 0xFFFEFFFF
movq %rcx, (%rax)
jmp 0xb85f
jmp 0xb861
jmp 0xb863
movq -0x18(%rbp), %rax
movq (%rax), %rax
andq $0x10000, %rax          # imm = 0x10000
cmpq $0x0, %rax
je 0xb893
movq -0x38(%rbp), %rax
sarq $0x8, %rax
movq -0x38(%rbp), %rcx
shlq $0x8, %rcx
orq %rcx, %rax
andq $0xffff, %rax           # imm = 0xFFFF
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
andq $0xffff, %rax           # imm = 0xFFFF
cmpq $0x0, %rax
je 0xb91d
cmpq $0xdc00, -0x38(%rbp)    # imm = 0xDC00
jl 0xb8ba
cmpq $0xe000, -0x38(%rbp)    # imm = 0xE000
jl 0xb8cb
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
jmp 0xb907
movq -0x38(%rbp), %rax
andq $0x3ff, %rax            # imm = 0x3FF
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
andq $0x3ff, %rax            # imm = 0x3FF
shlq $0xa, %rax
orq -0x38(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x38(%rbp), %rsi
addq $0x10000, %rsi          # imm = 0x10000
callq *%rax
movq -0x18(%rbp), %rax
movabsq $0xffff0000, %rcx       # imm = 0xFFFF0000
andq (%rax), %rcx
movq %rcx, (%rax)
jmp 0xb974
cmpq $0xdc00, -0x38(%rbp)    # imm = 0xDC00
jl 0xb942
cmpq $0xe000, -0x38(%rbp)    # imm = 0xE000
jge 0xb942
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movl $0xffff, %esi           # imm = 0xFFFF
callq *%rax
jmp 0xb974
cmpq $0xd800, -0x38(%rbp)    # imm = 0xD800
jl 0xb966
cmpq $0xdc00, -0x38(%rbp)    # imm = 0xDC00
jge 0xb966
movq -0x38(%rbp), %rcx
movq -0x18(%rbp), %rax
orq (%rax), %rcx
movq %rcx, (%rax)
jmp 0xb974
movq -0x20(%rbp), %rax
movq -0x28(%rbp), %rdi
movq -0x38(%rbp), %rsi
callq *%rax
addq $0x40, %rsp
popq %rbp
retq
nopw (%rax,%rax)