Mercurial > pidgin
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 13805:853fefb07c79 | 13806:25e63008d3bb |
|---|---|
| 27 * write my own stuff. Also, re-writing this lets me be as lightweight | 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 */ | 28 * as I want to be. Thank you libxode for giving me a good starting point */ |
| 29 | 29 |
| 30 #include "internal.h" | 30 #include "internal.h" |
| 31 | 31 |
| 32 #ifdef HAVE_LIBXML | |
| 33 #include <libxml/parser.h> | |
| 34 #endif | |
| 32 #include <string.h> | 35 #include <string.h> |
| 33 #include <glib.h> | 36 #include <glib.h> |
| 34 | 37 |
| 35 #include "xmlnode.h" | 38 #include "xmlnode.h" |
| 36 | 39 |
| 170 } | 173 } |
| 171 | 174 |
| 172 return NULL; | 175 return NULL; |
| 173 } | 176 } |
| 174 | 177 |
| 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 | |
| 175 void | 204 void |
| 176 xmlnode_free(xmlnode *node) | 205 xmlnode_free(xmlnode *node) |
| 177 { | 206 { |
| 178 xmlnode *x, *y; | 207 xmlnode *x, *y; |
| 179 | 208 |
| 188 | 217 |
| 189 if(node->name) | 218 if(node->name) |
| 190 g_free(node->name); | 219 g_free(node->name); |
| 191 if(node->data) | 220 if(node->data) |
| 192 g_free(node->data); | 221 g_free(node->data); |
| 222 #ifdef HAVE_LIBXML | |
| 223 if(node->namespace) | |
| 224 g_free(node->namespace); | |
| 225 #endif | |
| 193 g_free(node); | 226 g_free(node); |
| 194 } | 227 } |
| 195 | 228 |
| 196 xmlnode* | 229 xmlnode* |
| 197 xmlnode_get_child(const xmlnode *parent, const char *name) | 230 xmlnode_get_child(const xmlnode *parent, const char *name) |
| 214 child_name = names[1]; | 247 child_name = names[1]; |
| 215 | 248 |
| 216 for(x = parent->child; x; x = x->next) { | 249 for(x = parent->child; x; x = x->next) { |
| 217 const char *xmlns = NULL; | 250 const char *xmlns = NULL; |
| 218 if(ns) | 251 if(ns) |
| 219 xmlns = xmlnode_get_attrib(x, "xmlns"); | 252 xmlns = xmlnode_get_namespace(x); |
| 220 | 253 |
| 221 if(x->type == XMLNODE_TYPE_TAG && name && !strcmp(parent_name, x->name) | 254 if(x->type == XMLNODE_TYPE_TAG && name && !strcmp(parent_name, x->name) |
| 222 && (!ns || (xmlns && !strcmp(ns, xmlns)))) { | 255 && (!ns || (xmlns && !strcmp(ns, xmlns)))) { |
| 223 ret = x; | 256 ret = x; |
| 224 break; | 257 break; |
| 270 } | 303 } |
| 271 | 304 |
| 272 node_name = g_markup_escape_text(node->name, -1); | 305 node_name = g_markup_escape_text(node->name, -1); |
| 273 g_string_append_printf(text, "<%s", node_name); | 306 g_string_append_printf(text, "<%s", node_name); |
| 274 | 307 |
| 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 | |
| 275 for(c = node->child; c; c = c->next) | 315 for(c = node->child; c; c = c->next) |
| 276 { | 316 { |
| 277 if(c->type == XMLNODE_TYPE_ATTRIB) { | 317 if(c->type == XMLNODE_TYPE_ATTRIB) { |
| 278 esc = g_markup_escape_text(c->name, -1); | 318 esc = g_markup_escape_text(c->name, -1); |
| 279 esc2 = g_markup_escape_text(c->data, -1); | 319 esc2 = g_markup_escape_text(c->data, -1); |
| 345 | 385 |
| 346 struct _xmlnode_parser_data { | 386 struct _xmlnode_parser_data { |
| 347 xmlnode *current; | 387 xmlnode *current; |
| 348 }; | 388 }; |
| 349 | 389 |
| 390 #ifdef HAVE_LIBXML | |
| 350 static void | 391 static void |
| 351 xmlnode_parser_element_start(GMarkupParseContext *context, | 392 xmlnode_parser_element_start_libxml(void *user_data, |
| 352 const char *element_name, const char **attrib_names, | 393 const xmlChar *element_name, const xmlChar *prefix, const xmlChar *namespace, |
| 353 const char **attrib_values, gpointer user_data, GError **error) | 394 int nb_namespaces, const xmlChar **namespaces, |
| 395 int nb_attributes, int nb_defaulted, const xmlChar **attributes) | |
| 354 { | 396 { |
| 355 struct _xmlnode_parser_data *xpd = user_data; | 397 struct _xmlnode_parser_data *xpd = user_data; |
| 356 xmlnode *node; | 398 xmlnode *node; |
| 357 int i; | 399 int i; |
| 358 | 400 |
| 362 if(xpd->current) | 404 if(xpd->current) |
| 363 node = xmlnode_new_child(xpd->current, element_name); | 405 node = xmlnode_new_child(xpd->current, element_name); |
| 364 else | 406 else |
| 365 node = xmlnode_new(element_name); | 407 node = xmlnode_new(element_name); |
| 366 | 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 | |
| 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 | |
| 367 for(i=0; attrib_names[i]; i++) | 472 for(i=0; attrib_names[i]; i++) |
| 368 xmlnode_set_attrib(node, attrib_names[i], attrib_values[i]); | 473 xmlnode_set_attrib(node, attrib_names[i], attrib_values[i]); |
| 369 | 474 |
| 370 xpd->current = node; | 475 xpd->current = node; |
| 371 } | 476 } |
| 398 if(!text || !text_len) | 503 if(!text || !text_len) |
| 399 return; | 504 return; |
| 400 | 505 |
| 401 xmlnode_insert_data(xpd->current, text, text_len); | 506 xmlnode_insert_data(xpd->current, text, text_len); |
| 402 } | 507 } |
| 403 | 508 #endif |
| 509 | |
| 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 | |
| 404 static GMarkupParser xmlnode_parser = { | 546 static GMarkupParser xmlnode_parser = { |
| 405 xmlnode_parser_element_start, | 547 xmlnode_parser_element_start, |
| 406 xmlnode_parser_element_end, | 548 xmlnode_parser_element_end, |
| 407 xmlnode_parser_element_text, | 549 xmlnode_parser_element_text, |
| 408 NULL, | 550 NULL, |
| 409 NULL | 551 NULL |
| 410 }; | 552 }; |
| 411 | 553 #endif |
| 412 | 554 |
| 413 xmlnode * | 555 xmlnode * |
| 414 xmlnode_from_str(const char *str, gssize size) | 556 xmlnode_from_str(const char *str, gssize size) |
| 415 { | 557 { |
| 416 struct _xmlnode_parser_data *xpd; | 558 struct _xmlnode_parser_data *xpd; |
| 420 | 562 |
| 421 g_return_val_if_fail(str != NULL, NULL); | 563 g_return_val_if_fail(str != NULL, NULL); |
| 422 | 564 |
| 423 real_size = size < 0 ? strlen(str) : size; | 565 real_size = size < 0 ? strlen(str) : size; |
| 424 xpd = g_new0(struct _xmlnode_parser_data, 1); | 566 xpd = g_new0(struct _xmlnode_parser_data, 1); |
| 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 | |
| 425 context = g_markup_parse_context_new(&xmlnode_parser, 0, xpd, NULL); | 577 context = g_markup_parse_context_new(&xmlnode_parser, 0, xpd, NULL); |
| 426 | 578 |
| 427 if(!g_markup_parse_context_parse(context, str, real_size, NULL)) { | 579 if(!g_markup_parse_context_parse(context, str, real_size, NULL)) { |
| 428 while(xpd->current && xpd->current->parent) | 580 while(xpd->current && xpd->current->parent) |
| 429 xpd->current = xpd->current->parent; | 581 xpd->current = xpd->current->parent; |
| 430 if(xpd->current) | 582 if(xpd->current) |
| 431 xmlnode_free(xpd->current); | 583 xmlnode_free(xpd->current); |
| 432 xpd->current = NULL; | 584 xpd->current = NULL; |
| 433 } | 585 } |
| 434 g_markup_parse_context_free(context); | 586 g_markup_parse_context_free(context); |
| 435 | 587 #endif |
| 436 ret = xpd->current; | 588 ret = xpd->current; |
| 437 g_free(xpd); | 589 g_free(xpd); |
| 438 return ret; | 590 return ret; |
| 439 } | 591 } |
| 440 | 592 |
| 475 | 627 |
| 476 xmlnode * | 628 xmlnode * |
| 477 xmlnode_get_next_twin(xmlnode *node) | 629 xmlnode_get_next_twin(xmlnode *node) |
| 478 { | 630 { |
| 479 xmlnode *sibling; | 631 xmlnode *sibling; |
| 480 const char *ns = xmlnode_get_attrib(node, "xmlns"); | 632 const char *ns = xmlnode_get_namespace(node); |
| 481 | 633 |
| 482 g_return_val_if_fail(node != NULL, NULL); | 634 g_return_val_if_fail(node != NULL, NULL); |
| 483 g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL); | 635 g_return_val_if_fail(node->type == XMLNODE_TYPE_TAG, NULL); |
| 484 | 636 |
| 485 for(sibling = node->next; sibling; sibling = sibling->next) { | 637 for(sibling = node->next; sibling; sibling = sibling->next) { |
| 486 const char *xmlns = NULL; | 638 const char *xmlns = NULL; |
| 487 if(ns) | 639 if(ns) |
| 488 xmlns = xmlnode_get_attrib(sibling, "xmlns"); | 640 xmlns = xmlnode_get_namespace(sibling); |
| 489 | 641 |
| 490 if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) && | 642 if(sibling->type == XMLNODE_TYPE_TAG && !strcmp(node->name, sibling->name) && |
| 491 (!ns || (xmlns && !strcmp(ns, xmlns)))) | 643 (!ns || (xmlns && !strcmp(ns, xmlns)))) |
| 492 return sibling; | 644 return sibling; |
| 493 } | 645 } |
