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