Mercurial > pidgin
annotate 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 |
rev | line source |
---|---|
7131 | 1 /** |
2 * @file xmlnode.c XML DOM functions | |
3 * | |
4 * gaim | |
5 * | |
8046 | 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. | |
7131 | 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 "internal.h" | |
31 | |
13806 | 32 #ifdef HAVE_LIBXML |
33 #include <libxml/parser.h> | |
34 #endif | |
7131 | 35 #include <string.h> |
36 #include <glib.h> | |
37 | |
38 #include "xmlnode.h" | |
39 | |
12041
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
40 #ifdef _WIN32 |
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
41 # define NEWLINE_S "\r\n" |
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
42 #else |
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
43 # define NEWLINE_S "\n" |
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
44 #endif |
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
45 |
7131 | 46 static xmlnode* |
8135 | 47 new_node(const char *name, XMLNodeType type) |
7131 | 48 { |
49 xmlnode *node = g_new0(xmlnode, 1); | |
10423 | 50 |
7131 | 51 if(name) |
52 node->name = g_strdup(name); | |
53 node->type = type; | |
54 | |
55 return node; | |
56 } | |
57 | |
58 xmlnode* | |
59 xmlnode_new(const char *name) | |
60 { | |
61 g_return_val_if_fail(name != NULL, NULL); | |
62 | |
8135 | 63 return new_node(name, XMLNODE_TYPE_TAG); |
7131 | 64 } |
65 | |
10423 | 66 xmlnode * |
67 xmlnode_new_child(xmlnode *parent, const char *name) | |
7131 | 68 { |
69 xmlnode *node; | |
70 | |
71 g_return_val_if_fail(parent != NULL, NULL); | |
72 g_return_val_if_fail(name != NULL, NULL); | |
73 | |
8135 | 74 node = new_node(name, XMLNODE_TYPE_TAG); |
7131 | 75 |
76 xmlnode_insert_child(parent, node); | |
77 | |
78 return node; | |
79 } | |
80 | |
81 void | |
82 xmlnode_insert_child(xmlnode *parent, xmlnode *child) | |
83 { | |
84 g_return_if_fail(parent != NULL); | |
85 g_return_if_fail(child != NULL); | |
86 | |
87 child->parent = parent; | |
88 | |
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
89 if(parent->lastchild) { |
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
90 parent->lastchild->next = child; |
7131 | 91 } else { |
92 parent->child = child; | |
93 } | |
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
94 |
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
95 parent->lastchild = child; |
7131 | 96 } |
97 | |
98 void | |
10848 | 99 xmlnode_insert_data(xmlnode *node, const char *data, gssize size) |
7131 | 100 { |
10415 | 101 xmlnode *child; |
10848 | 102 gsize real_size; |
7131 | 103 |
10415 | 104 g_return_if_fail(node != NULL); |
7131 | 105 g_return_if_fail(data != NULL); |
106 g_return_if_fail(size != 0); | |
107 | |
108 real_size = size == -1 ? strlen(data) : size; | |
109 | |
10415 | 110 child = new_node(NULL, XMLNODE_TYPE_DATA); |
7131 | 111 |
10415 | 112 child->data = g_memdup(data, real_size); |
113 child->data_sz = real_size; | |
7131 | 114 |
10415 | 115 xmlnode_insert_child(node, child); |
7131 | 116 } |
117 | |
118 void | |
119 xmlnode_remove_attrib(xmlnode *node, const char *attr) | |
120 { | |
121 xmlnode *attr_node, *sibling = NULL; | |
122 | |
123 g_return_if_fail(node != NULL); | |
124 g_return_if_fail(attr != NULL); | |
125 | |
126 for(attr_node = node->child; attr_node; attr_node = attr_node->next) | |
127 { | |
8135 | 128 if(attr_node->type == XMLNODE_TYPE_ATTRIB && |
7131 | 129 !strcmp(attr_node->name, attr)) { |
130 if(node->child == attr_node) { | |
131 node->child = attr_node->next; | |
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
132 } else if (node->lastchild == attr_node) { |
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
133 node->lastchild = sibling; |
7131 | 134 } else { |
135 sibling->next = attr_node->next; | |
136 } | |
137 xmlnode_free(attr_node); | |
138 return; | |
139 } | |
140 sibling = attr_node; | |
141 } | |
142 } | |
143 | |
144 void | |
145 xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value) | |
146 { | |
147 xmlnode *attrib_node; | |
148 | |
149 g_return_if_fail(node != NULL); | |
150 g_return_if_fail(attr != NULL); | |
151 g_return_if_fail(value != NULL); | |
152 | |
153 xmlnode_remove_attrib(node, attr); | |
154 | |
8135 | 155 attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB); |
7131 | 156 |
157 attrib_node->data = g_strdup(value); | |
158 | |
159 xmlnode_insert_child(node, attrib_node); | |
160 } | |
161 | |
10425 | 162 const char * |
7131 | 163 xmlnode_get_attrib(xmlnode *node, const char *attr) |
164 { | |
165 xmlnode *x; | |
166 | |
167 g_return_val_if_fail(node != NULL, NULL); | |
168 | |
169 for(x = node->child; x; x = x->next) { | |
8135 | 170 if(x->type == XMLNODE_TYPE_ATTRIB && !strcmp(attr, x->name)) { |
7131 | 171 return x->data; |
172 } | |
173 } | |
174 | |
175 return NULL; | |
176 } | |
177 | |
13806 | 178 |
179 void xmlnode_set_namespace(xmlnode *node, const char *xmlns) | |
180 { | |
181 #ifdef HAVE_LIBXML | |
182 g_return_if_fail(node != NULL); | |
183 | |
184 if (node->namespace) | |
185 g_free(node->namespace); | |
186 | |
187 node->namespace = g_strdup(xmlns); | |
188 #else | |
189 return xmlnode_set_attrib(node, "xmlns", xmlns); | |
190 #endif | |
191 } | |
192 | |
193 const char *xmlnode_get_namespace(xmlnode *node) | |
194 { | |
195 #ifdef HAVE_LIBXML | |
196 g_return_val_if_fail(node != NULL, NULL); | |
197 | |
198 return node->namespace; | |
199 #else | |
200 return xmlnode_get_attrib(node, "xmlns"); | |
201 #endif | |
202 } | |
203 | |
10423 | 204 void |
205 xmlnode_free(xmlnode *node) | |
7131 | 206 { |
207 xmlnode *x, *y; | |
208 | |
209 g_return_if_fail(node != NULL); | |
210 | |
211 x = node->child; | |
212 while(x) { | |
213 y = x->next; | |
214 xmlnode_free(x); | |
215 x = y; | |
216 } | |
217 | |
218 if(node->name) | |
219 g_free(node->name); | |
220 if(node->data) | |
221 g_free(node->data); | |
13806 | 222 #ifdef HAVE_LIBXML |
223 if(node->namespace) | |
224 g_free(node->namespace); | |
225 #endif | |
7131 | 226 g_free(node); |
227 } | |
228 | |
229 xmlnode* | |
10736 | 230 xmlnode_get_child(const xmlnode *parent, const char *name) |
231 { | |
232 return xmlnode_get_child_with_namespace(parent, name, NULL); | |
233 } | |
234 | |
235 xmlnode * | |
236 xmlnode_get_child_with_namespace(const xmlnode *parent, const char *name, const char *ns) | |
7131 | 237 { |
238 xmlnode *x, *ret = NULL; | |
239 char **names; | |
240 char *parent_name, *child_name; | |
241 | |
242 g_return_val_if_fail(parent != NULL, NULL); | |
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
243 g_return_val_if_fail(name != NULL, NULL); |
7131 | 244 |
245 names = g_strsplit(name, "/", 2); | |
246 parent_name = names[0]; | |
247 child_name = names[1]; | |
248 | |
249 for(x = parent->child; x; x = x->next) { | |
8262 | 250 const char *xmlns = NULL; |
251 if(ns) | |
13806 | 252 xmlns = xmlnode_get_namespace(x); |
8262 | 253 |
254 if(x->type == XMLNODE_TYPE_TAG && name && !strcmp(parent_name, x->name) | |
255 && (!ns || (xmlns && !strcmp(ns, xmlns)))) { | |
7131 | 256 ret = x; |
257 break; | |
258 } | |
259 } | |
260 | |
261 if(child_name && ret) | |
8262 | 262 ret = xmlnode_get_child(ret, child_name); |
7131 | 263 |
264 g_strfreev(names); | |
265 return ret; | |
266 } | |
267 | |
268 char * | |
269 xmlnode_get_data(xmlnode *node) | |
270 { | |
271 GString *str = NULL; | |
272 xmlnode *c; | |
273 | |
274 g_return_val_if_fail(node != NULL, NULL); | |
275 | |
276 for(c = node->child; c; c = c->next) { | |
8135 | 277 if(c->type == XMLNODE_TYPE_DATA) { |
7131 | 278 if(!str) |
279 str = g_string_new(""); | |
280 str = g_string_append_len(str, c->data, c->data_sz); | |
281 } | |
282 } | |
283 | |
10331 | 284 if (str == NULL) |
285 return NULL; | |
7131 | 286 |
10331 | 287 return g_string_free(str, FALSE); |
7131 | 288 } |
289 | |
10425 | 290 static char * |
10423 | 291 xmlnode_to_str_helper(xmlnode *node, int *len, gboolean formatting, int depth) |
7131 | 292 { |
293 GString *text = g_string_new(""); | |
294 xmlnode *c; | |
9837 | 295 char *node_name, *esc, *esc2, *tab = NULL; |
9838 | 296 gboolean need_end = FALSE, pretty = formatting; |
9837 | 297 |
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
298 g_return_val_if_fail(node != NULL, NULL); |
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
299 |
9837 | 300 if(pretty && depth) { |
301 tab = g_strnfill(depth, '\t'); | |
302 text = g_string_append(text, tab); | |
303 } | |
7131 | 304 |
305 node_name = g_markup_escape_text(node->name, -1); | |
306 g_string_append_printf(text, "<%s", node_name); | |
307 | |
13806 | 308 #ifdef HAVE_LIBXML |
309 if (node->namespace) { | |
310 char *namespace = g_markup_escape_text(node->namespace, -1); | |
311 g_string_append_printf(text, " xmlns='%s'", namespace); | |
312 g_free(namespace); | |
313 } | |
314 #endif | |
7131 | 315 for(c = node->child; c; c = c->next) |
316 { | |
8135 | 317 if(c->type == XMLNODE_TYPE_ATTRIB) { |
7131 | 318 esc = g_markup_escape_text(c->name, -1); |
319 esc2 = g_markup_escape_text(c->data, -1); | |
320 g_string_append_printf(text, " %s='%s'", esc, esc2); | |
321 g_free(esc); | |
322 g_free(esc2); | |
8135 | 323 } else if(c->type == XMLNODE_TYPE_TAG || c->type == XMLNODE_TYPE_DATA) { |
9837 | 324 if(c->type == XMLNODE_TYPE_DATA) |
9838 | 325 pretty = FALSE; |
7131 | 326 need_end = TRUE; |
327 } | |
328 } | |
329 | |
330 if(need_end) { | |
12041
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
331 g_string_append_printf(text, ">%s", pretty ? NEWLINE_S : ""); |
7131 | 332 |
333 for(c = node->child; c; c = c->next) | |
334 { | |
8135 | 335 if(c->type == XMLNODE_TYPE_TAG) { |
7642 | 336 int esc_len; |
9838 | 337 esc = xmlnode_to_str_helper(c, &esc_len, pretty, depth+1); |
7642 | 338 text = g_string_append_len(text, esc, esc_len); |
7131 | 339 g_free(esc); |
12198 | 340 } else if(c->type == XMLNODE_TYPE_DATA && c->data_sz > 0) { |
7131 | 341 esc = g_markup_escape_text(c->data, c->data_sz); |
7642 | 342 text = g_string_append(text, esc); |
7131 | 343 g_free(esc); |
344 } | |
345 } | |
346 | |
9838 | 347 if(tab && pretty) |
9837 | 348 text = g_string_append(text, tab); |
12041
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
349 g_string_append_printf(text, "</%s>%s", node_name, formatting ? NEWLINE_S : ""); |
7131 | 350 } else { |
12041
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
351 g_string_append_printf(text, "/>%s", formatting ? NEWLINE_S : ""); |
7131 | 352 } |
353 | |
354 g_free(node_name); | |
355 | |
9837 | 356 if(tab) |
357 g_free(tab); | |
358 | |
7642 | 359 if(len) |
360 *len = text->len; | |
10331 | 361 |
362 return g_string_free(text, FALSE); | |
7131 | 363 } |
364 | |
10425 | 365 char * |
10423 | 366 xmlnode_to_str(xmlnode *node, int *len) |
367 { | |
9837 | 368 return xmlnode_to_str_helper(node, len, FALSE, 0); |
369 } | |
370 | |
10425 | 371 char * |
10423 | 372 xmlnode_to_formatted_str(xmlnode *node, int *len) |
373 { | |
10425 | 374 char *xml, *xml_with_declaration; |
10415 | 375 |
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
376 g_return_val_if_fail(node != NULL, NULL); |
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
377 |
10415 | 378 xml = xmlnode_to_str_helper(node, len, TRUE, 0); |
379 xml_with_declaration = | |
12041
da44f68fb4d2
[gaim-migrate @ 14334]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11705
diff
changeset
|
380 g_strdup_printf("<?xml version='1.0' encoding='UTF-8' ?>" NEWLINE_S NEWLINE_S "%s", xml); |
10415 | 381 g_free(xml); |
382 | |
383 return xml_with_declaration; | |
9837 | 384 } |
385 | |
7131 | 386 struct _xmlnode_parser_data { |
387 xmlnode *current; | |
388 }; | |
389 | |
13806 | 390 #ifdef HAVE_LIBXML |
391 static void | |
392 xmlnode_parser_element_start_libxml(void *user_data, | |
393 const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace, | |
394 int nb_namespaces, const xmlChar **namespaces, | |
395 int nb_attributes, int nb_defaulted, const xmlChar **attributes) | |
396 { | |
397 struct _xmlnode_parser_data *xpd = user_data; | |
398 xmlnode *node; | |
399 int i; | |
400 | |
401 if(!element_name) { | |
402 return; | |
403 } else { | |
404 if(xpd->current) | |
405 node = xmlnode_new_child(xpd->current, element_name); | |
406 else | |
407 node = xmlnode_new(element_name); | |
408 | |
409 xmlnode_set_namespace(node, namespace); | |
410 | |
411 for(i=0; i < nb_attributes * 5; i+=5) { | |
412 int attrib_len = attributes[i+4] - attributes[i+3]; | |
413 char *attrib = g_malloc(attrib_len + 1); | |
414 memcpy(attrib, attributes[i+3], attrib_len); | |
415 attrib[attrib_len] = '\0'; | |
416 xmlnode_set_attrib(node, attributes[i], attrib); | |
417 g_free(attrib); | |
418 } | |
419 | |
420 xpd->current = node; | |
421 } | |
422 } | |
423 | |
424 static void | |
425 xmlnode_parser_element_end_libxml(void *user_data, const xmlChar *element_name, | |
426 const xmlChar *prefix, const xmlChar *namespace) | |
427 { | |
428 struct _xmlnode_parser_data *xpd = user_data; | |
429 | |
430 if(!element_name || !xpd->current) | |
431 return; | |
432 | |
433 if(xpd->current->parent) { | |
434 if(!strcmp(xpd->current->name, element_name)) | |
435 xpd->current = xpd->current->parent; | |
436 } | |
437 } | |
438 | |
439 static void | |
440 xmlnode_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len) | |
441 { | |
442 struct _xmlnode_parser_data *xpd = user_data; | |
443 | |
444 if(!xpd->current) | |
445 return; | |
446 | |
447 if(!text || !text_len) | |
448 return; | |
449 | |
450 xmlnode_insert_data(xpd->current, text, text_len); | |
451 } | |
452 | |
453 #else | |
454 | |
7131 | 455 static void |
456 xmlnode_parser_element_start(GMarkupParseContext *context, | |
457 const char *element_name, const char **attrib_names, | |
458 const char **attrib_values, gpointer user_data, GError **error) | |
459 { | |
460 struct _xmlnode_parser_data *xpd = user_data; | |
461 xmlnode *node; | |
462 int i; | |
463 | |
464 if(!element_name) { | |
465 return; | |
466 } else { | |
467 if(xpd->current) | |
468 node = xmlnode_new_child(xpd->current, element_name); | |
469 else | |
470 node = xmlnode_new(element_name); | |
471 | |
472 for(i=0; attrib_names[i]; i++) | |
473 xmlnode_set_attrib(node, attrib_names[i], attrib_values[i]); | |
474 | |
475 xpd->current = node; | |
476 } | |
477 } | |
478 | |
479 static void | |
480 xmlnode_parser_element_end(GMarkupParseContext *context, | |
481 const char *element_name, gpointer user_data, GError **error) | |
482 { | |
483 struct _xmlnode_parser_data *xpd = user_data; | |
484 | |
485 if(!element_name || !xpd->current) | |
486 return; | |
487 | |
488 if(xpd->current->parent) { | |
489 if(!strcmp(xpd->current->name, element_name)) | |
490 xpd->current = xpd->current->parent; | |
491 } | |
492 } | |
493 | |
494 static void | |
495 xmlnode_parser_element_text(GMarkupParseContext *context, const char *text, | |
496 gsize text_len, gpointer user_data, GError **error) | |
497 { | |
498 struct _xmlnode_parser_data *xpd = user_data; | |
499 | |
500 if(!xpd->current) | |
501 return; | |
502 | |
503 if(!text || !text_len) | |
504 return; | |
505 | |
506 xmlnode_insert_data(xpd->current, text, text_len); | |
507 } | |
13806 | 508 #endif |
7131 | 509 |
13806 | 510 #ifdef HAVE_LIBXML |
511 static xmlSAXHandler xmlnode_parser_libxml = { | |
512 .internalSubset = NULL, | |
513 .isStandalone = NULL, | |
514 .hasInternalSubset = NULL, | |
515 .hasExternalSubset = NULL, | |
516 .resolveEntity = NULL, | |
517 .getEntity = NULL, | |
518 .entityDecl = NULL, | |
519 .notationDecl = NULL, | |
520 .attributeDecl = NULL, | |
521 .elementDecl = NULL, | |
522 .unparsedEntityDecl = NULL, | |
523 .setDocumentLocator = NULL, | |
524 .startDocument = NULL, | |
525 .endDocument = NULL, | |
526 .startElement = NULL, | |
527 .endElement = NULL, | |
528 .reference = NULL, | |
529 .characters = xmlnode_parser_element_text_libxml, | |
530 .ignorableWhitespace = NULL, | |
531 .processingInstruction = NULL, | |
532 .comment = NULL, | |
533 .warning = NULL, | |
534 .error = NULL, | |
535 .fatalError = NULL, | |
536 .getParameterEntity = NULL, | |
537 .cdataBlock = NULL, | |
538 .externalSubset = NULL, | |
539 .initialized = XML_SAX2_MAGIC, | |
540 ._private = NULL, | |
541 .startElementNs = xmlnode_parser_element_start_libxml, | |
542 .endElementNs = xmlnode_parser_element_end_libxml, | |
543 .serror = NULL | |
544 }; | |
545 #else | |
7131 | 546 static GMarkupParser xmlnode_parser = { |
547 xmlnode_parser_element_start, | |
548 xmlnode_parser_element_end, | |
549 xmlnode_parser_element_text, | |
550 NULL, | |
551 NULL | |
552 }; | |
13806 | 553 #endif |
7131 | 554 |
10423 | 555 xmlnode * |
10848 | 556 xmlnode_from_str(const char *str, gssize size) |
7131 | 557 { |
11390 | 558 struct _xmlnode_parser_data *xpd; |
7131 | 559 xmlnode *ret; |
560 GMarkupParseContext *context; | |
11390 | 561 gsize real_size; |
7131 | 562 |
11390 | 563 g_return_val_if_fail(str != NULL, NULL); |
564 | |
11705
0906a3e9626c
[gaim-migrate @ 13996]
Richard Laager <rlaager@wiktel.com>
parents:
11390
diff
changeset
|
565 real_size = size < 0 ? strlen(str) : size; |
11390 | 566 xpd = g_new0(struct _xmlnode_parser_data, 1); |
13806 | 567 |
568 #ifdef HAVE_LIBXML | |
569 if (xmlSAXUserParseMemory(&xmlnode_parser_libxml, xpd, str, size) < 0) { | |
570 while(xpd->current && xpd->current->parent) | |
571 xpd->current = xpd->current->parent; | |
572 if(xpd->current) | |
573 xmlnode_free(xpd->current); | |
574 xpd->current = NULL; | |
575 } | |
576 #else | |
7131 | 577 context = g_markup_parse_context_new(&xmlnode_parser, 0, xpd, NULL); |
578 | |
579 if(!g_markup_parse_context_parse(context, str, real_size, NULL)) { | |
580 while(xpd->current && xpd->current->parent) | |
581 xpd->current = xpd->current->parent; | |
582 if(xpd->current) | |
583 xmlnode_free(xpd->current); | |
584 xpd->current = NULL; | |
585 } | |
586 g_markup_parse_context_free(context); | |
13806 | 587 #endif |
7131 | 588 ret = xpd->current; |
589 g_free(xpd); | |
590 return ret; | |
591 } | |
8135 | 592 |
10423 | 593 xmlnode * |
594 xmlnode_copy(xmlnode *src) | |
8135 | 595 { |
596 xmlnode *ret; | |
597 xmlnode *child; | |
598 xmlnode *sibling = NULL; | |
599 | |
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
600 g_return_val_if_fail(src != NULL, NULL); |
8135 | 601 |
602 ret = new_node(src->name, src->type); | |
603 if(src->data) { | |
8167 | 604 if(src->data_sz) { |
605 ret->data = g_memdup(src->data, src->data_sz); | |
606 ret->data_sz = src->data_sz; | |
607 } else { | |
608 ret->data = g_strdup(src->data); | |
609 } | |
8135 | 610 } |
611 | |
612 for(child = src->child; child; child = child->next) { | |
613 if(sibling) { | |
614 sibling->next = xmlnode_copy(child); | |
615 sibling = sibling->next; | |
616 } else { | |
617 ret->child = xmlnode_copy(child); | |
618 sibling = ret->child; | |
619 } | |
620 sibling->parent = ret; | |
621 } | |
622 | |
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
623 ret->lastchild = sibling; |
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
624 |
8135 | 625 return ret; |
626 } | |
627 | |
10423 | 628 xmlnode * |
629 xmlnode_get_next_twin(xmlnode *node) | |
630 { | |
8135 | 631 xmlnode *sibling; |
13806 | 632 const char *ns = xmlnode_get_namespace(node); |
8135 | 633 |
634 g_return_val_if_fail(node != NULL, NULL); | |
635 g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL); | |
636 | |
637 for(sibling = node->next; sibling; sibling = sibling->next) { | |
8283 | 638 const char *xmlns = NULL; |
8262 | 639 if(ns) |
13806 | 640 xmlns = xmlnode_get_namespace(sibling); |
8262 | 641 |
642 if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) && | |
643 (!ns || (xmlns && !strcmp(ns, xmlns)))) | |
8135 | 644 return sibling; |
645 } | |
646 | |
647 return NULL; | |
648 } |