diff options
Diffstat (limited to 'src/rexmpp_xml.c')
-rw-r--r-- | src/rexmpp_xml.c | 276 |
1 files changed, 121 insertions, 155 deletions
diff --git a/src/rexmpp_xml.c b/src/rexmpp_xml.c index 862a783..4907d4e 100644 --- a/src/rexmpp_xml.c +++ b/src/rexmpp_xml.c @@ -8,8 +8,6 @@ #include <string.h> #include <stdio.h> -#include <libxml/tree.h> -#include <libxml/xmlsave.h> #include "rexmpp.h" #include "rexmpp_utf8.h" #include "rexmpp_xml.h" @@ -119,135 +117,7 @@ rexmpp_xml_t *rexmpp_xml_clone_list (rexmpp_xml_t *node) { } return first; } -#endif - -rexmpp_xml_t *rexmpp_xml_from_libxml2 (xmlNodePtr from) { - if (from == NULL) { - return NULL; - } - - rexmpp_xml_t *to = NULL; - if (from->type == XML_ELEMENT_NODE) { - to = malloc(sizeof(rexmpp_xml_t)); - - /* Type */ - to->type = REXMPP_XML_ELEMENT; - - /* Name and namespace */ - to->alt.elem.qname.name = strdup(from->name); - if (from->nsDef != NULL && from->nsDef->href != NULL) { - to->alt.elem.qname.namespace = strdup(from->nsDef->href); - } else { - to->alt.elem.qname.namespace = NULL; - } - - /* Attributes */ - to->alt.elem.attributes = NULL; - struct _xmlAttr *from_attr; - rexmpp_xml_attr_t **to_next_attr = &(to->alt.elem.attributes); - for (from_attr = from->properties; - from_attr != NULL; - from_attr = from_attr->next) - { - rexmpp_xml_attr_t *to_attr = - malloc(sizeof(rexmpp_xml_attr_t)); - to_attr->qname.name = strdup(from_attr->name); - to_attr->qname.namespace = NULL; - if (from_attr->ns != NULL && from_attr->ns->href != NULL) { - to_attr->qname.namespace = strdup(from_attr->ns->href); - to_attr->value = - xmlGetNsProp(from, to_attr->qname.name, to_attr->qname.namespace); - } else { - to_attr->value = xmlGetProp(from, to_attr->qname.name); - } - to_attr->next = NULL; - - *to_next_attr = to_attr; - to_next_attr = &(to_attr->next); - } - - /* Children */ - to->alt.elem.children = NULL; - xmlNodePtr from_child; - rexmpp_xml_t **to_next_child = &(to->alt.elem.children); - for (from_child = from->children; - from_child != NULL; - from_child = from_child->next) - { - rexmpp_xml_t *next_child = rexmpp_xml_from_libxml2(from_child); - if (next_child != NULL) { - *to_next_child = next_child; - to_next_child = &(next_child->next); - } - } - - /* Next */ - to->next = NULL; - - } else if (from->type == XML_TEXT_NODE) { - to = malloc(sizeof(rexmpp_xml_t)); - to->type = REXMPP_XML_TEXT; - to->alt.text = xmlNodeGetContent(from); - to->next = NULL; - } - return to; -} - -rexmpp_xml_t *rexmpp_xml_from_libxml2_list (xmlNodePtr from) { - if (from == NULL) { - return NULL; - } - rexmpp_xml_t *to = rexmpp_xml_from_libxml2(from); - if (from->next != NULL) { - to->next = rexmpp_xml_from_libxml2_list(from->next); - } - return to; -} - -xmlNodePtr rexmpp_xml_to_libxml2 (rexmpp_xml_t *from) { - if (from == NULL) { - return NULL; - } - - if (from->type == REXMPP_XML_TEXT) { - xmlNodePtr to = xmlNewText(from->alt.text); - to->next = rexmpp_xml_to_libxml2(from->next); - return to; - } - - /* Name and namespace */ - xmlNodePtr to = xmlNewNode(NULL, from->alt.elem.qname.name); - if (from->alt.elem.qname.namespace != NULL) { - xmlNewNs(to, from->alt.elem.qname.namespace, NULL); - } - - /* Attributes */ - rexmpp_xml_attr_t *attr = from->alt.elem.attributes; - while (attr != NULL) { - /* TODO: Would be nice to take namespaces into account, though - they are currently not used for attributes. */ - xmlNewProp(to, attr->qname.name, attr->value); - attr = attr->next; - } - - /* Children */ - rexmpp_xml_t *child = from->alt.elem.children; - while (child != NULL) { - xmlAddChild(to, rexmpp_xml_to_libxml2(child)); - child = child->next; - } - return to; -} - -xmlNodePtr rexmpp_xml_to_libxml2_list (rexmpp_xml_t *from) { - xmlNodePtr to = rexmpp_xml_to_libxml2(from); - if (from->next != NULL) { - xmlAddNextSibling(to, rexmpp_xml_to_libxml2_list(from->next)); - } - return to; -} -#ifndef USE_RUST rexmpp_xml_t *rexmpp_xml_new_text (const char *str) { rexmpp_xml_t *node = malloc(sizeof(rexmpp_xml_t)); node->type = REXMPP_XML_TEXT; @@ -590,32 +460,126 @@ rexmpp_xml_add_id (rexmpp_t *s, } #endif -xmlNodePtr rexmpp_xml_parse_libxml2 (const char *str, int str_len) { - xmlNodePtr elem = NULL; - xmlDocPtr doc = xmlReadMemory(str, str_len, "", "utf-8", XML_PARSE_NONET); - if (doc != NULL) { - elem = xmlCopyNode(xmlDocGetRootElement(doc), 1); - xmlFreeDoc(doc); +/* These SAX handlers are similar to those from rexmpp.c, and perhaps + can be reused. */ +void rexmpp_xml_parse_sax_characters (struct rexmpp_xml_builder *builder, + const char *ch, + size_t len) +{ + if (builder->current != NULL) { + rexmpp_xml_t *last_node = builder->current->alt.elem.children; + if (last_node != NULL && last_node->type == REXMPP_XML_TEXT) { + /* The last child is textual as well, just extend it */ + size_t last_len = strlen(last_node->alt.text); + last_node->alt.text = realloc(last_node->alt.text, last_len + len + 1); + strncpy(last_node->alt.text + last_len, ch, len); + last_node->alt.text[last_len + len] = '\0'; + } else { + rexmpp_xml_t *text_node = rexmpp_xml_new_text_len(ch, len); + if (text_node != NULL) { + text_node->next = builder->current->alt.elem.children; + builder->current->alt.elem.children = text_node; + } + } + } +} + +void rexmpp_xml_parse_sax_start_elem_ns (struct rexmpp_xml_builder *builder, + const char *name, + const char *namespace, + rexmpp_xml_attr_t *attributes) +{ + if (builder->current == NULL && builder->root == NULL) { + /* Just started */ + builder->current = rexmpp_xml_new_elem(name, namespace); + builder->root = builder->current; + } else if (builder->current != NULL) { + /* Parsing is in progress */ + rexmpp_xml_t *node = rexmpp_xml_new_elem(name, namespace); + node->next = builder->current->alt.elem.children; + builder->current->alt.elem.children = node; + builder->current = node; + } else { + /* The parsind is over, but we are receiving these events + still. Just free the attribute lists, ignore the rest. */ + rexmpp_xml_attribute_free_list(attributes); } - return elem; + builder->current->alt.elem.attributes = attributes; } +void rexmpp_xml_parse_sax_end_elem_ns (struct rexmpp_xml_builder *builder) +{ + if (builder->current != builder->root) { + /* Find the parent, set it as current element. */ + rexmpp_xml_t *parent = builder->root; + while (parent->alt.elem.children != builder->current) { + parent = parent->alt.elem.children; + } + builder->current = parent; + } else { + /* Done parsing this element; reverse all the lists of children. */ + builder->current = NULL; + rexmpp_xml_reverse_children(builder->root); + } +} + +struct rexmpp_xml_parser_handlers builder_sax = { + (rexmpp_xml_parser_element_start)rexmpp_xml_parse_sax_start_elem_ns, + (rexmpp_xml_parser_element_end)rexmpp_xml_parse_sax_end_elem_ns, + (rexmpp_xml_parser_characters)rexmpp_xml_parse_sax_characters +}; + rexmpp_xml_t *rexmpp_xml_parse (const char *str, int str_len) { - xmlNodePtr node_lxml2 = rexmpp_xml_parse_libxml2(str, str_len); - if (node_lxml2 != NULL) { - rexmpp_xml_t *node = rexmpp_xml_from_libxml2(node_lxml2); - xmlFreeNode(node_lxml2); - return node; + struct rexmpp_xml_builder builder = { NULL, NULL }; + rexmpp_xml_parser_ctx_t parser = + rexmpp_xml_parser_new(&builder_sax, &builder); + rexmpp_xml_parser_feed(parser, str, str_len); + rexmpp_xml_parser_free(parser); + if (builder.current != NULL) { + /* The parsing is not complete. */ + rexmpp_xml_free(builder.root); + return NULL; } - return NULL; + return builder.root; +} + +rexmpp_xml_t *rexmpp_xml_read_fd (FILE *fd) { + struct rexmpp_xml_builder builder = { NULL, NULL }; + rexmpp_xml_parser_ctx_t parser = + rexmpp_xml_parser_new(&builder_sax, &builder); + if (parser == NULL) { + return NULL; + } + + char *buf; + size_t len = 0; + do { + len = getline(&buf, &len, fd); + if (len > 0) { + rexmpp_xml_parser_feed(parser, buf, len); + } + } while (len > 0 && + ! (builder.root != NULL && builder.current == NULL) ); + + rexmpp_xml_parser_free(parser); + + if (builder.current != NULL) { + /* The parsing is not complete. */ + rexmpp_xml_free(builder.root); + return NULL; + } + + return builder.root; } rexmpp_xml_t *rexmpp_xml_read_file (const char *path) { - xmlDocPtr doc = xmlReadFile(path, "utf-8", XML_PARSE_NONET); - xmlNodePtr lxml2 = xmlDocGetRootElement(doc); - rexmpp_xml_t *ret = rexmpp_xml_from_libxml2(lxml2); - xmlFreeDoc(doc); - return ret; + FILE *fd = fopen(path, "r"); + if (fd == NULL) { + return NULL; + } + rexmpp_xml_t *node = rexmpp_xml_read_fd(fd); + fclose(fd); + return node; } #ifndef USE_RUST @@ -806,7 +770,7 @@ char *rexmpp_xml_text_child (rexmpp_xml_t *node) { return rexmpp_xml_text(rexmpp_xml_children(node)); } -rexmpp_xml_t *rexmpp_xml_reverse (rexmpp_xml_t *node) { +rexmpp_xml_t *rexmpp_xml_reverse_list (rexmpp_xml_t *node) { rexmpp_xml_t *next, *prev = NULL; while (node != NULL) { next = node->next; @@ -817,15 +781,17 @@ rexmpp_xml_t *rexmpp_xml_reverse (rexmpp_xml_t *node) { return prev; } -rexmpp_xml_t *rexmpp_xml_reverse_all (rexmpp_xml_t *node) { - node = rexmpp_xml_reverse(node); +void rexmpp_xml_reverse_children (rexmpp_xml_t *node) { + if (node == NULL || node->type != REXMPP_XML_ELEMENT) { + return; + } + node->alt.elem.children = rexmpp_xml_reverse_list(node->alt.elem.children); rexmpp_xml_t *cur; - for (cur = node; cur != NULL; cur = cur->next) { - if (cur->type == REXMPP_XML_ELEMENT) { - cur->alt.elem.children = rexmpp_xml_reverse_all(cur->alt.elem.children); + for (cur = node->alt.elem.children; cur != NULL; cur = cur->next) { + if (cur->type == REXMPP_XML_ELEMENT && cur->alt.elem.children != NULL) { + rexmpp_xml_reverse_children(cur); } } - return node; } #endif |