/ext/standard/html.c
C | 1502 lines | 1288 code | 88 blank | 126 comment | 116 complexity | f6e540c24befc7f60b8b45016771f6a5 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause
- /*
- +----------------------------------------------------------------------+
- | PHP Version 5 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2011 The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Rasmus Lerdorf <rasmus@php.net> |
- | Jaakko Hyv�tti <jaakko.hyvatti@iki.fi> |
- | Wez Furlong <wez@thebrainroom.com> |
- +----------------------------------------------------------------------+
- */
- /* $Id: html.c 306939 2011-01-01 02:19:59Z felipe $ */
- /*
- * HTML entity resources:
- *
- * http://msdn.microsoft.com/workshop/author/dhtml/reference/charsets/charset2.asp
- * http://msdn.microsoft.com/workshop/author/dhtml/reference/charsets/charset3.asp
- * http://www.unicode.org/Public/MAPPINGS/OBSOLETE/UNI2SGML.TXT
- *
- * http://www.w3.org/TR/2002/REC-xhtml1-20020801/dtds.html#h-A2
- *
- */
- #include "php.h"
- #if PHP_WIN32
- #include "config.w32.h"
- #else
- #include <php_config.h>
- #endif
- #include "html.h"
- #include "php_string.h"
- #include "SAPI.h"
- #if HAVE_LOCALE_H
- #include <locale.h>
- #endif
- #if HAVE_LANGINFO_H
- #include <langinfo.h>
- #endif
- #if HAVE_MBSTRING
- # include "ext/mbstring/mbstring.h"
- ZEND_EXTERN_MODULE_GLOBALS(mbstring)
- #endif
- enum entity_charset { cs_terminator, cs_8859_1, cs_cp1252,
- cs_8859_15, cs_utf_8, cs_big5, cs_gb2312,
- cs_big5hkscs, cs_sjis, cs_eucjp, cs_koi8r,
- cs_cp1251, cs_8859_5, cs_cp866, cs_macroman
- };
- typedef const char *const entity_table_t;
- /* codepage 1252 is a Windows extension to iso-8859-1. */
- static entity_table_t ent_cp_1252[] = {
- "euro", NULL, "sbquo", "fnof", "bdquo", "hellip", "dagger",
- "Dagger", "circ", "permil", "Scaron", "lsaquo", "OElig",
- NULL, NULL, NULL, NULL, "lsquo", "rsquo", "ldquo", "rdquo",
- "bull", "ndash", "mdash", "tilde", "trade", "scaron", "rsaquo",
- "oelig", NULL, NULL, "Yuml"
- };
- static entity_table_t ent_iso_8859_1[] = {
- "nbsp", "iexcl", "cent", "pound", "curren", "yen", "brvbar",
- "sect", "uml", "copy", "ordf", "laquo", "not", "shy", "reg",
- "macr", "deg", "plusmn", "sup2", "sup3", "acute", "micro",
- "para", "middot", "cedil", "sup1", "ordm", "raquo", "frac14",
- "frac12", "frac34", "iquest", "Agrave", "Aacute", "Acirc",
- "Atilde", "Auml", "Aring", "AElig", "Ccedil", "Egrave",
- "Eacute", "Ecirc", "Euml", "Igrave", "Iacute", "Icirc",
- "Iuml", "ETH", "Ntilde", "Ograve", "Oacute", "Ocirc", "Otilde",
- "Ouml", "times", "Oslash", "Ugrave", "Uacute", "Ucirc", "Uuml",
- "Yacute", "THORN", "szlig", "agrave", "aacute", "acirc",
- "atilde", "auml", "aring", "aelig", "ccedil", "egrave",
- "eacute", "ecirc", "euml", "igrave", "iacute", "icirc",
- "iuml", "eth", "ntilde", "ograve", "oacute", "ocirc", "otilde",
- "ouml", "divide", "oslash", "ugrave", "uacute", "ucirc",
- "uuml", "yacute", "thorn", "yuml"
- };
- static entity_table_t ent_iso_8859_15[] = {
- "nbsp", "iexcl", "cent", "pound", "euro", "yen", "Scaron",
- "sect", "scaron", "copy", "ordf", "laquo", "not", "shy", "reg",
- "macr", "deg", "plusmn", "sup2", "sup3", NULL, /* Zcaron */
- "micro", "para", "middot", NULL, /* zcaron */ "sup1", "ordm",
- "raquo", "OElig", "oelig", "Yuml", "iquest", "Agrave", "Aacute",
- "Acirc", "Atilde", "Auml", "Aring", "AElig", "Ccedil", "Egrave",
- "Eacute", "Ecirc", "Euml", "Igrave", "Iacute", "Icirc",
- "Iuml", "ETH", "Ntilde", "Ograve", "Oacute", "Ocirc", "Otilde",
- "Ouml", "times", "Oslash", "Ugrave", "Uacute", "Ucirc", "Uuml",
- "Yacute", "THORN", "szlig", "agrave", "aacute", "acirc",
- "atilde", "auml", "aring", "aelig", "ccedil", "egrave",
- "eacute", "ecirc", "euml", "igrave", "iacute", "icirc",
- "iuml", "eth", "ntilde", "ograve", "oacute", "ocirc", "otilde",
- "ouml", "divide", "oslash", "ugrave", "uacute", "ucirc",
- "uuml", "yacute", "thorn", "yuml"
- };
- static entity_table_t ent_uni_338_402[] = {
- /* 338 (0x0152) */
- "OElig", "oelig", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 352 (0x0160) */
- "Scaron", "scaron", NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 376 (0x0178) */
- "Yuml", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 400 (0x0190) */
- NULL, NULL, "fnof"
- };
- static entity_table_t ent_uni_spacing[] = {
- /* 710 */
- "circ",
- /* 711 - 730 */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 731 - 732 */
- NULL, "tilde"
- };
- static entity_table_t ent_uni_greek[] = {
- /* 913 */
- "Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta",
- "Iota", "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omicron", "Pi", "Rho",
- NULL, "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega",
- /* 938 - 944 are not mapped */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta",
- "iota", "kappa", "lambda", "mu", "nu", "xi", "omicron", "pi", "rho",
- "sigmaf", "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega",
- /* 970 - 976 are not mapped */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- "thetasym", "upsih",
- NULL, NULL, NULL,
- "piv"
- };
- static entity_table_t ent_uni_punct[] = {
- /* 8194 */
- "ensp", "emsp", NULL, NULL, NULL, NULL, NULL,
- "thinsp", NULL, NULL, "zwnj", "zwj", "lrm", "rlm",
- NULL, NULL, NULL, "ndash", "mdash", NULL, NULL, NULL,
- /* 8216 */
- "lsquo", "rsquo", "sbquo", NULL, "ldquo", "rdquo", "bdquo", NULL,
- "dagger", "Dagger", "bull", NULL, NULL, NULL, "hellip",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "permil", NULL,
- /* 8242 */
- "prime", "Prime", NULL, NULL, NULL, NULL, NULL, "lsaquo", "rsaquo", NULL,
- NULL, NULL, "oline", NULL, NULL, NULL, NULL, NULL,
- "frasl"
- };
- static entity_table_t ent_uni_euro[] = {
- "euro"
- };
- static entity_table_t ent_uni_8465_8501[] = {
- /* 8465 */
- "image", NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8472 */
- "weierp", NULL, NULL, NULL,
- /* 8476 */
- "real", NULL, NULL, NULL, NULL, NULL,
- /* 8482 */
- "trade", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8501 */
- "alefsym",
- };
- static entity_table_t ent_uni_8592_9002[] = {
- /* 8592 (0x2190) */
- "larr", "uarr", "rarr", "darr", "harr", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8608 (0x21a0) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8624 (0x21b0) */
- NULL, NULL, NULL, NULL, NULL, "crarr", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8640 (0x21c0) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8656 (0x21d0) */
- "lArr", "uArr", "rArr", "dArr", "hArr", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8672 (0x21e0) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8704 (0x2200) */
- "forall", NULL, "part", "exist", NULL, "empty", NULL, "nabla",
- "isin", "notin", NULL, "ni", NULL, NULL, NULL, "prod",
- /* 8720 (0x2210) */
- NULL, "sum", "minus", NULL, NULL, NULL, NULL, "lowast",
- NULL, NULL, "radic", NULL, NULL, "prop", "infin", NULL,
- /* 8736 (0x2220) */
- "ang", NULL, NULL, NULL, NULL, NULL, NULL, "and",
- "or", "cap", "cup", "int", NULL, NULL, NULL, NULL,
- /* 8752 (0x2230) */
- NULL, NULL, NULL, NULL, "there4", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, "sim", NULL, NULL, NULL,
- /* 8768 (0x2240) */
- NULL, NULL, NULL, NULL, NULL, "cong", NULL, NULL,
- "asymp", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8784 (0x2250) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8800 (0x2260) */
- "ne", "equiv", NULL, NULL, "le", "ge", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8816 (0x2270) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8832 (0x2280) */
- NULL, NULL, "sub", "sup", "nsub", NULL, "sube", "supe",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8848 (0x2290) */
- NULL, NULL, NULL, NULL, NULL, "oplus", NULL, "otimes",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8864 (0x22a0) */
- NULL, NULL, NULL, NULL, NULL, "perp", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8880 (0x22b0) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8896 (0x22c0) */
- NULL, NULL, NULL, NULL, NULL, "sdot", NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8912 (0x22d0) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8928 (0x22e0) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8944 (0x22f0) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8960 (0x2300) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- "lceil", "rceil", "lfloor", "rfloor", NULL, NULL, NULL, NULL,
- /* 8976 (0x2310) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- /* 8992 (0x2320) */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, "lang", "rang"
- };
- static entity_table_t ent_uni_9674[] = {
- /* 9674 */
- "loz"
- };
- static entity_table_t ent_uni_9824_9830[] = {
- /* 9824 */
- "spades", NULL, NULL, "clubs", NULL, "hearts", "diams"
- };
- static entity_table_t ent_koi8r[] = {
- "#1105", /* "jo "*/
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, "#1025", /* "JO" */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- "#1102", "#1072", "#1073", "#1094", "#1076", "#1077", "#1092",
- "#1075", "#1093", "#1080", "#1081", "#1082", "#1083", "#1084",
- "#1085", "#1086", "#1087", "#1103", "#1088", "#1089", "#1090",
- "#1091", "#1078", "#1074", "#1100", "#1099", "#1079", "#1096",
- "#1101", "#1097", "#1095", "#1098", "#1070", "#1040", "#1041",
- "#1062", "#1044", "#1045", "#1060", "#1043", "#1061", "#1048",
- "#1049", "#1050", "#1051", "#1052", "#1053", "#1054", "#1055",
- "#1071", "#1056", "#1057", "#1058", "#1059", "#1046", "#1042",
- "#1068", "#1067", "#1047", "#1064", "#1069", "#1065", "#1063",
- "#1066"
- };
- static entity_table_t ent_cp_1251[] = {
- "#1026", "#1027", "#8218", "#1107", "#8222", "hellip", "dagger",
- "Dagger", "euro", "permil", "#1033", "#8249", "#1034", "#1036",
- "#1035", "#1039", "#1106", "#8216", "#8217", "#8219", "#8220",
- "bull", "ndash", "mdash", NULL, "trade", "#1113", "#8250",
- "#1114", "#1116", "#1115", "#1119", "nbsp", "#1038", "#1118",
- "#1032", "curren", "#1168", "brvbar", "sect", "#1025", "copy",
- "#1028", "laquo", "not", "shy", "reg", "#1031", "deg", "plusmn",
- "#1030", "#1110", "#1169", "micro", "para", "middot", "#1105",
- "#8470", "#1108", "raquo", "#1112", "#1029", "#1109", "#1111",
- "#1040", "#1041", "#1042", "#1043", "#1044", "#1045", "#1046",
- "#1047", "#1048", "#1049", "#1050", "#1051", "#1052", "#1053",
- "#1054", "#1055", "#1056", "#1057", "#1058", "#1059", "#1060",
- "#1061", "#1062", "#1063", "#1064", "#1065", "#1066", "#1067",
- "#1068", "#1069", "#1070", "#1071", "#1072", "#1073", "#1074",
- "#1075", "#1076", "#1077", "#1078", "#1079", "#1080", "#1081",
- "#1082", "#1083", "#1084", "#1085", "#1086", "#1087", "#1088",
- "#1089", "#1090", "#1091", "#1092", "#1093", "#1094", "#1095",
- "#1096", "#1097", "#1098", "#1099", "#1100", "#1101", "#1102",
- "#1103"
- };
- static entity_table_t ent_iso_8859_5[] = {
- "#1056", "#1057", "#1058", "#1059", "#1060", "#1061", "#1062",
- "#1063", "#1064", "#1065", "#1066", "#1067", "#1068", "#1069",
- "#1070", "#1071", "#1072", "#1073", "#1074", "#1075", "#1076",
- "#1077", "#1078", "#1079", "#1080", "#1081", "#1082", "#1083",
- "#1084", "#1085", "#1086", "#1087", "#1088", "#1089", "#1090",
- "#1091", "#1092", "#1093", "#1094", "#1095", "#1096", "#1097",
- "#1098", "#1099", "#1100", "#1101", "#1102", "#1103", "#1104",
- "#1105", "#1106", "#1107", "#1108", "#1109", "#1110", "#1111",
- "#1112", "#1113", "#1114", "#1115", "#1116", "#1117", "#1118",
- "#1119"
- };
- static entity_table_t ent_cp_866[] = {
- "#9492", "#9524", "#9516", "#9500", "#9472", "#9532", "#9566",
- "#9567", "#9562", "#9556", "#9577", "#9574", "#9568", "#9552",
- "#9580", "#9575", "#9576", "#9572", "#9573", "#9561", "#9560",
- "#9554", "#9555", "#9579", "#9578", "#9496", "#9484", "#9608",
- "#9604", "#9612", "#9616", "#9600", "#1088", "#1089", "#1090",
- "#1091", "#1092", "#1093", "#1094", "#1095", "#1096", "#1097",
- "#1098", "#1099", "#1100", "#1101", "#1102", "#1103", "#1025",
- "#1105", "#1028", "#1108", "#1031", "#1111", "#1038", "#1118",
- "#176", "#8729", "#183", "#8730", "#8470", "#164", "#9632",
- "#160"
- };
- /* MacRoman has a couple of low-ascii chars that need mapping too */
- /* Vertical tab (ASCII 11) is often used to store line breaks inside */
- /* DB exports, this mapping changes it to a space */
- static entity_table_t ent_macroman[] = {
- "sp", NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, "quot", NULL,
- NULL, NULL, "amp", NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "lt", NULL, "gt", NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, "Auml", "Aring", "Ccedil", "Eacute", "Ntilde", "Ouml",
- "Uuml", "aacute", "agrave", "acirc", "auml", "atilde", "aring",
- "ccedil", "eacute", "egrave", "ecirc", "euml", "iacute", "igrave",
- "icirc", "iuml", "ntilde", "oacute", "ograve", "ocirc", "ouml",
- "otilde", "uacute", "ugrave", "ucirc", "uuml", "dagger", "deg",
- "cent", "pound", "sect", "bull", "para", "szlig", "reg",
- "copy", "trade", "acute", "uml", "ne", "AElig", "Oslash",
- "infin", "plusmn", "le", "ge", "yen", "micro", "part",
- "sum", "prod", "pi", "int", "ordf", "ordm", "Omega",
- "aelig", "oslash", "iquest", "iexcl", "not", "radic", "fnof",
- "asymp", "#8710", "laquo", "raquo", "hellip", "nbsp", "Agrave",
- "Atilde", "Otilde", "OElig", "oelig", "ndash", "mdash", "ldquo",
- "rdquo", "lsquo", "rsquo", "divide", "loz", "yuml", "Yuml",
- "frasl", "euro", "lsaquo", "rsaquo", "#xFB01", "#xFB02", "Dagger",
- "middot", "sbquo", "bdquo", "permil", "Acirc", "Ecirc", "Aacute",
- "Euml", "Egrave", "Iacute", "Icirc", "Iuml", "Igrave", "Oacute",
- "Ocirc", "#xF8FF", "Ograve", "Uacute", "Ucirc", "Ugrave", "#305",
- "circ", "tilde", "macr", "#728", "#729", "#730", "cedil",
- "#733", "#731", "#711"
- };
- struct html_entity_map {
- enum entity_charset charset; /* charset identifier */
- unsigned int basechar; /* char code at start of table */
- unsigned int endchar; /* last char code in the table */
- entity_table_t *table; /* the table of mappings */
- };
- static const struct html_entity_map entity_map[] = {
- { cs_cp1252, 0x80, 0x9f, ent_cp_1252 },
- { cs_cp1252, 0xa0, 0xff, ent_iso_8859_1 },
- { cs_8859_1, 0xa0, 0xff, ent_iso_8859_1 },
- { cs_8859_15, 0xa0, 0xff, ent_iso_8859_15 },
- { cs_utf_8, 0xa0, 0xff, ent_iso_8859_1 },
- { cs_utf_8, 338, 402, ent_uni_338_402 },
- { cs_utf_8, 710, 732, ent_uni_spacing },
- { cs_utf_8, 913, 982, ent_uni_greek },
- { cs_utf_8, 8194, 8260, ent_uni_punct },
- { cs_utf_8, 8364, 8364, ent_uni_euro },
- { cs_utf_8, 8465, 8501, ent_uni_8465_8501 },
- { cs_utf_8, 8592, 9002, ent_uni_8592_9002 },
- { cs_utf_8, 9674, 9674, ent_uni_9674 },
- { cs_utf_8, 9824, 9830, ent_uni_9824_9830 },
- { cs_big5, 0xa0, 0xff, ent_iso_8859_1 },
- { cs_gb2312, 0xa0, 0xff, ent_iso_8859_1 },
- { cs_big5hkscs, 0xa0, 0xff, ent_iso_8859_1 },
- { cs_sjis, 0xa0, 0xff, ent_iso_8859_1 },
- { cs_eucjp, 0xa0, 0xff, ent_iso_8859_1 },
- { cs_koi8r, 0xa3, 0xff, ent_koi8r },
- { cs_cp1251, 0x80, 0xff, ent_cp_1251 },
- { cs_8859_5, 0xc0, 0xff, ent_iso_8859_5 },
- { cs_cp866, 0xc0, 0xff, ent_cp_866 },
- { cs_macroman, 0x0b, 0xff, ent_macroman },
- { cs_terminator }
- };
- static const struct {
- const char *codeset;
- enum entity_charset charset;
- } charset_map[] = {
- { "ISO-8859-1", cs_8859_1 },
- { "ISO8859-1", cs_8859_1 },
- { "ISO-8859-15", cs_8859_15 },
- { "ISO8859-15", cs_8859_15 },
- { "utf-8", cs_utf_8 },
- { "cp1252", cs_cp1252 },
- { "Windows-1252", cs_cp1252 },
- { "1252", cs_cp1252 },
- { "BIG5", cs_big5 },
- { "950", cs_big5 },
- { "GB2312", cs_gb2312 },
- { "936", cs_gb2312 },
- { "BIG5-HKSCS", cs_big5hkscs },
- { "Shift_JIS", cs_sjis },
- { "SJIS", cs_sjis },
- { "932", cs_sjis },
- { "EUCJP", cs_eucjp },
- { "EUC-JP", cs_eucjp },
- { "KOI8-R", cs_koi8r },
- { "koi8-ru", cs_koi8r },
- { "koi8r", cs_koi8r },
- { "cp1251", cs_cp1251 },
- { "Windows-1251", cs_cp1251 },
- { "win-1251", cs_cp1251 },
- { "iso8859-5", cs_8859_5 },
- { "iso-8859-5", cs_8859_5 },
- { "cp866", cs_cp866 },
- { "866", cs_cp866 },
- { "ibm866", cs_cp866 },
- { "MacRoman", cs_macroman },
- { NULL }
- };
- static const struct {
- unsigned short charcode;
- char *entity;
- int entitylen;
- int flags;
- } basic_entities[] = {
- { '"', """, 6, ENT_HTML_QUOTE_DOUBLE },
- { '\'', "'", 6, ENT_HTML_QUOTE_SINGLE },
- { '\'', "'", 5, ENT_HTML_QUOTE_SINGLE },
- { '<', "<", 4, 0 },
- { '>', ">", 4, 0 },
- { 0, NULL, 0, 0 }
- };
-
- struct basic_entities_dec {
- unsigned short charcode;
- char entity[8];
- int entitylen;
- };
-
- #define MB_RETURN { \
- *newpos = pos; \
- mbseq[mbpos] = '\0'; \
- *mbseqlen = mbpos; \
- return this_char; }
-
- #define MB_WRITE(mbchar) { \
- mbspace--; \
- if (mbspace == 0) { \
- MB_RETURN; \
- } \
- mbseq[mbpos++] = (mbchar); }
- /* skip one byte and return */
- #define MB_FAILURE(pos) do { \
- *newpos = pos + 1; \
- *status = FAILURE; \
- return 0; \
- } while (0)
- #define CHECK_LEN(pos, chars_need) \
- if (chars_need < 1) { \
- if((str_len - (pos)) < chars_need) { \
- *newpos = pos; \
- *status = FAILURE; \
- return 0; \
- } \
- } else { \
- if((str_len - (pos)) < chars_need) { \
- *newpos = pos + 1; \
- *status = FAILURE; \
- return 0; \
- } \
- }
- /* {{{ get_next_char
- */
- inline static unsigned int get_next_char(enum entity_charset charset,
- unsigned char * str,
- int str_len,
- int * newpos,
- unsigned char * mbseq,
- int * mbseqlen,
- int *status)
- {
- int pos = *newpos;
- int mbpos = 0;
- int mbspace = *mbseqlen;
- unsigned int this_char = 0;
- unsigned char next_char;
- *status = SUCCESS;
- if (mbspace <= 0) {
- *mbseqlen = 0;
- CHECK_LEN(pos, 1);
- *newpos = pos + 1;
- return str[pos];
- }
- switch (charset) {
- case cs_utf_8:
- {
- unsigned char c;
- CHECK_LEN(pos, 1);
- c = str[pos];
- if (c < 0x80) {
- MB_WRITE(c);
- this_char = c;
- pos++;
- } else if (c < 0xc2) {
- MB_FAILURE(pos);
- } else if (c < 0xe0) {
- CHECK_LEN(pos, 2);
- if (str[pos + 1] < 0x80 || str[pos + 1] > 0xbf) {
- MB_FAILURE(pos);
- }
- this_char = ((c & 0x1f) << 6) | (str[pos + 1] & 0x3f);
- if (this_char < 0x80) {
- MB_FAILURE(pos);
- }
- MB_WRITE((unsigned char)c);
- MB_WRITE((unsigned char)str[pos + 1]);
- pos += 2;
- } else if (c < 0xf0) {
- CHECK_LEN(pos, 3);
- if (str[pos + 1] < 0x80 || str[pos + 1] > 0xbf) {
- MB_FAILURE(pos);
- }
- if (str[pos + 2] < 0x80 || str[pos + 2] > 0xbf) {
- MB_FAILURE(pos);
- }
- this_char = ((c & 0x0f) << 12) | ((str[pos + 1] & 0x3f) << 6) | (str[pos + 2] & 0x3f);
- if (this_char < 0x800) {
- MB_FAILURE(pos);
- } else if (this_char >= 0xd800 && this_char <= 0xdfff) {
- MB_FAILURE(pos);
- }
- MB_WRITE((unsigned char)c);
- MB_WRITE((unsigned char)str[pos + 1]);
- MB_WRITE((unsigned char)str[pos + 2]);
- pos += 3;
- } else if (c < 0xf5) {
- CHECK_LEN(pos, 4);
- if (str[pos + 1] < 0x80 || str[pos + 1] > 0xbf) {
- MB_FAILURE(pos);
- }
- if (str[pos + 2] < 0x80 || str[pos + 2] > 0xbf) {
- MB_FAILURE(pos);
- }
- if (str[pos + 3] < 0x80 || str[pos + 3] > 0xbf) {
- MB_FAILURE(pos);
- }
- this_char = ((c & 0x07) << 18) | ((str[pos + 1] & 0x3f) << 12) | ((str[pos + 2] & 0x3f) << 6) | (str[pos + 3] & 0x3f);
- if (this_char < 0x10000 || this_char > 0x10FFFF) {
- MB_FAILURE(pos);
- }
- MB_WRITE((unsigned char)c);
- MB_WRITE((unsigned char)str[pos + 1]);
- MB_WRITE((unsigned char)str[pos + 2]);
- MB_WRITE((unsigned char)str[pos + 3]);
- pos += 4;
- } else {
- MB_FAILURE(pos);
- }
- }
- break;
- case cs_big5:
- case cs_gb2312:
- case cs_big5hkscs:
- {
- CHECK_LEN(pos, 1);
- this_char = str[pos++];
- /* check if this is the first of a 2-byte sequence */
- if (this_char >= 0x81 && this_char <= 0xfe) {
- /* peek at the next char */
- CHECK_LEN(pos, 1);
- next_char = str[pos++];
- if ((next_char >= 0x40 && next_char <= 0x7e) ||
- (next_char >= 0xa1 && next_char <= 0xfe)) {
- /* yes, this a wide char */
- MB_WRITE(this_char);
- MB_WRITE(next_char);
- this_char = (this_char << 8) | next_char;
- } else {
- MB_FAILURE(pos);
- }
- } else {
- MB_WRITE(this_char);
- }
- }
- break;
- case cs_sjis:
- {
- CHECK_LEN(pos, 1);
- this_char = str[pos++];
- /* check if this is the first of a 2-byte sequence */
- if ((this_char >= 0x81 && this_char <= 0x9f) ||
- (this_char >= 0xe0 && this_char <= 0xfc)) {
- /* peek at the next char */
- CHECK_LEN(pos, 1);
- next_char = str[pos++];
- if ((next_char >= 0x40 && next_char <= 0x7e) ||
- (next_char >= 0x80 && next_char <= 0xfc))
- {
- /* yes, this a wide char */
- MB_WRITE(this_char);
- MB_WRITE(next_char);
- this_char = (this_char << 8) | next_char;
- } else {
- MB_FAILURE(pos);
- }
- } else {
- MB_WRITE(this_char);
- }
- break;
- }
- case cs_eucjp:
- {
- CHECK_LEN(pos, 1);
- this_char = str[pos++];
- /* check if this is the first of a multi-byte sequence */
- if (this_char >= 0xa1 && this_char <= 0xfe) {
- /* peek at the next char */
- CHECK_LEN(pos, 1);
- next_char = str[pos++];
- if (next_char >= 0xa1 && next_char <= 0xfe) {
- /* yes, this a jis kanji char */
- MB_WRITE(this_char);
- MB_WRITE(next_char);
- this_char = (this_char << 8) | next_char;
- } else {
- MB_FAILURE(pos);
- }
- } else if (this_char == 0x8e) {
- /* peek at the next char */
- CHECK_LEN(pos, 1);
- next_char = str[pos++];
- if (next_char >= 0xa1 && next_char <= 0xdf) {
- /* JIS X 0201 kana */
- MB_WRITE(this_char);
- MB_WRITE(next_char);
- this_char = (this_char << 8) | next_char;
- } else {
- MB_FAILURE(pos);
- }
- } else if (this_char == 0x8f) {
- /* peek at the next two char */
- unsigned char next2_char;
- CHECK_LEN(pos, 2);
- next_char = str[pos];
- next2_char = str[pos + 1];
- pos += 2;
- if ((next_char >= 0xa1 && next_char <= 0xfe) &&
- (next2_char >= 0xa1 && next2_char <= 0xfe)) {
- /* JIS X 0212 hojo-kanji */
- MB_WRITE(this_char);
- MB_WRITE(next_char);
- MB_WRITE(next2_char);
- this_char = (this_char << 16) | (next_char << 8) | next2_char;
- } else {
- MB_FAILURE(pos);
- }
- } else {
- MB_WRITE(this_char);
- }
- break;
- }
- default:
- /* single-byte charsets */
- CHECK_LEN(pos, 1);
- this_char = str[pos++];
- MB_WRITE(this_char);
- break;
- }
- MB_RETURN;
- }
- /* }}} */
- /* {{{ entity_charset determine_charset
- * returns the charset identifier based on current locale or a hint.
- * defaults to iso-8859-1 */
- static enum entity_charset determine_charset(char *charset_hint TSRMLS_DC)
- {
- int i;
- enum entity_charset charset = cs_utf_8;
- int len = 0;
- zval *uf_result = NULL;
- /* Guarantee default behaviour for backwards compatibility */
- if (charset_hint == NULL)
- return cs_utf_8;
- if ((len = strlen(charset_hint)) != 0) {
- goto det_charset;
- }
- #if HAVE_MBSTRING
- #if !defined(COMPILE_DL_MBSTRING)
- /* XXX: Ugly things. Why don't we look for a more sophisticated way? */
- switch (MBSTRG(current_internal_encoding)) {
- case mbfl_no_encoding_8859_1:
- return cs_8859_1;
- case mbfl_no_encoding_utf8:
- return cs_utf_8;
- case mbfl_no_encoding_euc_jp:
- case mbfl_no_encoding_eucjp_win:
- return cs_eucjp;
- case mbfl_no_encoding_sjis:
- case mbfl_no_encoding_sjis_open:
- case mbfl_no_encoding_cp932:
- return cs_sjis;
- case mbfl_no_encoding_cp1252:
- return cs_cp1252;
- case mbfl_no_encoding_8859_15:
- return cs_8859_15;
- case mbfl_no_encoding_big5:
- return cs_big5;
- case mbfl_no_encoding_euc_cn:
- case mbfl_no_encoding_hz:
- case mbfl_no_encoding_cp936:
- return cs_gb2312;
- case mbfl_no_encoding_koi8r:
- return cs_koi8r;
- case mbfl_no_encoding_cp866:
- return cs_cp866;
- case mbfl_no_encoding_cp1251:
- return cs_cp1251;
- case mbfl_no_encoding_8859_5:
- return cs_8859_5;
- default:
- ;
- }
- #else
- {
- zval nm_mb_internal_encoding;
- ZVAL_STRING(&nm_mb_internal_encoding, "mb_internal_encoding", 0);
- if (call_user_function_ex(CG(function_table), NULL, &nm_mb_internal_encoding, &uf_result, 0, NULL, 1, NULL TSRMLS_CC) != FAILURE) {
- charset_hint = Z_STRVAL_P(uf_result);
- len = Z_STRLEN_P(uf_result);
-
- if (len == 4) { /* sizeof(none|auto|pass)-1 */
- if (!memcmp("pass", charset_hint, sizeof("pass") - 1) ||
- !memcmp("auto", charset_hint, sizeof("auto") - 1) ||
- !memcmp("none", charset_hint, sizeof("none") - 1)) {
-
- charset_hint = NULL;
- len = 0;
- }
- }
- goto det_charset;
- }
- }
- #endif
- #endif
- charset_hint = SG(default_charset);
- if (charset_hint != NULL && (len=strlen(charset_hint)) != 0) {
- goto det_charset;
- }
- /* try to detect the charset for the locale */
- #if HAVE_NL_LANGINFO && HAVE_LOCALE_H && defined(CODESET)
- charset_hint = nl_langinfo(CODESET);
- if (charset_hint != NULL && (len=strlen(charset_hint)) != 0) {
- goto det_charset;
- }
- #endif
- #if HAVE_LOCALE_H
- /* try to figure out the charset from the locale */
- {
- char *localename;
- char *dot, *at;
- /* lang[_territory][.codeset][@modifier] */
- localename = setlocale(LC_CTYPE, NULL);
- dot = strchr(localename, '.');
- if (dot) {
- dot++;
- /* locale specifies a codeset */
- at = strchr(dot, '@');
- if (at)
- len = at - dot;
- else
- len = strlen(dot);
- charset_hint = dot;
- } else {
- /* no explicit name; see if the name itself
- * is the charset */
- charset_hint = localename;
- len = strlen(charset_hint);
- }
- }
- #endif
- det_charset:
- if (charset_hint) {
- int found = 0;
-
- /* now walk the charset map and look for the codeset */
- for (i = 0; charset_map[i].codeset; i++) {
- if (len == strlen(charset_map[i].codeset) && strncasecmp(charset_hint, charset_map[i].codeset, len) == 0) {
- charset = charset_map[i].charset;
- found = 1;
- break;
- }
- }
- if (!found) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "charset `%s' not supported, assuming iso-8859-1",
- charset_hint);
- }
- }
- if (uf_result != NULL) {
- zval_ptr_dtor(&uf_result);
- }
- return charset;
- }
- /* }}} */
- /* {{{ php_utf32_utf8 */
- size_t php_utf32_utf8(unsigned char *buf, unsigned k)
- {
- size_t retval = 0;
- if (k < 0x80) {
- buf[0] = k;
- retval = 1;
- } else if (k < 0x800) {
- buf[0] = 0xc0 | (k >> 6);
- buf[1] = 0x80 | (k & 0x3f);
- retval = 2;
- } else if (k < 0x10000) {
- buf[0] = 0xe0 | (k >> 12);
- buf[1] = 0x80 | ((k >> 6) & 0x3f);
- buf[2] = 0x80 | (k & 0x3f);
- retval = 3;
- } else if (k < 0x200000) {
- buf[0] = 0xf0 | (k >> 18);
- buf[1] = 0x80 | ((k >> 12) & 0x3f);
- buf[2] = 0x80 | ((k >> 6) & 0x3f);
- buf[3] = 0x80 | (k & 0x3f);
- retval = 4;
- } else if (k < 0x4000000) {
- buf[0] = 0xf8 | (k >> 24);
- buf[1] = 0x80 | ((k >> 18) & 0x3f);
- buf[2] = 0x80 | ((k >> 12) & 0x3f);
- buf[3] = 0x80 | ((k >> 6) & 0x3f);
- buf[4] = 0x80 | (k & 0x3f);
- retval = 5;
- } else {
- buf[0] = 0xfc | (k >> 30);
- buf[1] = 0x80 | ((k >> 24) & 0x3f);
- buf[2] = 0x80 | ((k >> 18) & 0x3f);
- buf[3] = 0x80 | ((k >> 12) & 0x3f);
- buf[4] = 0x80 | ((k >> 6) & 0x3f);
- buf[5] = 0x80 | (k & 0x3f);
- retval = 6;
- }
- buf[retval] = '\0';
- return retval;
- }
- /* }}} */
- /* {{{ php_unescape_html_entities
- */
- PHPAPI char *php_unescape_html_entities(unsigned char *old, int oldlen, int *newlen, int all, int quote_style, char *hint_charset TSRMLS_DC)
- {
- int retlen;
- int j, k;
- char *replaced, *ret, *p, *q, *lim, *next;
- enum entity_charset charset = determine_charset(hint_charset TSRMLS_CC);
- unsigned char replacement[15];
- int replacement_len;
- ret = estrndup(old, oldlen);
- retlen = oldlen;
- if (!retlen) {
- goto empty_source;
- }
-
- if (all) {
- /* look for a match in the maps for this charset */
- for (j = 0; entity_map[j].charset != cs_terminator; j++) {
- if (entity_map[j].charset != charset)
- continue;
- for (k = entity_map[j].basechar; k <= entity_map[j].endchar; k++) {
- unsigned char entity[32];
- int entity_length = 0;
- if (entity_map[j].table[k - entity_map[j].basechar] == NULL)
- continue;
- entity_length = slprintf(entity, sizeof(entity), "&%s;", entity_map[j].table[k - entity_map[j].basechar]);
- if (entity_length >= sizeof(entity)) {
- continue;
- }
- /* When we have MBCS entities in the tables above, this will need to handle it */
- replacement_len = 0;
- switch (charset) {
- case cs_8859_1:
- case cs_cp1252:
- case cs_8859_15:
- case cs_cp1251:
- case cs_8859_5:
- case cs_cp866:
- case cs_koi8r:
- replacement[0] = k;
- replacement[1] = '\0';
- replacement_len = 1;
- break;
- case cs_big5:
- case cs_gb2312:
- case cs_big5hkscs:
- case cs_sjis:
- case cs_eucjp:
- /* we cannot properly handle those multibyte encodings
- * with php_str_to_str. skip it. */
- continue;
- case cs_utf_8:
- replacement_len = php_utf32_utf8(replacement, k);
- break;
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot yet handle MBCS!");
- efree(ret);
- return NULL;
- }
- if (php_memnstr(ret, entity, entity_length, ret+retlen)) {
- replaced = php_str_to_str(ret, retlen, entity, entity_length, replacement, replacement_len, &retlen);
- efree(ret);
- ret = replaced;
- }
- }
- }
- }
- for (j = 0; basic_entities[j].charcode != 0; j++) {
- if (basic_entities[j].flags && (quote_style & basic_entities[j].flags) == 0)
- continue;
-
- replacement[0] = (unsigned char)basic_entities[j].charcode;
- replacement[1] = '\0';
- if (php_memnstr(ret, basic_entities[j].entity, basic_entities[j].entitylen, ret+retlen)) {
- replaced = php_str_to_str(ret, retlen, basic_entities[j].entity, basic_entities[j].entitylen, replacement, 1, &retlen);
- efree(ret);
- ret = replaced;
- }
- }
- /* replace numeric entities & "&" */
- lim = ret + retlen;
- for (p = ret, q = ret; p < lim;) {
- int code;
- if (p[0] == '&') {
- if (p + 2 < lim) {
- if (p[1] == '#') {
- int invalid_code = 0;
- if (p[2] == 'x' || p[2] == 'X') {
- code = strtol(p + 3, &next, 16);
- } else {
- code = strtol(p + 2, &next, 10);
- }
- if (code == '\'' && !(quote_style & ENT_HTML_QUOTE_SINGLE) ||
- code == '"' && !(quote_style & ENT_HTML_QUOTE_DOUBLE)) {
- invalid_code = 1;
- }
- if (next != NULL && *next == ';' && !invalid_code) {
- switch (charset) {
- case cs_utf_8:
- q += php_utf32_utf8(q, code);
- break;
- case cs_8859_1:
- case cs_8859_5:
- case cs_8859_15:
- if ((code >= 0x80 && code < 0xa0) || code > 0xff) {
- invalid_code = 1;
- } else {
- *(q++) = code;
- }
- break;
- case cs_cp1252:
- if (code > 0xff) {
- invalid_code = 1;
- } else {
- *(q++) = code;
- }
- break;
- case cs_cp1251:
- case cs_cp866:
- case cs_big5:
- case cs_big5hkscs:
- case cs_sjis:
- case cs_eucjp:
- if (code >= 0x80) {
- invalid_code = 1;
- } else {
- *(q++) = code;
- }
- break;
- case cs_gb2312:
- if (code >= 0x81) {
- invalid_code = 1;
- } else {
- *(q++) = code;
- }
- break;
- default:
- /* for backwards compatilibity */
- invalid_code = 1;
- break;
- }
- if (invalid_code) {
- for (; p <= next; p++) {
- *(q++) = *p;
- }
- }
- p = next + 1;
- } else {
- *(q++) = *(p++);
- *(q++) = *(p++);
- }
- } else if (p + 4 < lim &&
- p[1] == 'a' && p[2] == 'm' &&p[3] == 'p' &&
- p[4] == ';') {
- *(q++) = '&';
- p += 5;
- } else {
- *(q++) = *(p++);
- *(q++) = *(p++);
- }
- } else {
- *(q++) = *(p++);
- }
- } else {
- *(q++) = *(p++);
- }
- }
- *q = '\0';
- retlen = (size_t)(q - ret);
- empty_source:
- *newlen = retlen;
- return ret;
- }
- /* }}} */
- PHPAPI char *php_escape_html_entities(unsigned char *old, int oldlen, int *newlen, int all, int quote_style, char *hint_charset TSRMLS_DC)
- {
- return php_escape_html_entities_ex(old, oldlen, newlen, all, quote_style, hint_charset, 1 TSRMLS_CC);
- }
- /* {{{ php_escape_html_entities
- */
- PHPAPI char *php_escape_html_entities_ex(unsigned char *old, int oldlen, int *newlen, int all, int quote_style, char *hint_charset, zend_bool double_encode TSRMLS_DC)
- {
- int i, j, maxlen, len;
- char *replaced;
- enum entity_charset charset = determine_charset(hint_charset TSRMLS_CC);
- int matches_map;
- maxlen = 2 * oldlen;
- if (maxlen < 128)
- maxlen = 128;
- replaced = emalloc (maxlen);
- len = 0;
- i = 0;
- while (i < oldlen) {
- unsigned char mbsequence[16]; /* allow up to 15 characters in a multibyte sequence */
- int mbseqlen = sizeof(mbsequence);
- int status = SUCCESS;
- unsigned int this_char = get_next_char(charset, old, oldlen, &i, mbsequence, &mbseqlen, &status);
- if(status == FAILURE) {
- /* invalid MB sequence */
- if (quote_style & ENT_HTML_IGNORE_ERRORS) {
- continue;
- }
- efree(replaced);
- if(!PG(display_errors)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid multibyte sequence in argument");
- }
- *newlen = 0;
- return STR_EMPTY_ALLOC();
- }
- matches_map = 0;
- if (len + 16 > maxlen)
- replaced = erealloc (replaced, maxlen += 128);
- if (all) {
- /* look for a match in the maps for this charset */
- unsigned char *rep = NULL;
- for (j = 0; entity_map[j].charset != cs_terminator; j++) {
- if (entity_map[j].charset == charset
- && this_char >= entity_map[j].basechar
- && this_char <= entity_map[j].endchar) {
- rep = (unsigned char*)entity_map[j].table[this_char - entity_map[j].basechar];
- if (rep == NULL) {
- /* there is no entity for this position; fall through and
- * just output the character itself */
- break;
- }
- matches_map = 1;
- break;
- }
- }
- if (matches_map) {
- int l = strlen(rep);
- /* increase the buffer size */
- if (len + 2 + l >= maxlen) {
- replaced = erealloc(replaced, maxlen += 128);
- }
- replaced[len++] = '&';
- strlcpy(replaced + len, rep, maxlen);
- len += l;
- replaced[len++] = ';';
- }
- }
- if (!matches_map) {
- int is_basic = 0;
- if (this_char == '&') {
- if (double_encode) {
- encode_amp:
- memcpy(replaced + len, "&", sizeof("&") - 1);
- len += sizeof("&") - 1;
- } else {
- char *e = memchr(old + i, ';', oldlen - i);
- char *s = old + i;
- if (!e || (e - s) > 10) { /* minor optimization to avoid "entities" over 10 chars in length */
- goto encode_amp;
- } else {
- if (*s == '#') { /* numeric entities */
- s++;
- /* Hex (Z) */
- if (*s == 'x' || *s == 'X') {
- s++;
- while (s < e) {
- if (!isxdigit((int)*(unsigned char *)s++)) {
- goto encode_amp;
- }
- }
- /* Dec (Z)*/
- } else {
- while (s < e) {
- if (!isdigit((int)*(unsigned char *)s++)) {
- goto encode_amp;
- }
- }
- }
- } else { /* text entities */
- while (s < e) {
- if (!isalnum((int)*(unsigned char *)s++)) {
- goto encode_amp;
- }
- }
- }
- replaced[len++] = '&';
- }
- }
- is_basic = 1;
- } else {
- for (j = 0; basic_entities[j].charcode != 0; j++) {
- if ((basic_entities[j].charcode != this_char) ||
- (basic_entities[j].flags &&
- (quote_style & basic_entities[j].flags) == 0)) {
- continue;
- }
- memcpy(replaced + len, basic_entities[j].entity, basic_entities[j].entitylen);
- len += basic_entities[j].entitylen;
-
- is_basic = 1;
- break;
- }
- }
- if (!is_basic) {
- /* a wide char without a named entity; pass through the original sequence */
- if (mbseqlen > 1) {
- memcpy(replaced + len, mbsequence, mbseqlen);
- len += mbseqlen;
- } else {
- replaced[len++] = (unsigned char)this_char;
- }
- }
- }
- }
- replaced[len] = '\0';
- *newlen = len;
- return replaced;
- }
- /* }}} */
- /* {{{ php_html_entities
- */
- static void php_html_entities(INTERNAL_FUNCTION_PARAMETERS, int all)
- {
- char *str, *hint_charset = NULL;
- int str_len, hint_charset_len = 0;
- int len;
- long quote_style = ENT_QUOTES;
- char *replaced;
- zend_bool double_encode = 1;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls!b", &str, &str_len, "e_style, &hint_charset, &hint_charset_len, &double_encode) == FAILURE) {
- return;
- }
- replaced = php_escape_html_entities_ex(str, str_len, &len, all, quote_style, hint_charset, double_encode TSRMLS_CC);
- RETVAL_STRINGL(replaced, len, 0);
- }
- /* }}} */
- #define HTML_SPECIALCHARS 0
- #define HTML_ENTITIES 1
- /* {{{ register_html_constants
- */
- void register_html_constants(INIT_FUNC_ARGS)
- {
- REGISTER_LONG_CONSTANT("HTML_SPECIALCHARS", HTML_SPECIALCHARS, CONST_PERSISTENT|CONST_CS);
- REGISTER_LONG_CONSTANT("HTML_ENTITIES", HTML_ENTITIES, CONST_PERSISTENT|CONST_CS);
- REGISTER_LONG_CONSTANT("ENT_COMPAT", ENT_COMPAT, CONST_PERSISTENT|CONST_CS);
- REGISTER_LONG_CONSTANT("ENT_QUOTES", ENT_QUOTES, CONST_PERSISTENT|CONST_CS);
- REGISTER_LONG_CONSTANT("ENT_NOQUOTES", ENT_NOQUOTES, CONST_PERSISTENT|CONST_CS);
- REGISTER_LONG_CONSTANT("ENT_IGNORE", ENT_IGNORE, CONST_PERSISTENT|CONST_CS);
- }
- /* }}} */
- /* {{{ proto string htmlspecialchars(string string [, int quote_style[, string charset[, bool double_encode]]])
- Convert special characters to HTML entities */
- PHP_FUNCTION(htmlspecialchars)
- {
- php_html_entities(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
- }
- /* }}} */
- /* {{{ proto string htmlspecialchars_decode(string string [, int quote_style])
- Convert special HTML entities back to characters */
- PHP_FUNCTION(htmlspecialchars_decode)
- {
- char *str, *new_str, *e, *p;
- int len, j, i, new_len;
- long quote_style = ENT_QUOTES;
- struct basic_entities_dec basic_entities_dec[8];
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &len, "e_style) == FAILURE) {
- return;
- }
- new_str = estrndup(str, len);
- new_len = len;
- e = new_str + new_len;
- if (!(p = memchr(new_str, '&', new_len))) {
- RETURN_STRINGL(new_str, new_len, 0);
- }
- for (j = 0, i = 0; basic_entities[i].charcode != 0; i++) {
- if (basic_entities[i].flags && !(quote_style & basic_entities[i].flags)) {
- continue;
- }
- basic_entities_dec[j].charcode = basic_entities[i].charcode;
- memcpy(basic_entities_dec[j].entity, basic_entities[i].entity, basic_entities[i].entitylen + 1);
- basic_entities_dec[j].entitylen = basic_entities[i].entitylen;
- j++;
- }
- basic_entities_dec[j].charcode = '&';
- basic_entities_dec[j].entitylen = sizeof("&") - 1;
- memcpy(basic_entities_dec[j].entity, "&", sizeof("&"));
- i = j + 1;
-
- do {
- int l = e - p;
-
- for (j = 0; j < i; j++) {
- if (basic_entities_dec[j].entitylen > l) {
- continue;
- }
- if (!memcmp(p, basic_entities_dec[j].entity, basic_entities_dec[j].entitylen)) {
- int e_len = basic_entities_dec[j].entitylen - 1;
-
- *p++ = basic_entities_dec[j].charcode;
- memmove(p, p + e_len, (e - p - e_len));
- e -= e_len;
- goto done;
- }
- }
- p++;
- done:
- if (p >= e) {
- break;
- }
- } while ((p = memchr(p, '&', (e - p))));
- new_len = e - new_str;
- new_str[new_len] = '\0';
- RETURN_STRINGL(new_str, new_len, 0);
- }
- /* }}} */
- /* {{{ proto string html_entity_decode(string string [, int quote_style][, string charset])
- Convert all HTML entities to their applicable characters */
- PHP_FUNCTION(html_entity_decode)
- {
- char *str, *hint_charset = NULL;
- int str_len, hint_charset_len = 0, len;
- long quote_style = ENT_QUOTES;
- char *replaced;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len,
- "e_style, &hint_charset, &hint_charset_len) == FAILURE) {
- return;
- }
- replaced = php_unescape_html_entities(str, str_len, &len, 1, quote_style, hint_charset TSRMLS_CC);
- if (replaced) {
- RETURN_STRINGL(replaced, len, 0);
- }
- RETURN_FALSE;
- }
- /* }}} */
- /* {{{ proto string htmlentities(string string [, int quote_style[, string charset[, bool double_encode]]])
- Convert all applicable characters to HTML entities */
- PHP_FUNCTION(htmlentities)
- {
- php_html_entities(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
- }
- /* }}} */
- /* {{{ proto array get_html_translation_table([int table [, int quote_style [, string charset_hint]]])
- Returns the internal translation table used by htmlspecialchars and htmlentities */
- PHP_FUNCTION(get_html_translation_table)
- {
- long which = HTML_SPECIALCHARS, quote_style = ENT_QUOTES;
- unsigned int i;
- int j;
- unsigned char ind[5]; /* max # of 8-bit code units (4; for UTF-8) + 1 for \0 */
- void *dummy;
- char *charset_hint = NULL;
- int charset_hint_len;
- enum entity_charset charset;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lls",
- &which, "e_style, &charset_hint, &charset_hint_len) == FAILURE) {
- return;
- }
- charset = determine_charset(charset_hint TSRMLS_CC);
- array_init(return_value);
- switch (which) {
- case HTML_ENTITIES:
- for (j = 0; entity_map[j].charset != cs_terminator; j++) {
- if (entity_map[j].charset != charset)
- continue;
- for (i = 0; i <= entity_map[j].endchar - entity_map[j].basechar; i++) {
- char buffer[16];
- unsigned k;
- size_t written;
- if (entity_map[j].table[i] == NULL)
- continue;
-
- k = i + entity_map[j].basechar;
- switch (charset) {
- case cs_utf_8:
- written = php_utf32_utf8(ind, k);
- ind[written] = '\0';
- break;
- case cs_big5:
- case cs_gb2312:
- case cs_big5hkscs:
- case cs_sjis:
- /* we have no mappings for these, but if we had... */
- /* break through */
- default: /* one byte */
- written = 1;
- ind[0] = (unsigned char)k;
- ind[1] = '\0';
- break;
- }
- snprintf(buffer, sizeof(buffer), "&%s;", entity_map[j].table[i]);
- if (zend_hash_find(Z_ARRVAL_P(return_value), (const char*)ind, written+1, &dummy) == FAILURE) {
- /* in case of the single quote, which is repeated, the first one wins,
- * so don't replace the existint mapping */
- add_assoc_string(return_value, (const char*)ind, buffer, 1);
- }
- }
- }
- /* break thru */
- case HTML_SPECIALCHARS:
- add_assoc_stringl(return_value, "&", "&", sizeof("&") - 1, 1);
- for (j = 0; basic_entities[j].charcode != 0; j++) {
- if (basic_entities[j].flags && (quote_style & basic_entities[j].flags) == 0)
- continue;
-
- ind[0] = (unsigned char)basic_entities[j].charcode;
- ind[1] = '\0';
- if (zend_hash_find(Z_ARRVAL_P(return_value), (const char*)ind, 2, &dummy) == FAILURE) {
- add_assoc_stringl(return_value, ind, basic_entities[j].entity,
- basic_entities[j].entitylen, 1);
- }
- }
- break;
- }
- }
- /* }}} */
- /*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */