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