From 8ad4bdf887bea263e8431446015e8cd5dc89e7ca Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Mon, 15 Mar 2010 23:30:49 +0200 Subject: [PATCH] xml: first implementation bits Code is loosely based on libpurple xmlnode.c. Some bits here and there, but the real juicy parts are still missing. Add warning level do SIPE backend debug API. --- src/api/sipe-backend-debug.h | 8 +- src/core/sipe-xml.c | 201 ++++++++++++++++++++++++++++++++++++++----- src/purple/purple-debug.c | 3 + 3 files changed, 188 insertions(+), 24 deletions(-) diff --git a/src/api/sipe-backend-debug.h b/src/api/sipe-backend-debug.h index c8d007ec..47fdfd7c 100644 --- a/src/api/sipe-backend-debug.h +++ b/src/api/sipe-backend-debug.h @@ -22,6 +22,7 @@ typedef enum { SIPE_DEBUG_LEVEL_INFO, + SIPE_DEBUG_LEVEL_WARNING, SIPE_DEBUG_LEVEL_ERROR, SIPE_DEBUG_LEVEL_FATAL, } sipe_debug_level; @@ -39,6 +40,7 @@ void sipe_backend_debug(sipe_debug_level level, ...) G_GNUC_PRINTF(2, 3); /* Convenience macros */ -#define SIPE_DEBUG_INFO(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_INFO, fmt, __VA_ARGS__) -#define SIPE_DEBUG_ERROR(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_ERROR, fmt, __VA_ARGS__) -#define SIPE_DEBUG_FATAL(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_FATAL, fmt, __VA_ARGS__) +#define SIPE_DEBUG_INFO(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_INFO, fmt, __VA_ARGS__) +#define SIPE_DEBUG_WARNING(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_WARNING, fmt, __VA_ARGS__) +#define SIPE_DEBUG_ERROR(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_ERROR, fmt, __VA_ARGS__) +#define SIPE_DEBUG_FATAL(fmt, ...) sipe_backend_debug(SIPE_DEBUG_LEVEL_FATAL, fmt, __VA_ARGS__) diff --git a/src/core/sipe-xml.c b/src/core/sipe-xml.c index 59e1b218..db428ebf 100644 --- a/src/core/sipe-xml.c +++ b/src/core/sipe-xml.c @@ -20,25 +20,157 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + * This code is loosely based on libpurple xmlnode.c + */ + #include +#include "libxml/parser.h" #include "glib.h" +#include "glib/gprintf.h" #include "sipe-xml.h" +#include "sipe.h" /* TEMPORARY: to include sipe-utils.h without errors */ +#include "sipe-utils.h" +#include "sipe-backend-debug.h" struct _sipe_xml { - sipe_xml *twin; - sipe_xml *children; + gchar *name; + sipe_xml *parent; + sipe_xml *next; + sipe_xml *child; gchar **attributes; - gchar *data; + GString *data; }; -sipe_xml *sipe_xml_parse(const gchar *string, gsize length) +struct _parser_data { + sipe_xml *root; + sipe_xml *current; + gboolean error; +}; + +static void callback_start_element(void *user_data, const xmlChar *text, const xmlChar **attrs) { /* @TODO: implement me :-) */ - (void) string; - (void) length; - return NULL; + (void) user_data; + (void) text; + (void) attrs; +} + +static void callback_end_element(void *user_data, const xmlChar *name) +{ + /* @TODO: implement me :-) */ + (void) user_data; + (void) name; +} + +static void callback_characters(void *user_data, const xmlChar *text, int text_len) +{ + struct _parser_data *pd = user_data; + sipe_xml *node; + + if (!pd->current || pd->error || !text || !text_len) return; + + node = pd->current; + if (node->data) + node->data = g_string_append_len(node->data, (gchar *)text, text_len); + else + node->data = g_string_new_len((gchar *)text, text_len); +} + +static void callback_error(void *user_data, const char *msg, ...) +{ + struct _parser_data *pd = user_data; + gchar *errmsg; + va_list args; + + pd->error = TRUE; + + va_start(args, msg); + errmsg = g_strdup_vprintf(msg, args); + va_end(args); + + SIPE_DEBUG_ERROR("error parsing xml string: %s", errmsg); + g_free(errmsg); +} + +static void callback_serror(void *user_data, xmlErrorPtr error) +{ + struct _parser_data *pd = user_data; + + if (error && (error->level == XML_ERR_ERROR || + error->level == XML_ERR_FATAL)) { + pd->error = TRUE; + SIPE_DEBUG_ERROR("XML parser error: Domain %i, code %i, level %i: %s", + error->domain, error->code, error->level, + error->message ? error->message : "(null)"); + } else if (error) { + SIPE_DEBUG_WARNING("XML parser error: Domain %i, code %i, level %i: %s", + error->domain, error->code, error->level, + error->message ? error->message : "(null)"); + } else { + /* *sigh* macro expects at least two parameters */ + SIPE_DEBUG_WARNING("XML parser error%s", ""); + } +} + +/* API doesn't accept const data structure */ +static xmlSAXHandler parser = { + NULL, /* 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 */ + callback_start_element, /* startElement */ + callback_end_element, /* endElement */ + NULL, /* reference */ + callback_characters, /* characters */ + NULL, /* ignorableWhitespace */ + NULL, /* processingInstruction */ + NULL, /* comment */ + NULL, /* warning */ + callback_error, /* error */ + NULL, /* fatalError */ + NULL, /* getParameterEntity */ + NULL, /* cdataBlock */ + NULL, /* externalSubset */ + XML_SAX2_MAGIC, /* initialized */ + NULL, /* _private */ + NULL, /* startElementNs */ + NULL, /* endElementNs */ + callback_serror, /* serror */ +}; + +sipe_xml *sipe_xml_parse(const gchar *string, gsize length) +{ + sipe_xml *result = NULL; + + if (string && length) { + struct _parser_data *pd = g_new0(struct _parser_data, 1); + + if (xmlSAXUserParseMemory(&parser, pd, string, length)) + pd->error = TRUE; + + if (pd->error) { + sipe_xml_free(pd->root); + } else { + result = pd->current; + } + + g_free(pd); + } + + return result; } void sipe_xml_free(sipe_xml *xml) @@ -56,27 +188,55 @@ gchar *sipe_xml_to_string(const sipe_xml *xml) sipe_xml *sipe_xml_get_child(const sipe_xml *parent, const gchar *name) { - /* @TODO: implement me :-) */ - (void) parent; - (void) name; - return NULL; + gchar **names; + sipe_xml *child = NULL; + + if (!parent || !name) return NULL; + + /* 0: child name */ + /* 1: trailing path (optional) */ + names = g_strsplit(name, "/", 2); + + for (child = parent->child; child; child = child->next) { + if (sipe_strequal(names[0], child->name)) + break; + } + + /* recurse into path */ + if (child && names[1]) + child = sipe_xml_get_child(child, names[1]); + + g_strfreev(names); + return child; } sipe_xml *sipe_xml_get_descendant(const sipe_xml *parent, ...) { - va_list ap; + va_list args; + sipe_xml *node = NULL; + const gchar *name; - /* @TODO: implement me :-) */ - va_start(ap, parent); - va_end(ap); + va_start(args, parent); + while ((name = va_arg(args, const char *)) != NULL) { + node = sipe_xml_get_child(parent, name); + if (node == NULL) break; + parent = node; + } + va_end(args); - return NULL; + return node; } sipe_xml *sipe_xml_get_next_twin(const sipe_xml *node) { - /* @TODO: implement me :-) */ - (void) node; + sipe_xml *sibling; + + if (!node) return NULL; + + for (sibling = node->next; sibling; sibling = sibling->next) { + if (sipe_strequal(node->name, sibling->name)) + return sibling; + } return NULL; } @@ -99,9 +259,8 @@ gint sipe_xml_get_int_attribute(const sipe_xml *node, const gchar *attr, gchar *sipe_xml_get_data(const sipe_xml *node) { - /* @TODO: implement me :-) */ - (void) node; - return NULL; + if (!node || !node->data || !node->data->str) return NULL; + return g_strdup(node->data->str); } /* diff --git a/src/purple/purple-debug.c b/src/purple/purple-debug.c index 7b9e25a7..88cc215a 100644 --- a/src/purple/purple-debug.c +++ b/src/purple/purple-debug.c @@ -45,6 +45,9 @@ void sipe_backend_debug(sipe_debug_level level, case SIPE_DEBUG_LEVEL_INFO: purple_debug_info("sipe", "%s\n", msg); break; + case SIPE_DEBUG_LEVEL_WARNING: + purple_debug_warning("sipe", "%s\n", msg); + break; case SIPE_DEBUG_LEVEL_ERROR: purple_debug_error("sipe", "%s\n", msg); break; -- 2.11.4.GIT