entity.c (7959B)
1 /* 2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client 3 * Copyright (C) 2017 Ricardo Mones and the Claws Mail team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "utils.h" 20 21 #define ENTITY_MAX_LEN 8 22 #define DECODED_MAX_LEN 6 23 24 static GHashTable *symbol_table = NULL; 25 26 typedef struct _EntitySymbol EntitySymbol; 27 28 struct _EntitySymbol 29 { 30 gchar *const key; 31 gchar *const value; 32 }; 33 34 /* in alphabetical order with upper-case version first */ 35 static EntitySymbol symbolic_entities[] = { 36 /* A */ 37 {"Aacute", "Á"}, 38 {"aacute", "á"}, 39 {"Acirc", "Â"}, 40 {"acirc", "â"}, 41 {"acute", "´"}, 42 {"AElig", "Æ"}, 43 {"aelig", "æ"}, 44 {"Agrave", "À"}, 45 {"agrave", "à"}, 46 {"alefsym", "ℵ"}, 47 {"Alpha", "Α"}, 48 {"alpha", "α"}, 49 {"amp", "&"}, 50 {"and", "∧"}, 51 {"ang", "∠"}, 52 {"apos", "'"}, 53 {"Aring", "Å"}, 54 {"aring", "å"}, 55 {"asymp", "≈"}, 56 {"Atilde", "Ã"}, 57 {"atilde", "ã"}, 58 {"Auml", "Ä"}, 59 {"auml", "ä"}, 60 /* B */ 61 {"bdquo", "„"}, 62 {"Beta", "Β"}, 63 {"beta", "β"}, 64 {"brvbar", "¦"}, 65 {"bull", "•"}, 66 /* C */ 67 {"cap", "∩"}, 68 {"Ccedil", "Ç"}, 69 {"ccedil", "ç"}, 70 {"cedil", "¸"}, 71 {"cent", "¢"}, 72 {"Chi", "Χ"}, 73 {"chi", "χ"}, 74 {"circ", "ˆ"}, 75 {"clubs", "♣"}, 76 {"cong", "≅"}, 77 {"copy", "©"}, 78 {"crarr", "↵"}, 79 {"cup", "∪"}, 80 {"curren", "¤"}, 81 /* D */ 82 {"dagger", "†"}, 83 {"Dagger", "‡"}, 84 {"dArr", "⇓"}, 85 {"darr", "↓"}, 86 {"deg", "°"}, 87 {"Delta", "Δ"}, 88 {"delta", "δ"}, 89 {"diams", "♦"}, 90 {"divide", "÷"}, 91 /* E */ 92 {"Eacute", "É"}, 93 {"eacute", "é"}, 94 {"Ecirc", "Ê"}, 95 {"ecirc", "ê"}, 96 {"Egrave", "È"}, 97 {"egrave", "è"}, 98 {"empty", "∅"}, 99 {"emsp", "\xE2\x80\x83"}, 100 {"ensp", "\xE2\x80\x82"}, 101 {"Epsilon", "Ε"}, 102 {"epsilon", "ε"}, 103 {"equiv", "≡"}, 104 {"Eta", "Η"}, 105 {"eta", "η"}, 106 {"ETH", "Ð"}, 107 {"eth", "ð"}, 108 {"Euml", "Ë"}, 109 {"euml", "ë"}, 110 {"euro", "€"}, 111 {"exist", "∃"}, 112 /* F */ 113 {"fnof", "ƒ"}, 114 {"forall", "∀"}, 115 {"frac12", "½"}, 116 {"frac14", "¼"}, 117 {"frac34", "¾"}, 118 {"frasl", "⁄"}, 119 /* G */ 120 {"Gamma", "Γ"}, 121 {"gamma", "γ"}, 122 {"ge", "≥"}, 123 {"gt", ">"}, 124 /* H */ 125 {"hArr", "⇔"}, 126 {"harr", "↔"}, 127 {"hearts", "♥"}, 128 {"hellip", "…"}, 129 /* I */ 130 {"Iacute", "Í"}, 131 {"iacute", "í"}, 132 {"IArr", "⇐"}, 133 {"Icirc", "Î"}, 134 {"icirc", "î"}, 135 {"iexcl", "¡"}, 136 {"Igrave", "Ì"}, 137 {"igrave", "ì"}, 138 {"image", "ℑ"}, 139 {"infin", "∞"}, 140 {"int", "∫"}, 141 {"Iota", "Ι"}, 142 {"iota", "ι"}, 143 {"iquest", "¿"}, 144 {"isin", "∈"}, 145 {"Iuml", "Ï"}, 146 {"iuml", "ï"}, 147 /* K */ 148 {"Kappa", "Κ"}, 149 {"kappa", "κ"}, 150 /* L */ 151 {"Lambda", "Λ"}, 152 {"lambda", "λ"}, 153 {"lang", "〈"}, 154 {"laquo", "«"}, 155 {"larr", "←"}, 156 {"lceil", "⌈"}, 157 {"ldquo", "“"}, 158 {"le", "≤"}, 159 {"lfloor", "⌊"}, 160 {"lowast", "∗"}, 161 {"loz", "◊"}, 162 {"lrm", "\xE2\x80\x8E"}, 163 {"lsaquo", "‹"}, 164 {"lsquo", "‘"}, 165 {"lt", "<"}, 166 /* M */ 167 {"macr", "¯"}, 168 {"mdash", "—"}, 169 {"micro", "µ"}, 170 {"middot", "·"}, 171 {"minus", "−"}, 172 {"Mu", "Μ"}, 173 {"mu", "μ"}, 174 /* N */ 175 {"nabla", "∇"}, 176 {"nbsp", "\xC2\xA0"}, 177 {"ndash", "–"}, 178 {"ne", "≠"}, 179 {"ni", "∋"}, 180 {"not", "¬"}, 181 {"notin", "∉"}, 182 {"nsub", "⊄"}, 183 {"Ntilde", "Ñ"}, 184 {"ntilde", "ñ"}, 185 {"Nu", "Ν"}, 186 {"nu", "ν"}, 187 /* O */ 188 {"Oacute", "Ó"}, 189 {"oacute", "ó"}, 190 {"Ocirc", "Ô"}, 191 {"ocirc", "ô"}, 192 {"OElig", "Œ"}, 193 {"oelig", "œ"}, 194 {"Ograve", "Ò"}, 195 {"ograve", "ò"}, 196 {"oline", "‾"}, 197 {"Omega", "Ω"}, 198 {"omega", "ω"}, 199 {"Omicron", "Ο"}, 200 {"omicron", "ο"}, 201 {"oplus", "⊕"}, 202 {"or", "∨"}, 203 {"ordf", "ª"}, 204 {"ordm", "º"}, 205 {"Oslash", "Ø"}, 206 {"oslash", "ø"}, 207 {"Otilde", "Õ"}, 208 {"otilde", "õ"}, 209 {"otimes", "⊗"}, 210 {"Ouml", "Ö"}, 211 {"ouml", "ö"}, 212 /* P */ 213 {"para", "¶"}, 214 {"part", "∂"}, 215 {"permil", "‰"}, 216 {"perp", "⊥"}, 217 {"Phi", "Φ"}, 218 {"phi", "φ"}, 219 {"Pi", "Π"}, 220 {"pi", "π"}, 221 {"piv", "ϖ"}, 222 {"plusmn", "±"}, 223 {"pound", "£"}, 224 {"Prime", "″"}, 225 {"prime", "′"}, 226 {"prod", "∏"}, 227 {"prop", "∝"}, 228 {"Psi", "Ψ"}, 229 {"psi", "ψ"}, 230 /* Q */ 231 {"quot", "\""}, 232 /* R */ 233 {"radic", "√"}, 234 {"rang", "〉"}, 235 {"raquo", "»"}, 236 {"rArr", "⇒"}, 237 {"rarr", "→"}, 238 {"rceil", "⌉"}, 239 {"rdquo", "”"}, 240 {"real", "ℜ"}, 241 {"reg", "®"}, 242 {"rfloor", "⌋"}, 243 {"Rho", "Ρ"}, 244 {"rho", "ρ"}, 245 {"rlm", "\xE2\x80\x8F"}, 246 {"rsaquo", "›"}, 247 {"rsquo", "’"}, 248 /* S */ 249 {"sbquo", "‚"}, 250 {"Scaron", "Š"}, 251 {"scaron", "š"}, 252 {"sdot", "⋅"}, 253 {"sect", "§"}, 254 {"shy", "\xC2\xAD"}, 255 {"Sigma", "Σ"}, 256 {"sigma", "σ"}, 257 {"sigmaf", "ς"}, 258 {"sim", "∼"}, 259 {"spades", "♠"}, 260 {"sub", "⊂"}, 261 {"sube", "⊆"}, 262 {"sum", "∑"}, 263 {"sup", "⊃"}, 264 {"sup1", "¹"}, 265 {"sup2", "²"}, 266 {"sup3", "³"}, 267 {"supe", "⊇"}, 268 {"szlig", "ß"}, 269 /* T */ 270 {"Tau", "Τ"}, 271 {"tau", "τ"}, 272 {"there4", "∴"}, 273 {"Theta", "Θ"}, 274 {"theta", "θ"}, 275 {"thetasym", "ϑ"}, 276 {"thinsp", "\xE2\x80\x89"}, 277 {"THORN", "Þ"}, 278 {"thorn", "þ"}, 279 {"tilde", "˜"}, 280 {"times", "×"}, 281 {"trade", "™"}, 282 /* U */ 283 {"Uacute", "Ú"}, 284 {"uacute", "ú"}, 285 {"uArr", "⇑"}, 286 {"uarr", "↑"}, 287 {"Ucirc", "Û"}, 288 {"ucirc", "û"}, 289 {"Ugrave", "Ù"}, 290 {"ugrave", "ù"}, 291 {"uml", "¨"}, 292 {"upsih", "ϒ"}, 293 {"Upsilon", "Υ"}, 294 {"upsilon", "υ"}, 295 {"Uuml", "Ü"}, 296 {"uuml", "ü"}, 297 /* W */ 298 {"weierp", "℘"}, 299 /* X */ 300 {"Xi", "Ξ"}, 301 {"xi", "ξ"}, 302 /* Y */ 303 {"Yacute", "Ý"}, 304 {"yacute", "ý"}, 305 {"yen", "¥"}, 306 {"Yuml", "Ÿ"}, 307 {"yuml", "ÿ"}, 308 /* Z */ 309 {"Zeta", "Ζ"}, 310 {"zeta", "ζ"}, 311 {"zwj", "\xE2\x80\x8D"}, 312 {"zwnj", "\xE2\x80\x8C"}, 313 {NULL, NULL} 314 }; 315 316 static gchar* entity_extract_to_buffer(gchar *p, gchar b[]) 317 { 318 gint i = 0; 319 320 while (*p != '\0' && *p != ';' && i < ENTITY_MAX_LEN) { 321 b[i] = *p; 322 ++i, ++p; 323 } 324 if (*p != ';' || i == 0 || i == ENTITY_MAX_LEN) 325 return NULL; 326 b[i] = '\0'; 327 328 return b; 329 } 330 331 static gchar *entity_decode_numeric(gchar *str) 332 { 333 gchar b[ENTITY_MAX_LEN]; 334 gchar *p = str, *res; 335 gboolean hex = FALSE; 336 gunichar c = 0; 337 gint ret; 338 339 ++p; 340 if (*p == '\0') 341 return NULL; 342 343 if (*p == 'x') { 344 hex = TRUE; 345 ++p; 346 if (*p == '\0') 347 return NULL; 348 } 349 350 if (entity_extract_to_buffer (p, b) == NULL) 351 return NULL; 352 353 if (strlen(b) > 0) 354 c = g_ascii_strtoll (b, NULL, (hex ? 16 : 10)); 355 356 if (c < 32) 357 /* An unprintable character; return the Unicode replacement symbol */ 358 return g_strdup("\xef\xbf\xbd"); 359 360 if (!g_unichar_validate(c)) { 361 /* Make sure the character is valid Unicode */ 362 debug_print("Numeric reference '&#%s;' is invalid in Unicode codespace\n", b); 363 return NULL; 364 } 365 366 res = g_malloc0 (DECODED_MAX_LEN + 1); 367 ret = g_unichar_to_utf8 (c, res); 368 if (ret == 0) { 369 debug_print("Failed to convert unicode character %u to UTF-8\n", c); 370 g_free(res); 371 res = NULL; 372 } 373 374 return res; 375 } 376 377 static gchar *entity_decode_symbol(gchar *str) 378 { 379 gchar b[ENTITY_MAX_LEN]; 380 gchar *decoded; 381 382 if (entity_extract_to_buffer (str, b) == NULL) 383 return NULL; 384 385 if (symbol_table == NULL) { 386 gint i; 387 388 symbol_table = g_hash_table_new (g_str_hash, g_str_equal); 389 for (i = 0; symbolic_entities[i].key != NULL; ++i) { 390 g_hash_table_insert (symbol_table, 391 symbolic_entities[i].key, symbolic_entities[i].value); 392 } 393 debug_print("initialized entities table with %d symbols\n", i); 394 } 395 396 decoded = g_hash_table_lookup (symbol_table, b); 397 if (decoded != NULL) 398 return g_strdup (decoded); 399 400 return NULL; 401 } 402 403 gchar *entity_decode(gchar *str) 404 { 405 gchar *p = str; 406 if (p == NULL || *p != '&') 407 return NULL; 408 ++p; 409 if (*p == '\0') 410 return NULL; 411 if (*p == '#') 412 return entity_decode_numeric(p); 413 else 414 return entity_decode_symbol(p); 415 }