diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/xine-utils/xmlparser.c | 103 | ||||
-rw-r--r-- | src/xine-utils/xmlparser.h | 15 |
2 files changed, 89 insertions, 29 deletions
diff --git a/src/xine-utils/xmlparser.c b/src/xine-utils/xmlparser.c index 326e21997..fe78e8e88 100644 --- a/src/xine-utils/xmlparser.c +++ b/src/xine-utils/xmlparser.c @@ -80,8 +80,11 @@ static xml_node_t * new_xml_node(void) { return new_node; } +static const char cdata[] = CDATA_MARKER; + static void free_xml_node(xml_node_t * node) { - free (node->name); + if (node->name != cdata) + free (node->name); free (node->data); free(node); } @@ -180,9 +183,42 @@ typedef enum { STATE_CDATA, } parser_state_t; +static xml_node_t *xml_parser_append_text (xml_node_t *node, xml_node_t *subnode, const char *text, int flags) +{ + if (!text || !*text) + return subnode; /* empty string -> nothing to do */ + + if ((flags & XML_PARSER_MULTI_TEXT) && subnode) { + /* we have a subtree, so we can't use node->data */ + if (subnode->name == cdata) { + /* most recent node is CDATA - append to it */ + char *newtext; + asprintf (&newtext, "%s%s", subnode->data, text); + free (subnode->data); + subnode->data = newtext; + } else { + /* most recent node is not CDATA - add a sibling */ + subnode->next = new_xml_node (); + subnode->next->name = cdata; + subnode->next->data = strdup (text); + subnode = subnode->next; + } + } else if (node->data) { + /* "no" subtree, but we have existing text - append to it */ + char *newtext; + asprintf (&newtext, "%s%s", node->data, text); + free (node->data); + node->data = newtext; + } else + /* no text, "no" subtree - duplicate & assign */ + node->data = strdup (text); + + return subnode; +} + #define Q_STATE(CURRENT,NEW) (STATE_##NEW + state - STATE_##CURRENT) -static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_names[], int rec, int relaxed) +static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_names[], int rec, int flags) { char tok[TOKEN_SIZE]; char property_name[TOKEN_SIZE]; @@ -233,16 +269,11 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na break; case (T_DATA): /* current data */ - if (current_node->data) { - /* Append to existing text. FIXME - should use a child node */ - char *data, *decoded = lexer_decode_entities (tok); - asprintf (&data, "%s%s", current_node->data, decoded); + { + char *decoded = lexer_decode_entities (tok); + current_subtree = xml_parser_append_text (current_node, current_subtree, decoded, flags); free (decoded); - free (current_node->data); - current_node->data = data; } - else - current_node->data = lexer_decode_entities (tok); lprintf("info: node data : %s\n", current_node->data); break; default: @@ -296,7 +327,7 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na subtree->props = properties; lprintf("info: rec %d new subtree %s\n", rec, node_name); root_names[rec + 1] = node_name; - parse_res = xml_parser_get_node_internal(subtree, root_names, rec + 1, relaxed); + parse_res = xml_parser_get_node_internal(subtree, root_names, rec + 1, flags); if (parse_res == -1 || parse_res > 0) { return parse_res; } @@ -379,7 +410,7 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na } if (strcmp(tok, root_names[rec]) == 0) { state = STATE_TAG_TERM; - } else if (relaxed) { + } else if (flags & XML_PARSER_RELAXED) { int r = rec; while (--r >= 0) if (strcmp(tok, root_names[r]) == 0) { @@ -546,16 +577,8 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na case STATE_CDATA: switch (res) { case (T_CDATA_STOP): - if (current_node->data) { - /* Append to existing text. FIXME - should use a child node */ - char *data; - asprintf (&data, "%s%s", current_node->data, tok); - free (current_node->data); - current_node->data = data; - } - else - current_node->data = strdup (tok); - lprintf("info: node cdata : %s\n", current_node->data); + current_subtree = xml_parser_append_text (current_node, current_subtree, tok, flags); + lprintf("info: node cdata : %s\n", tok); state = STATE_IDLE; break; default: @@ -594,22 +617,40 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na } } -static int xml_parser_get_node (xml_node_t *current_node, int relaxed) +static int xml_parser_get_node (xml_node_t *current_node, int flags) { char *root_names[MAX_RECURSION + 1]; root_names[0] = ""; - return xml_parser_get_node_internal (current_node, root_names, 0, relaxed); + return xml_parser_get_node_internal (current_node, root_names, 0, flags); } -int xml_parser_build_tree_relaxed(xml_node_t **root_node, int relaxed) { - xml_node_t *tmp_node, *pri_node, *q_node = NULL; +int xml_parser_build_tree_with_options(xml_node_t **root_node, int flags) { + xml_node_t *tmp_node, *pri_node, *q_node; int res; tmp_node = new_xml_node(); - res = xml_parser_get_node(tmp_node, relaxed); + res = xml_parser_get_node(tmp_node, flags); + + /* delete any top-level [CDATA] nodes */; + pri_node = tmp_node->child; + q_node = NULL; + while (pri_node) { + if (pri_node->name == cdata) { + xml_node_t *old = pri_node; + if (q_node) + q_node->next = pri_node->next; + else + q_node = pri_node; + pri_node = pri_node->next; + free_xml_node (old); + } else { + q_node = pri_node; + pri_node = pri_node->next; + } + } /* find first non-<?...?> node */; - for (pri_node = tmp_node->child; + for (pri_node = tmp_node->child, q_node = NULL; pri_node && pri_node->name[0] == '?'; pri_node = pri_node->next) q_node = pri_node; /* last <?...?> node (eventually), or NULL */ @@ -631,8 +672,12 @@ int xml_parser_build_tree_relaxed(xml_node_t **root_node, int relaxed) { return res; } +int xml_parser_build_tree_relaxed(xml_node_t **root_node, int relaxed) { + return xml_parser_build_tree_with_options (root_node, relaxed ? XML_PARSER_RELAXED : 0); +} + int xml_parser_build_tree(xml_node_t **root_node) { - return xml_parser_build_tree_relaxed (root_node, 0); + return xml_parser_build_tree_with_options (root_node, 0); } const char *xml_parser_get_property (const xml_node_t *node, const char *name) { diff --git a/src/xine-utils/xmlparser.h b/src/xine-utils/xmlparser.h index 8d4915abf..364cc4c2b 100644 --- a/src/xine-utils/xmlparser.h +++ b/src/xine-utils/xmlparser.h @@ -37,6 +37,12 @@ #define XML_PARSER_OK 0 #define XML_PARSER_ERROR 1 +/* xml_parser_build_tree_with_options flag bits */ +#define XML_PARSER_RELAXED 1 +#define XML_PARSER_MULTI_TEXT 2 + +/* node name for extra text chunks */ +#define CDATA_MARKER "[CDATA]" /* xml property */ typedef struct xml_property_s { @@ -46,6 +52,14 @@ typedef struct xml_property_s { } xml_property_t; /* xml node */ +/* .data contains any text which precedes any subtree elements; + * subtree elements may also contain only text; if so, name is "[CDATA]". + * e.g. <a>b<c />d</a> + * node1: .name="a" .data="b" .child=node2 .next=NULL + * node2: .name="c" .data=NULL .child=NULL .next=node3 + * node3: .name="[CDATA]" .data="d" .child=NULL .next=NULL + * Adjacent text items are merged. + */ typedef struct xml_node_s { char *name; char *data; @@ -58,6 +72,7 @@ void xml_parser_init(const char * buf, int size, int mode) XINE_PROTECTED; int xml_parser_build_tree(xml_node_t **root_node) XINE_PROTECTED; int xml_parser_build_tree_relaxed(xml_node_t **root_node, int relaxed) XINE_PROTECTED; +int xml_parser_build_tree_with_options(xml_node_t **root_node, int flags) XINE_PROTECTED; void xml_parser_free_tree(xml_node_t *root_node) XINE_PROTECTED; |