Mercurial > pidgin
diff src/xmlnode.c @ 13806:25e63008d3bb
[gaim-migrate @ 16229]
Use libxml2 for XML parsing, if available. The biggest benefit from this is actual support for XML namespaces. This fixes a handful of Google Talk integration problems, including typing notifications and buddy icons.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Thu, 08 Jun 2006 01:03:51 +0000 |
parents | 02833a0ae716 |
children | 3c6d0c24179a |
line wrap: on
line diff
--- a/src/xmlnode.c Wed Jun 07 15:58:27 2006 +0000 +++ b/src/xmlnode.c Thu Jun 08 01:03:51 2006 +0000 @@ -29,6 +29,9 @@ #include "internal.h" +#ifdef HAVE_LIBXML +#include <libxml/parser.h> +#endif #include <string.h> #include <glib.h> @@ -172,6 +175,32 @@ return NULL; } + +void xmlnode_set_namespace(xmlnode *node, const char *xmlns) +{ +#ifdef HAVE_LIBXML + g_return_if_fail(node != NULL); + + if (node->namespace) + g_free(node->namespace); + + node->namespace = g_strdup(xmlns); +#else + return xmlnode_set_attrib(node, "xmlns", xmlns); +#endif +} + +const char *xmlnode_get_namespace(xmlnode *node) +{ +#ifdef HAVE_LIBXML + g_return_val_if_fail(node != NULL, NULL); + + return node->namespace; +#else + return xmlnode_get_attrib(node, "xmlns"); +#endif +} + void xmlnode_free(xmlnode *node) { @@ -190,6 +219,10 @@ g_free(node->name); if(node->data) g_free(node->data); +#ifdef HAVE_LIBXML + if(node->namespace) + g_free(node->namespace); +#endif g_free(node); } @@ -216,7 +249,7 @@ for(x = parent->child; x; x = x->next) { const char *xmlns = NULL; if(ns) - xmlns = xmlnode_get_attrib(x, "xmlns"); + xmlns = xmlnode_get_namespace(x); if(x->type == XMLNODE_TYPE_TAG && name && !strcmp(parent_name, x->name) && (!ns || (xmlns && !strcmp(ns, xmlns)))) { @@ -272,6 +305,13 @@ node_name = g_markup_escape_text(node->name, -1); g_string_append_printf(text, "<%s", node_name); +#ifdef HAVE_LIBXML + if (node->namespace) { + char *namespace = g_markup_escape_text(node->namespace, -1); + g_string_append_printf(text, " xmlns='%s'", namespace); + g_free(namespace); + } +#endif for(c = node->child; c; c = c->next) { if(c->type == XMLNODE_TYPE_ATTRIB) { @@ -347,6 +387,71 @@ xmlnode *current; }; +#ifdef HAVE_LIBXML +static void +xmlnode_parser_element_start_libxml(void *user_data, + const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace, + int nb_namespaces, const xmlChar **namespaces, + int nb_attributes, int nb_defaulted, const xmlChar **attributes) +{ + struct _xmlnode_parser_data *xpd = user_data; + xmlnode *node; + int i; + + if(!element_name) { + return; + } else { + if(xpd->current) + node = xmlnode_new_child(xpd->current, element_name); + else + node = xmlnode_new(element_name); + + xmlnode_set_namespace(node, namespace); + + for(i=0; i < nb_attributes * 5; i+=5) { + int attrib_len = attributes[i+4] - attributes[i+3]; + char *attrib = g_malloc(attrib_len + 1); + memcpy(attrib, attributes[i+3], attrib_len); + attrib[attrib_len] = '\0'; + xmlnode_set_attrib(node, attributes[i], attrib); + g_free(attrib); + } + + xpd->current = node; + } +} + +static void +xmlnode_parser_element_end_libxml(void *user_data, const xmlChar *element_name, + const xmlChar *prefix, const xmlChar *namespace) +{ + struct _xmlnode_parser_data *xpd = user_data; + + if(!element_name || !xpd->current) + return; + + if(xpd->current->parent) { + if(!strcmp(xpd->current->name, element_name)) + xpd->current = xpd->current->parent; + } +} + +static void +xmlnode_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len) +{ + struct _xmlnode_parser_data *xpd = user_data; + + if(!xpd->current) + return; + + if(!text || !text_len) + return; + + xmlnode_insert_data(xpd->current, text, text_len); +} + +#else + static void xmlnode_parser_element_start(GMarkupParseContext *context, const char *element_name, const char **attrib_names, @@ -400,7 +505,44 @@ xmlnode_insert_data(xpd->current, text, text_len); } +#endif +#ifdef HAVE_LIBXML +static xmlSAXHandler xmlnode_parser_libxml = { + .internalSubset = NULL, + .isStandalone = NULL, + .hasInternalSubset = NULL, + .hasExternalSubset = NULL, + .resolveEntity = NULL, + .getEntity = NULL, + .entityDecl = NULL, + .notationDecl = NULL, + .attributeDecl = NULL, + .elementDecl = NULL, + .unparsedEntityDecl = NULL, + .setDocumentLocator = NULL, + .startDocument = NULL, + .endDocument = NULL, + .startElement = NULL, + .endElement = NULL, + .reference = NULL, + .characters = xmlnode_parser_element_text_libxml, + .ignorableWhitespace = NULL, + .processingInstruction = NULL, + .comment = NULL, + .warning = NULL, + .error = NULL, + .fatalError = NULL, + .getParameterEntity = NULL, + .cdataBlock = NULL, + .externalSubset = NULL, + .initialized = XML_SAX2_MAGIC, + ._private = NULL, + .startElementNs = xmlnode_parser_element_start_libxml, + .endElementNs = xmlnode_parser_element_end_libxml, + .serror = NULL +}; +#else static GMarkupParser xmlnode_parser = { xmlnode_parser_element_start, xmlnode_parser_element_end, @@ -408,7 +550,7 @@ NULL, NULL }; - +#endif xmlnode * xmlnode_from_str(const char *str, gssize size) @@ -422,6 +564,16 @@ real_size = size < 0 ? strlen(str) : size; xpd = g_new0(struct _xmlnode_parser_data, 1); + +#ifdef HAVE_LIBXML + if (xmlSAXUserParseMemory(&xmlnode_parser_libxml, xpd, str, size) < 0) { + while(xpd->current && xpd->current->parent) + xpd->current = xpd->current->parent; + if(xpd->current) + xmlnode_free(xpd->current); + xpd->current = NULL; + } +#else context = g_markup_parse_context_new(&xmlnode_parser, 0, xpd, NULL); if(!g_markup_parse_context_parse(context, str, real_size, NULL)) { @@ -432,7 +584,7 @@ xpd->current = NULL; } g_markup_parse_context_free(context); - +#endif ret = xpd->current; g_free(xpd); return ret; @@ -477,7 +629,7 @@ xmlnode_get_next_twin(xmlnode *node) { xmlnode *sibling; - const char *ns = xmlnode_get_attrib(node, "xmlns"); + const char *ns = xmlnode_get_namespace(node); g_return_val_if_fail(node != NULL, NULL); g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL); @@ -485,7 +637,7 @@ for(sibling = node->next; sibling; sibling = sibling->next) { const char *xmlns = NULL; if(ns) - xmlns = xmlnode_get_attrib(sibling, "xmlns"); + xmlns = xmlnode_get_namespace(sibling); if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) && (!ns || (xmlns && !strcmp(ns, xmlns))))