diff --git a/include/xine/xmlparser.h b/include/xine/xmlparser.h --- a/include/xine/xmlparser.h +++ b/include/xine/xmlparser.h @@ -37,6 +37,10 @@ /* xml_parser_build_tree_with_options flag bits */ #define XML_PARSER_RELAXED 1 #define XML_PARSER_MULTI_TEXT 2 +/* normally, the "closed" array lists nodes which do not have sub-nodes; + * with this flag set, it lists nodes which may have sub-nodes + */ +#define XML_PARSER_INVERT_CLOSED_LIST 4 /* node name for extra text chunks */ #define CDATA_MARKER "[CDATA]" @@ -69,6 +73,7 @@ void xml_parser_init(const char * buf, i int xml_parser_build_tree(xml_node_t **root_node) XINE_PROTECTED; int xml_parser_build_tree_with_options(xml_node_t **root_node, int flags) XINE_PROTECTED; +int xml_parser_build_tree_full(xml_node_t **root_node, int flags, const char *const closed[]) XINE_PROTECTED; void xml_parser_free_tree(xml_node_t *root_node) XINE_PROTECTED; diff --git a/src/xine-utils/xmllexer.c b/src/xine-utils/xmllexer.c --- a/src/xine-utils/xmllexer.c +++ b/src/xine-utils/xmllexer.c @@ -48,6 +48,7 @@ static const char * lexbuf; static const char * lexbuf; static int lexbuf_size = 0; static int lexbuf_pos = 0; +static int lexbuf_saved_pos = 0; static int in_comment = 0; static char *lex_malloc = NULL; @@ -575,6 +576,16 @@ int lexer_get_token (char *tok, int tok_ return lexer_get_token_d (&tok, &tok_size, 1); } +void lexer_save_pos (void) +{ + lexbuf_saved_pos = lexbuf_pos; +} + +void lexer_restore_pos (void) +{ + lexbuf_pos = lexbuf_saved_pos; +} + static struct { char code; unsigned char namelen; diff --git a/src/xine-utils/xmlparser.c b/src/xine-utils/xmlparser.c --- a/src/xine-utils/xmlparser.c +++ b/src/xine-utils/xmlparser.c @@ -32,9 +32,9 @@ #define LOG_MODULE "xmlparser" #define LOG_VERBOSE -/* +//* #define LOG -*/ +//*/ #ifdef XINE_COMPILE #include @@ -219,10 +219,13 @@ static xml_node_t *xml_parser_append_tex #define Q_STATE(CURRENT,NEW) (STATE_##NEW + state - STATE_##CURRENT) +#define XML_PARSER_INTERNAL_CLOSE_ONLY (1ULL << 63) + static int xml_parser_get_node_internal (char ** token_buffer, int * token_buffer_size, char ** pname_buffer, int * pname_buffer_size, char ** nname_buffer, int * nname_buffer_size, - xml_node_t *current_node, char *root_names[], int rec, int flags) + xml_node_t *current_node, char *root_names[], int rec, + uint64_t flags, const char *const closed[]) { char *tok = *token_buffer; char *property_name = *pname_buffer; @@ -240,6 +243,7 @@ static int xml_parser_get_node_internal if (rec < MAX_RECURSION) { memset (tok, 0, *token_buffer_size); + lexer_save_pos (); while ((bypass_get_token) || (res = lexer_get_token_d(token_buffer, token_buffer_size, 0)) != T_ERROR) { tok = *token_buffer; @@ -278,7 +282,25 @@ static int xml_parser_get_node_internal /* current data */ { char *decoded = lexer_decode_entities (tok); - current_subtree = xml_parser_append_text (current_node, current_subtree, decoded, flags); + if (flags & XML_PARSER_INTERNAL_CLOSE_ONLY) + { + char *s = decoded; + while (isspace (*s)) + ++s; + if (*s) + { + /* looking for but found a non-empty string */ + if (1 || flags & XML_PARSER_RELAXED) { + lprintf("warning: wanted , got something else", root_names[rec]); + lexer_restore_pos (); + return 0; + } + lprintf("error: unexpected token \"%s\", state %d\n", tok, state); + return -1; + } + } + else + current_subtree = xml_parser_append_text (current_node, current_subtree, decoded, flags); free (decoded); } lprintf("info: node data : %s\n", current_node->data); @@ -287,6 +309,18 @@ static int xml_parser_get_node_internal lprintf("error: unexpected token \"%s\", state %d\n", tok, state); return -1; break; + } + if ((flags & XML_PARSER_INTERNAL_CLOSE_ONLY) && state != STATE_IDLE + && state != STATE_NODE_CLOSE && state != STATE_COMMENT) + { + /* looking for but found something else */ + if (1 || flags & XML_PARSER_RELAXED) { + lprintf("warning: wanted , got something else", root_names[rec]); + lexer_restore_pos (); + return 0; + } + lprintf("error: unexpected token \"%s\", state %d\n", tok, state); + return -1; } break; @@ -338,11 +372,37 @@ static int xml_parser_get_node_internal /* set node propertys */ subtree->props = properties; lprintf("info: rec %d new subtree %s\n", rec, node_name); + + parse_res = 0; + if (closed) + { + int i; + if (flags & XML_PARSER_INVERT_CLOSED_LIST) + { + for (i = 0; closed[i]; ++i) + if (!strcasecmp (node_name, closed[i])) + break; + if (!closed[i]) + parse_res = 1; + } + else + { + for (i = 0; closed[i]; ++i) + if (!strcasecmp (node_name, closed[i])) + { + parse_res = 1; + break; + } + } + } + root_names[rec + 1] = strdup (node_name); parse_res = xml_parser_get_node_internal (token_buffer, token_buffer_size, pname_buffer, pname_buffer_size, nname_buffer, nname_buffer_size, - subtree, root_names, rec + 1, flags); + subtree, root_names, rec + 1, + flags | (parse_res ? XML_PARSER_INTERNAL_CLOSE_ONLY : 0), + closed); free (root_names[rec + 1]); if (parse_res == -1 || parse_res > 0) { return parse_res; @@ -639,7 +699,7 @@ static int xml_parser_get_node_internal } } -static int xml_parser_get_node (xml_node_t *current_node, int flags) +static int xml_parser_get_node (xml_node_t *current_node, int flags, const char *const closed[]) { int res = 0; int token_buffer_size = TOKEN_SIZE; @@ -653,7 +713,7 @@ static int xml_parser_get_node (xml_node res = xml_parser_get_node_internal (&token_buffer, &token_buffer_size, &pname_buffer, &pname_buffer_size, &nname_buffer, &nname_buffer_size, - current_node, root_names, 0, flags); + current_node, root_names, 0, flags, closed); free (token_buffer); free (pname_buffer); @@ -662,12 +722,13 @@ static int xml_parser_get_node (xml_node return res; } -int xml_parser_build_tree_with_options(xml_node_t **root_node, int flags) { +int xml_parser_build_tree_full (xml_node_t **root_node, int flags, const char *const closed[]) +{ xml_node_t *tmp_node, *pri_node, *q_node; int res; tmp_node = new_xml_node(); - res = xml_parser_get_node(tmp_node, flags); + res = xml_parser_get_node(tmp_node, flags, closed); /* delete any top-level [CDATA] nodes */; pri_node = tmp_node->child; @@ -710,8 +771,12 @@ int xml_parser_build_tree_with_options(x return res; } +int xml_parser_build_tree_with_options(xml_node_t **root_node, int flags) { + return xml_parser_build_tree_full (root_node, flags, NULL); +} + int xml_parser_build_tree(xml_node_t **root_node) { - return xml_parser_build_tree_with_options (root_node, 0); + return xml_parser_build_tree_full (root_node, 0, NULL); } const char *xml_parser_get_property (const xml_node_t *node, const char *name) {