]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-plist.c
include telepathy-glib.h
[empathy.git] / libempathy-gtk / empathy-plist.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2008 Christophe Fergeau <teuf@gnome.org>
4  * Based on itdb_plist parser from the gtkpod project.
5  *
6  * The code contained in this file is free software; you can redistribute
7  * it and/or modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either version
9  * 2.1 of the License, or (at your option) any later version.
10  *
11  * This file is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this code; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <libxml/parser.h>
25 #include <libxml/tree.h>
26 #include <telepathy-glib/telepathy-glib.h>
27
28 #include "empathy-plist.h"
29
30 static GValue *empathy_plist_parse_node (xmlNode *a_node);
31
32 static GValue *
33 empathy_plist_parse_integer (xmlNode *a_node)
34 {
35         char *str_val;
36         char *end_ptr;
37         gint int_val;
38
39         str_val = (char *) xmlNodeGetContent (a_node);
40         int_val = strtol (str_val, &end_ptr, 0);
41         if (*end_ptr != '\0') {
42                 xmlFree (str_val);
43                 return NULL;
44         }
45         xmlFree (str_val);
46
47         return tp_g_value_slice_new_int (int_val);
48 }
49
50 static GValue *
51 empathy_plist_parse_string (xmlNode *a_node)
52 {
53         char *str_val;
54         GValue *value;
55
56         str_val = (char *) xmlNodeGetContent (a_node);
57
58         value = tp_g_value_slice_new_string (str_val);
59
60         xmlFree (str_val);
61
62         return value;
63 }
64
65 static GValue *
66 empathy_plist_parse_real (xmlNode *a_node)
67 {
68         char *str_val;
69         char *end_ptr;
70         gdouble double_val;
71
72         str_val = (char *) xmlNodeGetContent (a_node);
73         double_val = g_ascii_strtod (str_val, &end_ptr);
74         if (*end_ptr != '\0') {
75                 xmlFree (str_val);
76                 return NULL;
77         }
78         xmlFree (str_val);
79
80         return tp_g_value_slice_new_double (double_val);
81 }
82
83 static GValue *
84 empathy_plist_parse_boolean (xmlNode *a_node)
85 {
86         gboolean bool_val;
87
88         if (strcmp ((char *) a_node->name, "true") == 0) {
89                 bool_val = TRUE;
90         } else if (strcmp ((char *) a_node->name, "false") == 0) {
91                 bool_val = FALSE;
92         } else {
93                 return NULL;
94         }
95
96         return tp_g_value_slice_new_boolean (bool_val);
97 }
98
99 static GValue *
100 empathy_plist_parse_data (xmlNode *a_node)
101 {
102         char *str_val;
103         guchar *raw_data;
104         gsize len;
105         GValue *value;
106
107         str_val = (char *) xmlNodeGetContent (a_node);
108         raw_data = g_base64_decode (str_val, &len);
109         xmlFree (str_val);
110
111         value = tp_g_value_slice_new_bytes (len, raw_data);
112
113         g_free (raw_data);
114
115         return value;
116 }
117
118 static xmlNode *
119 empathy_plist_parse_one_dict_entry (xmlNode *a_node, GHashTable *dict)
120 {
121         xmlNode *cur_node = a_node;
122         xmlChar *key_name;
123         GValue *value;
124
125         while (cur_node &&
126                (xmlStrcmp (cur_node->name, (xmlChar *) "key") != 0)) {
127                 cur_node = cur_node->next;
128         }
129         if (!cur_node) {
130                 return NULL;
131         }
132         key_name = xmlNodeGetContent (cur_node);
133         cur_node = cur_node->next;
134         while (cur_node && xmlIsBlankNode (cur_node)) {
135                 cur_node = cur_node->next;
136         }
137         if (!cur_node) {
138                 xmlFree (key_name);
139                 return NULL;
140         }
141
142         value = empathy_plist_parse_node (cur_node);
143         if (value) {
144                 g_hash_table_insert (dict, g_strdup ((char *) key_name), value);
145         }
146         xmlFree (key_name);
147
148         return cur_node->next;
149 }
150
151 static GValue *
152 empathy_plist_parse_dict (xmlNode *a_node)
153 {
154         xmlNode *cur_node = a_node->children;
155         GHashTable *dict;
156
157         dict = g_hash_table_new_full (g_str_hash, g_str_equal,
158                                       g_free, (GDestroyNotify) tp_g_value_slice_free);
159
160         while (cur_node) {
161                 if (xmlIsBlankNode (cur_node)) {
162                         cur_node = cur_node->next;
163                 } else {
164                         cur_node = empathy_plist_parse_one_dict_entry (cur_node, dict);
165                 }
166         }
167
168         return tp_g_value_slice_new_take_boxed (G_TYPE_HASH_TABLE, dict);
169 }
170
171 typedef GValue *(*ParseCallback) (xmlNode *);
172
173 struct Parser {
174         const char * const type_name;
175         ParseCallback parser;
176 };
177
178 static const struct Parser parsers[] = { {"integer", empathy_plist_parse_integer},
179                                          {"real",    empathy_plist_parse_real},
180                                          {"string",  empathy_plist_parse_string},
181                                          {"true",    empathy_plist_parse_boolean},
182                                          {"false",   empathy_plist_parse_boolean},
183                                          {"data",    empathy_plist_parse_data},
184                                          {"dict",    empathy_plist_parse_dict},
185                                          {NULL,   NULL} };
186
187 static ParseCallback
188 empathy_plist_get_parser_for_type (const xmlChar *type)
189 {
190         guint i = 0;
191
192         while (parsers[i].type_name) {
193                 if (xmlStrcmp (type, (xmlChar *) parsers[i].type_name) == 0) {
194                         if (parsers[i].parser) {
195                                 return parsers[i].parser;
196                         }
197                 }
198                 i++;
199         }
200         return NULL;
201 }
202
203 static GValue *
204 empathy_plist_parse_node (xmlNode *a_node)
205 {
206         ParseCallback parser;
207
208         g_return_val_if_fail (a_node != NULL, NULL);
209         parser = empathy_plist_get_parser_for_type (a_node->name);
210         if (parser) {
211                 return parser (a_node);
212         } else {
213                 return NULL;
214         }
215 }
216
217 static GValue *
218 empathy_plist_parse (xmlNode * a_node)
219 {
220         xmlNode *cur_node;
221
222         if (!a_node) {
223                 return NULL;
224         }
225         if (xmlStrcmp (a_node->name, (xmlChar *) "plist") != 0) {
226                 return NULL;
227         }
228         cur_node = a_node->xmlChildrenNode;
229         while (cur_node && (xmlIsBlankNode (cur_node))) {
230                 cur_node = cur_node->next;
231         }
232         if (cur_node) {
233                 return empathy_plist_parse_node (cur_node);
234         }
235
236         return NULL;
237 }
238
239 /**
240  * empathy_plist_parse_from_file:
241  * @filename: file containing XML plist data to parse
242  *
243  * Parses the XML plist file. If an error occurs during the parsing,
244  * empathy_plist_parse_from_file() will return NULL.
245  *
246  * Returns: NULL on error, a newly allocated
247  * #GValue otherwise. Free it using tp_g_value_slice_free()
248  */
249 GValue *
250 empathy_plist_parse_from_file (const char *filename)
251 {
252         xmlDoc *doc = NULL;
253         xmlNode *root_element = NULL;
254         GValue *parsed_doc;
255
256         doc = xmlReadFile (filename, NULL, 0);
257
258         if (!doc) {
259                 return NULL;
260         }
261
262         root_element = xmlDocGetRootElement (doc);
263
264         parsed_doc = empathy_plist_parse (root_element);
265
266         xmlFreeDoc (doc);
267
268         return parsed_doc;
269 }
270
271 /**
272  * empathy_plist_parse_from_memory:
273  * @data:   memory location containing XML plist data to parse
274  * @len:        length in bytes of the string to parse
275  *
276  * Parses the XML plist file stored in @data which length is @len
277  * bytes. If an error occurs during the parsing,
278  * empathy_plist_parse_from_memory() will return NULL.
279  *
280  * Returns: NULL on error, a newly allocated
281  * #GValue otherwise. Free it using tp_g_value_slice_free()
282  */
283 GValue *
284 empathy_plist_parse_from_memory (const char *data, gsize len)
285 {
286         xmlDoc *doc = NULL;
287         xmlNode *root_element = NULL;
288         GValue *parsed_doc;
289
290         doc = xmlReadMemory (data, len, "noname.xml", NULL, 0);
291
292         if (doc == NULL) {
293                 return NULL;
294         }
295
296         root_element = xmlDocGetRootElement (doc);
297
298         parsed_doc = empathy_plist_parse (root_element);
299
300         xmlFreeDoc (doc);
301
302         return parsed_doc;
303 }
304