* converts a CP1252/ISO-8859-1(5) hybrid to UTF-8 */ /* Features: 1. It never fails, all 00-FF chars are converted to valid UTF-8 */ /* 2. Uses CP1252 in the range 80-9f because ISO doesn't have any- */ /* thing useful in this range and it helps us receive from mIRC */ /* 3. The five undefined chars in CP1252 80-9f are replaced with */ /* ISO-8859-15 control codes. */ /* 4. Handles 0xa4 as a Euro symbol ala ISO-8859-15. */ /* 5. Uses ISO-8859-1 (which matches CP1252) for everything else. */ /* 6. This routine measured 3x faster than g_convert :) */ static unsigned char * iso_8859_1_to_utf8 (unsigned char *text, int len, gsize *bytes_written) { unsigned int idx; unsigned char *res, *output; static const unsigned short lowtable[] = /* 74 byte table for 80-a4 */ { /* compressed utf-8 table: if the first byte's 0x20 bit is set, it indicates a 2-byte utf-8 sequence, otherwise prepend a 0xe2. */ 0x82ac, /* 80 Euro. CP1252 from here on... */ 0xe281, /* 81 NA */ 0x809a, /* 82 */ 0xe692, /* 83 */ 0x809e, /* 84 */ 0x80a6, /* 85 */ 0x80a0, /* 86 */ 0x80a1, /* 87 */ 0xeb86, /* 88 */ 0x80b0, /* 89 */ 0xe5a0, /* 8a */ 0x80b9, /* 8b */ 0xe592, /* 8c */ 0xe28d, /* 8d NA */ 0xe5bd, /* 8e */ 0xe28f, /* 8f NA */ 0xe290, /* 90 NA */ 0x8098, /* 91 */ 0x8099, /* 92 */ 0x809c, /* 93 */ 0x809d, /* 94 */ 0x80a2, /* 95 */ 0x8093, /* 96 */ 0x8094, /* 97 */ 0xeb9c, /* 98 */ 0x84a2, /* 99 */ 0xe5a1, /* 9a */ 0x80ba, /* 9b */ 0xe593, /* 9c */ 0xe29d, /* 9d NA */ 0xe5be, /* 9e */ 0xe5b8, /* 9f */ 0xe2a0, /* a0 */ 0xe2a1, /* a1 */ 0xe2a2, /* a2 */ 0xe2a3, /* a3 */ 0x82ac /* a4 ISO-8859-15 Euro. */ }; if (len == -1) len = strlen (text); /* worst case scenario: every byte turns into 3 bytes */ res = output = g_malloc ((len * 3) + 1); if (!output) return NULL; while (len) { if (G_LIKELY (*text < 0x80)) { *output = *text; /* ascii maps directly */ } else if (*text <= 0xa4) /* 80-a4 use a lookup table */ { idx = *text - 0x80; if (lowtable[idx] & 0x2000) { *output++ = (lowtable[idx] >> 8) & 0xdf; /* 2 byte utf-8 */ *output = lowtable[idx] & 0xff; } else { *output++ = 0xe2; /* 3 byte utf-8 */ *output++ = (lowtable[idx] >> 8) & 0xff; *output = lowtable[idx] & 0xff; } } else if (*text < 0xc0) { *output++ = 0xc2; *output = *text; } else { *output++ = 0xc3; *output = *text - 0x40; } output++; text++; len--; } *output = 0; /* terminate */ *bytes_written = output - res; return res; }