Following up: a UTF-8 plain text checker. Only lightly tested, and I'm
not yet clear how to integrate this cleanly with the sendlib.c routines.
-- Andras Salamon [email protected]
/*
* is_utf8_text(): check if buffer is valid UTF-8 text; exclude control chars
* via RFC 3629
*/
#include <stddef.h>
#define O '\000'
#define I '\001'
/* allow control characters ESC BEL BS HT LF VT FF CR, 7-bit text, UTF-8 */
const char BADFIRST[] = {
I,I,I,I,I,I,I,O,O,O,O,O,O,O,I,I, /* 0x0_ */
I,I,I,I,I,I,I,I,I,I,I,O,I,I,I,I, /* 0x1_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0x2_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0x3_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0x4_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0x5_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0x6_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,I, /* 0x7_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x8_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x9_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0xa_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0xb_ */
I,I,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0xc_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0xd_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0xe_ */
O,O,O,O,O,I,I,I,I,I,I,I,I,I,I,I /* 0xf_ */
};
/* allow 10xxxxxx */
const char BADCONT[] = {
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x0_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x1_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x2_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x3_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x4_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x5_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x6_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0x7_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0x8_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0x9_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0xa_ */
O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O, /* 0xb_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0xc_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0xd_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I, /* 0xe_ */
I,I,I,I,I,I,I,I,I,I,I,I,I,I,I,I /* 0xf_ */
};
/*
* check if plain UTF-8 text
* returns:
* 0 uses unusual control characters, or is invalid UTF-8
* 1 valid UTF-8
*/
int
is_utf8_text(const unsigned char *buf, size_t numbytes) {
size_t i;
/* overlong:
* 4-byte 11110000 1000.... 0xf0 0x8.
* 3-byte 11100000 100..... 0xe0 0x[8|9].
* 2-byte 1100000x 0xc[01]
* invalid:
* 11101101 101..... 0xed 0x[ab]. U+D800 to U+DFFF
* 11110100 1001.... 0xf4 0x9. U+110000 to U+11FFFF
* 11110100 101..... 0xf4 0x[ab]. U+120000 to U+13FFFF
* 0xf[5-9a-f] U+140000 to U+1FFFFF
*/
for (i = 0; i < numbytes; i++) {
if (BADFIRST[buf[i]])
return 0;
/* the remainder can now assume first byte is reasonable */
if ((buf[i] & 0xc0) == 0xc0) { /* UTF-8 byte1 11xxxxxx */
if ((buf[i] & 0x20) == 0) { /* 110xxxxx */
if (i+1 >= numbytes)
return 0;
if (BADCONT[buf[i+1]])
return 0;
i++;
} else if ((buf[i] & 0x10) == 0) { /* 1110xxxx */
if (i+2 >= numbytes)
return 0;
if (BADCONT[buf[i+1]])
return 0;
if (BADCONT[buf[i+2]])
return 0;
if ((buf[i] == 0xed) && ((buf[i+1] & 0x20) !=
0))
return 0;
i += 2;
} else { /* must be 11110xxx */
if (i+3 >= numbytes)
return 0;
if (BADCONT[buf[i+1]])
return 0;
if (BADCONT[buf[i+2]])
return 0;
if (BADCONT[buf[i+3]])
return 0;
if ((buf[i] == 0xf4) && ((buf[i+1] & 0x30) !=
0))
return 0;
i += 3;
}
}
}
return 1;
}