Mercurial > pidgin.yaz
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 } |