summaryrefslogtreecommitdiffstats
path: root/src/xplist.c
diff options
context:
space:
mode:
authorGravatar Jonathan Beck2008-12-11 23:05:29 +0100
committerGravatar Jonathan Beck2008-12-11 23:05:29 +0100
commit31379321cec6bf6c6d670e0738d1b1e23dc92ac1 (patch)
tree47aad4a390bcab10ff4fc6c36b35f0b89c06c1eb /src/xplist.c
parent18d1ee3b0f17325fdffe0cf3e2770a3f0f45a1b9 (diff)
downloadlibimobiledevice-31379321cec6bf6c6d670e0738d1b1e23dc92ac1.tar.gz
libimobiledevice-31379321cec6bf6c6d670e0738d1b1e23dc92ac1.tar.bz2
dissect plists in three file (abstract binary xml)
Diffstat (limited to 'src/xplist.c')
-rw-r--r--src/xplist.c306
1 files changed, 306 insertions, 0 deletions
diff --git a/src/xplist.c b/src/xplist.c
new file mode 100644
index 0000000..a87b259
--- /dev/null
+++ b/src/xplist.c
@@ -0,0 +1,306 @@
1/*
2 * plist.c
3 * XML plist implementation
4 *
5 * Copyright (c) 2008 Jonathan Beck All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library 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 GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22
23#include <string.h>
24#include <assert.h>
25#include "utils.h"
26#include "plist.h"
27#include <wchar.h>
28#include <stdlib.h>
29#include <stdio.h>
30
31
32#include <libxml/parser.h>
33#include <libxml/tree.h>
34
35
36const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
37<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\
38<plist version=\"1.0\">\n\
39</plist>\0";
40
41
42/** Formats a block of text to be a given indentation and width.
43 *
44 * The total width of the return string will be depth + cols.
45 *
46 * @param buf The string to format.
47 * @param cols The number of text columns for returned block of text.
48 * @param depth The number of tabs to indent the returned block of text.
49 *
50 * @return The formatted string.
51 */
52char *format_string(const char *buf, int cols, int depth)
53{
54 int colw = depth + cols + 1;
55 int len = strlen(buf);
56 int nlines = len / cols + 1;
57 char *new_buf = (char *) malloc(nlines * colw + depth + 1);
58 int i = 0;
59 int j = 0;
60
61 assert(cols >= 0);
62 assert(depth >= 0);
63
64 // Inserts new lines and tabs at appropriate locations
65 for (i = 0; i < nlines; i++) {
66 new_buf[i * colw] = '\n';
67 for (j = 0; j < depth; j++)
68 new_buf[i * colw + 1 + j] = '\t';
69 memcpy(new_buf + i * colw + 1 + depth, buf + i * cols, cols);
70 }
71 new_buf[len + (1 + depth) * nlines] = '\n';
72
73 // Inserts final row of indentation and termination character
74 for (j = 0; j < depth; j++)
75 new_buf[len + (1 + depth) * nlines + 1 + j] = '\t';
76 new_buf[len + (1 + depth) * nlines + depth + 1] = '\0';
77
78 return new_buf;
79}
80
81
82
83struct xml_node {
84 xmlNodePtr xml;
85 uint32_t depth;
86};
87
88/** Creates a new plist XML document.
89 *
90 * @return The plist XML document.
91 */
92xmlDocPtr new_plist()
93{
94 char *plist = strdup(plist_base);
95 xmlDocPtr plist_xml = xmlReadMemory(plist, strlen(plist), NULL, NULL, 0);
96
97 if (!plist_xml)
98 return NULL;
99
100 free(plist);
101
102 return plist_xml;
103}
104
105/** Destroys a previously created XML document.
106 *
107 * @param plist The XML document to destroy.
108 */
109void free_plist(xmlDocPtr plist)
110{
111 if (!plist)
112 return;
113
114 xmlFreeDoc(plist);
115}
116
117void node_to_xml(GNode * node, gpointer xml_struct)
118{
119 if (!node)
120 return;
121
122 struct xml_node *xstruct = (struct xml_node *) xml_struct;
123 struct plist_data *node_data = (struct plist_data *) node->data;
124
125 xmlNodePtr child_node = NULL;
126 char isStruct = FALSE;
127
128 gchar *tag = NULL;
129 gchar *val = NULL;
130
131 switch (node_data->type) {
132 case PLIST_BOOLEAN:
133 {
134 if (node_data->boolval)
135 tag = "true";
136 else
137 tag = "false";
138 }
139 break;
140
141 case PLIST_UINT:
142 tag = "integer";
143 val = g_strdup_printf("%lu", (long unsigned int) node_data->intval);
144 break;
145
146 case PLIST_REAL:
147 tag = "real";
148 val = g_strdup_printf("%Lf", (long double) node_data->realval);
149 break;
150
151 case PLIST_STRING:
152 tag = "string";
153 val = g_strdup(node_data->strval);
154 break;
155
156 case PLIST_UNICODE:
157 tag = "string";
158 val = g_strdup((gchar *) node_data->unicodeval);
159 break;
160
161 case PLIST_KEY:
162 tag = "key";
163 val = g_strdup((gchar *) node_data->strval);
164 break;
165
166 case PLIST_DATA:
167 tag = "data";
168 val = format_string(node_data->buff, 60, xstruct->depth);
169 break;
170 case PLIST_ARRAY:
171 tag = "array";
172 isStruct = TRUE;
173 break;
174 case PLIST_DICT:
175 tag = "dict";
176 isStruct = TRUE;
177 break;
178 case PLIST_DATE: //TODO : handle date tag
179 default:
180 break;
181 }
182
183 int i = 0;
184 for (i = 0; i < xstruct->depth; i++) {
185 xmlNodeAddContent(xstruct->xml, "\t");
186 }
187 child_node = xmlNewChild(xstruct->xml, NULL, tag, val);
188 xmlNodeAddContent(xstruct->xml, "\n");
189 g_free(val);
190
191 //add return for structured types
192 if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA)
193 xmlNodeAddContent(child_node, "\n");
194
195 if (isStruct) {
196 struct xml_node child = { child_node, xstruct->depth + 1 };
197 g_node_children_foreach(node, G_TRAVERSE_ALL, node_to_xml, &child);
198 }
199 //fix indent for structured types
200 if (node_data->type == PLIST_ARRAY || node_data->type == PLIST_DICT || node_data->type == PLIST_DATA) {
201
202 for (i = 0; i < xstruct->depth; i++) {
203 xmlNodeAddContent(child_node, "\t");
204 }
205 }
206
207 return;
208}
209
210void xml_to_node(xmlNodePtr xml_node, GNode * plist_node)
211{
212 xmlNodePtr node = NULL;
213
214 for (node = xml_node->children; node; node = node->next) {
215
216 while (node && !xmlStrcmp(node->name, "text"))
217 node = node->next;
218 if (!node)
219 break;
220
221 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
222 GNode *subnode = g_node_new(data);
223 g_node_append(plist_node, subnode);
224
225 if (!xmlStrcmp(node->name, "true")) {
226 data->boolval = 1;
227 data->type = PLIST_BOOLEAN;
228 continue;
229 }
230
231 if (!xmlStrcmp(node->name, "false")) {
232 data->boolval = 0;
233 data->type = PLIST_BOOLEAN;
234 continue;
235 }
236
237 if (!xmlStrcmp(node->name, "integer")) {
238 char *strval = xmlNodeGetContent(node);
239 data->intval = atoi(strval);
240 data->type = PLIST_UINT;
241 continue;
242 }
243
244 if (!xmlStrcmp(node->name, "real")) {
245 char *strval = xmlNodeGetContent(node);
246 data->realval = atof(strval);
247 data->type = PLIST_REAL;
248 continue;
249 }
250
251 if (!xmlStrcmp(node->name, "date"))
252 continue; //TODO : handle date tag
253
254 if (!xmlStrcmp(node->name, "string")) {
255 data->strval = strdup(xmlNodeGetContent(node));
256 data->type = PLIST_STRING;
257 continue;
258 }
259
260 if (!xmlStrcmp(node->name, "key")) {
261 data->strval = strdup(xmlNodeGetContent(node));
262 data->type = PLIST_KEY;
263 continue;
264 }
265
266 if (!xmlStrcmp(node->name, "data")) {
267 data->buff = strdup(xmlNodeGetContent(node));
268 data->type = PLIST_DATA;
269 continue;
270 }
271
272 if (!xmlStrcmp(node->name, "array")) {
273 data->type = PLIST_ARRAY;
274 xml_to_node(node, subnode);
275 continue;
276 }
277
278 if (!xmlStrcmp(node->name, "dict")) {
279 data->type = PLIST_DICT;
280 xml_to_node(node, subnode);
281 continue;
282 }
283 }
284}
285
286void plist_to_xml(plist_t plist, char **plist_xml, uint32_t * length)
287{
288 if (!plist || !plist_xml || *plist_xml)
289 return;
290 xmlDocPtr plist_doc = new_plist();
291 xmlNodePtr root_node = xmlDocGetRootElement(plist_doc);
292 struct xml_node root = { root_node, 0 };
293 g_node_children_foreach(plist, G_TRAVERSE_ALL, node_to_xml, &root);
294 xmlDocDumpMemory(plist_doc, (xmlChar **) plist_xml, length);
295}
296
297void xml_to_plist(const char *plist_xml, uint32_t length, plist_t * plist)
298{
299 xmlDocPtr plist_doc = xmlReadMemory(plist_xml, length, NULL, NULL, 0);
300 xmlNodePtr root_node = xmlDocGetRootElement(plist_doc);
301
302 struct plist_data *data = (struct plist_data *) calloc(sizeof(struct plist_data), 1);
303 *plist = g_node_new(data);
304 data->type = PLIST_DICT;
305 xml_to_node(root_node, *plist);
306}