]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-plist.c
Merge branch 'gnome-3-4'
[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/util.h>
27 #include <telepathy-glib/dbus.h>
28
29 #include "empathy-plist.h"
30
31 static GValue *empathy_plist_parse_node (xmlNode *a_node);
32
33 static GValue *
34 empathy_plist_parse_integer (xmlNode *a_node)
35 {
36         char *str_val;
37         char *end_ptr;
38         gint int_val;
39
40         str_val = (char *) xmlNodeGetContent (a_node);
41         int_val = strtol (str_val, &end_ptr, 0);
42         if (*end_ptr != '\0') {
43                 xmlFree (str_val);
44                 return NULL;
45         }
46         xmlFree (str_val);
47
48         return tp_g_value_slice_new_int (int_val);
49 }
50
51 static GValue *
52 empathy_plist_parse_string (xmlNode *a_node)
53 {
54         char *str_val;
55         GValue *value;
56
57         str_val = (char *) xmlNodeGetContent (a_node);
58
59         value = tp_g_value_slice_new_string (str_val);
60
61         xmlFree (str_val);
62
63         return value;
64 }
65
66 static GValue *
67 empathy_plist_parse_real (xmlNode *a_node)
68 {
69         char *str_val;
70         char *end_ptr;
71         gdouble double_val;
72
73         str_val = (char *) xmlNodeGetContent (a_node);
74         double_val = g_ascii_strtod (str_val, &end_ptr);
75         if (*end_ptr != '\0') {
76                 xmlFree (str_val);
77                 return NULL;
78         }
79         xmlFree (str_val);
80
81         return tp_g_value_slice_new_double (double_val);
82 }
83
84 static GValue *
85 empathy_plist_parse_boolean (xmlNode *a_node)
86 {
87         gboolean bool_val;
88
89         if (strcmp ((char *) a_node->name, "true") == 0) {
90                 bool_val = TRUE;
91         } else if (strcmp ((char *) a_node->name, "false") == 0) {
92                 bool_val = FALSE;
93         } else {
94                 return NULL;
95         }
96
97         return tp_g_value_slice_new_boolean (bool_val);
98 }
99
100 static GValue *
101 empathy_plist_parse_data (xmlNode *a_node)
102 {
103         char *str_val;
104         guchar *raw_data;
105         gsize len;
106         GValue *value;
107
108         str_val = (char *) xmlNodeGetContent (a_node);
109         raw_data = g_base64_decode (str_val, &len);
110         xmlFree (str_val);
111
112         value = tp_g_value_slice_new_bytes (len, raw_data);
113
114         g_free (raw_data);
115
116         return value;
117 }
118
119 static xmlNode *
120 empathy_plist_parse_one_dict_entry (xmlNode *a_node, GHashTable *dict)
121 {
122         xmlNode *cur_node = a_node;
123         xmlChar *key_name;
124         GValue *value;
125
126         while (cur_node &&
127                (xmlStrcmp (cur_node->name, (xmlChar *) "key") != 0)) {
128                 cur_node = cur_node->next;
129         }
130         if (!cur_node) {
131                 return NULL;
132         }
133         key_name = xmlNodeGetContent (cur_node);
134         cur_node = cur_node->next;
135         while (cur_node && xmlIsBlankNode (cur_node)) {
136                 cur_node = cur_node->next;
137         }
138         if (!cur_node) {
139                 xmlFree (key_name);
140                 return NULL;
141         }
142
143         value = empathy_plist_parse_node (cur_node);
144         if (value) {
145                 g_hash_table_insert (dict, g_strdup ((char *) key_name), value);
146         }
147         xmlFree (key_name);
148
149         return cur_node->next;
150 }
151
152 static GValue *
153 empathy_plist_parse_dict (xmlNode *a_node)
154 {
155         xmlNode *cur_node = a_node->children;
156         GHashTable *dict;
157
158         dict = g_hash_table_new_full (g_str_hash, g_str_equal,
159                                       g_free, (GDestroyNotify) tp_g_value_slice_free);
160
161         while (cur_node) {
162                 if (xmlIsBlankNode (cur_node)) {
163                         cur_node = cur_node->next;
164                 } else {
165                         cur_node = empathy_plist_parse_one_dict_entry (cur_node, dict);
166                 }
167         }
168
169         return tp_g_value_slice_new_take_boxed (G_TYPE_HASH_TABLE, dict);
170 }
171
172 typedef GValue *(*ParseCallback) (xmlNode *);
173
174 struct Parser {
175         const char * const type_name;
176         ParseCallback parser;
177 };
178
179 static const struct Parser parsers[] = { {"integer", empathy_plist_parse_integer},
180                                          {"real",    empathy_plist_parse_real},
181                                          {"string",  empathy_plist_parse_string},
182                                          {"true",    empathy_plist_parse_boolean},
183                                          {"false",   empathy_plist_parse_boolean},
184                                          {"data",    empathy_plist_parse_data},
185                                          {"dict",    empathy_plist_parse_dict},
186                                          {NULL,   NULL} };
187
188 static ParseCallback
189 empathy_plist_get_parser_for_type (const xmlChar *type)
190 {
191         guint i = 0;
192
193         while (parsers[i].type_name) {
194                 if (xmlStrcmp (type, (xmlChar *) parsers[i].type_name) == 0) {
195                         if (parsers[i].parser) {
196                                 return parsers[i].parser;
197                         }
198                 }
199                 i++;
200         }
201         return NULL;
202 }
203
204 static GValue *
205 empathy_plist_parse_node (xmlNode *a_node)
206 {
207         ParseCallback parser;
208
209         g_return_val_if_fail (a_node != NULL, NULL);
210         parser = empathy_plist_get_parser_for_type (a_node->name);
211         if (parser) {
212                 return parser (a_node);
213         } else {
214                 return NULL;
215         }
216 }
217
218 static GValue *
219 empathy_plist_parse (xmlNode * a_node)
220 {
221         xmlNode *cur_node;
222
223         if (!a_node) {
224                 return NULL;
225         }
226         if (xmlStrcmp (a_node->name, (xmlChar *) "plist") != 0) {
227                 return NULL;
228         }
229         cur_node = a_node->xmlChildrenNode;
230         while (cur_node && (xmlIsBlankNode (cur_node))) {
231                 cur_node = cur_node->next;
232         }
233         if (cur_node) {
234                 return empathy_plist_parse_node (cur_node);
235         }
236
237         return NULL;
238 }
239
240 /**
241  * empathy_plist_parse_from_file:
242  * @filename: file containing XML plist data to parse
243  *
244  * Parses the XML plist file. If an error occurs during the parsing,
245  * empathy_plist_parse_from_file() will return NULL.
246  *
247  * Returns: NULL on error, a newly allocated
248  * #GValue otherwise. Free it using tp_g_value_slice_free()
249  */
250 GValue *
251 empathy_plist_parse_from_file (const char *filename)
252 {
253         xmlDoc *doc = NULL;
254         xmlNode *root_element = NULL;
255         GValue *parsed_doc;
256
257         doc = xmlReadFile (filename, NULL, 0);
258
259         if (!doc) {
260                 return NULL;
261         }
262
263         root_element = xmlDocGetRootElement (doc);
264
265         parsed_doc = empathy_plist_parse (root_element);
266
267         xmlFreeDoc (doc);
268
269         return parsed_doc;
270 }
271
272 /**
273  * empathy_plist_parse_from_memory:
274  * @data:   memory location containing XML plist data to parse
275  * @len:        length in bytes of the string to parse
276  *
277  * Parses the XML plist file stored in @data which length is @len
278  * bytes. If an error occurs during the parsing,
279  * empathy_plist_parse_from_memory() will return NULL.
280  *
281  * Returns: NULL on error, a newly allocated
282  * #GValue otherwise. Free it using tp_g_value_slice_free()
283  */
284 GValue *
285 empathy_plist_parse_from_memory (const char *data, gsize len)
286 {
287         xmlDoc *doc = NULL;
288         xmlNode *root_element = NULL;
289         GValue *parsed_doc;
290
291         doc = xmlReadMemory (data, len, "noname.xml", NULL, 0);
292
293         if (doc == NULL) {
294                 return NULL;
295         }
296
297         root_element = xmlDocGetRootElement (doc);
298
299         parsed_doc = empathy_plist_parse (root_element);
300
301         xmlFreeDoc (doc);
302
303         return parsed_doc;
304 }
305