aboutsummaryrefslogtreecommitdiff
path: root/src/upnp/upnp_xmlnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/upnp/upnp_xmlnode.c')
-rw-r--r--src/upnp/upnp_xmlnode.c487
1 files changed, 487 insertions, 0 deletions
diff --git a/src/upnp/upnp_xmlnode.c b/src/upnp/upnp_xmlnode.c
new file mode 100644
index 000000000..b37528f00
--- /dev/null
+++ b/src/upnp/upnp_xmlnode.c
@@ -0,0 +1,487 @@
1/**
2 * @file xmlnode.c XML DOM functions
3 *
4 * gaim
5 *
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
8 * source distribution.
9 *
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.
14 *
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.
19 *
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
23 */
24
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 */
29
30#include "platform.h"
31
32#include "util.h"
33#include "gnunet_util.h"
34#include "xmlnode.h"
35
36#include <libxml/parser.h>
37#include <string.h>
38
39
40#ifdef _WIN32
41# define NEWLINE_S "\r\n"
42#else
43# define NEWLINE_S "\n"
44#endif
45
46#define TRUE GNUNET_YES
47#define FALSE GNUNET_NO
48
49#define g_return_if_fail(a) if(!(a)) return;
50#define g_return_val_if_fail(a, val) if(!(a)) return (val);
51
52/**
53 * The valid types for an xmlnode
54 */
55typedef enum _XMLNodeType
56{
57 XMLNODE_TYPE_TAG, /**< Just a tag */
58 XMLNODE_TYPE_ATTRIB, /**< Has attributes */
59 XMLNODE_TYPE_DATA /**< Has data */
60} XMLNodeType;
61
62typedef struct
63{
64 xmlnode *current;
65 xmlnode **nodes;
66 unsigned int pos;
67 unsigned int size;
68} XMLNodePool;
69
70struct _xmlnode
71{
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. */
81 XMLNodePool *pool;
82 int free_pool; /* set to GNUNET_YES for the root node, which must free the pool */
83};
84
85
86static void *
87g_memdup (const void *data, size_t s)
88{
89 void *ret;
90
91 ret = GNUNET_malloc (s);
92 memcpy (ret, data, s);
93 return ret;
94}
95
96static char *
97g_string_append_len (char *prefix, const void *data, size_t s)
98{
99 char *ret;
100
101 ret = g_strdup_printf ("%s%.*s", prefix, s, data);
102 GNUNET_free (prefix);
103 return ret;
104}
105
106static xmlnode *
107new_node (const char *name, XMLNodeType type, void *user_data)
108{
109 xmlnode *node = GNUNET_malloc (sizeof (xmlnode));
110
111 node->name = name == NULL ? NULL : GNUNET_strdup (name);
112 node->type = type;
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;
118 node->free_pool = 0;
119 return node;
120}
121
122static xmlnode *
123xmlnode_new (const char *name, void *user_data)
124{
125 g_return_val_if_fail (name != NULL, NULL);
126 return new_node (name, XMLNODE_TYPE_TAG, user_data);
127}
128
129static void
130xmlnode_insert_child (xmlnode * parent, xmlnode * child)
131{
132 g_return_if_fail (parent != NULL);
133 g_return_if_fail (child != NULL);
134
135 child->parent = parent;
136 if (parent->lastchild)
137 parent->lastchild->next = child;
138 else
139 parent->child = child;
140 parent->lastchild = child;
141}
142
143static xmlnode *
144xmlnode_new_child (xmlnode * parent, const char *name, void *user_data)
145{
146 xmlnode *node;
147
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);
152 return node;
153}
154
155static void
156xmlnode_insert_data (xmlnode * node,
157 const char *data, int size, void *user_data)
158{
159 xmlnode *child;
160 size_t real_size;
161
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);
170}
171
172static void
173xmlnode_remove_attrib (xmlnode * node, const char *attr)
174{
175 xmlnode *attr_node, *sibling = NULL;
176
177 g_return_if_fail (node != NULL);
178 g_return_if_fail (attr != NULL);
179
180 for (attr_node = node->child; attr_node; attr_node = attr_node->next)
181 {
182 if (attr_node->type == XMLNODE_TYPE_ATTRIB &&
183 !strcmp (attr_node->name, attr))
184 {
185 if (node->child == attr_node)
186 {
187 node->child = attr_node->next;
188 }
189 else
190 {
191 sibling->next = attr_node->next;
192 }
193 if (node->lastchild == attr_node)
194 {
195 node->lastchild = sibling;
196 }
197 xmlnode_free (attr_node);
198 return;
199 }
200 sibling = attr_node;
201 }
202}
203
204static void
205xmlnode_set_attrib (xmlnode * node,
206 const char *attr, const char *value, void *user_data)
207{
208 xmlnode *attrib_node;
209
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);
217}
218
219static void
220xmlnode_set_namespace (xmlnode * node, const char *xmlns)
221{
222 g_return_if_fail (node != NULL);
223 GNUNET_free_non_null (node->xmlns);
224 node->xmlns = GNUNET_strdup (xmlns);
225}
226
227static const char *
228xmlnode_get_namespace (xmlnode * node)
229{
230 g_return_val_if_fail (node != NULL, NULL);
231 return node->xmlns;
232}
233
234static void
235freePool (XMLNodePool * pool)
236{
237 unsigned int i;
238 xmlnode *x;
239
240 for (i = 0; i < pool->pos; i++)
241 {
242 x = pool->nodes[i];
243 GNUNET_free_non_null (x->name);
244 GNUNET_free_non_null (x->data);
245 GNUNET_free_non_null (x->xmlns);
246 GNUNET_free (x);
247 }
248 GNUNET_array_grow (pool->nodes, pool->size, 0);
249 GNUNET_free (pool);
250}
251
252void
253xmlnode_free (xmlnode * node)
254{
255 g_return_if_fail (node != NULL);
256 if (node->free_pool != GNUNET_YES)
257 return;
258 freePool (node->pool);
259}
260
261static xmlnode *
262xmlnode_get_child_with_namespace (const xmlnode * parent,
263 const char *name, const char *ns)
264{
265 xmlnode *x;
266 xmlnode *ret = NULL;
267 char *parent_name;
268 char *child_name;
269
270 if (parent == NULL)
271 return NULL;
272 if (name == NULL)
273 return NULL;
274
275 parent_name = GNUNET_strdup (name);
276 child_name = strstr (parent_name, "/");
277 if (child_name != NULL)
278 {
279 child_name[0] = '\0';
280 child_name++;
281 }
282
283 for (x = parent->child; x; x = x->next)
284 {
285 const char *xmlns = NULL;
286 if (ns)
287 xmlns = xmlnode_get_namespace (x);
288
289 if (x->type == XMLNODE_TYPE_TAG && name
290 && !strcmp (parent_name, x->name) && (!ns
291 || (xmlns
292 && !strcmp (ns, xmlns))))
293 {
294 ret = x;
295 break;
296 }
297 }
298
299 if (child_name && ret)
300 ret = xmlnode_get_child (ret, child_name);
301
302 GNUNET_free (parent_name);
303 return ret;
304}
305
306xmlnode *
307xmlnode_get_child (const xmlnode * parent, const char *name)
308{
309 return xmlnode_get_child_with_namespace (parent, name, NULL);
310}
311
312char *
313xmlnode_get_data (xmlnode * node)
314{
315 char *str = NULL;
316 xmlnode *c;
317
318 if (node == NULL)
319 return NULL;
320 for (c = node->child; c; c = c->next)
321 {
322 if (c->type == XMLNODE_TYPE_DATA)
323 {
324 if (!str)
325 str = GNUNET_strdup ("");
326 str = g_string_append_len (str, c->data, c->data_sz);
327 }
328 }
329 if (str == NULL)
330 return NULL;
331
332 return str;
333}
334
335static void
336xmlnode_parser_element_start_libxml (void *user_data,
337 const xmlChar * element_name,
338 const xmlChar * prefix,
339 const xmlChar * xmlns,
340 int nb_namespaces,
341 const xmlChar ** namespaces,
342 int nb_attributes,
343 int nb_defaulted,
344 const xmlChar ** attributes)
345{
346 XMLNodePool *xpd = user_data;
347 xmlnode *node;
348 int i;
349
350 if (!element_name)
351 return;
352 if (xpd->current)
353 node =
354 xmlnode_new_child (xpd->current, (const char *) element_name,
355 user_data);
356 else
357 node = xmlnode_new ((const char *) element_name, user_data);
358
359 xmlnode_set_namespace (node, (const char *) xmlns);
360
361 for (i = 0; i < nb_attributes * 5; i += 5)
362 {
363 char *txt;
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';
368 txt = attrib;
369 attrib = gaim_unescape_html (txt);
370 GNUNET_free (txt);
371 xmlnode_set_attrib (node, (const char *) attributes[i], attrib,
372 user_data);
373 GNUNET_free (attrib);
374 }
375 xpd->current = node;
376}
377
378static void
379xmlnode_parser_element_end_libxml (void *user_data,
380 const xmlChar * element_name,
381 const xmlChar * prefix,
382 const xmlChar * xmlns)
383{
384 XMLNodePool *xpd = user_data;
385
386 if (!element_name || !xpd->current)
387 return;
388 if (xpd->current->parent)
389 {
390 if (!xmlStrcmp ((xmlChar *) xpd->current->name, element_name))
391 xpd->current = xpd->current->parent;
392 }
393}
394
395static void
396xmlnode_parser_element_text_libxml (void *user_data,
397 const xmlChar * text, int text_len)
398{
399 XMLNodePool *xpd = user_data;
400
401 if (!xpd->current || !text || !text_len)
402 return;
403 xmlnode_insert_data (xpd->current,
404 (const char *) text, text_len, user_data);
405}
406
407static xmlSAXHandler xmlnode_parser_libxml = {
408 .internalSubset = NULL,
409 .isStandalone = NULL,
410 .hasInternalSubset = NULL,
411 .hasExternalSubset = NULL,
412 .resolveEntity = NULL,
413 .getEntity = NULL,
414 .entityDecl = NULL,
415 .notationDecl = NULL,
416 .attributeDecl = NULL,
417 .elementDecl = NULL,
418 .unparsedEntityDecl = NULL,
419 .setDocumentLocator = NULL,
420 .startDocument = NULL,
421 .endDocument = NULL,
422 .startElement = NULL,
423 .endElement = NULL,
424 .reference = NULL,
425 .characters = xmlnode_parser_element_text_libxml,
426 .ignorableWhitespace = NULL,
427 .processingInstruction = NULL,
428 .comment = NULL,
429 .warning = NULL,
430 .error = NULL,
431 .fatalError = NULL,
432 .getParameterEntity = NULL,
433 .cdataBlock = NULL,
434 .externalSubset = NULL,
435 .initialized = XML_SAX2_MAGIC,
436 ._private = NULL,
437 .startElementNs = xmlnode_parser_element_start_libxml,
438 .endElementNs = xmlnode_parser_element_end_libxml,
439 .serror = NULL
440};
441
442xmlnode *
443xmlnode_from_str (const char *str, int size)
444{
445 XMLNodePool *xpd;
446 xmlnode *ret;
447 size_t real_size;
448
449 g_return_val_if_fail (str != NULL, NULL);
450
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)
455 {
456 freePool (xpd);
457 return NULL;
458 }
459 ret = xpd->current;
460 ret->free_pool = GNUNET_YES;
461 return ret;
462}
463
464xmlnode *
465xmlnode_get_next_twin (xmlnode * node)
466{
467 xmlnode *sibling;
468 const char *ns = xmlnode_get_namespace (node);
469
470 g_return_val_if_fail (node != NULL, NULL);
471 g_return_val_if_fail (node->type == XMLNODE_TYPE_TAG, NULL);
472
473 for (sibling = node->next; sibling; sibling = sibling->next)
474 {
475 const char *xmlns = NULL;
476 if (ns)
477 xmlns = xmlnode_get_namespace (sibling);
478
479 if (sibling->type == XMLNODE_TYPE_TAG
480 && !strcmp (node->name, sibling->name) && (!ns
481 || (xmlns
482 && !strcmp (ns,
483 xmlns))))
484 return sibling;
485 }
486 return NULL;
487}