Created
September 24, 2012 18:08
-
-
Save pauline2k/3777367 to your computer and use it in GitHub Desktop.
The Amazing C UTF-8 validator/XML escaper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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