// File: /workspace/github_c_makefile_star2_O2/mloar[P]charset/utf7.c
// Function: write_utf7
static int write_utf7(charset_spec const *charset, long int input_chr,
		      charset_state *state,
		      void (*emit)(void *ctx, long int output),
		      void *emitctx)
{
    unsigned long hws[2];
    int nhws;
    int i;

    /*
     * For writing: state->s0 contains accumulated base64 data with
     * a 1 in front, and state->s1 indicates how many bits of it we
     * have.
     */

    if ((input_chr >= 0xD800 && input_chr < 0xE000) ||
	input_chr >= 0x110000) {
	/*
	 * We can't output surrogates, or anything above 0x10FFFF.
	 */
	return FALSE;
    }

    /*
     * Look for characters which we output in ASCII mode. A special
     * case here is +, which can be encoded as the empty base64
     * escape sequence `+-': if we're _already_ in ASCII mode we do
     * that, but if we're in base64 mode at the point we see the +
     * then we simply stay in base64 mode and output it as a
     * halfword. (Switching back would cost three bytes, whereas
     * staying in base64 costs only 2 2/3.)
     */
    if (input_chr == -1 || SET_D(input_chr) ||
	(charset->charset == CS_UTF7 && SET_O(input_chr)) ||
	(!state->s0 && input_chr == '+')) {
	if (state->s0) {
	    /*
	     * These characters are output in ASCII mode, so flush any
	     * lingering base64 data.
	     */
	    state->s0 <<= 6 - state->s1;
	    emit(emitctx, base64_chars[state->s0 & 0x3F]);
	    /*
	     * I'm going to arbitrarily decide to always use the
	     * terminating minus sign. It's easier than figuring out
	     * whether to do so or not, and looks prettier besides.
	     */
	    emit(emitctx, '-');
	    state->s0 = state->s1 = 0;
	}

	/*
	 * Now output the character.
	 */
	if (input_chr != -1)	       /* special case: just reset state */
	    emit(emitctx, input_chr);
	if (input_chr == '+')
	    emit(emitctx, '-');	       /* +- encodes + */
	return TRUE;
    }

    /*
     * Now we know we have a character that needs to be output as
     * either one base64-encoded halfword or two. So first figure
     * out how many...
     */
    if (input_chr < 0x10000) {
	nhws = 1;
	hws[0] = input_chr;
    } else {
	input_chr -= 0x10000;
	if (input_chr >= 0x100000) {
	    /* Anything above 0x10FFFF is outside UTF-7 range. */
	    return FALSE;
	}

	nhws = 2;
	hws[0] = 0xD800 | ((input_chr >> 10) & 0x3FF);
	hws[1] = 0xDC00 | (input_chr & 0x3FF);
    }

    /*
     * ... switch into base64 mode if required ...
     */
    if (!state->s0) {
	emit(emitctx, '+');
	state->s0 = 1;
	state->s1 = 0;
    }

    /*
     * ... and do the base64 output.
     */
    for (i = 0; i < nhws; i++) {
	state->s0 = (state->s0 << 16) | hws[i];
	state->s1 += 16;

	while (state->s1 >= 6) {
	    /*
	     * The top set bit must be in position 16, 18 or 20.
	     */
	    unsigned long out, topbit;
	    
	    out = (state->s0 >> (state->s1 - 6)) & 0x3F;
	    state->s1 -= 6;
	    topbit = 1 << state->s1;
	    state->s0 = (state->s0 & (topbit-1)) | topbit;

	    emit(emitctx, base64_chars[out]);
	}
    }
    return TRUE;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rcx, %rbx
movq %rsi, %rax
andq $-0x800, %rax           # imm = 0xF800
cmpq $0xd800, %rax           # imm = 0xD800
sete %al
cmpq $0x110000, %rsi         # imm = 0x110000
setge %cl
xorl %ebp, %ebp
orb %al, %cl
jne 0x9900
movq %r8, %r14
movq %rdx, %r15
movq %rsi, %r12
cmpq $-0x1, %rsi
je 0x98a5
cmpq $0x7f, %r12
ja 0x9880
leaq 0x99566(%rip), %rax     # 0xa2dd0
movb (%r12,%rax), %al
testb $0x1, %al
jne 0x98a5
cmpl $0x3c, (%rdi)
sete %cl
andb $0x2, %al
shrb %al
testb %al, %cl
jne 0x98a5
movq (%r15), %rax
movq %r12, %rcx
xorq $0x2b, %rcx
orq %rax, %rcx
je 0x98e2
cmpq $0x10000, %r12          # imm = 0x10000
jge 0x9911
pushq $0x1
popq %rcx
movq %rcx, 0x8(%rsp)
jmp 0x9942
movq (%r15), %rax
testq %rax, %rax
je 0x98dc
movb $0x6, %cl
subb 0x8(%r15), %cl
shlq %cl, %rax
movq %rax, (%r15)
andl $0x3f, %eax
leaq 0x9958d(%rip), %rcx     # 0xa2e50
movsbq (%rax,%rcx), %rsi
movq %r14, %rdi
callq *%rbx
pushq $0x2d
popq %rsi
movq %r14, %rdi
callq *%rbx
xorps %xmm0, %xmm0
movups %xmm0, (%r15)
cmpq $-0x1, %r12
je 0x98fd
movq %r14, %rdi
movq %r12, %rsi
callq *%rbx
pushq $0x1
popq %rbp
cmpq $0x2b, %r12
jne 0x9900
pushq $0x2d
popq %rsi
movq %r14, %rdi
callq *%rbx
jmp 0x9900
pushq $0x1
popq %rbp
movl %ebp, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq -0x10000(%r12), %rcx
shrq $0xa, %rcx
orq $0xd800, %rcx           # imm = 0xD800
andl $0x3ff, %r12d           # imm = 0x3FF
orq $0xdc00, %r12           # imm = 0xDC00
movq %r12, 0x18(%rsp)
pushq $0x2
popq %rdx
movq %rdx, 0x8(%rsp)
movq %rcx, %r12
movq %r12, 0x10(%rsp)
testq %rax, %rax
jne 0x9960
pushq $0x2b
popq %rsi
movq %r14, %rdi
callq *%rbx
movq $0x1, (%r15)
andq $0x0, 0x8(%r15)
xorl %r12d, %r12d
pushq $0x1
popq %rbp
leaq 0x994e3(%rip), %r13     # 0xa2e50
cmpq 0x8(%rsp), %r12
je 0x9900
movq (%r15), %rax
shlq $0x10, %rax
orq 0x10(%rsp,%r12,8), %rax
movq 0x8(%r15), %rcx
movq %rax, (%r15)
addq $0x10, %rcx
movq %rcx, 0x8(%r15)
cmpq $0x6, %rcx
jb 0x99cd
movq (%r15), %rax
addq $-0x6, %rcx
movq %rax, %rdx
shrq %cl, %rdx
movl %ebp, %esi
shll %cl, %esi
andl $0x3f, %edx
movq %rcx, 0x8(%r15)
movslq %esi, %rcx
leaq -0x1(%rcx), %rsi
andq %rax, %rsi
orq %rcx, %rsi
movq %rsi, (%r15)
movsbq (%rdx,%r13), %rsi
movq %r14, %rdi
callq *%rbx
movq 0x8(%r15), %rcx
jmp 0x998f
incq %r12
jmp 0x996d
nop