6 * Copyright (C) 2010 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * This code is loosely based on libpurple xmlnode.c
29 #include "libxml/parser.h"
31 #include "glib/gprintf.h"
34 #include "sipe.h" /* TEMPORARY: to include sipe-utils.h without errors */
35 #include "sipe-utils.h"
36 #include "sipe-backend-debug.h"
54 static void callback_start_element(void *user_data
, const xmlChar
*text
, const xmlChar
**attrs
)
56 /* @TODO: implement me :-) */
62 static void callback_end_element(void *user_data
, const xmlChar
*name
)
64 /* @TODO: implement me :-) */
69 static void callback_characters(void *user_data
, const xmlChar
*text
, int text_len
)
71 struct _parser_data
*pd
= user_data
;
74 if (!pd
->current
|| pd
->error
|| !text
|| !text_len
) return;
78 node
->data
= g_string_append_len(node
->data
, (gchar
*)text
, text_len
);
80 node
->data
= g_string_new_len((gchar
*)text
, text_len
);
83 static void callback_error(void *user_data
, const char *msg
, ...)
85 struct _parser_data
*pd
= user_data
;
92 errmsg
= g_strdup_vprintf(msg
, args
);
95 SIPE_DEBUG_ERROR("error parsing xml string: %s", errmsg
);
99 static void callback_serror(void *user_data
, xmlErrorPtr error
)
101 struct _parser_data
*pd
= user_data
;
103 if (error
&& (error
->level
== XML_ERR_ERROR
||
104 error
->level
== XML_ERR_FATAL
)) {
106 SIPE_DEBUG_ERROR("XML parser error: Domain %i, code %i, level %i: %s",
107 error
->domain
, error
->code
, error
->level
,
108 error
->message
? error
->message
: "(null)");
110 SIPE_DEBUG_WARNING("XML parser error: Domain %i, code %i, level %i: %s",
111 error
->domain
, error
->code
, error
->level
,
112 error
->message
? error
->message
: "(null)");
114 /* *sigh* macro expects at least two parameters */
115 SIPE_DEBUG_WARNING("XML parser error%s", "");
119 /* API doesn't accept const data structure */
120 static xmlSAXHandler parser
= {
121 NULL
, /* internalSubset */
122 NULL
, /* isStandalone */
123 NULL
, /* hasInternalSubset */
124 NULL
, /* hasExternalSubset */
125 NULL
, /* resolveEntity */
126 NULL
, /* getEntity */
127 NULL
, /* entityDecl */
128 NULL
, /* notationDecl */
129 NULL
, /* attributeDecl */
130 NULL
, /* elementDecl */
131 NULL
, /* unparsedEntityDecl */
132 NULL
, /* setDocumentLocator */
133 NULL
, /* startDocument */
134 NULL
, /* endDocument */
135 callback_start_element
, /* startElement */
136 callback_end_element
, /* endElement */
137 NULL
, /* reference */
138 callback_characters
, /* characters */
139 NULL
, /* ignorableWhitespace */
140 NULL
, /* processingInstruction */
143 callback_error
, /* error */
144 NULL
, /* fatalError */
145 NULL
, /* getParameterEntity */
146 NULL
, /* cdataBlock */
147 NULL
, /* externalSubset */
148 XML_SAX2_MAGIC
, /* initialized */
150 NULL
, /* startElementNs */
151 NULL
, /* endElementNs */
152 callback_serror
, /* serror */
155 sipe_xml
*sipe_xml_parse(const gchar
*string
, gsize length
)
157 sipe_xml
*result
= NULL
;
159 if (string
&& length
) {
160 struct _parser_data
*pd
= g_new0(struct _parser_data
, 1);
162 if (xmlSAXUserParseMemory(&parser
, pd
, string
, length
))
166 sipe_xml_free(pd
->root
);
168 result
= pd
->current
;
177 void sipe_xml_free(sipe_xml
*node
)
183 /* we don't support partial tree deletion */
184 if (node
->parent
!= NULL
) {
185 SIPE_DEBUG_ERROR("sipe_xml_free: partial delete attempt! Expect crash or memory leaks...%s", "");
191 sipe_xml
*tmp
= child
->sibling
;
192 child
->parent
= NULL
; /* detach from tree, see above */
193 sipe_xml_free(child
);
199 g_string_free(node
->data
, TRUE
);
203 gchar
*sipe_xml_to_string(const sipe_xml
*node
)
205 /* @TODO: implement me :-) */
210 sipe_xml
*sipe_xml_get_child(const sipe_xml
*parent
, const gchar
*name
)
213 sipe_xml
*child
= NULL
;
215 if (!parent
|| !name
) return NULL
;
218 /* 1: trailing path (optional) */
219 names
= g_strsplit(name
, "/", 2);
221 for (child
= parent
->first
; child
; child
= child
->sibling
) {
222 if (sipe_strequal(names
[0], child
->name
))
226 /* recurse into path */
227 if (child
&& names
[1])
228 child
= sipe_xml_get_child(child
, names
[1]);
234 sipe_xml
*sipe_xml_get_descendant(const sipe_xml
*parent
, ...)
237 sipe_xml
*node
= NULL
;
240 va_start(args
, parent
);
241 while ((name
= va_arg(args
, const char *)) != NULL
) {
242 node
= sipe_xml_get_child(parent
, name
);
243 if (node
== NULL
) break;
251 sipe_xml
*sipe_xml_get_next_twin(const sipe_xml
*node
)
255 if (!node
) return NULL
;
257 for (sibling
= node
->sibling
; sibling
; sibling
= sibling
->sibling
) {
258 if (sipe_strequal(node
->name
, sibling
->name
))
264 const gchar
*sipe_xml_get_attribute(const sipe_xml
*node
, const gchar
*attr
)
266 /* @TODO: implement me :-) */
272 gint
sipe_xml_get_int_attribute(const sipe_xml
*node
, const gchar
*attr
,
275 /* @TODO: implement me :-) */
281 gchar
*sipe_xml_get_data(const sipe_xml
*node
)
283 if (!node
|| !node
->data
|| !node
->data
->str
) return NULL
;
284 return g_strdup(node
->data
->str
);