summaryrefslogtreecommitdiff
path: root/src/xine-utils/xmlparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xine-utils/xmlparser.c')
-rw-r--r--src/xine-utils/xmlparser.c170
1 files changed, 127 insertions, 43 deletions
diff --git a/src/xine-utils/xmlparser.c b/src/xine-utils/xmlparser.c
index 7140bea5d..93217637d 100644
--- a/src/xine-utils/xmlparser.c
+++ b/src/xine-utils/xmlparser.c
@@ -152,16 +152,37 @@ void xml_parser_free_tree(xml_node_t *current_node) {
xml_parser_free_tree_rec(current_node, 1);
}
-#define STATE_IDLE 0
-#define STATE_NODE 1
-#define STATE_COMMENT 7
+typedef enum {
+ /*0*/
+ STATE_IDLE,
+ /* <foo ...> */
+ STATE_NODE,
+ STATE_ATTRIBUTE,
+ STATE_NODE_CLOSE,
+ STATE_TAG_TERM,
+ STATE_ATTRIBUTE_EQUALS,
+ STATE_STRING,
+ STATE_TAG_TERM_IGNORE,
+ /* <?foo ...?> */
+ STATE_Q_NODE,
+ STATE_Q_ATTRIBUTE,
+ STATE_Q_NODE_CLOSE,
+ STATE_Q_TAG_TERM,
+ STATE_Q_ATTRIBUTE_EQUALS,
+ STATE_Q_STRING,
+ /* Others */
+ STATE_COMMENT,
+ STATE_DOCTYPE,
+} parser_state_t;
+
+#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)
{
char tok[TOKEN_SIZE];
char property_name[TOKEN_SIZE];
char node_name[TOKEN_SIZE];
- int state = STATE_IDLE;
+ parser_state_t state = STATE_IDLE;
int res = 0;
int parse_res;
int bypass_get_token = 0;
@@ -191,16 +212,16 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
state = STATE_NODE;
break;
case (T_M_START_2):
- state = 3;
+ state = STATE_NODE_CLOSE;
break;
case (T_C_START):
state = STATE_COMMENT;
break;
case (T_TI_START):
- state = 8;
+ state = STATE_Q_NODE;
break;
case (T_DOCTYPE_START):
- state = 9;
+ state = STATE_DOCTYPE;
break;
case (T_DATA):
/* current data */
@@ -219,6 +240,7 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
break;
case STATE_NODE:
+ case STATE_Q_NODE:
switch (res) {
case (T_IDENT):
properties = NULL;
@@ -228,8 +250,13 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
if (xml_parser_mode == XML_PARSER_CASE_INSENSITIVE) {
strtoupper(tok);
}
- strcpy(node_name, tok);
- state = 2;
+ if (state == STATE_Q_NODE) {
+ snprintf (node_name, TOKEN_SIZE, "?%s", tok);
+ state = STATE_Q_ATTRIBUTE;
+ } else {
+ strcpy(node_name, tok);
+ state = STATE_ATTRIBUTE;
+ }
lprintf("info: current node name \"%s\"\n", node_name);
break;
default:
@@ -238,7 +265,8 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
break;
}
break;
- case 2:
+
+ case STATE_ATTRIBUTE:
switch (res) {
case (T_EOL):
case (T_SEPAR):
@@ -275,6 +303,7 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
case (T_M_STOP_2):
/* new leaf */
/* new subtree */
+ new_leaf:
subtree = new_xml_node();
/* set node name */
@@ -296,11 +325,12 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
break;
case (T_IDENT):
/* save property name */
+ new_prop:
if (xml_parser_mode == XML_PARSER_CASE_INSENSITIVE) {
strtoupper(tok);
}
strcpy(property_name, tok);
- state = 5;
+ state = Q_STATE(ATTRIBUTE, ATTRIBUTE_EQUALS);
lprintf("info: current property name \"%s\"\n", property_name);
break;
default:
@@ -310,7 +340,24 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
}
break;
- case 3:
+ case STATE_Q_ATTRIBUTE:
+ switch (res) {
+ case (T_EOL):
+ case (T_SEPAR):
+ /* nothing */
+ break;
+ case (T_TI_STOP):
+ goto new_leaf;
+ case (T_IDENT):
+ goto new_prop;
+ default:
+ lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+ return -1;
+ break;
+ }
+ break;
+
+ case STATE_NODE_CLOSE:
switch (res) {
case (T_IDENT):
/* must be equal to root_name */
@@ -318,20 +365,20 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
strtoupper(tok);
}
if (strcmp(tok, root_names[rec]) == 0) {
- state = 4;
+ state = STATE_TAG_TERM;
} else if (relaxed) {
int r = rec;
while (--r >= 0)
if (strcmp(tok, root_names[r]) == 0) {
lprintf("warning: wanted %s, got %s - assuming missing close tags\n", root_names[rec], tok);
retval = r - rec - 1; /* -1 - (no. of implied close tags) */
- state = 4;
+ state = STATE_TAG_TERM;
break;
}
/* relaxed parsing, ignoring extra close tag (but we don't handle out-of-order) */
if (r < 0) {
lprintf("warning: extra close tag %s - ignoring\n", tok);
- state = 10;
+ state = STATE_TAG_TERM_IGNORE;
}
}
else
@@ -348,7 +395,7 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
break;
/* > expected */
- case 4:
+ case STATE_TAG_TERM:
switch (res) {
case (T_M_STOP_1):
return retval;
@@ -361,18 +408,18 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
break;
/* = or > or ident or separator expected */
- case 5:
+ case STATE_ATTRIBUTE_EQUALS:
switch (res) {
case (T_EOL):
case (T_SEPAR):
/* do nothing */
break;
case (T_EQUAL):
- state = 6;
+ state = STATE_STRING;
break;
case (T_IDENT):
bypass_get_token = 1; /* jump to state 2 without get a new token */
- state = 2;
+ state = STATE_ATTRIBUTE;
break;
case (T_M_STOP_1):
/* add a new property without value */
@@ -386,7 +433,42 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
current_property->name = strdup (property_name);
lprintf("info: new property %s\n", current_property->name);
bypass_get_token = 1; /* jump to state 2 without get a new token */
- state = 2;
+ state = STATE_ATTRIBUTE;
+ break;
+ default:
+ lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
+ return -1;
+ break;
+ }
+ break;
+
+ /* = or ?> or ident or separator expected */
+ case STATE_Q_ATTRIBUTE_EQUALS:
+ switch (res) {
+ case (T_EOL):
+ case (T_SEPAR):
+ /* do nothing */
+ break;
+ case (T_EQUAL):
+ state = STATE_Q_STRING;
+ break;
+ case (T_IDENT):
+ bypass_get_token = 1; /* jump to state 2 without get a new token */
+ state = STATE_Q_ATTRIBUTE;
+ break;
+ case (T_TI_STOP):
+ /* add a new property without value */
+ if (current_property == NULL) {
+ properties = new_xml_property();
+ current_property = properties;
+ } else {
+ current_property->next = new_xml_property();
+ current_property = current_property->next;
+ }
+ current_property->name = strdup (property_name);
+ lprintf("info: new property %s\n", current_property->name);
+ bypass_get_token = 1; /* jump to state 2 without get a new token */
+ state = STATE_Q_ATTRIBUTE;
break;
default:
lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
@@ -396,7 +478,8 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
break;
/* string or ident or separator expected */
- case 6:
+ case STATE_STRING:
+ case STATE_Q_STRING:
switch (res) {
case (T_EOL):
case (T_SEPAR):
@@ -415,7 +498,7 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
current_property->name = strdup(property_name);
current_property->value = lexer_decode_entities(tok);
lprintf("info: new property %s=%s\n", current_property->name, current_property->value);
- state = 2;
+ state = Q_STATE(STRING, ATTRIBUTE);
break;
default:
lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
@@ -431,40 +514,26 @@ static int xml_parser_get_node_internal (xml_node_t *current_node, char *root_na
state = STATE_IDLE;
break;
default:
- state = STATE_COMMENT;
break;
}
break;
/* > expected */
- case 8:
- switch (res) {
- case (T_TI_STOP):
- state = 0;
- break;
- default:
- state = 8;
- break;
- }
- break;
-
- /* ?> expected */
- case 9:
+ case STATE_DOCTYPE:
switch (res) {
case (T_M_STOP_1):
state = 0;
break;
default:
- state = 9;
break;
}
break;
/* > expected (following unmatched "</...") */
- case 10:
+ case STATE_TAG_TERM_IGNORE:
switch (res) {
case (T_M_STOP_1):
- state = 0;
+ state = STATE_IDLE;
break;
default:
lprintf("error: unexpected token \"%s\", state %d\n", tok, state);
@@ -497,13 +566,25 @@ static int xml_parser_get_node (xml_node_t *current_node, int relaxed)
}
int xml_parser_build_tree_relaxed(xml_node_t **root_node, int relaxed) {
- xml_node_t *tmp_node;
+ xml_node_t *tmp_node, *pri_node, *q_node;
int res;
tmp_node = new_xml_node();
res = xml_parser_get_node(tmp_node, relaxed);
- if ((tmp_node->child) && (!tmp_node->child->next)) {
- *root_node = tmp_node->child;
+
+ /* find first non-<?...?> node */;
+ for (pri_node = tmp_node->child;
+ pri_node && pri_node->name[0] == '?';
+ pri_node = pri_node->next)
+ q_node = pri_node; /* last <?...?> node (eventually), or NULL */
+
+ if (pri_node && !pri_node->next) {
+ /* move the tail to the head (for compatibility reasons) */
+ if (q_node) {
+ pri_node->next = tmp_node->child;
+ q_node->next = NULL;
+ }
+ *root_node = pri_node;
free_xml_node(tmp_node);
res = 0;
} else {
@@ -636,5 +717,8 @@ static void xml_parser_dump_node (const xml_node_t *node, int indent) {
}
void xml_parser_dump_tree (const xml_node_t *node) {
- xml_parser_dump_node (node, 0);
+ do {
+ xml_parser_dump_node (node, 0);
+ node = node->next;
+ } while (node);
}