01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
static const unsigned char sqlite3UtfTrans1[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
};
int sqlite3Utf8Read(
const unsigned char *z, /* First byte of UTF-8 character */
const unsigned char *zTerm, /* Pretend this byte is 0x00 */
const unsigned char **pzNext /* Write first byte past UTF-8 char here */
){
int c = *(z++);
if( c>=0xc0 ){
c = sqlite3UtfTrans1[c-0xc0];
while( z!=zTerm && (*z & 0xc0)==0x80 ){
c = (c<<6) + (0x3f & *(z++));
}
if( c<0x80
|| (c&0xFFFFF800)==0xD800
|| (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; }
}
*pzNext = z;
return c;
}
int main(int argc, char** argv) {
unsigned char *str = (unsigned char*) argv[1];
unsigned int c, i;
printf("ORIGINAL: %s\nORIGINAL: ", str);
for(i = 0; i < strlen(str); i++) {
printf("\\x%02x", str[i]);
}
printf("\nConverted: ");
while( *str ) {
c = sqlite3Utf8Read(str, 0, &str);
printf("\\x%02x", c);
}
printf("\n");
}
% cc test_utf.c
% ./a.out "サービスラーニング"
ORIGINAL: サービスラーニング
ORIGINAL: \xa5\xb5\xa1\xbc\xa5\xd3\xa5\xb9\xa5\xe9\xa1\xbc\xa5\xcb\xa5\xf3\xa5\xb0
Converted: \xa5\xb5\xa1\xbc\xa5\x4e5e65\x261f25\x2e5\x3970
% ./a.out "サービス"
ORIGINAL: サービス
ORIGINAL: \xa5\xb5\xa1\xbc\xa5\xd3\xa5\xb9
Converted: \xa5\xb5\xa1\xbc\xa5\x13979
% ./a.out "ラーニング"
ORIGINAL: ラーニング
ORIGINAL: \xa5\xe9\xa1\xbc\xa5\xcb\xa5\xf3\xa5\xb0
Converted: \xa5\x261f25\x2e5\x3970
% ./a.out "「サービスラーニング」"
ORIGINAL: 「サービスラーニング」
ORIGINAL: \xa1\xd6\xa5\xb5\xa1\xbc\xa5\xd3\xa5\xb9\xa5\xe9\xa1\xbc\xa5\xcb\xa5\xf3\xa5\xb0\xa1\xd7
Converted: \xa1\xfffd\x4e5e65\x261f25\x2e5\xe5c21\xfffd