Mercurial > pidgin
annotate libgaim/xmlnode.c @ 15278:00fbd797dc29
[gaim-migrate @ 18068]
This guy sent us an email on December 25th, 2006 and said he
contributed some stuff for getting libgaim to be portable between
Unix and Windows. Adam corroborated that, but we're not sure
if the stuff he contributed is still around, or if it's been
rewritten, etc. So I'm going to add his name in, just in case.
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Wed, 03 Jan 2007 19:43:33 +0000 |
| parents | c65def04fb44 |
| children | 682908b965cf |
| 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 && | |
| 15215 | 130 !strcmp(attr_node->name, attr)) |
| 131 { | |
| 14192 | 132 if(node->child == attr_node) { |
| 133 node->child = attr_node->next; | |
| 134 } else { | |
| 135 sibling->next = attr_node->next; | |
| 136 } | |
| 15215 | 137 if (node->lastchild == attr_node) { |
| 138 node->lastchild = sibling; | |
| 139 } | |
| 14192 | 140 xmlnode_free(attr_node); |
| 141 return; | |
| 142 } | |
| 143 sibling = attr_node; | |
| 144 } | |
| 145 } | |
| 146 | |
| 15203 | 147 |
| 148 void | |
| 149 xmlnode_remove_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns) | |
| 150 { | |
| 151 xmlnode *attr_node, *sibling = NULL; | |
| 152 | |
| 153 g_return_if_fail(node != NULL); | |
| 154 g_return_if_fail(attr != NULL); | |
| 155 | |
| 156 for(attr_node = node->child; attr_node; attr_node = attr_node->next) | |
| 157 { | |
| 158 if(attr_node->type == XMLNODE_TYPE_ATTRIB && | |
| 159 !strcmp(attr_node->name, attr) && | |
| 15215 | 160 !strcmp(attr_node->xmlns, xmlns)) |
| 161 { | |
| 15203 | 162 if(node->child == attr_node) { |
| 163 node->child = attr_node->next; | |
| 164 } else { | |
| 165 sibling->next = attr_node->next; | |
| 166 } | |
| 15215 | 167 if (node->lastchild == attr_node) { |
| 168 node->lastchild = sibling; | |
| 169 } | |
| 15203 | 170 xmlnode_free(attr_node); |
| 171 return; | |
| 172 } | |
| 173 sibling = attr_node; | |
| 174 } | |
| 175 } | |
| 176 | |
| 14192 | 177 void |
| 178 xmlnode_set_attrib(xmlnode *node, const char *attr, const char *value) | |
| 179 { | |
| 180 xmlnode *attrib_node; | |
| 181 | |
| 182 g_return_if_fail(node != NULL); | |
| 183 g_return_if_fail(attr != NULL); | |
| 184 g_return_if_fail(value != NULL); | |
| 185 | |
| 186 xmlnode_remove_attrib(node, attr); | |
| 187 | |
| 188 attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB); | |
| 189 | |
| 190 attrib_node->data = g_strdup(value); | |
| 191 | |
| 192 xmlnode_insert_child(node, attrib_node); | |
| 193 } | |
| 194 | |
| 15203 | 195 void |
| 196 xmlnode_set_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns, const char *value) | |
| 197 { | |
| 198 xmlnode *attrib_node; | |
| 199 | |
| 200 g_return_if_fail(node != NULL); | |
| 201 g_return_if_fail(attr != NULL); | |
| 202 g_return_if_fail(value != NULL); | |
| 203 | |
| 204 xmlnode_remove_attrib_with_namespace(node, attr, xmlns); | |
| 205 | |
| 206 attrib_node = new_node(attr, XMLNODE_TYPE_ATTRIB); | |
| 207 | |
| 208 attrib_node->data = g_strdup(value); | |
| 209 attrib_node->xmlns = g_strdup(xmlns); | |
| 210 | |
| 15215 | 211 xmlnode_insert_child(node, attrib_node); |
| 15203 | 212 } |
| 213 | |
| 14192 | 214 const char * |
| 215 xmlnode_get_attrib(xmlnode *node, const char *attr) | |
| 216 { | |
| 217 xmlnode *x; | |
| 218 | |
| 219 g_return_val_if_fail(node != NULL, NULL); | |
| 220 | |
| 221 for(x = node->child; x; x = x->next) { | |
| 222 if(x->type == XMLNODE_TYPE_ATTRIB && !strcmp(attr, x->name)) { | |
| 223 return x->data; | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 return NULL; | |
| 228 } | |
| 229 | |
| 15203 | 230 const char * |
| 231 xmlnode_get_attrib_with_namespace(xmlnode *node, const char *attr, const char *xmlns) | |
| 232 { | |
| 233 xmlnode *x; | |
| 234 | |
| 235 g_return_val_if_fail(node != NULL, NULL); | |
| 236 | |
| 237 for(x = node->child; x; x = x->next) { | |
| 15215 | 238 if(x->type == XMLNODE_TYPE_ATTRIB && |
| 15203 | 239 !strcmp(attr, x->name) && !strcmp(x->xmlns, xmlns)) { |
| 240 return x->data; | |
| 241 } | |
| 242 } | |
| 243 | |
| 15215 | 244 return NULL; |
| 15203 | 245 } |
| 246 | |
| 14192 | 247 |
| 248 void xmlnode_set_namespace(xmlnode *node, const char *xmlns) | |
| 249 { | |
| 250 g_return_if_fail(node != NULL); | |
| 251 | |
| 15176 | 252 g_free(node->xmlns); |
| 253 node->xmlns = g_strdup(xmlns); | |
| 14192 | 254 } |
| 255 | |
| 256 const char *xmlnode_get_namespace(xmlnode *node) | |
| 257 { | |
| 258 g_return_val_if_fail(node != NULL, NULL); | |
| 259 | |
| 15176 | 260 return node->xmlns; |
| 14192 | 261 } |
| 262 | |
| 263 void | |
| 264 xmlnode_free(xmlnode *node) | |
| 265 { | |
| 266 xmlnode *x, *y; | |
| 267 | |
| 268 g_return_if_fail(node != NULL); | |
| 269 | |
| 270 x = node->child; | |
| 271 while(x) { | |
| 272 y = x->next; | |
| 273 xmlnode_free(x); | |
| 274 x = y; | |
| 275 } | |
| 276 | |
| 277 g_free(node->name); | |
| 278 g_free(node->data); | |
| 15176 | 279 g_free(node->xmlns); |
| 14324 | 280 |
| 281 GAIM_DBUS_UNREGISTER_POINTER(node); | |
| 14192 | 282 g_free(node); |
| 283 } | |
| 284 | |
| 285 xmlnode* | |
| 286 xmlnode_get_child(const xmlnode *parent, const char *name) | |
| 287 { | |
| 288 return xmlnode_get_child_with_namespace(parent, name, NULL); | |
| 289 } | |
| 290 | |
| 291 xmlnode * | |
| 292 xmlnode_get_child_with_namespace(const xmlnode *parent, const char *name, const char *ns) | |
| 293 { | |
| 294 xmlnode *x, *ret = NULL; | |
| 295 char **names; | |
| 296 char *parent_name, *child_name; | |
| 297 | |
| 298 g_return_val_if_fail(parent != NULL, NULL); | |
| 299 g_return_val_if_fail(name != NULL, NULL); | |
| 300 | |
| 301 names = g_strsplit(name, "/", 2); | |
| 302 parent_name = names[0]; | |
| 303 child_name = names[1]; | |
| 304 | |
| 305 for(x = parent->child; x; x = x->next) { | |
| 306 const char *xmlns = NULL; | |
| 307 if(ns) | |
| 308 xmlns = xmlnode_get_namespace(x); | |
| 309 | |
| 310 if(x->type == XMLNODE_TYPE_TAG && name && !strcmp(parent_name, x->name) | |
| 311 && (!ns || (xmlns && !strcmp(ns, xmlns)))) { | |
| 312 ret = x; | |
| 313 break; | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 if(child_name && ret) | |
| 318 ret = xmlnode_get_child(ret, child_name); | |
| 319 | |
| 320 g_strfreev(names); | |
| 321 return ret; | |
| 322 } | |
| 323 | |
| 324 char * | |
| 325 xmlnode_get_data(xmlnode *node) | |
| 326 { | |
| 327 GString *str = NULL; | |
| 328 xmlnode *c; | |
| 329 | |
| 330 g_return_val_if_fail(node != NULL, NULL); | |
| 331 | |
| 332 for(c = node->child; c; c = c->next) { | |
| 333 if(c->type == XMLNODE_TYPE_DATA) { | |
| 334 if(!str) | |
| 335 str = g_string_new(""); | |
| 336 str = g_string_append_len(str, c->data, c->data_sz); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 if (str == NULL) | |
| 341 return NULL; | |
| 342 | |
| 343 return g_string_free(str, FALSE); | |
| 344 } | |
| 345 | |
| 346 static char * | |
| 347 xmlnode_to_str_helper(xmlnode *node, int *len, gboolean formatting, int depth) | |
| 348 { | |
| 349 GString *text = g_string_new(""); | |
| 350 xmlnode *c; | |
| 351 char *node_name, *esc, *esc2, *tab = NULL; | |
| 352 gboolean need_end = FALSE, pretty = formatting; | |
| 353 | |
| 354 g_return_val_if_fail(node != NULL, NULL); | |
| 355 | |
| 356 if(pretty && depth) { | |
| 357 tab = g_strnfill(depth, '\t'); | |
| 358 text = g_string_append(text, tab); | |
| 359 } | |
| 360 | |
| 361 node_name = g_markup_escape_text(node->name, -1); | |
| 362 g_string_append_printf(text, "<%s", node_name); | |
| 363 | |
| 15176 | 364 if (node->xmlns) { |
| 365 if(!node->parent || !node->parent->xmlns || strcmp(node->xmlns, node->parent->xmlns)) | |
| 15122 | 366 { |
| 15176 | 367 char *xmlns = g_markup_escape_text(node->xmlns, -1); |
| 368 g_string_append_printf(text, " xmlns='%s'", xmlns); | |
| 369 g_free(xmlns); | |
| 15122 | 370 } |
| 14192 | 371 } |
| 372 for(c = node->child; c; c = c->next) | |
| 373 { | |
| 374 if(c->type == XMLNODE_TYPE_ATTRIB) { | |
| 375 esc = g_markup_escape_text(c->name, -1); | |
| 376 esc2 = g_markup_escape_text(c->data, -1); | |
| 377 g_string_append_printf(text, " %s='%s'", esc, esc2); | |
| 378 g_free(esc); | |
| 379 g_free(esc2); | |
| 380 } else if(c->type == XMLNODE_TYPE_TAG || c->type == XMLNODE_TYPE_DATA) { | |
| 381 if(c->type == XMLNODE_TYPE_DATA) | |
| 382 pretty = FALSE; | |
| 383 need_end = TRUE; | |
| 384 } | |
| 385 } | |
| 386 | |
| 387 if(need_end) { | |
| 388 g_string_append_printf(text, ">%s", pretty ? NEWLINE_S : ""); | |
| 389 | |
| 390 for(c = node->child; c; c = c->next) | |
| 391 { | |
| 392 if(c->type == XMLNODE_TYPE_TAG) { | |
| 393 int esc_len; | |
| 394 esc = xmlnode_to_str_helper(c, &esc_len, pretty, depth+1); | |
| 395 text = g_string_append_len(text, esc, esc_len); | |
| 396 g_free(esc); | |
| 397 } else if(c->type == XMLNODE_TYPE_DATA && c->data_sz > 0) { | |
| 398 esc = g_markup_escape_text(c->data, c->data_sz); | |
| 399 text = g_string_append(text, esc); | |
| 400 g_free(esc); | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 if(tab && pretty) | |
| 405 text = g_string_append(text, tab); | |
| 406 g_string_append_printf(text, "</%s>%s", node_name, formatting ? NEWLINE_S : ""); | |
| 407 } else { | |
| 408 g_string_append_printf(text, "/>%s", formatting ? NEWLINE_S : ""); | |
| 409 } | |
| 410 | |
| 411 g_free(node_name); | |
| 412 | |
| 413 g_free(tab); | |
| 414 | |
| 415 if(len) | |
| 416 *len = text->len; | |
| 417 | |
| 418 return g_string_free(text, FALSE); | |
| 419 } | |
| 420 | |
| 421 char * | |
| 422 xmlnode_to_str(xmlnode *node, int *len) | |
| 423 { | |
| 424 return xmlnode_to_str_helper(node, len, FALSE, 0); | |
| 425 } | |
| 426 | |
| 427 char * | |
| 428 xmlnode_to_formatted_str(xmlnode *node, int *len) | |
| 429 { | |
| 430 char *xml, *xml_with_declaration; | |
| 431 | |
| 432 g_return_val_if_fail(node != NULL, NULL); | |
| 433 | |
| 434 xml = xmlnode_to_str_helper(node, len, TRUE, 0); | |
| 435 xml_with_declaration = | |
| 436 g_strdup_printf("<?xml version='1.0' encoding='UTF-8' ?>" NEWLINE_S NEWLINE_S "%s", xml); | |
| 437 g_free(xml); | |
| 438 | |
| 439 return xml_with_declaration; | |
| 440 } | |
| 441 | |
| 442 struct _xmlnode_parser_data { | |
| 443 xmlnode *current; | |
| 444 }; | |
| 445 | |
| 446 static void | |
| 447 xmlnode_parser_element_start_libxml(void *user_data, | |
| 15176 | 448 const xmlChar *element_name, const xmlChar *prefix, const xmlChar *xmlns, |
| 14192 | 449 int nb_namespaces, const xmlChar **namespaces, |
| 450 int nb_attributes, int nb_defaulted, const xmlChar **attributes) | |
| 451 { | |
| 452 struct _xmlnode_parser_data *xpd = user_data; | |
| 453 xmlnode *node; | |
| 454 int i; | |
| 455 | |
| 456 if(!element_name) { | |
| 457 return; | |
| 458 } else { | |
| 459 if(xpd->current) | |
|
14628
58202142e9ad
[gaim-migrate @ 17369]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14436
diff
changeset
|
460 node = xmlnode_new_child(xpd->current, (const char*) element_name); |
| 14192 | 461 else |
|
14628
58202142e9ad
[gaim-migrate @ 17369]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14436
diff
changeset
|
462 node = xmlnode_new((const char *) element_name); |
| 14192 | 463 |
| 15176 | 464 xmlnode_set_namespace(node, (const char *) xmlns); |
| 14192 | 465 |
| 466 for(i=0; i < nb_attributes * 5; i+=5) { | |
| 14228 | 467 char *txt; |
| 14192 | 468 int attrib_len = attributes[i+4] - attributes[i+3]; |
| 469 char *attrib = g_malloc(attrib_len + 1); | |
| 470 memcpy(attrib, attributes[i+3], attrib_len); | |
| 471 attrib[attrib_len] = '\0'; | |
| 14228 | 472 txt = attrib; |
| 14192 | 473 attrib = gaim_unescape_html(txt); |
| 474 g_free(txt); | |
|
14628
58202142e9ad
[gaim-migrate @ 17369]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14436
diff
changeset
|
475 xmlnode_set_attrib(node, (const char*) attributes[i], attrib); |
| 14192 | 476 g_free(attrib); |
| 477 } | |
| 478 | |
| 479 xpd->current = node; | |
| 480 } | |
| 481 } | |
| 482 | |
| 483 static void | |
| 484 xmlnode_parser_element_end_libxml(void *user_data, const xmlChar *element_name, | |
| 15176 | 485 const xmlChar *prefix, const xmlChar *xmlns) |
| 14192 | 486 { |
| 487 struct _xmlnode_parser_data *xpd = user_data; | |
| 488 | |
| 489 if(!element_name || !xpd->current) | |
| 490 return; | |
| 491 | |
| 492 if(xpd->current->parent) { | |
|
14628
58202142e9ad
[gaim-migrate @ 17369]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14436
diff
changeset
|
493 if(!xmlStrcmp((xmlChar*) xpd->current->name, element_name)) |
| 14192 | 494 xpd->current = xpd->current->parent; |
| 495 } | |
| 496 } | |
| 497 | |
| 498 static void | |
| 499 xmlnode_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len) | |
| 500 { | |
| 501 struct _xmlnode_parser_data *xpd = user_data; | |
| 502 | |
| 503 if(!xpd->current) | |
| 504 return; | |
| 505 | |
| 506 if(!text || !text_len) | |
| 507 return; | |
| 508 | |
|
14628
58202142e9ad
[gaim-migrate @ 17369]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14436
diff
changeset
|
509 xmlnode_insert_data(xpd->current, (const char*) text, text_len); |
| 14192 | 510 } |
| 511 | |
| 512 static xmlSAXHandler xmlnode_parser_libxml = { | |
| 513 .internalSubset = NULL, | |
| 514 .isStandalone = NULL, | |
| 515 .hasInternalSubset = NULL, | |
| 516 .hasExternalSubset = NULL, | |
| 517 .resolveEntity = NULL, | |
| 518 .getEntity = NULL, | |
| 519 .entityDecl = NULL, | |
| 520 .notationDecl = NULL, | |
| 521 .attributeDecl = NULL, | |
| 522 .elementDecl = NULL, | |
| 523 .unparsedEntityDecl = NULL, | |
| 524 .setDocumentLocator = NULL, | |
| 525 .startDocument = NULL, | |
| 526 .endDocument = NULL, | |
| 527 .startElement = NULL, | |
| 528 .endElement = NULL, | |
| 529 .reference = NULL, | |
| 530 .characters = xmlnode_parser_element_text_libxml, | |
| 531 .ignorableWhitespace = NULL, | |
| 532 .processingInstruction = NULL, | |
| 533 .comment = NULL, | |
| 534 .warning = NULL, | |
| 535 .error = NULL, | |
| 536 .fatalError = NULL, | |
| 537 .getParameterEntity = NULL, | |
| 538 .cdataBlock = NULL, | |
| 539 .externalSubset = NULL, | |
| 540 .initialized = XML_SAX2_MAGIC, | |
| 541 ._private = NULL, | |
| 542 .startElementNs = xmlnode_parser_element_start_libxml, | |
| 543 .endElementNs = xmlnode_parser_element_end_libxml, | |
| 544 .serror = NULL | |
| 545 }; | |
| 546 | |
| 547 xmlnode * | |
| 548 xmlnode_from_str(const char *str, gssize size) | |
| 549 { | |
| 550 struct _xmlnode_parser_data *xpd; | |
| 551 xmlnode *ret; | |
| 552 gsize real_size; | |
| 553 | |
| 554 g_return_val_if_fail(str != NULL, NULL); | |
| 555 | |
| 556 real_size = size < 0 ? strlen(str) : size; | |
| 557 xpd = g_new0(struct _xmlnode_parser_data, 1); | |
| 558 | |
| 14322 | 559 if (xmlSAXUserParseMemory(&xmlnode_parser_libxml, xpd, str, real_size) < 0) { |
| 14192 | 560 while(xpd->current && xpd->current->parent) |
| 561 xpd->current = xpd->current->parent; | |
| 562 if(xpd->current) | |
| 563 xmlnode_free(xpd->current); | |
| 564 xpd->current = NULL; | |
| 565 } | |
| 566 ret = xpd->current; | |
| 567 g_free(xpd); | |
| 568 return ret; | |
| 569 } | |
| 570 | |
| 571 xmlnode * | |
| 572 xmlnode_copy(xmlnode *src) | |
| 573 { | |
| 574 xmlnode *ret; | |
| 575 xmlnode *child; | |
| 576 xmlnode *sibling = NULL; | |
| 577 | |
| 578 g_return_val_if_fail(src != NULL, NULL); | |
| 579 | |
| 580 ret = new_node(src->name, src->type); | |
| 581 if(src->data) { | |
| 582 if(src->data_sz) { | |
| 583 ret->data = g_memdup(src->data, src->data_sz); | |
| 584 ret->data_sz = src->data_sz; | |
| 585 } else { | |
| 586 ret->data = g_strdup(src->data); | |
| 587 } | |
| 588 } | |
| 589 | |
| 590 for(child = src->child; child; child = child->next) { | |
| 591 if(sibling) { | |
| 592 sibling->next = xmlnode_copy(child); | |
| 593 sibling = sibling->next; | |
| 594 } else { | |
| 595 ret->child = xmlnode_copy(child); | |
| 596 sibling = ret->child; | |
| 597 } | |
| 598 sibling->parent = ret; | |
| 599 } | |
| 600 | |
| 601 ret->lastchild = sibling; | |
| 602 | |
| 603 return ret; | |
| 604 } | |
| 605 | |
| 606 xmlnode * | |
| 607 xmlnode_get_next_twin(xmlnode *node) | |
| 608 { | |
| 609 xmlnode *sibling; | |
| 610 const char *ns = xmlnode_get_namespace(node); | |
| 611 | |
| 612 g_return_val_if_fail(node != NULL, NULL); | |
| 613 g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL); | |
| 614 | |
| 615 for(sibling = node->next; sibling; sibling = sibling->next) { | |
| 616 const char *xmlns = NULL; | |
| 617 if(ns) | |
| 618 xmlns = xmlnode_get_namespace(sibling); | |
| 619 | |
| 620 if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) && | |
| 621 (!ns || (xmlns && !strcmp(ns, xmlns)))) | |
| 622 return sibling; | |
| 623 } | |
| 624 | |
| 625 return NULL; | |
| 626 } |
