+ switch (c->state)
+ {
+ case SINGLE_WRITE:
+ if (d >= de)
+ goto cde;
+ *d++ = c->code;
+ break;
+ case SEQ_WRITE:
+ while (c->remains)
+ {
+ if (d >= de)
+ goto cde;
+ *d++ = *c->string_at++;
+ c->remains--;
+ }
+ break;
+ case UTF8_READ:
+ while (c->remains)
+ {
+ if (s >= se)
+ goto cse;
+ if ((*s & 0xc0) != 0x80)
+ {
+ c->code = 0xfffd;
+ break;
+ }
+ c->code = (c->code << 6) | (*s++ & 0x3f);
+ c->remains--;
+ }
+ if (c->code >= 0x10000)
+ c->code = 0xfffd;
+ c->source = s;
+ c->state = 0;
+ return -1;
+ case UTF8_WRITE_START:
+ if (d >= de)
+ goto cde;
+ if (c->code < 0x80)
+ {
+ *d++ = c->code;
+ break;
+ }
+ else if (c->code < 0x800)
+ {
+ *d++ = 0xc0 | (c->code >> 6);
+ c->code <<= 10;
+ c->remains = 1;
+ }
+ else
+ {
+ *d++ = 0xe0 | (c->code >> 12);
+ c->code <<= 4;
+ c->remains = 2;
+ }
+ c->code &= 0xffff;
+ c->state = UTF8_WRITE_CONT;
+ /* fall-thru */
+ case UTF8_WRITE_CONT:
+ while (c->remains)
+ {
+ if (d >= de)
+ goto cde;
+ *d++ = 0x80 | (c->code >> 10);
+ c->code <<= 6;
+ c->remains--;
+ }
+ break;
+ default:
+ ASSERT(0);
+ }
+ c->source = s;
+ c->dest = d;
+ c->state = 0;
+ return 0;
+
+ cse:
+ c->source = s;
+ return CONV_SOURCE_END;
+
+ cde:
+ c->dest = d;
+ return CONV_DEST_END;
+}