xml: implement deallocator
[siplcs.git] / src / core / sipe-xml.c
blobf278d9023bbcf05a2932dd9244d610007db7f454
1 /**
2 * @file sipe-xml.c
4 * pidgin-sipe
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
27 #include <stdarg.h>
29 #include "libxml/parser.h"
30 #include "glib.h"
31 #include "glib/gprintf.h"
33 #include "sipe-xml.h"
34 #include "sipe.h" /* TEMPORARY: to include sipe-utils.h without errors */
35 #include "sipe-utils.h"
36 #include "sipe-backend-debug.h"
38 struct _sipe_xml {
39 gchar *name;
40 sipe_xml *parent;
41 sipe_xml *sibling;
42 sipe_xml *first;
43 sipe_xml *last;
44 GString *data;
45 gchar **attributes;
48 struct _parser_data {
49 sipe_xml *root;
50 sipe_xml *current;
51 gboolean error;
54 static void callback_start_element(void *user_data, const xmlChar *text, const xmlChar **attrs)
56 /* @TODO: implement me :-) */
57 (void) user_data;
58 (void) text;
59 (void) attrs;
62 static void callback_end_element(void *user_data, const xmlChar *name)
64 /* @TODO: implement me :-) */
65 (void) user_data;
66 (void) name;
69 static void callback_characters(void *user_data, const xmlChar *text, int text_len)
71 struct _parser_data *pd = user_data;
72 sipe_xml *node;
74 if (!pd->current || pd->error || !text || !text_len) return;
76 node = pd->current;
77 if (node->data)
78 node->data = g_string_append_len(node->data, (gchar *)text, text_len);
79 else
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;
86 gchar *errmsg;
87 va_list args;
89 pd->error = TRUE;
91 va_start(args, msg);
92 errmsg = g_strdup_vprintf(msg, args);
93 va_end(args);
95 SIPE_DEBUG_ERROR("error parsing xml string: %s", errmsg);
96 g_free(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)) {
105 pd->error = TRUE;
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)");
109 } else if (error) {
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)");
113 } else {
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 */
141 NULL, /* comment */
142 NULL, /* warning */
143 callback_error, /* error */
144 NULL, /* fatalError */
145 NULL, /* getParameterEntity */
146 NULL, /* cdataBlock */
147 NULL, /* externalSubset */
148 XML_SAX2_MAGIC, /* initialized */
149 NULL, /* _private */
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))
163 pd->error = TRUE;
165 if (pd->error) {
166 sipe_xml_free(pd->root);
167 } else {
168 result = pd->current;
171 g_free(pd);
174 return result;
177 void sipe_xml_free(sipe_xml *node)
179 sipe_xml *child;
181 if (!node) return;
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", "");
188 /* free children */
189 child = node->first;
190 while (child) {
191 sipe_xml *tmp = child->sibling;
192 child->parent = NULL; /* detach from tree, see above */
193 sipe_xml_free(child);
194 child = tmp;
197 /* free node */
198 g_free(node->name);
199 g_string_free(node->data, TRUE);
200 g_free(node);
203 gchar *sipe_xml_to_string(const sipe_xml *node)
205 /* @TODO: implement me :-) */
206 (void) node;
207 return NULL;
210 sipe_xml *sipe_xml_get_child(const sipe_xml *parent, const gchar *name)
212 gchar **names;
213 sipe_xml *child = NULL;
215 if (!parent || !name) return NULL;
217 /* 0: child name */
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))
223 break;
226 /* recurse into path */
227 if (child && names[1])
228 child = sipe_xml_get_child(child, names[1]);
230 g_strfreev(names);
231 return child;
234 sipe_xml *sipe_xml_get_descendant(const sipe_xml *parent, ...)
236 va_list args;
237 sipe_xml *node = NULL;
238 const gchar *name;
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;
244 parent = node;
246 va_end(args);
248 return node;
251 sipe_xml *sipe_xml_get_next_twin(const sipe_xml *node)
253 sipe_xml *sibling;
255 if (!node) return NULL;
257 for (sibling = node->sibling; sibling; sibling = sibling->sibling) {
258 if (sipe_strequal(node->name, sibling->name))
259 return sibling;
261 return NULL;
264 const gchar *sipe_xml_get_attribute(const sipe_xml *node, const gchar *attr)
266 /* @TODO: implement me :-) */
267 (void) node;
268 (void) attr;
269 return NULL;
272 gint sipe_xml_get_int_attribute(const sipe_xml *node, const gchar *attr,
273 gint fallback)
275 /* @TODO: implement me :-) */
276 (void) node;
277 (void) attr;
278 return fallback;
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);
288 Local Variables:
289 mode: c
290 c-file-style: "bsd"
291 indent-tabs-mode: t
292 tab-width: 8
293 End: