| 156 PurpleXmlNode *attr_node, *sibling = NULL; |
154 PurpleXmlNode *attr_node, *sibling = NULL; |
| 157 |
155 |
| 158 g_return_if_fail(node != NULL); |
156 g_return_if_fail(node != NULL); |
| 159 g_return_if_fail(attr != NULL); |
157 g_return_if_fail(attr != NULL); |
| 160 |
158 |
| 161 for(attr_node = node->child; attr_node; attr_node = attr_node->next) |
159 for(attr_node = node->child; attr_node; attr_node = attr_node->next) { |
| 162 { |
|
| 163 if(attr_node->type == PURPLE_XMLNODE_TYPE_ATTRIB && |
160 if(attr_node->type == PURPLE_XMLNODE_TYPE_ATTRIB && |
| 164 purple_strequal(attr, attr_node->name) && |
161 purple_strequal(attr, attr_node->name) && |
| 165 purple_strequal(xmlns, attr_node->xmlns)) |
162 purple_strequal(xmlns, attr_node->xmlns)) |
| 166 { |
163 { |
| 167 if(sibling == NULL) { |
164 if(sibling == NULL) { |
| 368 |
367 |
| 369 /* if we're part of a tree, remove ourselves from the tree first */ |
368 /* if we're part of a tree, remove ourselves from the tree first */ |
| 370 if(NULL != node->parent) { |
369 if(NULL != node->parent) { |
| 371 if(node->parent->child == node) { |
370 if(node->parent->child == node) { |
| 372 node->parent->child = node->next; |
371 node->parent->child = node->next; |
| 373 if (node->parent->lastchild == node) |
372 if (node->parent->lastchild == node) { |
| 374 node->parent->lastchild = node->next; |
373 node->parent->lastchild = node->next; |
| |
374 } |
| 375 } else { |
375 } else { |
| 376 PurpleXmlNode *prev = node->parent->child; |
376 PurpleXmlNode *prev = node->parent->child; |
| 377 while(prev && prev->next != node) { |
377 while(prev && prev->next != node) { |
| 378 prev = prev->next; |
378 prev = prev->next; |
| 379 } |
379 } |
| 380 if(prev) { |
380 if(prev) { |
| 381 prev->next = node->next; |
381 prev->next = node->next; |
| 382 if (node->parent->lastchild == node) |
382 if (node->parent->lastchild == node) { |
| 383 node->parent->lastchild = prev; |
383 node->parent->lastchild = prev; |
| |
384 } |
| 384 } |
385 } |
| 385 } |
386 } |
| 386 } |
387 } |
| 387 |
388 |
| 388 /* now free our children */ |
389 /* now free our children */ |
| 426 child_name = names[1]; |
426 child_name = names[1]; |
| 427 |
427 |
| 428 for(x = parent->child; x; x = x->next) { |
428 for(x = parent->child; x; x = x->next) { |
| 429 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */ |
429 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */ |
| 430 const char *xmlns = NULL; |
430 const char *xmlns = NULL; |
| 431 if(ns) |
431 if(ns) { |
| 432 xmlns = purple_xmlnode_get_namespace(x); |
432 xmlns = purple_xmlnode_get_namespace(x); |
| |
433 } |
| 433 |
434 |
| 434 if(x->type == PURPLE_XMLNODE_TYPE_TAG && purple_strequal(parent_name, x->name) |
435 if(x->type == PURPLE_XMLNODE_TYPE_TAG && purple_strequal(parent_name, x->name) |
| 435 && purple_strequal(ns, xmlns)) { |
436 && purple_strequal(ns, xmlns)) { |
| 436 ret = x; |
437 ret = x; |
| 437 break; |
438 break; |
| 438 } |
439 } |
| 439 } |
440 } |
| 440 |
441 |
| 441 if(child_name && ret) |
442 if(child_name && ret) { |
| 442 ret = purple_xmlnode_get_child(ret, child_name); |
443 ret = purple_xmlnode_get_child(ret, child_name); |
| |
444 } |
| 443 |
445 |
| 444 g_strfreev(names); |
446 g_strfreev(names); |
| 445 return ret; |
447 return ret; |
| 446 } |
448 } |
| 447 |
449 |
| 523 (GHFunc)purple_xmlnode_to_str_foreach_append_ns, text); |
527 (GHFunc)purple_xmlnode_to_str_foreach_append_ns, text); |
| 524 } else { |
528 } else { |
| 525 /* Figure out if this node has a different default namespace from parent */ |
529 /* Figure out if this node has a different default namespace from parent */ |
| 526 const char *xmlns = NULL; |
530 const char *xmlns = NULL; |
| 527 const char *parent_xmlns = NULL; |
531 const char *parent_xmlns = NULL; |
| 528 if (!prefix) |
532 if (!prefix) { |
| 529 xmlns = node->xmlns; |
533 xmlns = node->xmlns; |
| 530 |
534 } |
| 531 if (!xmlns) |
535 |
| |
536 if (!xmlns) { |
| 532 xmlns = purple_xmlnode_get_default_namespace(node); |
537 xmlns = purple_xmlnode_get_default_namespace(node); |
| 533 if (node->parent) |
538 } |
| |
539 if (node->parent) { |
| 534 parent_xmlns = purple_xmlnode_get_default_namespace(node->parent); |
540 parent_xmlns = purple_xmlnode_get_default_namespace(node->parent); |
| 535 if (!purple_strequal(xmlns, parent_xmlns)) |
541 } |
| 536 { |
542 if (!purple_strequal(xmlns, parent_xmlns)) { |
| 537 char *escaped_xmlns = g_markup_escape_text(xmlns, -1); |
543 char *escaped_xmlns = g_markup_escape_text(xmlns, -1); |
| 538 g_string_append_printf(text, " xmlns='%s'", escaped_xmlns); |
544 g_string_append_printf(text, " xmlns='%s'", escaped_xmlns); |
| 539 g_free(escaped_xmlns); |
545 g_free(escaped_xmlns); |
| 540 } |
546 } |
| 541 } |
547 } |
| 542 for(c = node->child; c; c = c->next) |
548 for(c = node->child; c; c = c->next) { |
| 543 { |
|
| 544 if(c->type == PURPLE_XMLNODE_TYPE_ATTRIB) { |
549 if(c->type == PURPLE_XMLNODE_TYPE_ATTRIB) { |
| 545 const char *aprefix = purple_xmlnode_get_prefix(c); |
550 const char *aprefix = purple_xmlnode_get_prefix(c); |
| 546 esc = g_markup_escape_text(c->name, -1); |
551 esc = g_markup_escape_text(c->name, -1); |
| 547 esc2 = g_markup_escape_text(c->data, -1); |
552 esc2 = g_markup_escape_text(c->data, -1); |
| 548 if (aprefix) { |
553 if (aprefix) { |
| 551 g_string_append_printf(text, " %s='%s'", esc, esc2); |
556 g_string_append_printf(text, " %s='%s'", esc, esc2); |
| 552 } |
557 } |
| 553 g_free(esc); |
558 g_free(esc); |
| 554 g_free(esc2); |
559 g_free(esc2); |
| 555 } else if(c->type == PURPLE_XMLNODE_TYPE_TAG || c->type == PURPLE_XMLNODE_TYPE_DATA) { |
560 } else if(c->type == PURPLE_XMLNODE_TYPE_TAG || c->type == PURPLE_XMLNODE_TYPE_DATA) { |
| 556 if(c->type == PURPLE_XMLNODE_TYPE_DATA) |
561 if(c->type == PURPLE_XMLNODE_TYPE_DATA) { |
| 557 pretty = FALSE; |
562 pretty = FALSE; |
| |
563 } |
| 558 need_end = TRUE; |
564 need_end = TRUE; |
| 559 } |
565 } |
| 560 } |
566 } |
| 561 |
567 |
| 562 if(need_end) { |
568 if(need_end) { |
| 563 g_string_append_printf(text, ">%s", pretty ? NEWLINE_S : ""); |
569 g_string_append_printf(text, ">%s", pretty ? NEWLINE_S : ""); |
| 564 |
570 |
| 565 for(c = node->child; c; c = c->next) |
571 for(c = node->child; c; c = c->next) { |
| 566 { |
|
| 567 if(c->type == PURPLE_XMLNODE_TYPE_TAG) { |
572 if(c->type == PURPLE_XMLNODE_TYPE_TAG) { |
| 568 int esc_len; |
573 int esc_len; |
| 569 esc = purple_xmlnode_to_str_helper(c, &esc_len, pretty, depth+1); |
574 esc = purple_xmlnode_to_str_helper(c, &esc_len, pretty, depth+1); |
| 570 text = g_string_append_len(text, esc, esc_len); |
575 text = g_string_append_len(text, esc, esc_len); |
| 571 g_free(esc); |
576 g_free(esc); |
| 680 purple_xmlnode_parser_element_end_libxml(void *user_data, const xmlChar *element_name, |
689 purple_xmlnode_parser_element_end_libxml(void *user_data, const xmlChar *element_name, |
| 681 const xmlChar *prefix, const xmlChar *xmlns) |
690 const xmlChar *prefix, const xmlChar *xmlns) |
| 682 { |
691 { |
| 683 struct _xmlnode_parser_data *xpd = user_data; |
692 struct _xmlnode_parser_data *xpd = user_data; |
| 684 |
693 |
| 685 if(!element_name || !xpd->current || xpd->error) |
694 if(!element_name || !xpd->current || xpd->error) { |
| 686 return; |
695 return; |
| |
696 } |
| 687 |
697 |
| 688 if(xpd->current->parent) { |
698 if(xpd->current->parent) { |
| 689 if(!xmlStrcmp((xmlChar*) xpd->current->name, element_name)) |
699 if(!xmlStrcmp((xmlChar*) xpd->current->name, element_name)) { |
| 690 xpd->current = xpd->current->parent; |
700 xpd->current = xpd->current->parent; |
| |
701 } |
| 691 } |
702 } |
| 692 } |
703 } |
| 693 |
704 |
| 694 static void |
705 static void |
| 695 purple_xmlnode_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len) |
706 purple_xmlnode_parser_element_text_libxml(void *user_data, const xmlChar *text, int text_len) |
| 696 { |
707 { |
| 697 struct _xmlnode_parser_data *xpd = user_data; |
708 struct _xmlnode_parser_data *xpd = user_data; |
| 698 |
709 |
| 699 if(!xpd->current || xpd->error) |
710 if(!xpd->current || xpd->error) { |
| 700 return; |
711 return; |
| 701 |
712 } |
| 702 if(!text || !text_len) |
713 |
| |
714 if(!text || !text_len) { |
| 703 return; |
715 return; |
| |
716 } |
| 704 |
717 |
| 705 purple_xmlnode_insert_data(xpd->current, (const char*) text, text_len); |
718 purple_xmlnode_insert_data(xpd->current, (const char*) text, text_len); |
| 706 } |
719 } |
| 707 |
720 |
| 708 static void |
721 static void |
| 730 error->level == XML_ERR_FATAL)) { |
743 error->level == XML_ERR_FATAL)) { |
| 731 xpd->error = TRUE; |
744 xpd->error = TRUE; |
| 732 purple_debug_error("xmlnode", "XML parser error for PurpleXmlNode %p: " |
745 purple_debug_error("xmlnode", "XML parser error for PurpleXmlNode %p: " |
| 733 "Domain %i, code %i, level %i: %s", |
746 "Domain %i, code %i, level %i: %s", |
| 734 user_data, error->domain, error->code, error->level, |
747 user_data, error->domain, error->code, error->level, |
| 735 error->message ? error->message : "(null)\n"); |
748 error->message ? error->message : "(null)"); |
| 736 } else if (error) |
749 } else if (error) { |
| 737 purple_debug_warning("xmlnode", "XML parser error for PurpleXmlNode %p: " |
750 purple_debug_warning("xmlnode", "XML parser error for PurpleXmlNode %p: " |
| 738 "Domain %i, code %i, level %i: %s", |
751 "Domain %i, code %i, level %i: %s", |
| 739 user_data, error->domain, error->code, error->level, |
752 user_data, error->domain, error->code, error->level, |
| 740 error->message ? error->message : "(null)\n"); |
753 error->message ? error->message : "(null)"); |
| 741 else |
754 } else { |
| 742 purple_debug_warning("xmlnode", "XML parser error for PurpleXmlNode %p\n", |
755 purple_debug_warning("xmlnode", "XML parser error for PurpleXmlNode %p", |
| 743 user_data); |
756 user_data); |
| |
757 } |
| 744 } |
758 } |
| 745 |
759 |
| 746 static xmlSAXHandler purple_xmlnode_parser_libxml = { |
760 static xmlSAXHandler purple_xmlnode_parser_libxml = { |
| 747 NULL, /* internalSubset */ |
761 NULL, /* internalSubset */ |
| 748 NULL, /* isStandalone */ |
762 NULL, /* isStandalone */ |
| 789 |
803 |
| 790 real_size = size < 0 ? strlen(str) : (gsize)size; |
804 real_size = size < 0 ? strlen(str) : (gsize)size; |
| 791 xpd = g_new0(struct _xmlnode_parser_data, 1); |
805 xpd = g_new0(struct _xmlnode_parser_data, 1); |
| 792 |
806 |
| 793 if (xmlSAXUserParseMemory(&purple_xmlnode_parser_libxml, xpd, str, real_size) < 0) { |
807 if (xmlSAXUserParseMemory(&purple_xmlnode_parser_libxml, xpd, str, real_size) < 0) { |
| 794 while(xpd->current && xpd->current->parent) |
808 while(xpd->current && xpd->current->parent) { |
| 795 xpd->current = xpd->current->parent; |
809 xpd->current = xpd->current->parent; |
| 796 if(xpd->current) |
810 } |
| 797 purple_xmlnode_free(xpd->current); |
811 g_clear_pointer(&xpd->current, purple_xmlnode_free); |
| 798 xpd->current = NULL; |
|
| 799 } |
812 } |
| 800 ret = xpd->current; |
813 ret = xpd->current; |
| 801 if (xpd->error) { |
814 if (xpd->error) { |
| 802 ret = NULL; |
815 ret = NULL; |
| 803 if (xpd->current) |
816 g_clear_pointer(&xpd->current, purple_xmlnode_free); |
| 804 purple_xmlnode_free(xpd->current); |
|
| 805 } |
817 } |
| 806 |
818 |
| 807 g_free(xpd); |
819 g_free(xpd); |
| 808 return ret; |
820 return ret; |
| 809 } |
821 } |
| 817 gsize length; |
829 gsize length; |
| 818 PurpleXmlNode *node = NULL; |
830 PurpleXmlNode *node = NULL; |
| 819 |
831 |
| 820 g_return_val_if_fail(dir != NULL, NULL); |
832 g_return_val_if_fail(dir != NULL, NULL); |
| 821 |
833 |
| 822 purple_debug_misc(process, "Reading file %s from directory %s\n", |
834 purple_debug_misc(process, "Reading file %s from directory %s", |
| 823 filename, dir); |
835 filename, dir); |
| 824 |
836 |
| 825 filename_full = g_build_filename(dir, filename, NULL); |
837 filename_full = g_build_filename(dir, filename, NULL); |
| 826 |
838 |
| 827 if (!g_file_test(filename_full, G_FILE_TEST_EXISTS)) |
839 if (!g_file_test(filename_full, G_FILE_TEST_EXISTS)) { |
| 828 { |
|
| 829 purple_debug_info(process, "File %s does not exist (this is not " |
840 purple_debug_info(process, "File %s does not exist (this is not " |
| 830 "necessarily an error)\n", filename_full); |
841 "necessarily an error)", filename_full); |
| 831 g_free(filename_full); |
842 g_free(filename_full); |
| 832 return NULL; |
843 return NULL; |
| 833 } |
844 } |
| 834 |
845 |
| 835 if (!g_file_get_contents(filename_full, &contents, &length, &error)) |
846 if (!g_file_get_contents(filename_full, &contents, &length, &error)) { |
| 836 { |
847 purple_debug_error(process, "Error reading file %s: %s", |
| 837 purple_debug_error(process, "Error reading file %s: %s\n", |
|
| 838 filename_full, error->message); |
848 filename_full, error->message); |
| 839 g_error_free(error); |
849 g_error_free(error); |
| 840 } |
850 } |
| 841 |
851 |
| 842 if ((contents != NULL) && (length > 0)) |
852 if ((contents != NULL) && (length > 0)) { |
| 843 { |
|
| 844 node = purple_xmlnode_from_str(contents, length); |
853 node = purple_xmlnode_from_str(contents, length); |
| 845 |
854 |
| 846 /* If we were unable to parse the file then save its contents to a backup file */ |
855 /* If we were unable to parse the file then save its contents to a backup file */ |
| 847 if (node == NULL) |
856 if (node == NULL) { |
| 848 { |
|
| 849 gchar *filename_temp, *filename_temp_full; |
857 gchar *filename_temp, *filename_temp_full; |
| 850 |
858 |
| 851 filename_temp = g_strdup_printf("%s~", filename); |
859 filename_temp = g_strdup_printf("%s~", filename); |
| 852 filename_temp_full = g_build_filename(dir, filename_temp, NULL); |
860 filename_temp_full = g_build_filename(dir, filename_temp, NULL); |
| 853 |
861 |
| 854 purple_debug_error("util", "Error parsing file %s. Renaming old " |
862 purple_debug_error("util", "Error parsing file %s. Renaming old " |
| 855 "file to %s\n", filename_full, filename_temp); |
863 "file to %s", filename_full, filename_temp); |
| 856 g_file_set_contents(filename_temp_full, contents, length, NULL); |
864 g_file_set_contents(filename_temp_full, contents, length, NULL); |
| 857 |
865 |
| 858 g_free(filename_temp_full); |
866 g_free(filename_temp_full); |
| 859 g_free(filename_temp); |
867 g_free(filename_temp); |
| 860 } |
868 } |
| 861 |
869 |
| 862 g_free(contents); |
870 g_free(contents); |
| 863 } |
871 } |
| 864 |
872 |
| 865 /* If we could not parse the file then show the user an error message */ |
873 /* If we could not parse the file then show the user an error message */ |
| 866 if (node == NULL) |
874 if (node == NULL) { |
| 867 { |
|
| 868 gchar *title, *msg; |
875 gchar *title, *msg; |
| 869 title = g_strdup_printf(_("Error Reading %s"), filename); |
876 title = g_strdup_printf(_("Error Reading %s"), filename); |
| 870 msg = g_strdup_printf(_("An error was encountered reading your " |
877 msg = g_strdup_printf(_("An error was encountered reading your " |
| 871 "%s. The file has not been loaded, and the old file " |
878 "%s. The file has not been loaded, and the old file " |
| 872 "has been renamed to %s~."), description, filename_full); |
879 "has been renamed to %s~."), description, filename_full); |
| 938 g_return_val_if_fail(node->type == PURPLE_XMLNODE_TYPE_TAG, NULL); |
945 g_return_val_if_fail(node->type == PURPLE_XMLNODE_TYPE_TAG, NULL); |
| 939 |
946 |
| 940 for(sibling = node->next; sibling; sibling = sibling->next) { |
947 for(sibling = node->next; sibling; sibling = sibling->next) { |
| 941 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */ |
948 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */ |
| 942 const char *xmlns = NULL; |
949 const char *xmlns = NULL; |
| 943 if(ns) |
950 if(ns) { |
| 944 xmlns = purple_xmlnode_get_namespace(sibling); |
951 xmlns = purple_xmlnode_get_namespace(sibling); |
| |
952 } |
| 945 |
953 |
| 946 if(sibling->type == PURPLE_XMLNODE_TYPE_TAG && purple_strequal(node->name, sibling->name) && |
954 if(sibling->type == PURPLE_XMLNODE_TYPE_TAG && purple_strequal(node->name, sibling->name) && |
| 947 purple_strequal(ns, xmlns)) |
955 purple_strequal(ns, xmlns)) { |
| 948 return sibling; |
956 return sibling; |
| |
957 } |
| 949 } |
958 } |
| 950 |
959 |
| 951 return NULL; |
960 return NULL; |
| 952 } |
961 } |
| 953 |
962 |