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
)
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 text
= g_string_new("");
503 if(pretty
&& depth
) {
504 tab
= g_strnfill(depth
, '\t');
505 text
= g_string_append(text
, tab
);
508 node_name
= g_markup_escape_text(node
->name
, -1);
509 prefix
= purple_xmlnode_get_prefix(node
);
512 g_string_append_printf(text
, "<%s:%s", prefix
, node_name
);
514 g_string_append_printf(text
, "<%s", node_name
);
517 if (node
->namespace_map
) {
518 g_hash_table_foreach(node
->namespace_map
,
519 (GHFunc
)purple_xmlnode_to_str_foreach_append_ns
, text
);
521 /* Figure out if this node has a different default namespace from parent */
522 const char *xmlns
= NULL
;
523 const char *parent_xmlns
= NULL
;
528 xmlns
= purple_xmlnode_get_default_namespace(node
);
530 parent_xmlns
= purple_xmlnode_get_default_namespace(node
->parent
);
531 if (!purple_strequal(xmlns
, parent_xmlns
))
533 char *escaped_xmlns
= g_markup_escape_text(xmlns
, -1);
534 g_string_append_printf(text
, " xmlns='%s'", escaped_xmlns
);
535 g_free(escaped_xmlns
);
538 for(c
= node
->child
; c
; c
= c
->next
)
540 if(c
->type
== PURPLE_XMLNODE_TYPE_ATTRIB
) {
541 const char *aprefix
= purple_xmlnode_get_prefix(c
);
542 esc
= g_markup_escape_text(c
->name
, -1);
543 esc2
= g_markup_escape_text(c
->data
, -1);
545 g_string_append_printf(text
, " %s:%s='%s'", aprefix
, esc
, esc2
);
547 g_string_append_printf(text
, " %s='%s'", esc
, esc2
);
551 } else if(c
->type
== PURPLE_XMLNODE_TYPE_TAG
|| c
->type
== PURPLE_XMLNODE_TYPE_DATA
) {
552 if(c
->type
== PURPLE_XMLNODE_TYPE_DATA
)
559 g_string_append_printf(text
, ">%s", pretty
? NEWLINE_S
: "");
561 for(c
= node
->child
; c
; c
= c
->next
)
563 if(c
->type
== PURPLE_XMLNODE_TYPE_TAG
) {
565 esc
= purple_xmlnode_to_str_helper(c
, &esc_len
, pretty
, depth
+1);
566 text
= g_string_append_len(text
, esc
, esc_len
);
568 } else if(c
->type
== PURPLE_XMLNODE_TYPE_DATA
&& c
->data_sz
> 0) {
569 esc
= g_markup_escape_text(c
->data
, c
->data_sz
);
570 text
= g_string_append(text
, esc
);
576 text
= g_string_append(text
, tab
);
578 g_string_append_printf(text
, "</%s:%s>%s", prefix
, node_name
, formatting
? NEWLINE_S
: "");
580 g_string_append_printf(text
, "</%s>%s", node_name
, formatting
? NEWLINE_S
: "");
583 g_string_append_printf(text
, "/>%s", formatting
? NEWLINE_S
: "");
593 return g_string_free(text
, FALSE
);
597 purple_xmlnode_to_str(const PurpleXmlNode
*node
, int *len
)
599 return purple_xmlnode_to_str_helper(node
, len
, FALSE
, 0);
603 purple_xmlnode_to_formatted_str(const PurpleXmlNode
*node
, int *len
)
605 char *xml
, *xml_with_declaration
;
607 g_return_val_if_fail(node
!= NULL
, NULL
);
609 xml
= purple_xmlnode_to_str_helper(node
, len
, TRUE
, 0);
610 xml_with_declaration
=
611 g_strdup_printf("<?xml version='1.0' encoding='UTF-8' ?>" NEWLINE_S NEWLINE_S
"%s", xml
);
615 *len
+= sizeof("<?xml version='1.0' encoding='UTF-8' ?>" NEWLINE_S NEWLINE_S
) - 1;
617 return xml_with_declaration
;
620 struct _xmlnode_parser_data
{
621 PurpleXmlNode
*current
;
626 purple_xmlnode_parser_element_start_libxml(void *user_data
,
627 const xmlChar
*element_name
, const xmlChar
*prefix
, const xmlChar
*xmlns
,
628 int nb_namespaces
, const xmlChar
**namespaces
,
629 int nb_attributes
, int nb_defaulted
, const xmlChar
**attributes
)
631 struct _xmlnode_parser_data
*xpd
= user_data
;
635 if(!element_name
|| xpd
->error
) {
639 node
= purple_xmlnode_new_child(xpd
->current
, (const char*) element_name
);
641 node
= purple_xmlnode_new((const char *) element_name
);
643 purple_xmlnode_set_namespace(node
, (const char *) xmlns
);
644 purple_xmlnode_set_prefix(node
, (const char *)prefix
);
646 if (nb_namespaces
!= 0) {
647 node
->namespace_map
= g_hash_table_new_full(
648 g_str_hash
, g_str_equal
, g_free
, g_free
);
650 for (i
= 0, j
= 0; i
< nb_namespaces
; i
++, j
+= 2) {
651 const char *key
= (const char *)namespaces
[j
];
652 const char *val
= (const char *)namespaces
[j
+ 1];
653 g_hash_table_insert(node
->namespace_map
,
654 g_strdup(key
? key
: ""), g_strdup(val
? val
: ""));
658 for(i
=0; i
< nb_attributes
* 5; i
+=5) {
659 const char *name
= (const char *)attributes
[i
];
660 const char *prefix
= (const char *)attributes
[i
+1];
662 int attrib_len
= attributes
[i
+4] - attributes
[i
+3];
663 char *attrib
= g_strndup((const char *)attributes
[i
+3], attrib_len
);
665 attrib
= purple_unescape_text(txt
);
667 purple_xmlnode_set_attrib_full(node
, name
, NULL
, prefix
, attrib
);
676 purple_xmlnode_parser_element_end_libxml(void *user_data
, const xmlChar
*element_name
,
677 const xmlChar
*prefix
, const xmlChar
*xmlns
)
679 struct _xmlnode_parser_data
*xpd
= user_data
;
681 if(!element_name
|| !xpd
->current
|| xpd
->error
)
684 if(xpd
->current
->parent
) {
685 if(!xmlStrcmp((xmlChar
*) xpd
->current
->name
, element_name
))
686 xpd
->current
= xpd
->current
->parent
;
691 purple_xmlnode_parser_element_text_libxml(void *user_data
, const xmlChar
*text
, int text_len
)
693 struct _xmlnode_parser_data
*xpd
= user_data
;
695 if(!xpd
->current
|| xpd
->error
)
698 if(!text
|| !text_len
)
701 purple_xmlnode_insert_data(xpd
->current
, (const char*) text
, text_len
);
705 purple_xmlnode_parser_error_libxml(void *user_data
, const char *msg
, ...)
707 struct _xmlnode_parser_data
*xpd
= user_data
;
714 vsnprintf(errmsg
, sizeof(errmsg
), msg
, args
);
717 purple_debug_error("xmlnode", "Error parsing xml file: %s", errmsg
);
721 purple_xmlnode_parser_structural_error_libxml(void *user_data
, xmlErrorPtr error
)
723 struct _xmlnode_parser_data
*xpd
= user_data
;
725 if (error
&& (error
->level
== XML_ERR_ERROR
||
726 error
->level
== XML_ERR_FATAL
)) {
728 purple_debug_error("xmlnode", "XML parser error for PurpleXmlNode %p: "
729 "Domain %i, code %i, level %i: %s",
730 user_data
, error
->domain
, error
->code
, error
->level
,
731 error
->message
? error
->message
: "(null)\n");
733 purple_debug_warning("xmlnode", "XML parser error for PurpleXmlNode %p: "
734 "Domain %i, code %i, level %i: %s",
735 user_data
, error
->domain
, error
->code
, error
->level
,
736 error
->message
? error
->message
: "(null)\n");
738 purple_debug_warning("xmlnode", "XML parser error for PurpleXmlNode %p\n",
742 static xmlSAXHandler purple_xmlnode_parser_libxml
= {
743 NULL
, /* internalSubset */
744 NULL
, /* isStandalone */
745 NULL
, /* hasInternalSubset */
746 NULL
, /* hasExternalSubset */
747 NULL
, /* resolveEntity */
748 NULL
, /* getEntity */
749 NULL
, /* entityDecl */
750 NULL
, /* notationDecl */
751 NULL
, /* attributeDecl */
752 NULL
, /* elementDecl */
753 NULL
, /* unparsedEntityDecl */
754 NULL
, /* setDocumentLocator */
755 NULL
, /* startDocument */
756 NULL
, /* endDocument */
757 NULL
, /* startElement */
758 NULL
, /* endElement */
759 NULL
, /* reference */
760 purple_xmlnode_parser_element_text_libxml
, /* characters */
761 NULL
, /* ignorableWhitespace */
762 NULL
, /* processingInstruction */
765 purple_xmlnode_parser_error_libxml
, /* error */
766 NULL
, /* fatalError */
767 NULL
, /* getParameterEntity */
768 NULL
, /* cdataBlock */
769 NULL
, /* externalSubset */
770 XML_SAX2_MAGIC
, /* initialized */
772 purple_xmlnode_parser_element_start_libxml
, /* startElementNs */
773 purple_xmlnode_parser_element_end_libxml
, /* endElementNs */
774 purple_xmlnode_parser_structural_error_libxml
, /* serror */
778 purple_xmlnode_from_str(const char *str
, gssize size
)
780 struct _xmlnode_parser_data
*xpd
;
784 g_return_val_if_fail(str
!= NULL
, NULL
);
786 real_size
= size
< 0 ? strlen(str
) : (gsize
)size
;
787 xpd
= g_new0(struct _xmlnode_parser_data
, 1);
789 if (xmlSAXUserParseMemory(&purple_xmlnode_parser_libxml
, xpd
, str
, real_size
) < 0) {
790 while(xpd
->current
&& xpd
->current
->parent
)
791 xpd
->current
= xpd
->current
->parent
;
793 purple_xmlnode_free(xpd
->current
);
800 purple_xmlnode_free(xpd
->current
);
808 purple_xmlnode_from_file(const char *dir
, const char *filename
, const char *description
, const char *process
)
810 gchar
*filename_full
;
811 GError
*error
= NULL
;
812 gchar
*contents
= NULL
;
814 PurpleXmlNode
*node
= NULL
;
816 g_return_val_if_fail(dir
!= NULL
, NULL
);
818 purple_debug_misc(process
, "Reading file %s from directory %s\n",
821 filename_full
= g_build_filename(dir
, filename
, NULL
);
823 if (!g_file_test(filename_full
, G_FILE_TEST_EXISTS
))
825 purple_debug_info(process
, "File %s does not exist (this is not "
826 "necessarily an error)\n", filename_full
);
827 g_free(filename_full
);
831 if (!g_file_get_contents(filename_full
, &contents
, &length
, &error
))
833 purple_debug_error(process
, "Error reading file %s: %s\n",
834 filename_full
, error
->message
);
838 if ((contents
!= NULL
) && (length
> 0))
840 node
= purple_xmlnode_from_str(contents
, length
);
842 /* If we were unable to parse the file then save its contents to a backup file */
845 gchar
*filename_temp
, *filename_temp_full
;
847 filename_temp
= g_strdup_printf("%s~", filename
);
848 filename_temp_full
= g_build_filename(dir
, filename_temp
, NULL
);
850 purple_debug_error("util", "Error parsing file %s. Renaming old "
851 "file to %s\n", filename_full
, filename_temp
);
852 purple_util_write_data_to_file_absolute(filename_temp_full
, contents
, length
);
854 g_free(filename_temp_full
);
855 g_free(filename_temp
);
861 /* If we could not parse the file then show the user an error message */
865 title
= g_strdup_printf(_("Error Reading %s"), filename
);
866 msg
= g_strdup_printf(_("An error was encountered reading your "
867 "%s. The file has not been loaded, and the old file "
868 "has been renamed to %s~."), description
, filename_full
);
869 purple_notify_error(NULL
, NULL
, title
, msg
, NULL
);
874 g_free(filename_full
);
880 purple_xmlnode_copy_foreach_ns(gpointer key
, gpointer value
, gpointer user_data
)
882 GHashTable
*ret
= (GHashTable
*)user_data
;
883 g_hash_table_insert(ret
, g_strdup(key
), g_strdup(value
));
887 purple_xmlnode_copy(const PurpleXmlNode
*src
)
890 PurpleXmlNode
*child
;
891 PurpleXmlNode
*sibling
= NULL
;
893 g_return_val_if_fail(src
!= NULL
, NULL
);
895 ret
= new_node(src
->name
, src
->type
);
896 ret
->xmlns
= g_strdup(src
->xmlns
);
899 ret
->data
= g_memdup(src
->data
, src
->data_sz
);
900 ret
->data_sz
= src
->data_sz
;
902 ret
->data
= g_strdup(src
->data
);
905 ret
->prefix
= g_strdup(src
->prefix
);
906 if (src
->namespace_map
) {
907 ret
->namespace_map
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
909 g_hash_table_foreach(src
->namespace_map
, purple_xmlnode_copy_foreach_ns
, ret
->namespace_map
);
912 for (child
= src
->child
; child
; child
= child
->next
) {
914 sibling
->next
= purple_xmlnode_copy(child
);
915 sibling
= sibling
->next
;
917 ret
->child
= sibling
= purple_xmlnode_copy(child
);
919 sibling
->parent
= ret
;
922 ret
->lastchild
= sibling
;
928 purple_xmlnode_get_next_twin(PurpleXmlNode
*node
)
930 PurpleXmlNode
*sibling
;
931 const char *ns
= purple_xmlnode_get_namespace(node
);
933 g_return_val_if_fail(node
!= NULL
, NULL
);
934 g_return_val_if_fail(node
->type
== PURPLE_XMLNODE_TYPE_TAG
, NULL
);
936 for(sibling
= node
->next
; sibling
; sibling
= sibling
->next
) {
937 /* XXX: Is it correct to ignore the namespace for the match if none was specified? */
938 const char *xmlns
= NULL
;
940 xmlns
= purple_xmlnode_get_namespace(sibling
);
942 if(sibling
->type
== PURPLE_XMLNODE_TYPE_TAG
&& purple_strequal(node
->name
, sibling
->name
) &&
943 purple_strequal(ns
, xmlns
))
951 purple_xmlnode_get_type(void)
953 static GType type
= 0;
956 type
= g_boxed_type_register_static("PurpleXmlNode",
957 (GBoxedCopyFunc
)purple_xmlnode_copy
,
958 (GBoxedFreeFunc
)purple_xmlnode_free
);