3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 /* A lot of this code at least resembles the code in libxode, but since
23 * libxode uses memory pools that we simply have no need for, I decided to
24 * write my own stuff. Also, re-writing this lets me be as lightweight
25 * as I want to be. Thank you libxode for giving me a good starting point */
26 #define _PURPLE_XMLNODE_C_
31 #include <libxml/parser.h>
35 #include "dbus-maybe.h"
40 # define NEWLINE_S "\r\n"
42 # define NEWLINE_S "\n"
46 new_node(const char *name
, PurpleXmlNodeType type
)
48 PurpleXmlNode
*node
= g_new0(PurpleXmlNode
, 1);
50 node
->name
= g_strdup(name
);
53 // PURPLE_DBUS_REGISTER_POINTER(node, PurpleXmlNode);
59 purple_xmlnode_new(const char *name
)
61 g_return_val_if_fail(name
!= NULL
&& *name
!= '\0', NULL
);
63 return new_node(name
, PURPLE_XMLNODE_TYPE_TAG
);
67 purple_xmlnode_new_child(PurpleXmlNode
*parent
, const char *name
)
71 g_return_val_if_fail(parent
!= NULL
, NULL
);
72 g_return_val_if_fail(name
!= NULL
&& *name
!= '\0', NULL
);
74 node
= new_node(name
, PURPLE_XMLNODE_TYPE_TAG
);
76 purple_xmlnode_insert_child(parent
, node
);
82 purple_xmlnode_insert_child(PurpleXmlNode
*parent
, PurpleXmlNode
*child
)
84 g_return_if_fail(parent
!= NULL
);
85 g_return_if_fail(child
!= NULL
);
87 child
->parent
= parent
;
89 if(parent
->lastchild
) {
90 parent
->lastchild
->next
= child
;
92 parent
->child
= child
;
95 parent
->lastchild
= child
;
99 purple_xmlnode_insert_data(PurpleXmlNode
*node
, const char *data
, gssize size
)
101 PurpleXmlNode
*child
;
104 g_return_if_fail(node
!= NULL
);
105 g_return_if_fail(data
!= NULL
);
106 g_return_if_fail(size
!= 0);
108 real_size
= size
== -1 ? strlen(data
) : (gsize
)size
;
110 child
= new_node(NULL
, PURPLE_XMLNODE_TYPE_DATA
);
112 child
->data
= g_memdup(data
, real_size
);
113 child
->data_sz
= real_size
;
115 purple_xmlnode_insert_child(node
, child
);
119 purple_xmlnode_remove_attrib(PurpleXmlNode
*node
, const char *attr
)
121 PurpleXmlNode
*attr_node
, *sibling
= NULL
;
123 g_return_if_fail(node
!= NULL
);
124 g_return_if_fail(attr
!= NULL
);
126 attr_node
= node
->child
;
128 if(attr_node
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
&&
129 purple_strequal(attr_node
->name
, attr
))
131 if (node
->lastchild
== attr_node
) {
132 node
->lastchild
= sibling
;
134 if (sibling
== NULL
) {
135 node
->child
= attr_node
->next
;
136 purple_xmlnode_free(attr_node
);
137 attr_node
= node
->child
;
139 sibling
->next
= attr_node
->next
;
140 sibling
= attr_node
->next
;
141 purple_xmlnode_free(attr_node
);
147 attr_node
= attr_node
->next
;
154 purple_xmlnode_remove_attrib_with_namespace(PurpleXmlNode
*node
, const char *attr
, const char *xmlns
)
156 PurpleXmlNode
*attr_node
, *sibling
= NULL
;
158 g_return_if_fail(node
!= NULL
);
159 g_return_if_fail(attr
!= NULL
);
161 for(attr_node
= node
->child
; attr_node
; attr_node
= attr_node
->next
)
163 if(attr_node
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
&&
164 purple_strequal(attr
, attr_node
->name
) &&
165 purple_strequal(xmlns
, attr_node
->xmlns
))
167 if(sibling
== NULL
) {
168 node
->child
= attr_node
->next
;
170 sibling
->next
= attr_node
->next
;
172 if (node
->lastchild
== attr_node
) {
173 node
->lastchild
= sibling
;
175 purple_xmlnode_free(attr_node
);
183 purple_xmlnode_set_attrib(PurpleXmlNode
*node
, const char *attr
, const char *value
)
185 purple_xmlnode_remove_attrib(node
, attr
);
186 purple_xmlnode_set_attrib_full(node
, attr
, NULL
, NULL
, value
);
190 purple_xmlnode_set_attrib_full(PurpleXmlNode
*node
, const char *attr
, const char *xmlns
, const char *prefix
, const char *value
)
192 PurpleXmlNode
*attrib_node
;
194 g_return_if_fail(node
!= NULL
);
195 g_return_if_fail(attr
!= NULL
);
196 g_return_if_fail(value
!= NULL
);
198 purple_xmlnode_remove_attrib_with_namespace(node
, attr
, xmlns
);
199 attrib_node
= new_node(attr
, PURPLE_XMLNODE_TYPE_ATTRIB
);
201 attrib_node
->data
= g_strdup(value
);
202 attrib_node
->xmlns
= g_strdup(xmlns
);
203 attrib_node
->prefix
= g_strdup(prefix
);
205 purple_xmlnode_insert_child(node
, attrib_node
);
210 purple_xmlnode_get_attrib(const PurpleXmlNode
*node
, const char *attr
)
214 g_return_val_if_fail(node
!= NULL
, NULL
);
215 g_return_val_if_fail(attr
!= NULL
, NULL
);
217 for(x
= node
->child
; x
; x
= x
->next
) {
218 if(x
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
&& purple_strequal(attr
, x
->name
)) {
227 purple_xmlnode_get_attrib_with_namespace(const PurpleXmlNode
*node
, const char *attr
, const char *xmlns
)
229 const PurpleXmlNode
*x
;
231 g_return_val_if_fail(node
!= NULL
, NULL
);
232 g_return_val_if_fail(attr
!= NULL
, NULL
);
234 for(x
= node
->child
; x
; x
= x
->next
) {
235 if(x
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
&&
236 purple_strequal(attr
, x
->name
) &&
237 purple_strequal(xmlns
, x
->xmlns
)) {
246 void purple_xmlnode_set_namespace(PurpleXmlNode
*node
, const char *xmlns
)
249 g_return_if_fail(node
!= NULL
);
252 node
->xmlns
= g_strdup(xmlns
);
254 if (node
->namespace_map
) {
255 g_hash_table_insert(node
->namespace_map
,
256 g_strdup(""), g_strdup(xmlns
));
262 const char *purple_xmlnode_get_namespace(const PurpleXmlNode
*node
)
264 g_return_val_if_fail(node
!= NULL
, NULL
);
269 const char *purple_xmlnode_get_default_namespace(const PurpleXmlNode
*node
)
271 const PurpleXmlNode
*current_node
;
272 const char *ns
= NULL
;
274 g_return_val_if_fail(node
!= NULL
, NULL
);
277 while (current_node
) {
278 /* If this node does *not* have a prefix, node->xmlns is the default
279 * namespace. Otherwise, it's the prefix namespace.
281 if (!current_node
->prefix
&& current_node
->xmlns
) {
282 return current_node
->xmlns
;
283 } else if (current_node
->namespace_map
) {
284 ns
= g_hash_table_lookup(current_node
->namespace_map
, "");
289 current_node
= current_node
->parent
;
295 void purple_xmlnode_set_prefix(PurpleXmlNode
*node
, const char *prefix
)
297 g_return_if_fail(node
!= NULL
);
299 g_free(node
->prefix
);
300 node
->prefix
= g_strdup(prefix
);
303 const char *purple_xmlnode_get_prefix(const PurpleXmlNode
*node
)
305 g_return_val_if_fail(node
!= NULL
, NULL
);
309 const char *purple_xmlnode_get_prefix_namespace(const PurpleXmlNode
*node
, const char *prefix
)
311 const PurpleXmlNode
*current_node
;
313 g_return_val_if_fail(node
!= NULL
, NULL
);
314 g_return_val_if_fail(prefix
!= NULL
, purple_xmlnode_get_default_namespace(node
));
317 while (current_node
) {
318 if (current_node
->prefix
&& g_str_equal(prefix
, current_node
->prefix
) &&
319 current_node
->xmlns
) {
320 return current_node
->xmlns
;
321 } else if (current_node
->namespace_map
) {
322 const char *ns
= g_hash_table_lookup(current_node
->namespace_map
, prefix
);
328 current_node
= current_node
->parent
;
334 void purple_xmlnode_strip_prefixes(PurpleXmlNode
*node
)
336 PurpleXmlNode
*child
;
339 g_return_if_fail(node
!= NULL
);
341 for (child
= node
->child
; child
; child
= child
->next
) {
342 if (child
->type
== PURPLE_XMLNODE_TYPE_TAG
)
343 purple_xmlnode_strip_prefixes(child
);
346 prefix
= purple_xmlnode_get_prefix(node
);
348 const char *ns
= purple_xmlnode_get_prefix_namespace(node
, prefix
);
349 purple_xmlnode_set_namespace(node
, ns
);
350 purple_xmlnode_set_prefix(node
, NULL
);
352 purple_xmlnode_set_namespace(node
, purple_xmlnode_get_default_namespace(node
));
356 PurpleXmlNode
*purple_xmlnode_get_parent(const PurpleXmlNode
*child
)
358 g_return_val_if_fail(child
!= NULL
, NULL
);
359 return child
->parent
;
363 purple_xmlnode_free(PurpleXmlNode
*node
)
365 PurpleXmlNode
*x
, *y
;
367 g_return_if_fail(node
!= NULL
);
369 /* if we're part of a tree, remove ourselves from the tree first */
370 if(NULL
!= node
->parent
) {
371 if(node
->parent
->child
== node
) {
372 node
->parent
->child
= node
->next
;
373 if (node
->parent
->lastchild
== node
)
374 node
->parent
->lastchild
= node
->next
;
376 PurpleXmlNode
*prev
= node
->parent
->child
;
377 while(prev
&& prev
->next
!= node
) {
381 prev
->next
= node
->next
;
382 if (node
->parent
->lastchild
== node
)
383 node
->parent
->lastchild
= prev
;
388 /* now free our children */
392 purple_xmlnode_free(x
);
396 /* now dispose of ourselves */
400 g_free(node
->prefix
);
402 if(node
->namespace_map
)
403 g_hash_table_destroy(node
->namespace_map
);
405 // PURPLE_DBUS_UNREGISTER_POINTER(node);
410 purple_xmlnode_get_child(const PurpleXmlNode
*parent
, const char *name
)
412 return purple_xmlnode_get_child_with_namespace(parent
, name
, NULL
);
416 purple_xmlnode_get_child_with_namespace(const PurpleXmlNode
*parent
, const char *name
, const char *ns
)
418 PurpleXmlNode
*x
, *ret
= NULL
;
420 char *parent_name
, *child_name
;
422 g_return_val_if_fail(parent
!= NULL
, NULL
);
423 g_return_val_if_fail(name
!= NULL
, NULL
);
425 names
= g_strsplit(name
, "/", 2);
426 parent_name
= names
[0];
427 child_name
= names
[1];
429 for(x
= parent
->child
; x
; x
= x
->next
) {
430 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */
431 const char *xmlns
= NULL
;
433 xmlns
= purple_xmlnode_get_namespace(x
);
435 if(x
->type
== PURPLE_XMLNODE_TYPE_TAG
&& purple_strequal(parent_name
, x
->name
)
436 && purple_strequal(ns
, xmlns
)) {
442 if(child_name
&& ret
)
443 ret
= purple_xmlnode_get_child(ret
, child_name
);
450 purple_xmlnode_get_data(const PurpleXmlNode
*node
)
455 g_return_val_if_fail(node
!= NULL
, NULL
);
457 for(c
= node
->child
; c
; c
= c
->next
) {
458 if(c
->type
== PURPLE_XMLNODE_TYPE_DATA
) {
460 str
= g_string_new_len(c
->data
, c
->data_sz
);
462 str
= g_string_append_len(str
, c
->data
, c
->data_sz
);
469 return g_string_free(str
, FALSE
);
473 purple_xmlnode_get_data_unescaped(const PurpleXmlNode
*node
)
475 char *escaped
= purple_xmlnode_get_data(node
);
477 char *unescaped
= escaped
? purple_unescape_html(escaped
) : NULL
;
485 purple_xmlnode_to_str_foreach_append_ns(const char *key
, const char *value
,
489 g_string_append_printf(buf
, " xmlns:%s='%s'", key
, value
);
491 g_string_append_printf(buf
, " xmlns='%s'", value
);
496 purple_xmlnode_to_str_helper(const PurpleXmlNode
*node
, int *len
, gboolean formatting
, int depth
)
498 GString
*text
= g_string_new("");
500 const PurpleXmlNode
*c
;
501 char *node_name
, *esc
, *esc2
, *tab
= NULL
;
502 gboolean need_end
= FALSE
, pretty
= formatting
;
504 g_return_val_if_fail(node
!= NULL
, NULL
);
506 if(pretty
&& depth
) {
507 tab
= g_strnfill(depth
, '\t');
508 text
= g_string_append(text
, tab
);
511 node_name
= g_markup_escape_text(node
->name
, -1);
512 prefix
= purple_xmlnode_get_prefix(node
);
515 g_string_append_printf(text
, "<%s:%s", prefix
, node_name
);
517 g_string_append_printf(text
, "<%s", node_name
);
520 if (node
->namespace_map
) {
521 g_hash_table_foreach(node
->namespace_map
,
522 (GHFunc
)purple_xmlnode_to_str_foreach_append_ns
, text
);
524 /* Figure out if this node has a different default namespace from parent */
525 const char *xmlns
= NULL
;
526 const char *parent_xmlns
= NULL
;
531 xmlns
= purple_xmlnode_get_default_namespace(node
);
533 parent_xmlns
= purple_xmlnode_get_default_namespace(node
->parent
);
534 if (!purple_strequal(xmlns
, parent_xmlns
))
536 char *escaped_xmlns
= g_markup_escape_text(xmlns
, -1);
537 g_string_append_printf(text
, " xmlns='%s'", escaped_xmlns
);
538 g_free(escaped_xmlns
);
541 for(c
= node
->child
; c
; c
= c
->next
)
543 if(c
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
) {
544 const char *aprefix
= purple_xmlnode_get_prefix(c
);
545 esc
= g_markup_escape_text(c
->name
, -1);
546 esc2
= g_markup_escape_text(c
->data
, -1);
548 g_string_append_printf(text
, " %s:%s='%s'", aprefix
, esc
, esc2
);
550 g_string_append_printf(text
, " %s='%s'", esc
, esc2
);
554 } else if(c
->type
== PURPLE_XMLNODE_TYPE_TAG
|| c
->type
== PURPLE_XMLNODE_TYPE_DATA
) {
555 if(c
->type
== PURPLE_XMLNODE_TYPE_DATA
)
562 g_string_append_printf(text
, ">%s", pretty
? NEWLINE_S
: "");
564 for(c
= node
->child
; c
; c
= c
->next
)
566 if(c
->type
== PURPLE_XMLNODE_TYPE_TAG
) {
568 esc
= purple_xmlnode_to_str_helper(c
, &esc_len
, pretty
, depth
+1);
569 text
= g_string_append_len(text
, esc
, esc_len
);
571 } else if(c
->type
== PURPLE_XMLNODE_TYPE_DATA
&& c
->data_sz
> 0) {
572 esc
= g_markup_escape_text(c
->data
, c
->data_sz
);
573 text
= g_string_append(text
, esc
);
579 text
= g_string_append(text
, tab
);
581 g_string_append_printf(text
, "</%s:%s>%s", prefix
, node_name
, formatting
? NEWLINE_S
: "");
583 g_string_append_printf(text
, "</%s>%s", node_name
, formatting
? NEWLINE_S
: "");
586 g_string_append_printf(text
, "/>%s", formatting
? NEWLINE_S
: "");
596 return g_string_free(text
, FALSE
);
600 purple_xmlnode_to_str(const PurpleXmlNode
*node
, int *len
)
602 return purple_xmlnode_to_str_helper(node
, len
, FALSE
, 0);
606 purple_xmlnode_to_formatted_str(const PurpleXmlNode
*node
, int *len
)
608 char *xml
, *xml_with_declaration
;
610 g_return_val_if_fail(node
!= NULL
, NULL
);
612 xml
= purple_xmlnode_to_str_helper(node
, len
, TRUE
, 0);
613 xml_with_declaration
=
614 g_strdup_printf("<?xml version='1.0' encoding='UTF-8' ?>" NEWLINE_S NEWLINE_S
"%s", xml
);
618 *len
+= sizeof("<?xml version='1.0' encoding='UTF-8' ?>" NEWLINE_S NEWLINE_S
) - 1;
620 return xml_with_declaration
;
623 struct _xmlnode_parser_data
{
624 PurpleXmlNode
*current
;
629 purple_xmlnode_parser_element_start_libxml(void *user_data
,
630 const xmlChar
*element_name
, const xmlChar
*prefix
, const xmlChar
*xmlns
,
631 int nb_namespaces
, const xmlChar
**namespaces
,
632 int nb_attributes
, int nb_defaulted
, const xmlChar
**attributes
)
634 struct _xmlnode_parser_data
*xpd
= user_data
;
638 if(!element_name
|| xpd
->error
) {
642 node
= purple_xmlnode_new_child(xpd
->current
, (const char*) element_name
);
644 node
= purple_xmlnode_new((const char *) element_name
);
646 purple_xmlnode_set_namespace(node
, (const char *) xmlns
);
647 purple_xmlnode_set_prefix(node
, (const char *)prefix
);
649 if (nb_namespaces
!= 0) {
650 node
->namespace_map
= g_hash_table_new_full(
651 g_str_hash
, g_str_equal
, g_free
, g_free
);
653 for (i
= 0, j
= 0; i
< nb_namespaces
; i
++, j
+= 2) {
654 const char *key
= (const char *)namespaces
[j
];
655 const char *val
= (const char *)namespaces
[j
+ 1];
656 g_hash_table_insert(node
->namespace_map
,
657 g_strdup(key
? key
: ""), g_strdup(val
? val
: ""));
661 for(i
=0; i
< nb_attributes
* 5; i
+=5) {
662 const char *name
= (const char *)attributes
[i
];
663 const char *prefix
= (const char *)attributes
[i
+1];
665 int attrib_len
= attributes
[i
+4] - attributes
[i
+3];
666 char *attrib
= g_strndup((const char *)attributes
[i
+3], attrib_len
);
668 attrib
= purple_unescape_text(txt
);
670 purple_xmlnode_set_attrib_full(node
, name
, NULL
, prefix
, attrib
);
679 purple_xmlnode_parser_element_end_libxml(void *user_data
, const xmlChar
*element_name
,
680 const xmlChar
*prefix
, const xmlChar
*xmlns
)
682 struct _xmlnode_parser_data
*xpd
= user_data
;
684 if(!element_name
|| !xpd
->current
|| xpd
->error
)
687 if(xpd
->current
->parent
) {
688 if(!xmlStrcmp((xmlChar
*) xpd
->current
->name
, element_name
))
689 xpd
->current
= xpd
->current
->parent
;
694 purple_xmlnode_parser_element_text_libxml(void *user_data
, const xmlChar
*text
, int text_len
)
696 struct _xmlnode_parser_data
*xpd
= user_data
;
698 if(!xpd
->current
|| xpd
->error
)
701 if(!text
|| !text_len
)
704 purple_xmlnode_insert_data(xpd
->current
, (const char*) text
, text_len
);
708 purple_xmlnode_parser_error_libxml(void *user_data
, const char *msg
, ...)
710 struct _xmlnode_parser_data
*xpd
= user_data
;
717 vsnprintf(errmsg
, sizeof(errmsg
), msg
, args
);
720 purple_debug_error("xmlnode", "Error parsing xml file: %s", errmsg
);
724 purple_xmlnode_parser_structural_error_libxml(void *user_data
, xmlErrorPtr error
)
726 struct _xmlnode_parser_data
*xpd
= user_data
;
728 if (error
&& (error
->level
== XML_ERR_ERROR
||
729 error
->level
== XML_ERR_FATAL
)) {
731 purple_debug_error("xmlnode", "XML parser error for PurpleXmlNode %p: "
732 "Domain %i, code %i, level %i: %s",
733 user_data
, error
->domain
, error
->code
, error
->level
,
734 error
->message
? error
->message
: "(null)\n");
736 purple_debug_warning("xmlnode", "XML parser error for PurpleXmlNode %p: "
737 "Domain %i, code %i, level %i: %s",
738 user_data
, error
->domain
, error
->code
, error
->level
,
739 error
->message
? error
->message
: "(null)\n");
741 purple_debug_warning("xmlnode", "XML parser error for PurpleXmlNode %p\n",
745 static xmlSAXHandler purple_xmlnode_parser_libxml
= {
746 NULL
, /* internalSubset */
747 NULL
, /* isStandalone */
748 NULL
, /* hasInternalSubset */
749 NULL
, /* hasExternalSubset */
750 NULL
, /* resolveEntity */
751 NULL
, /* getEntity */
752 NULL
, /* entityDecl */
753 NULL
, /* notationDecl */
754 NULL
, /* attributeDecl */
755 NULL
, /* elementDecl */
756 NULL
, /* unparsedEntityDecl */
757 NULL
, /* setDocumentLocator */
758 NULL
, /* startDocument */
759 NULL
, /* endDocument */
760 NULL
, /* startElement */
761 NULL
, /* endElement */
762 NULL
, /* reference */
763 purple_xmlnode_parser_element_text_libxml
, /* characters */
764 NULL
, /* ignorableWhitespace */
765 NULL
, /* processingInstruction */
768 purple_xmlnode_parser_error_libxml
, /* error */
769 NULL
, /* fatalError */
770 NULL
, /* getParameterEntity */
771 NULL
, /* cdataBlock */
772 NULL
, /* externalSubset */
773 XML_SAX2_MAGIC
, /* initialized */
775 purple_xmlnode_parser_element_start_libxml
, /* startElementNs */
776 purple_xmlnode_parser_element_end_libxml
, /* endElementNs */
777 purple_xmlnode_parser_structural_error_libxml
, /* serror */
781 purple_xmlnode_from_str(const char *str
, gssize size
)
783 struct _xmlnode_parser_data
*xpd
;
787 g_return_val_if_fail(str
!= NULL
, NULL
);
789 real_size
= size
< 0 ? strlen(str
) : (gsize
)size
;
790 xpd
= g_new0(struct _xmlnode_parser_data
, 1);
792 if (xmlSAXUserParseMemory(&purple_xmlnode_parser_libxml
, xpd
, str
, real_size
) < 0) {
793 while(xpd
->current
&& xpd
->current
->parent
)
794 xpd
->current
= xpd
->current
->parent
;
796 purple_xmlnode_free(xpd
->current
);
803 purple_xmlnode_free(xpd
->current
);
811 purple_xmlnode_from_file(const char *dir
, const char *filename
, const char *description
, const char *process
)
813 gchar
*filename_full
;
814 GError
*error
= NULL
;
815 gchar
*contents
= NULL
;
817 PurpleXmlNode
*node
= NULL
;
819 g_return_val_if_fail(dir
!= NULL
, NULL
);
821 purple_debug_misc(process
, "Reading file %s from directory %s\n",
824 filename_full
= g_build_filename(dir
, filename
, NULL
);
826 if (!g_file_test(filename_full
, G_FILE_TEST_EXISTS
))
828 purple_debug_info(process
, "File %s does not exist (this is not "
829 "necessarily an error)\n", filename_full
);
830 g_free(filename_full
);
834 if (!g_file_get_contents(filename_full
, &contents
, &length
, &error
))
836 purple_debug_error(process
, "Error reading file %s: %s\n",
837 filename_full
, error
->message
);
841 if ((contents
!= NULL
) && (length
> 0))
843 node
= purple_xmlnode_from_str(contents
, length
);
845 /* If we were unable to parse the file then save its contents to a backup file */
848 gchar
*filename_temp
, *filename_temp_full
;
850 filename_temp
= g_strdup_printf("%s~", filename
);
851 filename_temp_full
= g_build_filename(dir
, filename_temp
, NULL
);
853 purple_debug_error("util", "Error parsing file %s. Renaming old "
854 "file to %s\n", filename_full
, filename_temp
);
855 purple_util_write_data_to_file_absolute(filename_temp_full
, contents
, length
);
857 g_free(filename_temp_full
);
858 g_free(filename_temp
);
864 /* If we could not parse the file then show the user an error message */
868 title
= g_strdup_printf(_("Error Reading %s"), filename
);
869 msg
= g_strdup_printf(_("An error was encountered reading your "
870 "%s. The file has not been loaded, and the old file "
871 "has been renamed to %s~."), description
, filename_full
);
872 purple_notify_error(NULL
, NULL
, title
, msg
, NULL
);
877 g_free(filename_full
);
883 purple_xmlnode_copy_foreach_ns(gpointer key
, gpointer value
, gpointer user_data
)
885 GHashTable
*ret
= (GHashTable
*)user_data
;
886 g_hash_table_insert(ret
, g_strdup(key
), g_strdup(value
));
890 purple_xmlnode_copy(const PurpleXmlNode
*src
)
893 PurpleXmlNode
*child
;
894 PurpleXmlNode
*sibling
= NULL
;
896 g_return_val_if_fail(src
!= NULL
, NULL
);
898 ret
= new_node(src
->name
, src
->type
);
899 ret
->xmlns
= g_strdup(src
->xmlns
);
902 ret
->data
= g_memdup(src
->data
, src
->data_sz
);
903 ret
->data_sz
= src
->data_sz
;
905 ret
->data
= g_strdup(src
->data
);
908 ret
->prefix
= g_strdup(src
->prefix
);
909 if (src
->namespace_map
) {
910 ret
->namespace_map
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
912 g_hash_table_foreach(src
->namespace_map
, purple_xmlnode_copy_foreach_ns
, ret
->namespace_map
);
915 for (child
= src
->child
; child
; child
= child
->next
) {
917 sibling
->next
= purple_xmlnode_copy(child
);
918 sibling
= sibling
->next
;
920 ret
->child
= sibling
= purple_xmlnode_copy(child
);
922 sibling
->parent
= ret
;
925 ret
->lastchild
= sibling
;
931 purple_xmlnode_get_next_twin(PurpleXmlNode
*node
)
933 PurpleXmlNode
*sibling
;
934 const char *ns
= purple_xmlnode_get_namespace(node
);
936 g_return_val_if_fail(node
!= NULL
, NULL
);
937 g_return_val_if_fail(node
->type
== PURPLE_XMLNODE_TYPE_TAG
, NULL
);
939 for(sibling
= node
->next
; sibling
; sibling
= sibling
->next
) {
940 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */
941 const char *xmlns
= NULL
;
943 xmlns
= purple_xmlnode_get_namespace(sibling
);
945 if(sibling
->type
== PURPLE_XMLNODE_TYPE_TAG
&& purple_strequal(node
->name
, sibling
->name
) &&
946 purple_strequal(ns
, xmlns
))
954 purple_xmlnode_get_type(void)
956 static GType type
= 0;
959 type
= g_boxed_type_register_static("PurpleXmlNode",
960 (GBoxedCopyFunc
)purple_xmlnode_copy
,
961 (GBoxedFreeFunc
)purple_xmlnode_free
);