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 */
30 #include <libxml/parser.h>
38 # define NEWLINE_S "\r\n"
40 # define NEWLINE_S "\n"
44 new_node(const char *name
, PurpleXmlNodeType type
)
46 PurpleXmlNode
*node
= g_new0(PurpleXmlNode
, 1);
48 node
->name
= g_strdup(name
);
55 purple_xmlnode_new(const char *name
)
57 g_return_val_if_fail(name
!= NULL
&& *name
!= '\0', NULL
);
59 return new_node(name
, PURPLE_XMLNODE_TYPE_TAG
);
63 purple_xmlnode_new_child(PurpleXmlNode
*parent
, const char *name
)
67 g_return_val_if_fail(parent
!= NULL
, NULL
);
68 g_return_val_if_fail(name
!= NULL
&& *name
!= '\0', NULL
);
70 node
= new_node(name
, PURPLE_XMLNODE_TYPE_TAG
);
72 purple_xmlnode_insert_child(parent
, node
);
78 purple_xmlnode_insert_child(PurpleXmlNode
*parent
, PurpleXmlNode
*child
)
80 g_return_if_fail(parent
!= NULL
);
81 g_return_if_fail(child
!= NULL
);
83 child
->parent
= parent
;
85 if(parent
->lastchild
) {
86 parent
->lastchild
->next
= child
;
88 parent
->child
= child
;
91 parent
->lastchild
= child
;
95 purple_xmlnode_insert_data(PurpleXmlNode
*node
, const char *data
, gssize size
)
100 g_return_if_fail(node
!= NULL
);
101 g_return_if_fail(data
!= NULL
);
102 g_return_if_fail(size
!= 0);
104 real_size
= size
== -1 ? strlen(data
) : (gsize
)size
;
106 child
= new_node(NULL
, PURPLE_XMLNODE_TYPE_DATA
);
108 child
->data
= g_memdup(data
, real_size
);
109 child
->data_sz
= real_size
;
111 purple_xmlnode_insert_child(node
, child
);
115 purple_xmlnode_remove_attrib(PurpleXmlNode
*node
, const char *attr
)
117 PurpleXmlNode
*attr_node
, *sibling
= NULL
;
119 g_return_if_fail(node
!= NULL
);
120 g_return_if_fail(attr
!= NULL
);
122 attr_node
= node
->child
;
124 if(attr_node
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
&&
125 purple_strequal(attr_node
->name
, attr
))
127 if (node
->lastchild
== attr_node
) {
128 node
->lastchild
= sibling
;
130 if (sibling
== NULL
) {
131 node
->child
= attr_node
->next
;
132 purple_xmlnode_free(attr_node
);
133 attr_node
= node
->child
;
135 sibling
->next
= attr_node
->next
;
136 sibling
= attr_node
->next
;
137 purple_xmlnode_free(attr_node
);
143 attr_node
= attr_node
->next
;
150 purple_xmlnode_remove_attrib_with_namespace(PurpleXmlNode
*node
, const char *attr
, const char *xmlns
)
152 PurpleXmlNode
*attr_node
, *sibling
= NULL
;
154 g_return_if_fail(node
!= NULL
);
155 g_return_if_fail(attr
!= NULL
);
157 for(attr_node
= node
->child
; attr_node
; attr_node
= attr_node
->next
)
159 if(attr_node
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
&&
160 purple_strequal(attr
, attr_node
->name
) &&
161 purple_strequal(xmlns
, attr_node
->xmlns
))
163 if(sibling
== NULL
) {
164 node
->child
= attr_node
->next
;
166 sibling
->next
= attr_node
->next
;
168 if (node
->lastchild
== attr_node
) {
169 node
->lastchild
= sibling
;
171 purple_xmlnode_free(attr_node
);
179 purple_xmlnode_set_attrib(PurpleXmlNode
*node
, const char *attr
, const char *value
)
181 purple_xmlnode_remove_attrib(node
, attr
);
182 purple_xmlnode_set_attrib_full(node
, attr
, NULL
, NULL
, value
);
186 purple_xmlnode_set_attrib_full(PurpleXmlNode
*node
, const char *attr
, const char *xmlns
, const char *prefix
, const char *value
)
188 PurpleXmlNode
*attrib_node
;
190 g_return_if_fail(node
!= NULL
);
191 g_return_if_fail(attr
!= NULL
);
192 g_return_if_fail(value
!= NULL
);
194 purple_xmlnode_remove_attrib_with_namespace(node
, attr
, xmlns
);
195 attrib_node
= new_node(attr
, PURPLE_XMLNODE_TYPE_ATTRIB
);
197 attrib_node
->data
= g_strdup(value
);
198 attrib_node
->xmlns
= g_strdup(xmlns
);
199 attrib_node
->prefix
= g_strdup(prefix
);
201 purple_xmlnode_insert_child(node
, attrib_node
);
206 purple_xmlnode_get_attrib(const PurpleXmlNode
*node
, const char *attr
)
210 g_return_val_if_fail(node
!= NULL
, NULL
);
211 g_return_val_if_fail(attr
!= NULL
, NULL
);
213 for(x
= node
->child
; x
; x
= x
->next
) {
214 if(x
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
&& purple_strequal(attr
, x
->name
)) {
223 purple_xmlnode_get_attrib_with_namespace(const PurpleXmlNode
*node
, const char *attr
, const char *xmlns
)
225 const PurpleXmlNode
*x
;
227 g_return_val_if_fail(node
!= NULL
, NULL
);
228 g_return_val_if_fail(attr
!= NULL
, NULL
);
230 for(x
= node
->child
; x
; x
= x
->next
) {
231 if(x
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
&&
232 purple_strequal(attr
, x
->name
) &&
233 purple_strequal(xmlns
, x
->xmlns
)) {
242 void purple_xmlnode_set_namespace(PurpleXmlNode
*node
, const char *xmlns
)
245 g_return_if_fail(node
!= NULL
);
248 node
->xmlns
= g_strdup(xmlns
);
250 if (node
->namespace_map
) {
251 g_hash_table_insert(node
->namespace_map
,
252 g_strdup(""), g_strdup(xmlns
));
258 const char *purple_xmlnode_get_namespace(const PurpleXmlNode
*node
)
260 g_return_val_if_fail(node
!= NULL
, NULL
);
265 const char *purple_xmlnode_get_default_namespace(const PurpleXmlNode
*node
)
267 const PurpleXmlNode
*current_node
;
268 const char *ns
= NULL
;
270 g_return_val_if_fail(node
!= NULL
, NULL
);
273 while (current_node
) {
274 /* If this node does *not* have a prefix, node->xmlns is the default
275 * namespace. Otherwise, it's the prefix namespace.
277 if (!current_node
->prefix
&& current_node
->xmlns
) {
278 return current_node
->xmlns
;
279 } else if (current_node
->namespace_map
) {
280 ns
= g_hash_table_lookup(current_node
->namespace_map
, "");
285 current_node
= current_node
->parent
;
291 void purple_xmlnode_set_prefix(PurpleXmlNode
*node
, const char *prefix
)
293 g_return_if_fail(node
!= NULL
);
295 g_free(node
->prefix
);
296 node
->prefix
= g_strdup(prefix
);
299 const char *purple_xmlnode_get_prefix(const PurpleXmlNode
*node
)
301 g_return_val_if_fail(node
!= NULL
, NULL
);
305 const char *purple_xmlnode_get_prefix_namespace(const PurpleXmlNode
*node
, const char *prefix
)
307 const PurpleXmlNode
*current_node
;
309 g_return_val_if_fail(node
!= NULL
, NULL
);
310 g_return_val_if_fail(prefix
!= NULL
, purple_xmlnode_get_default_namespace(node
));
313 while (current_node
) {
314 if (current_node
->prefix
&& g_str_equal(prefix
, current_node
->prefix
) &&
315 current_node
->xmlns
) {
316 return current_node
->xmlns
;
317 } else if (current_node
->namespace_map
) {
318 const char *ns
= g_hash_table_lookup(current_node
->namespace_map
, prefix
);
324 current_node
= current_node
->parent
;
330 void purple_xmlnode_strip_prefixes(PurpleXmlNode
*node
)
332 PurpleXmlNode
*child
;
335 g_return_if_fail(node
!= NULL
);
337 for (child
= node
->child
; child
; child
= child
->next
) {
338 if (child
->type
== PURPLE_XMLNODE_TYPE_TAG
)
339 purple_xmlnode_strip_prefixes(child
);
342 prefix
= purple_xmlnode_get_prefix(node
);
344 const char *ns
= purple_xmlnode_get_prefix_namespace(node
, prefix
);
345 purple_xmlnode_set_namespace(node
, ns
);
346 purple_xmlnode_set_prefix(node
, NULL
);
348 purple_xmlnode_set_namespace(node
, purple_xmlnode_get_default_namespace(node
));
352 PurpleXmlNode
*purple_xmlnode_get_parent(const PurpleXmlNode
*child
)
354 g_return_val_if_fail(child
!= NULL
, NULL
);
355 return child
->parent
;
359 purple_xmlnode_free(PurpleXmlNode
*node
)
361 PurpleXmlNode
*x
, *y
;
363 g_return_if_fail(node
!= NULL
);
365 /* if we're part of a tree, remove ourselves from the tree first */
366 if(NULL
!= node
->parent
) {
367 if(node
->parent
->child
== node
) {
368 node
->parent
->child
= node
->next
;
369 if (node
->parent
->lastchild
== node
)
370 node
->parent
->lastchild
= node
->next
;
372 PurpleXmlNode
*prev
= node
->parent
->child
;
373 while(prev
&& prev
->next
!= node
) {
377 prev
->next
= node
->next
;
378 if (node
->parent
->lastchild
== node
)
379 node
->parent
->lastchild
= prev
;
384 /* now free our children */
388 purple_xmlnode_free(x
);
392 /* now dispose of ourselves */
396 g_free(node
->prefix
);
398 if(node
->namespace_map
)
399 g_hash_table_destroy(node
->namespace_map
);
405 purple_xmlnode_get_child(const PurpleXmlNode
*parent
, const char *name
)
407 return purple_xmlnode_get_child_with_namespace(parent
, name
, NULL
);
411 purple_xmlnode_get_child_with_namespace(const PurpleXmlNode
*parent
, const char *name
, const char *ns
)
413 PurpleXmlNode
*x
, *ret
= NULL
;
415 char *parent_name
, *child_name
;
417 g_return_val_if_fail(parent
!= NULL
, NULL
);
418 g_return_val_if_fail(name
!= NULL
, NULL
);
420 names
= g_strsplit(name
, "/", 2);
421 parent_name
= names
[0];
422 child_name
= names
[1];
424 for(x
= parent
->child
; x
; x
= x
->next
) {
425 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */
426 const char *xmlns
= NULL
;
428 xmlns
= purple_xmlnode_get_namespace(x
);
430 if(x
->type
== PURPLE_XMLNODE_TYPE_TAG
&& purple_strequal(parent_name
, x
->name
)
431 && purple_strequal(ns
, xmlns
)) {
437 if(child_name
&& ret
)
438 ret
= purple_xmlnode_get_child(ret
, child_name
);
445 purple_xmlnode_get_data(const PurpleXmlNode
*node
)
450 g_return_val_if_fail(node
!= NULL
, NULL
);
452 for(c
= node
->child
; c
; c
= c
->next
) {
453 if(c
->type
== PURPLE_XMLNODE_TYPE_DATA
) {
455 str
= g_string_new_len(c
->data
, c
->data_sz
);
457 str
= g_string_append_len(str
, c
->data
, c
->data_sz
);
464 return g_string_free(str
, FALSE
);
468 purple_xmlnode_get_data_unescaped(const PurpleXmlNode
*node
)
470 char *escaped
= purple_xmlnode_get_data(node
);
472 char *unescaped
= escaped
? purple_unescape_html(escaped
) : NULL
;
480 purple_xmlnode_to_str_foreach_append_ns(const char *key
, const char *value
,
484 g_string_append_printf(buf
, " xmlns:%s='%s'", key
, value
);
486 g_string_append_printf(buf
, " xmlns='%s'", value
);
491 purple_xmlnode_to_str_helper(const PurpleXmlNode
*node
, int *len
, gboolean formatting
, int depth
)
493 GString
*text
= g_string_new("");
495 const PurpleXmlNode
*c
;
496 char *node_name
, *esc
, *esc2
, *tab
= NULL
;
497 gboolean need_end
= FALSE
, pretty
= formatting
;
499 g_return_val_if_fail(node
!= NULL
, NULL
);
501 if(pretty
&& depth
) {
502 tab
= g_strnfill(depth
, '\t');
503 text
= g_string_append(text
, tab
);
506 node_name
= g_markup_escape_text(node
->name
, -1);
507 prefix
= purple_xmlnode_get_prefix(node
);
510 g_string_append_printf(text
, "<%s:%s", prefix
, node_name
);
512 g_string_append_printf(text
, "<%s", node_name
);
515 if (node
->namespace_map
) {
516 g_hash_table_foreach(node
->namespace_map
,
517 (GHFunc
)purple_xmlnode_to_str_foreach_append_ns
, text
);
519 /* Figure out if this node has a different default namespace from parent */
520 const char *xmlns
= NULL
;
521 const char *parent_xmlns
= NULL
;
526 xmlns
= purple_xmlnode_get_default_namespace(node
);
528 parent_xmlns
= purple_xmlnode_get_default_namespace(node
->parent
);
529 if (!purple_strequal(xmlns
, parent_xmlns
))
531 char *escaped_xmlns
= g_markup_escape_text(xmlns
, -1);
532 g_string_append_printf(text
, " xmlns='%s'", escaped_xmlns
);
533 g_free(escaped_xmlns
);
536 for(c
= node
->child
; c
; c
= c
->next
)
538 if(c
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
) {
539 const char *aprefix
= purple_xmlnode_get_prefix(c
);
540 esc
= g_markup_escape_text(c
->name
, -1);
541 esc2
= g_markup_escape_text(c
->data
, -1);
543 g_string_append_printf(text
, " %s:%s='%s'", aprefix
, esc
, esc2
);
545 g_string_append_printf(text
, " %s='%s'", esc
, esc2
);
549 } else if(c
->type
== PURPLE_XMLNODE_TYPE_TAG
|| c
->type
== PURPLE_XMLNODE_TYPE_DATA
) {
550 if(c
->type
== PURPLE_XMLNODE_TYPE_DATA
)
557 g_string_append_printf(text
, ">%s", pretty
? NEWLINE_S
: "");
559 for(c
= node
->child
; c
; c
= c
->next
)
561 if(c
->type
== PURPLE_XMLNODE_TYPE_TAG
) {
563 esc
= purple_xmlnode_to_str_helper(c
, &esc_len
, pretty
, depth
+1);
564 text
= g_string_append_len(text
, esc
, esc_len
);
566 } else if(c
->type
== PURPLE_XMLNODE_TYPE_DATA
&& c
->data_sz
> 0) {
567 esc
= g_markup_escape_text(c
->data
, c
->data_sz
);
568 text
= g_string_append(text
, esc
);
574 text
= g_string_append(text
, tab
);
576 g_string_append_printf(text
, "</%s:%s>%s", prefix
, node_name
, formatting
? NEWLINE_S
: "");
578 g_string_append_printf(text
, "</%s>%s", node_name
, formatting
? NEWLINE_S
: "");
581 g_string_append_printf(text
, "/>%s", formatting
? NEWLINE_S
: "");
591 return g_string_free(text
, FALSE
);
595 purple_xmlnode_to_str(const PurpleXmlNode
*node
, int *len
)
597 return purple_xmlnode_to_str_helper(node
, len
, FALSE
, 0);
601 purple_xmlnode_to_formatted_str(const PurpleXmlNode
*node
, int *len
)
603 char *xml
, *xml_with_declaration
;
605 g_return_val_if_fail(node
!= NULL
, NULL
);
607 xml
= purple_xmlnode_to_str_helper(node
, len
, TRUE
, 0);
608 xml_with_declaration
=
609 g_strdup_printf("<?xml version='1.0' encoding='UTF-8' ?>" NEWLINE_S NEWLINE_S
"%s", xml
);
613 *len
+= sizeof("<?xml version='1.0' encoding='UTF-8' ?>" NEWLINE_S NEWLINE_S
) - 1;
615 return xml_with_declaration
;
618 struct _xmlnode_parser_data
{
619 PurpleXmlNode
*current
;
624 purple_xmlnode_parser_element_start_libxml(void *user_data
,
625 const xmlChar
*element_name
, const xmlChar
*prefix
, const xmlChar
*xmlns
,
626 int nb_namespaces
, const xmlChar
**namespaces
,
627 int nb_attributes
, int nb_defaulted
, const xmlChar
**attributes
)
629 struct _xmlnode_parser_data
*xpd
= user_data
;
633 if(!element_name
|| xpd
->error
) {
637 node
= purple_xmlnode_new_child(xpd
->current
, (const char*) element_name
);
639 node
= purple_xmlnode_new((const char *) element_name
);
641 purple_xmlnode_set_namespace(node
, (const char *) xmlns
);
642 purple_xmlnode_set_prefix(node
, (const char *)prefix
);
644 if (nb_namespaces
!= 0) {
645 node
->namespace_map
= g_hash_table_new_full(
646 g_str_hash
, g_str_equal
, g_free
, g_free
);
648 for (i
= 0, j
= 0; i
< nb_namespaces
; i
++, j
+= 2) {
649 const char *key
= (const char *)namespaces
[j
];
650 const char *val
= (const char *)namespaces
[j
+ 1];
651 g_hash_table_insert(node
->namespace_map
,
652 g_strdup(key
? key
: ""), g_strdup(val
? val
: ""));
656 for(i
=0; i
< nb_attributes
* 5; i
+=5) {
657 const char *name
= (const char *)attributes
[i
];
658 const char *prefix
= (const char *)attributes
[i
+1];
660 int attrib_len
= attributes
[i
+4] - attributes
[i
+3];
661 char *attrib
= g_strndup((const char *)attributes
[i
+3], attrib_len
);
663 attrib
= purple_unescape_text(txt
);
665 purple_xmlnode_set_attrib_full(node
, name
, NULL
, prefix
, attrib
);
674 purple_xmlnode_parser_element_end_libxml(void *user_data
, const xmlChar
*element_name
,
675 const xmlChar
*prefix
, const xmlChar
*xmlns
)
677 struct _xmlnode_parser_data
*xpd
= user_data
;
679 if(!element_name
|| !xpd
->current
|| xpd
->error
)
682 if(xpd
->current
->parent
) {
683 if(!xmlStrcmp((xmlChar
*) xpd
->current
->name
, element_name
))
684 xpd
->current
= xpd
->current
->parent
;
689 purple_xmlnode_parser_element_text_libxml(void *user_data
, const xmlChar
*text
, int text_len
)
691 struct _xmlnode_parser_data
*xpd
= user_data
;
693 if(!xpd
->current
|| xpd
->error
)
696 if(!text
|| !text_len
)
699 purple_xmlnode_insert_data(xpd
->current
, (const char*) text
, text_len
);
703 purple_xmlnode_parser_error_libxml(void *user_data
, const char *msg
, ...)
705 struct _xmlnode_parser_data
*xpd
= user_data
;
712 vsnprintf(errmsg
, sizeof(errmsg
), msg
, args
);
715 purple_debug_error("xmlnode", "Error parsing xml file: %s", errmsg
);
719 purple_xmlnode_parser_structural_error_libxml(void *user_data
, xmlErrorPtr error
)
721 struct _xmlnode_parser_data
*xpd
= user_data
;
723 if (error
&& (error
->level
== XML_ERR_ERROR
||
724 error
->level
== XML_ERR_FATAL
)) {
726 purple_debug_error("xmlnode", "XML parser error for PurpleXmlNode %p: "
727 "Domain %i, code %i, level %i: %s",
728 user_data
, error
->domain
, error
->code
, error
->level
,
729 error
->message
? error
->message
: "(null)\n");
731 purple_debug_warning("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\n",
740 static xmlSAXHandler purple_xmlnode_parser_libxml
= {
741 NULL
, /* internalSubset */
742 NULL
, /* isStandalone */
743 NULL
, /* hasInternalSubset */
744 NULL
, /* hasExternalSubset */
745 NULL
, /* resolveEntity */
746 NULL
, /* getEntity */
747 NULL
, /* entityDecl */
748 NULL
, /* notationDecl */
749 NULL
, /* attributeDecl */
750 NULL
, /* elementDecl */
751 NULL
, /* unparsedEntityDecl */
752 NULL
, /* setDocumentLocator */
753 NULL
, /* startDocument */
754 NULL
, /* endDocument */
755 NULL
, /* startElement */
756 NULL
, /* endElement */
757 NULL
, /* reference */
758 purple_xmlnode_parser_element_text_libxml
, /* characters */
759 NULL
, /* ignorableWhitespace */
760 NULL
, /* processingInstruction */
763 purple_xmlnode_parser_error_libxml
, /* error */
764 NULL
, /* fatalError */
765 NULL
, /* getParameterEntity */
766 NULL
, /* cdataBlock */
767 NULL
, /* externalSubset */
768 XML_SAX2_MAGIC
, /* initialized */
770 purple_xmlnode_parser_element_start_libxml
, /* startElementNs */
771 purple_xmlnode_parser_element_end_libxml
, /* endElementNs */
772 purple_xmlnode_parser_structural_error_libxml
, /* serror */
776 purple_xmlnode_from_str(const char *str
, gssize size
)
778 struct _xmlnode_parser_data
*xpd
;
782 g_return_val_if_fail(str
!= NULL
, NULL
);
784 real_size
= size
< 0 ? strlen(str
) : (gsize
)size
;
785 xpd
= g_new0(struct _xmlnode_parser_data
, 1);
787 if (xmlSAXUserParseMemory(&purple_xmlnode_parser_libxml
, xpd
, str
, real_size
) < 0) {
788 while(xpd
->current
&& xpd
->current
->parent
)
789 xpd
->current
= xpd
->current
->parent
;
791 purple_xmlnode_free(xpd
->current
);
798 purple_xmlnode_free(xpd
->current
);
806 purple_xmlnode_from_file(const char *dir
, const char *filename
, const char *description
, const char *process
)
808 gchar
*filename_full
;
809 GError
*error
= NULL
;
810 gchar
*contents
= NULL
;
812 PurpleXmlNode
*node
= NULL
;
814 g_return_val_if_fail(dir
!= NULL
, NULL
);
816 purple_debug_misc(process
, "Reading file %s from directory %s\n",
819 filename_full
= g_build_filename(dir
, filename
, NULL
);
821 if (!g_file_test(filename_full
, G_FILE_TEST_EXISTS
))
823 purple_debug_info(process
, "File %s does not exist (this is not "
824 "necessarily an error)\n", filename_full
);
825 g_free(filename_full
);
829 if (!g_file_get_contents(filename_full
, &contents
, &length
, &error
))
831 purple_debug_error(process
, "Error reading file %s: %s\n",
832 filename_full
, error
->message
);
836 if ((contents
!= NULL
) && (length
> 0))
838 node
= purple_xmlnode_from_str(contents
, length
);
840 /* If we were unable to parse the file then save its contents to a backup file */
843 gchar
*filename_temp
, *filename_temp_full
;
845 filename_temp
= g_strdup_printf("%s~", filename
);
846 filename_temp_full
= g_build_filename(dir
, filename_temp
, NULL
);
848 purple_debug_error("util", "Error parsing file %s. Renaming old "
849 "file to %s\n", filename_full
, filename_temp
);
850 purple_util_write_data_to_file_absolute(filename_temp_full
, contents
, length
);
852 g_free(filename_temp_full
);
853 g_free(filename_temp
);
859 /* If we could not parse the file then show the user an error message */
863 title
= g_strdup_printf(_("Error Reading %s"), filename
);
864 msg
= g_strdup_printf(_("An error was encountered reading your "
865 "%s. The file has not been loaded, and the old file "
866 "has been renamed to %s~."), description
, filename_full
);
867 purple_notify_error(NULL
, NULL
, title
, msg
, NULL
);
872 g_free(filename_full
);
878 purple_xmlnode_copy_foreach_ns(gpointer key
, gpointer value
, gpointer user_data
)
880 GHashTable
*ret
= (GHashTable
*)user_data
;
881 g_hash_table_insert(ret
, g_strdup(key
), g_strdup(value
));
885 purple_xmlnode_copy(const PurpleXmlNode
*src
)
888 PurpleXmlNode
*child
;
889 PurpleXmlNode
*sibling
= NULL
;
891 g_return_val_if_fail(src
!= NULL
, NULL
);
893 ret
= new_node(src
->name
, src
->type
);
894 ret
->xmlns
= g_strdup(src
->xmlns
);
897 ret
->data
= g_memdup(src
->data
, src
->data_sz
);
898 ret
->data_sz
= src
->data_sz
;
900 ret
->data
= g_strdup(src
->data
);
903 ret
->prefix
= g_strdup(src
->prefix
);
904 if (src
->namespace_map
) {
905 ret
->namespace_map
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
907 g_hash_table_foreach(src
->namespace_map
, purple_xmlnode_copy_foreach_ns
, ret
->namespace_map
);
910 for (child
= src
->child
; child
; child
= child
->next
) {
912 sibling
->next
= purple_xmlnode_copy(child
);
913 sibling
= sibling
->next
;
915 ret
->child
= sibling
= purple_xmlnode_copy(child
);
917 sibling
->parent
= ret
;
920 ret
->lastchild
= sibling
;
926 purple_xmlnode_get_next_twin(PurpleXmlNode
*node
)
928 PurpleXmlNode
*sibling
;
929 const char *ns
= purple_xmlnode_get_namespace(node
);
931 g_return_val_if_fail(node
!= NULL
, NULL
);
932 g_return_val_if_fail(node
->type
== PURPLE_XMLNODE_TYPE_TAG
, NULL
);
934 for(sibling
= node
->next
; sibling
; sibling
= sibling
->next
) {
935 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */
936 const char *xmlns
= NULL
;
938 xmlns
= purple_xmlnode_get_namespace(sibling
);
940 if(sibling
->type
== PURPLE_XMLNODE_TYPE_TAG
&& purple_strequal(node
->name
, sibling
->name
) &&
941 purple_strequal(ns
, xmlns
))
949 purple_xmlnode_get_type(void)
951 static GType type
= 0;
954 type
= g_boxed_type_register_static("PurpleXmlNode",
955 (GBoxedCopyFunc
)purple_xmlnode_copy
,
956 (GBoxedFreeFunc
)purple_xmlnode_free
);