2 * @file upnp/upnp_xmlnode.c XML DOM functions
6 * Gaim is the legal property of its developers, whose names are too numerous
7 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 /* A lot of this code at least resembles the code in libxode, but since
26 * libxode uses memory pools that we simply have no need for, I decided to
27 * write my own stuff. Also, re-writing this lets me be as lightweight
28 * as I want to be. Thank you libxode for giving me a good starting point */
33 #include "gnunet_util.h"
36 #include <libxml/parser.h>
41 # define NEWLINE_S "\r\n"
43 # define NEWLINE_S "\n"
46 #define TRUE GNUNET_YES
47 #define FALSE GNUNET_NO
49 #define g_return_if_fail(a) if(!(a)) return;
50 #define g_return_val_if_fail(a, val) if(!(a)) return (val);
53 * The valid types for an xmlnode
55 typedef enum _XMLNodeType
57 XMLNODE_TYPE_TAG, /**< Just a tag */
58 XMLNODE_TYPE_ATTRIB, /**< Has attributes */
59 XMLNODE_TYPE_DATA /**< Has data */
72 char *name; /**< The name of the node. */
73 char *xmlns; /**< The namespace of the node */
74 XMLNodeType type; /**< The type of the node. */
75 char *data; /**< The data for the node. */
76 size_t data_sz; /**< The size of the data. */
77 struct _xmlnode *parent; /**< The parent node or @c NULL.*/
78 struct _xmlnode *child; /**< The child node or @c NULL.*/
79 struct _xmlnode *lastchild; /**< The last child node or @c NULL.*/
80 struct _xmlnode *next; /**< The next node or @c NULL. */
82 int free_pool; /* set to GNUNET_YES for the root node, which must free the pool */
87 g_memdup (const void *data, size_t s)
91 ret = GNUNET_malloc (s);
92 memcpy (ret, data, s);
97 g_string_append_len (char *prefix, const void *data, size_t s)
101 ret = g_strdup_printf ("%s%.*s", prefix, s, data);
102 GNUNET_free (prefix);
107 new_node (const char *name, XMLNodeType type, void *user_data)
109 xmlnode *node = GNUNET_malloc (sizeof (xmlnode));
111 node->name = name == NULL ? NULL : GNUNET_strdup (name);
113 node->pool = user_data;
114 if (node->pool->size == node->pool->pos)
115 GNUNET_array_grow (node->pool->nodes, node->pool->size,
116 node->pool->size * 2 + 64);
117 node->pool->nodes[node->pool->pos++] = node;
123 xmlnode_new (const char *name, void *user_data)
125 g_return_val_if_fail (name != NULL, NULL);
126 return new_node (name, XMLNODE_TYPE_TAG, user_data);
130 xmlnode_insert_child (xmlnode * parent, xmlnode * child)
132 g_return_if_fail (parent != NULL);
133 g_return_if_fail (child != NULL);
135 child->parent = parent;
136 if (parent->lastchild)
137 parent->lastchild->next = child;
139 parent->child = child;
140 parent->lastchild = child;
144 xmlnode_new_child (xmlnode * parent, const char *name, void *user_data)
148 g_return_val_if_fail (parent != NULL, NULL);
149 g_return_val_if_fail (name != NULL, NULL);
150 node = new_node (name, XMLNODE_TYPE_TAG, user_data);
151 xmlnode_insert_child (parent, node);
156 xmlnode_insert_data (xmlnode * node,
157 const char *data, int size, void *user_data)
162 g_return_if_fail (node != NULL);
163 g_return_if_fail (data != NULL);
164 g_return_if_fail (size != 0);
165 real_size = size == -1 ? strlen (data) : size;
166 child = new_node (NULL, XMLNODE_TYPE_DATA, user_data);
167 child->data = g_memdup (data, real_size);
168 child->data_sz = real_size;
169 xmlnode_insert_child (node, child);
173 xmlnode_remove_attrib (xmlnode * node, const char *attr)
175 xmlnode *attr_node, *sibling = NULL;
177 g_return_if_fail (node != NULL);
178 g_return_if_fail (attr != NULL);
180 for (attr_node = node->child; attr_node; attr_node = attr_node->next)
182 if (attr_node->type == XMLNODE_TYPE_ATTRIB &&
183 !strcmp (attr_node->name, attr))
185 if (node->child == attr_node)
187 node->child = attr_node->next;
191 sibling->next = attr_node->next;
193 if (node->lastchild == attr_node)
195 node->lastchild = sibling;
197 xmlnode_free (attr_node);
205 xmlnode_set_attrib (xmlnode * node,
206 const char *attr, const char *value, void *user_data)
208 xmlnode *attrib_node;
210 g_return_if_fail (node != NULL);
211 g_return_if_fail (attr != NULL);
212 g_return_if_fail (value != NULL);
213 xmlnode_remove_attrib (node, attr);
214 attrib_node = new_node (attr, XMLNODE_TYPE_ATTRIB, user_data);
215 attrib_node->data = GNUNET_strdup (value);
216 xmlnode_insert_child (node, attrib_node);
220 xmlnode_set_namespace (xmlnode * node, const char *xmlns)
222 g_return_if_fail (node != NULL);
223 GNUNET_free_non_null (node->xmlns);
224 node->xmlns = GNUNET_strdup (xmlns);
228 xmlnode_get_namespace (xmlnode * node)
230 g_return_val_if_fail (node != NULL, NULL);
235 freePool (XMLNodePool * pool)
240 for (i = 0; i < pool->pos; i++)
243 GNUNET_free_non_null (x->name);
244 GNUNET_free_non_null (x->data);
245 GNUNET_free_non_null (x->xmlns);
248 GNUNET_array_grow (pool->nodes, pool->size, 0);
253 xmlnode_free (xmlnode * node)
255 g_return_if_fail (node != NULL);
256 if (node->free_pool != GNUNET_YES)
258 freePool (node->pool);
262 xmlnode_get_child_with_namespace (const xmlnode * parent,
263 const char *name, const char *ns)
275 parent_name = GNUNET_strdup (name);
276 child_name = strstr (parent_name, "/");
277 if (child_name != NULL)
279 child_name[0] = '\0';
283 for (x = parent->child; x; x = x->next)
285 const char *xmlns = NULL;
287 xmlns = xmlnode_get_namespace (x);
289 if (x->type == XMLNODE_TYPE_TAG && name
290 && !strcmp (parent_name, x->name) && (!ns
292 && !strcmp (ns, xmlns))))
299 if (child_name && ret)
300 ret = xmlnode_get_child (ret, child_name);
302 GNUNET_free (parent_name);
307 xmlnode_get_child (const xmlnode * parent, const char *name)
309 return xmlnode_get_child_with_namespace (parent, name, NULL);
313 xmlnode_get_data (xmlnode * node)
320 for (c = node->child; c; c = c->next)
322 if (c->type == XMLNODE_TYPE_DATA)
325 str = GNUNET_strdup ("");
326 str = g_string_append_len (str, c->data, c->data_sz);
336 xmlnode_parser_element_start_libxml (void *user_data,
337 const xmlChar * element_name,
338 const xmlChar * prefix,
339 const xmlChar * xmlns,
341 const xmlChar ** namespaces,
344 const xmlChar ** attributes)
346 XMLNodePool *xpd = user_data;
354 xmlnode_new_child (xpd->current, (const char *) element_name,
357 node = xmlnode_new ((const char *) element_name, user_data);
359 xmlnode_set_namespace (node, (const char *) xmlns);
361 for (i = 0; i < nb_attributes * 5; i += 5)
364 int attrib_len = attributes[i + 4] - attributes[i + 3];
365 char *attrib = GNUNET_malloc (attrib_len + 1);
366 memcpy (attrib, attributes[i + 3], attrib_len);
367 attrib[attrib_len] = '\0';
369 attrib = gaim_unescape_html (txt);
371 xmlnode_set_attrib (node, (const char *) attributes[i], attrib,
373 GNUNET_free (attrib);
379 xmlnode_parser_element_end_libxml (void *user_data,
380 const xmlChar * element_name,
381 const xmlChar * prefix,
382 const xmlChar * xmlns)
384 XMLNodePool *xpd = user_data;
386 if (!element_name || !xpd->current)
388 if (xpd->current->parent)
390 if (!xmlStrcmp ((xmlChar *) xpd->current->name, element_name))
391 xpd->current = xpd->current->parent;
396 xmlnode_parser_element_text_libxml (void *user_data,
397 const xmlChar * text, int text_len)
399 XMLNodePool *xpd = user_data;
401 if (!xpd->current || !text || !text_len)
403 xmlnode_insert_data (xpd->current,
404 (const char *) text, text_len, user_data);
407 static xmlSAXHandler xmlnode_parser_libxml = {
408 .internalSubset = NULL,
409 .isStandalone = NULL,
410 .hasInternalSubset = NULL,
411 .hasExternalSubset = NULL,
412 .resolveEntity = NULL,
415 .notationDecl = NULL,
416 .attributeDecl = NULL,
418 .unparsedEntityDecl = NULL,
419 .setDocumentLocator = NULL,
420 .startDocument = NULL,
422 .startElement = NULL,
425 .characters = xmlnode_parser_element_text_libxml,
426 .ignorableWhitespace = NULL,
427 .processingInstruction = NULL,
432 .getParameterEntity = NULL,
434 .externalSubset = NULL,
435 .initialized = XML_SAX2_MAGIC,
437 .startElementNs = xmlnode_parser_element_start_libxml,
438 .endElementNs = xmlnode_parser_element_end_libxml,
443 xmlnode_from_str (const char *str, int size)
449 g_return_val_if_fail (str != NULL, NULL);
451 real_size = size < 0 ? strlen (str) : size;
452 xpd = GNUNET_malloc (sizeof (XMLNodePool));
453 memset (xpd, 0, sizeof (XMLNodePool));
454 if (xmlSAXUserParseMemory (&xmlnode_parser_libxml, xpd, str, real_size) < 0)
460 ret->free_pool = GNUNET_YES;
465 xmlnode_get_next_twin (xmlnode * node)
468 const char *ns = xmlnode_get_namespace (node);
470 g_return_val_if_fail (node != NULL, NULL);
471 g_return_val_if_fail (node->type == XMLNODE_TYPE_TAG, NULL);
473 for (sibling = node->next; sibling; sibling = sibling->next)
475 const char *xmlns = NULL;
477 xmlns = xmlnode_get_namespace (sibling);
479 if (sibling->type == XMLNODE_TYPE_TAG
480 && !strcmp (node->name, sibling->name) && (!ns