Skip to content

Instantly share code, notes, and snippets.

@pauline2k
Created September 24, 2012 18:08
Show Gist options
  • Select an option

  • Save pauline2k/3777367 to your computer and use it in GitHub Desktop.

Select an option

Save pauline2k/3777367 to your computer and use it in GitHub Desktop.
The Amazing C UTF-8 validator/XML escaper
#adapted from http://stackoverflow.com/a/2977559
#define IS_IN_RANGE(c, f, l) (((c) >= (f)) && ((c) <= (l)))
int validUTF8(char *text, int *data_offset);
int validUTF8(char *text, int *data_offset)
{
if(data_offset)
*data_offset = 0;
unsigned char b, b2;
unsigned char *ptr = (unsigned char*) text;
int i = 0;
int seqlen;
while( ptr[i] != 0 ) {
b = ptr[i];
if( (b & 0x80) == 0 ) {
seqlen = 1;
} else if((b & 0xE0) == 0xC0) {
seqlen = 2;
} else if((b & 0xF0) == 0xE0) {
seqlen = 3;
} else if((b & 0xF8) == 0xF0) {
seqlen = 4;
} else {
return -1;
}
for (int j = 1; j < seqlen; ++j) {
b = ptr[i+j];
if((b & 0xC0) != 0x80)
return -1;
}
switch (seqlen) {
case 2:
{
b = ptr[i];
if(!IS_IN_RANGE(b, 0xC2, 0xDF)) {
return -1;
}
break;
}
case 3:
{
b = ptr[i];
b2 = ptr[i+1];
if(((b == 0xE0) && !IS_IN_RANGE(b2, 0xA0, 0xBF)) ||
((b == 0xED) && !IS_IN_RANGE(b2, 0x80, 0x9F)) ||
(!IS_IN_RANGE(b, 0xE1, 0xEC) && !IS_IN_RANGE(b, 0xEE, 0xEF)) ) {
return -1;
}
break;
}
case 4:
{
b = ptr[i];
b2 = ptr[i+1];
if(((b == 0xF0) && !IS_IN_RANGE(b2, 0x90, 0xBF)) ||
((b == 0xF4) && !IS_IN_RANGE(b2, 0x80, 0x8F)) ||
!IS_IN_RANGE(b, 0xF1, 0xF3)) {
return -1;
}
break;
}
}
i += seqlen;
}
if( data_offset )
*data_offset = i;
return 1;
}
char *input_text;
int textoffset;
int i = 0;
while(input_text[i] != 0) {
if( validUTF8(&input_text[i], &textoffset) == 1 )
{
for (int j=0; j < textoffset; j++) {
printf ("%s",&input_text[i]);
i++;
}
}
else
{
//assume win-1252 encoding
int codepoint = input_text[i] + 256;
if (IS_IN_RANGE(codepoint, 128, 159)) {
switch (codepoint) {
case 128: {codepoint = 0x20AC; break;}
case 130: {codepoint = 0x201A; break;}
case 131: {codepoint = 0x0192; break;}
case 132: {codepoint = 0x201E; break;}
case 133: {codepoint = 0x2026; break;}
case 134: {codepoint = 0x2020; break;}
case 135: {codepoint = 0x2021; break;}
case 136: {codepoint = 0x02C6; break;}
case 137: {codepoint = 0x2030; break;}
case 138: {codepoint = 0x0160; break;}
case 139: {codepoint = 0x2039; break;}
case 140: {codepoint = 0x0152; break;}
case 142: {codepoint = 0x017D; break;}
case 145: {codepoint = 0x2018; break;}
case 146: {codepoint = 0x2019; break;}
case 147: {codepoint = 0x201C; break;}
case 148: {codepoint = 0x201D; break;}
case 149: {codepoint = 0x2022; break;}
case 150: {codepoint = 0x2013; break;}
case 151: {codepoint = 0x2014; break;}
case 152: {codepoint = 0x02DC; break;}
case 153: {codepoint = 0x2122; break;}
case 154: {codepoint = 0x0161; break;}
case 155: {codepoint = 0x203A; break;}
case 156: {codepoint = 0x0153; break;}
case 158: {codepoint = 0x017E; break;}
case 159: {codepoint = 0x0178; break;}
}
}
printf ("&#%d;", codepoint);
i++;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment