Mercurial > pidgin
annotate src/xmlnode.c @ 13955:2d6f7ac4b6f2
[gaim-migrate @ 16503]
Get rid of an assertion failure when trying to load our D-BUS example
plugin if the D-BUS subsystem is not initialized for whatever reason.
Not only that, the plugin gracefully fails to load and prints an
error message.
These error messages could be improved. If you're familiar with how
D-BUS works then go for it.
Also, do we need to be uninitializing any of the D-BUS stuff?
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Mon, 17 Jul 2006 05:50:28 +0000 |
| parents | 3c6d0c24179a |
| children | 8bda65b88e49 |
| 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; |
|
13831
3c6d0c24179a
[gaim-migrate @ 16280]
Richard Laager <rlaager@wiktel.com>
parents:
13806
diff
changeset
|
560 #ifndef HAVE_LIBXML |
| 7131 | 561 GMarkupParseContext *context; |
|
13831
3c6d0c24179a
[gaim-migrate @ 16280]
Richard Laager <rlaager@wiktel.com>
parents:
13806
diff
changeset
|
562 #endif |
| 11390 | 563 gsize real_size; |
| 7131 | 564 |
| 11390 | 565 g_return_val_if_fail(str != NULL, NULL); |
| 566 | |
|
11705
0906a3e9626c
[gaim-migrate @ 13996]
Richard Laager <rlaager@wiktel.com>
parents:
11390
diff
changeset
|
567 real_size = size < 0 ? strlen(str) : size; |
| 11390 | 568 xpd = g_new0(struct _xmlnode_parser_data, 1); |
| 13806 | 569 |
| 570 #ifdef HAVE_LIBXML | |
| 571 if (xmlSAXUserParseMemory(&xmlnode_parser_libxml, xpd, str, size) < 0) { | |
| 572 while(xpd->current && xpd->current->parent) | |
| 573 xpd->current = xpd->current->parent; | |
| 574 if(xpd->current) | |
| 575 xmlnode_free(xpd->current); | |
| 576 xpd->current = NULL; | |
| 577 } | |
| 578 #else | |
| 7131 | 579 context = g_markup_parse_context_new(&xmlnode_parser, 0, xpd, NULL); |
| 580 | |
| 581 if(!g_markup_parse_context_parse(context, str, real_size, NULL)) { | |
| 582 while(xpd->current && xpd->current->parent) | |
| 583 xpd->current = xpd->current->parent; | |
| 584 if(xpd->current) | |
| 585 xmlnode_free(xpd->current); | |
| 586 xpd->current = NULL; | |
| 587 } | |
| 588 g_markup_parse_context_free(context); | |
| 13806 | 589 #endif |
| 7131 | 590 ret = xpd->current; |
| 591 g_free(xpd); | |
| 592 return ret; | |
| 593 } | |
| 8135 | 594 |
| 10423 | 595 xmlnode * |
| 596 xmlnode_copy(xmlnode *src) | |
| 8135 | 597 { |
| 598 xmlnode *ret; | |
| 599 xmlnode *child; | |
| 600 xmlnode *sibling = NULL; | |
| 601 | |
|
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
602 g_return_val_if_fail(src != NULL, NULL); |
| 8135 | 603 |
| 604 ret = new_node(src->name, src->type); | |
| 605 if(src->data) { | |
| 8167 | 606 if(src->data_sz) { |
| 607 ret->data = g_memdup(src->data, src->data_sz); | |
| 608 ret->data_sz = src->data_sz; | |
| 609 } else { | |
| 610 ret->data = g_strdup(src->data); | |
| 611 } | |
| 8135 | 612 } |
| 613 | |
| 614 for(child = src->child; child; child = child->next) { | |
| 615 if(sibling) { | |
| 616 sibling->next = xmlnode_copy(child); | |
| 617 sibling = sibling->next; | |
| 618 } else { | |
| 619 ret->child = xmlnode_copy(child); | |
| 620 sibling = ret->child; | |
| 621 } | |
| 622 sibling->parent = ret; | |
| 623 } | |
| 624 | |
|
12233
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
625 ret->lastchild = sibling; |
|
02833a0ae716
[gaim-migrate @ 14535]
Richard Laager <rlaager@wiktel.com>
parents:
12198
diff
changeset
|
626 |
| 8135 | 627 return ret; |
| 628 } | |
| 629 | |
| 10423 | 630 xmlnode * |
| 631 xmlnode_get_next_twin(xmlnode *node) | |
| 632 { | |
| 8135 | 633 xmlnode *sibling; |
| 13806 | 634 const char *ns = xmlnode_get_namespace(node); |
| 8135 | 635 |
| 636 g_return_val_if_fail(node != NULL, NULL); | |
| 637 g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL); | |
| 638 | |
| 639 for(sibling = node->next; sibling; sibling = sibling->next) { | |
| 8283 | 640 const char *xmlns = NULL; |
| 8262 | 641 if(ns) |
| 13806 | 642 xmlns = xmlnode_get_namespace(sibling); |
| 8262 | 643 |
| 644 if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) && | |
| 645 (!ns || (xmlns && !strcmp(ns, xmlns)))) | |
| 8135 | 646 return sibling; |
| 647 } | |
| 648 | |
| 649 return NULL; | |
| 650 } |
