diff options
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | src/xine-utils/xmllexer.c | 76 | ||||
-rw-r--r-- | src/xine-utils/xmllexer.h | 3 | ||||
-rw-r--r-- | src/xine-utils/xmlparser.c | 44 | ||||
-rw-r--r-- | src/xine-utils/xmlparser.h | 14 |
5 files changed, 129 insertions, 9 deletions
@@ -12,6 +12,7 @@ xine-lib (1.0.1) * Shoutcast: fixed meta info handling * MMST: fixed incorrect command length * support for WMA Voice codec + * add limited support for character entities to the XML parser xine-lib (1.0) * unbreak DXR3 plugin diff --git a/src/xine-utils/xmllexer.c b/src/xine-utils/xmllexer.c index 9a37ba29a..97a23b41e 100644 --- a/src/xine-utils/xmllexer.c +++ b/src/xine-utils/xmllexer.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xmllexer.c,v 1.8 2004/05/31 17:37:49 tmattern Exp $ + * $Id: xmllexer.c,v 1.9 2005/01/16 17:51:04 dsalt Exp $ * */ @@ -353,11 +353,13 @@ int lexer_get_token(char * tok, int tok_size) { } } else { /* data mode, stop if char equal '<' */ - if (c == '<') { + switch (c) + { + case '<': tok[tok_pos] = '\0'; lex_mode = NORMAL; return T_DATA; - } else { + default: tok[tok_pos] = c; tok_pos++; lexbuf_pos++; @@ -411,3 +413,71 @@ int lexer_get_token(char * tok, int tok_size) { lprintf("token buffer is null\n"); return T_ERROR; } + +static struct { + char code, namelen, name[6]; +} lexer_entities[] = { + { '"', 4, "quot" }, + { '&', 3, "amp" }, + { '\'', 4, "apos" }, + { '<', 2, "lt" }, + { '>', 2, "gt" }, + { 0 } +}; + +char *lexer_decode_entities (const char *tok) +{ + char *buf = xine_xmalloc (strlen (tok) + 1); + char *bp = buf; + char c; + + while ((c = *tok++)) + { + if (c != '&') + *bp++ = c; + else + { + /* parse the character entity (on failure, treat it as literal text) */ + const char *tp = tok; + long i; + + for (i = 0; lexer_entities[i].code; ++i) + if (!strncmp (lexer_entities[i].name, tok, lexer_entities[i].namelen) + && tok[lexer_entities[i].namelen] == ';') + break; + if (lexer_entities[i].code) + { + tok += lexer_entities[i].namelen + 1; + *bp++ = lexer_entities[i].code; + continue; + } + + if (*tp++ != '#') + { + /* not a recognised name and not numeric */ + *bp++ = '&'; + continue; + } + + /* entity is a number + * (note: strtol() allows "0x" prefix for hexadecimal, but we don't) + */ + if (*tp == 'x' && tp[1] && tp[2] != 'x') + i = strtol (tp + 1, &tp, 16); + else + i = strtol (tp, &tp, 10); + + if (i < 1 || i > 255 || *tp != ';') + { + /* out of range, or format error */ + *bp++ = '&'; + continue; + } + + tok = tp + 1; + *bp++ = i; + } + } + *bp = 0; + return buf; +} diff --git a/src/xine-utils/xmllexer.h b/src/xine-utils/xmllexer.h index 414021aad..d142c3d0f 100644 --- a/src/xine-utils/xmllexer.h +++ b/src/xine-utils/xmllexer.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xmllexer.h,v 1.3 2003/12/09 00:02:39 f1rmb Exp $ + * $Id: xmllexer.h,v 1.4 2005/01/16 17:51:04 dsalt Exp $ * */ @@ -50,5 +50,6 @@ /* public functions */ void lexer_init(char * buf, int size); int lexer_get_token(char * tok, int tok_size); +char *lexer_decode_entities (const char *tok); #endif diff --git a/src/xine-utils/xmlparser.c b/src/xine-utils/xmlparser.c index c36cb849b..95f9642f5 100644 --- a/src/xine-utils/xmlparser.c +++ b/src/xine-utils/xmlparser.c @@ -18,7 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xmlparser.c,v 1.13 2003/12/06 18:11:53 mroi Exp $ + * $Id: xmlparser.c,v 1.14 2005/01/16 17:51:04 dsalt Exp $ * */ @@ -205,7 +205,7 @@ static int xml_parser_get_node (xml_node_t *current_node, char *root_name, int r /* avoid a memory leak */ free(current_node->data); } - current_node->data = strdup(tok); + current_node->data = lexer_decode_entities(tok); lprintf("info: node data : %s\n", current_node->data); break; default: @@ -389,7 +389,7 @@ static int xml_parser_get_node (xml_node_t *current_node, char *root_name, int r current_property = current_property->next; } current_property->name = strdup(property_name); - current_property->value = strdup(tok); + current_property->value = lexer_decode_entities(tok); lprintf("info: new property %s=%s\n", current_property->name, current_property->value); state = 2; break; @@ -523,6 +523,40 @@ int xml_parser_get_property_bool (xml_node_t *node, const char *name, return 0; } +static int xml_escape_string_internal (char *buf, const char *s, + xml_escape_quote_t quote_type) +{ + int c, length = 0; + int sl = buf ? 8 : 0; + /* calculate max required buffer size */ + while ((c = *s++ & 0xFF)) + switch (c) + { + case '"': if (quote_type != XML_ESCAPE_DOUBLE_QUOTE) goto literal; + length += snprintf (buf + length, sl, """); break; + case '\'': if (quote_type != XML_ESCAPE_SINGLE_QUOTE) goto literal; + length += snprintf (buf + length, sl, "'"); break; + case '&': length += snprintf (buf + length, sl, "&"); break; + case '<': length += snprintf (buf + length, sl, "<"); break; + case '>': length += snprintf (buf + length, sl, ">"); break; + case 127: length += snprintf (buf + length, sl, ""); break; + case '\t': + case '\n': + literal: if (buf) buf[length] = c; ++length; break; + default: if (c >= ' ') goto literal; + length += snprintf (buf + length, sl, "&#%d;", c); break; + } + if (buf) + buf[length] = 0; + return length + 1; +} + +char *xml_escape_string (const char *s, xml_escape_quote_t quote_type) +{ + char *buf = xine_xmalloc (xml_escape_string_internal (NULL, s, quote_type)); + return buf ? (xml_escape_string_internal (buf, s, quote_type), buf) : NULL; +} + static void printf_indent (int indent, const char *format, ...) { int i ; @@ -550,7 +584,9 @@ static void xml_parser_dump_node (xml_node_t *node, int indent) { p = node->props; while (p) { - printf ("%s='%s'", p->name, p->value); + char *value = xml_escape_string (p->value, XML_ESCAPE_SINGLE_QUOTE); + printf ("%s='%s'", p->name, value); + free (value); p = p->next; if (p) { printf ("\n"); diff --git a/src/xine-utils/xmlparser.h b/src/xine-utils/xmlparser.h index ccf982f66..45217d3f9 100644 --- a/src/xine-utils/xmlparser.h +++ b/src/xine-utils/xmlparser.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xmlparser.h,v 1.2 2003/07/19 00:22:43 tmattern Exp $ + * $Id: xmlparser.h,v 1.3 2005/01/16 17:51:04 dsalt Exp $ * */ #ifndef XML_PARSER_H @@ -60,6 +60,18 @@ int xml_parser_get_property_int (xml_node_t *node, const char *name, int xml_parser_get_property_bool (xml_node_t *node, const char *name, int def_value); +/* for output: + * returns an escaped string (free() it when done) + * input must be in ASCII or UTF-8 + */ + +typedef enum { + XML_ESCAPE_NO_QUOTE, + XML_ESCAPE_SINGLE_QUOTE, + XML_ESCAPE_DOUBLE_QUOTE +} xml_escape_quote_t; +char *xml_escape_string (const char *s, xml_escape_quote_t quote_type); + /* for debugging purposes: dump read-in xml tree in a nicely * indented fashion */ |