rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 This file is part of the s-ray renderer <http://code.google.com/p/sray>.
|
nuclear@0
|
3 Copyright (C) 2009 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@0
|
4
|
nuclear@0
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@0
|
6 it under the terms of the GNU General Public License as published by
|
nuclear@0
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@0
|
8 (at your option) any later version.
|
nuclear@0
|
9
|
nuclear@0
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@0
|
13 GNU General Public License for more details.
|
nuclear@0
|
14
|
nuclear@0
|
15 You should have received a copy of the GNU General Public License
|
nuclear@0
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@0
|
17 */
|
nuclear@0
|
18 /* TODO list
|
nuclear@0
|
19 * - fix cdata handling. make a nodes's cdata into a number of ordered children
|
nuclear@0
|
20 */
|
nuclear@0
|
21 #include <stdio.h>
|
nuclear@0
|
22 #include <stdlib.h>
|
nuclear@0
|
23 #include <string.h>
|
nuclear@0
|
24 #include <ctype.h>
|
nuclear@0
|
25 #include <assert.h>
|
nuclear@0
|
26 #include <expat.h>
|
nuclear@0
|
27 #include "xmltree.h"
|
nuclear@0
|
28
|
nuclear@0
|
29 #ifdef _MSC_VER
|
nuclear@0
|
30 typedef int ssize_t;
|
nuclear@0
|
31 #endif
|
nuclear@0
|
32
|
nuclear@0
|
33 struct parse_data {
|
nuclear@0
|
34 XML_Parser parser;
|
nuclear@0
|
35 struct xml_node *cur_node;
|
nuclear@0
|
36
|
nuclear@0
|
37 char *buf;
|
nuclear@0
|
38 int buf_size;
|
nuclear@0
|
39 };
|
nuclear@0
|
40
|
nuclear@0
|
41 static void start(void *udata, const char *name, const char **atts);
|
nuclear@0
|
42 static void end(void *udata, const char *name);
|
nuclear@0
|
43 static void cdata(void *udata, const char *text, int len);
|
nuclear@0
|
44 static void finish_cdata(struct parse_data *pdata);
|
nuclear@0
|
45 static void abort_parsing(XML_Parser p);
|
nuclear@0
|
46 static int write_rec(struct xml_node *x, FILE *fp, int lvl);
|
nuclear@0
|
47
|
nuclear@0
|
48 #define IND_SPACES 4
|
nuclear@0
|
49 static void indent(FILE *fp, int lvl);
|
nuclear@0
|
50
|
nuclear@0
|
51 struct xml_attr *xml_create_attr(const char *name, const char *val)
|
nuclear@0
|
52 {
|
nuclear@0
|
53 struct xml_attr *attr;
|
nuclear@0
|
54
|
nuclear@0
|
55 if(!(attr = malloc(sizeof *attr))) {
|
nuclear@0
|
56 return 0;
|
nuclear@0
|
57 }
|
nuclear@0
|
58 memset(attr, 0, sizeof *attr);
|
nuclear@0
|
59
|
nuclear@0
|
60 if(name) {
|
nuclear@0
|
61 if(!(attr->name = malloc(strlen(name) + 1))) {
|
nuclear@0
|
62 free(attr);
|
nuclear@0
|
63 return 0;
|
nuclear@0
|
64 }
|
nuclear@0
|
65 strcpy(attr->name, name);
|
nuclear@0
|
66 }
|
nuclear@0
|
67
|
nuclear@0
|
68 if(val) {
|
nuclear@0
|
69 if(!(attr->str = malloc(strlen(val) + 1))) {
|
nuclear@0
|
70 free(attr->name);
|
nuclear@0
|
71 free(attr);
|
nuclear@0
|
72 return 0;
|
nuclear@0
|
73 }
|
nuclear@0
|
74 strcpy(attr->str, val);
|
nuclear@0
|
75
|
nuclear@0
|
76 if(isdigit(val[0]) || ((val[0] == '+' || val[0] == '-') && isdigit(val[1]))) {
|
nuclear@0
|
77 int i;
|
nuclear@0
|
78 attr->type = strchr(val, '.') ? ATYPE_FLT : ATYPE_INT;
|
nuclear@0
|
79 attr->ival = atoi(val);
|
nuclear@0
|
80 attr->fval = atof(val);
|
nuclear@0
|
81
|
nuclear@0
|
82 attr->vval[0] = attr->vval[1] = attr->vval[2] = attr->vval[3] = 1.0;
|
nuclear@0
|
83
|
nuclear@0
|
84 for(i=0; i<4; i++) {
|
nuclear@0
|
85 if(!*val) break;
|
nuclear@0
|
86 attr->vval[i] = atof(val);
|
nuclear@0
|
87
|
nuclear@0
|
88 while(*val && !isspace(*val)) val++;
|
nuclear@0
|
89 while(*val && isspace(*val)) val++;
|
nuclear@0
|
90 }
|
nuclear@0
|
91
|
nuclear@0
|
92 if(i > 1) {
|
nuclear@0
|
93 attr->type = ATYPE_VEC;
|
nuclear@0
|
94 }
|
nuclear@0
|
95 }
|
nuclear@0
|
96 }
|
nuclear@0
|
97
|
nuclear@0
|
98 return attr;
|
nuclear@0
|
99 }
|
nuclear@0
|
100
|
nuclear@0
|
101 void xml_free_attr(struct xml_attr *attr)
|
nuclear@0
|
102 {
|
nuclear@0
|
103 free(attr->name);
|
nuclear@0
|
104 free(attr->str);
|
nuclear@0
|
105 free(attr);
|
nuclear@0
|
106 }
|
nuclear@0
|
107
|
nuclear@0
|
108 void xml_free_attr_list(struct xml_attr *alist)
|
nuclear@0
|
109 {
|
nuclear@0
|
110 while(alist) {
|
nuclear@0
|
111 struct xml_attr *tmp = alist;
|
nuclear@0
|
112 alist = alist->next;
|
nuclear@0
|
113
|
nuclear@0
|
114 xml_free_attr(tmp);
|
nuclear@0
|
115 }
|
nuclear@0
|
116 }
|
nuclear@0
|
117
|
nuclear@0
|
118 struct xml_attr *xml_get_attr(struct xml_node *node, const char *attr_name)
|
nuclear@0
|
119 {
|
nuclear@0
|
120 struct xml_attr *attr;
|
nuclear@0
|
121
|
nuclear@0
|
122 attr = node->attr;
|
nuclear@0
|
123 while(attr) {
|
nuclear@0
|
124 if(strcmp(attr->name, attr_name) == 0) {
|
nuclear@0
|
125 return attr;
|
nuclear@0
|
126 }
|
nuclear@0
|
127 attr = attr->next;
|
nuclear@0
|
128 }
|
nuclear@0
|
129 return 0;
|
nuclear@0
|
130 }
|
nuclear@0
|
131
|
nuclear@0
|
132 struct xml_node *xml_create_tree(void)
|
nuclear@0
|
133 {
|
nuclear@0
|
134 struct xml_node *x;
|
nuclear@0
|
135
|
nuclear@0
|
136 if(!(x = malloc(sizeof *x))) {
|
nuclear@0
|
137 return 0;
|
nuclear@0
|
138 }
|
nuclear@0
|
139 memset(x, 0, sizeof *x);
|
nuclear@0
|
140
|
nuclear@0
|
141 return x;
|
nuclear@0
|
142 }
|
nuclear@0
|
143
|
nuclear@0
|
144 void xml_free_tree(struct xml_node *x)
|
nuclear@0
|
145 {
|
nuclear@0
|
146 while(x->chld) {
|
nuclear@0
|
147 void *tmp = x->chld;
|
nuclear@0
|
148
|
nuclear@0
|
149 x->chld = x->chld->next;
|
nuclear@0
|
150 xml_free_tree(tmp);
|
nuclear@0
|
151 }
|
nuclear@0
|
152
|
nuclear@0
|
153 while(x->attr) {
|
nuclear@0
|
154 struct xml_attr *tmp = x->attr;
|
nuclear@0
|
155 x->attr = x->attr->next;
|
nuclear@0
|
156
|
nuclear@0
|
157 free(tmp->name);
|
nuclear@0
|
158 free(tmp->str);
|
nuclear@0
|
159 free(tmp);
|
nuclear@0
|
160 }
|
nuclear@0
|
161
|
nuclear@0
|
162 free(x->cdata);
|
nuclear@0
|
163 free(x->name);
|
nuclear@0
|
164 free(x);
|
nuclear@0
|
165 }
|
nuclear@0
|
166
|
nuclear@0
|
167 struct xml_node *xml_read_tree(const char *fname)
|
nuclear@0
|
168 {
|
nuclear@0
|
169 FILE *fp;
|
nuclear@0
|
170 struct xml_node *xml;
|
nuclear@0
|
171
|
nuclear@0
|
172 if(!(fp = fopen(fname, "rb"))) {
|
nuclear@0
|
173 return 0;
|
nuclear@0
|
174 }
|
nuclear@0
|
175 xml = xml_read_tree_file(fp);
|
nuclear@0
|
176 fclose(fp);
|
nuclear@0
|
177 return xml;
|
nuclear@0
|
178 }
|
nuclear@0
|
179
|
nuclear@0
|
180 struct xml_node *xml_read_tree_file(FILE *fp)
|
nuclear@0
|
181 {
|
nuclear@0
|
182 struct parse_data pdata;
|
nuclear@0
|
183 struct xml_node node, *tree;
|
nuclear@0
|
184 XML_Parser p;
|
nuclear@0
|
185 ssize_t rdsz;
|
nuclear@0
|
186 void *buf;
|
nuclear@0
|
187
|
nuclear@0
|
188 memset(&node, 0, sizeof node);
|
nuclear@0
|
189
|
nuclear@0
|
190 if(!(p = XML_ParserCreate(0))) {
|
nuclear@0
|
191 return 0;
|
nuclear@0
|
192 }
|
nuclear@0
|
193 XML_SetElementHandler(p, start, end);
|
nuclear@0
|
194 XML_SetCharacterDataHandler(p, cdata);
|
nuclear@0
|
195 XML_SetUserData(p, &pdata);
|
nuclear@0
|
196
|
nuclear@0
|
197 memset(&pdata, 0, sizeof pdata);
|
nuclear@0
|
198 pdata.parser = p;
|
nuclear@0
|
199 pdata.cur_node = &node;
|
nuclear@0
|
200
|
nuclear@0
|
201 do {
|
nuclear@0
|
202 if(!(buf = XML_GetBuffer(p, 4096))) {
|
nuclear@0
|
203 break;
|
nuclear@0
|
204 }
|
nuclear@0
|
205
|
nuclear@0
|
206 if((rdsz = fread(buf, 1, 4096, fp)) == -1) {
|
nuclear@0
|
207 break;
|
nuclear@0
|
208 }
|
nuclear@0
|
209
|
nuclear@0
|
210 if(!XML_ParseBuffer(p, rdsz, rdsz < 4096)) {
|
nuclear@0
|
211 fprintf(stderr, "XML parsing error: %d: %s\n", (int)XML_GetCurrentLineNumber(p),
|
nuclear@0
|
212 XML_ErrorString(XML_GetErrorCode(p)));
|
nuclear@0
|
213 break;
|
nuclear@0
|
214 }
|
nuclear@0
|
215 } while(rdsz == 4096);
|
nuclear@0
|
216
|
nuclear@0
|
217 tree = node.chld;
|
nuclear@0
|
218 if(tree) {
|
nuclear@0
|
219 assert(tree->next == 0);
|
nuclear@0
|
220 }
|
nuclear@0
|
221
|
nuclear@0
|
222 if(pdata.cur_node != &node) { /* aborted */
|
nuclear@0
|
223 xml_free_tree(tree);
|
nuclear@0
|
224 tree = 0;
|
nuclear@0
|
225 }
|
nuclear@0
|
226
|
nuclear@0
|
227 if(pdata.buf) {
|
nuclear@0
|
228 free(pdata.buf);
|
nuclear@0
|
229 }
|
nuclear@0
|
230
|
nuclear@0
|
231 XML_ParserFree(p);
|
nuclear@0
|
232 return tree;
|
nuclear@0
|
233 }
|
nuclear@0
|
234
|
nuclear@0
|
235 static void start(void *udata, const char *name, const char **atts)
|
nuclear@0
|
236 {
|
nuclear@0
|
237 struct xml_node *node = 0;
|
nuclear@0
|
238 struct parse_data *pdata = udata;
|
nuclear@0
|
239
|
nuclear@0
|
240 finish_cdata(pdata);
|
nuclear@0
|
241
|
nuclear@0
|
242 if(!(node = malloc(sizeof *node))) {
|
nuclear@0
|
243 goto err;
|
nuclear@0
|
244 }
|
nuclear@0
|
245 memset(node, 0, sizeof *node);
|
nuclear@0
|
246
|
nuclear@0
|
247 if(!(node->name = malloc(strlen(name) + 1))) {
|
nuclear@0
|
248 goto err;
|
nuclear@0
|
249 }
|
nuclear@0
|
250 strcpy(node->name, name);
|
nuclear@0
|
251
|
nuclear@0
|
252 while(*atts) {
|
nuclear@0
|
253 struct xml_attr *attr;
|
nuclear@0
|
254
|
nuclear@0
|
255 if(!(attr = xml_create_attr(atts[0], atts[1]))) {
|
nuclear@0
|
256 goto err;
|
nuclear@0
|
257 }
|
nuclear@0
|
258 attr->next = node->attr;
|
nuclear@0
|
259 node->attr = attr;
|
nuclear@0
|
260
|
nuclear@0
|
261 atts += 2;
|
nuclear@0
|
262 }
|
nuclear@0
|
263
|
nuclear@0
|
264 xml_add_child(pdata->cur_node, node);
|
nuclear@0
|
265 pdata->cur_node = node;
|
nuclear@0
|
266 return;
|
nuclear@0
|
267
|
nuclear@0
|
268 err:
|
nuclear@0
|
269 if(node) {
|
nuclear@0
|
270 free(node->name);
|
nuclear@0
|
271 xml_free_attr_list(node->attr);
|
nuclear@0
|
272 }
|
nuclear@0
|
273 free(node);
|
nuclear@0
|
274 abort_parsing(pdata->parser);
|
nuclear@0
|
275 }
|
nuclear@0
|
276
|
nuclear@0
|
277 static void end(void *udata, const char *name)
|
nuclear@0
|
278 {
|
nuclear@0
|
279 struct parse_data *pdata = udata;
|
nuclear@0
|
280
|
nuclear@0
|
281 finish_cdata(pdata);
|
nuclear@0
|
282
|
nuclear@0
|
283 pdata->cur_node = pdata->cur_node->up;
|
nuclear@0
|
284 }
|
nuclear@0
|
285
|
nuclear@0
|
286 static void cdata(void *udata, const char *text, int len)
|
nuclear@0
|
287 {
|
nuclear@0
|
288 char *tmp;
|
nuclear@0
|
289 struct parse_data *pdata = udata;
|
nuclear@0
|
290
|
nuclear@0
|
291 if(!(tmp = realloc(pdata->buf, pdata->buf_size + len))) {
|
nuclear@0
|
292 abort_parsing(pdata->parser);
|
nuclear@0
|
293 return;
|
nuclear@0
|
294 }
|
nuclear@0
|
295 memcpy(tmp + pdata->buf_size, text, len);
|
nuclear@0
|
296 pdata->buf = tmp;
|
nuclear@0
|
297 pdata->buf_size += len;
|
nuclear@0
|
298 }
|
nuclear@0
|
299
|
nuclear@0
|
300 static void finish_cdata(struct parse_data *pdata)
|
nuclear@0
|
301 {
|
nuclear@0
|
302 char *tmp;
|
nuclear@0
|
303
|
nuclear@0
|
304 if(!pdata->buf) {
|
nuclear@0
|
305 return;
|
nuclear@0
|
306 }
|
nuclear@0
|
307
|
nuclear@0
|
308 if(!(tmp = realloc(pdata->buf, pdata->buf_size + 1))) {
|
nuclear@0
|
309 abort_parsing(pdata->parser);
|
nuclear@0
|
310 return;
|
nuclear@0
|
311 }
|
nuclear@0
|
312 tmp[pdata->buf_size] = 0;
|
nuclear@0
|
313 pdata->cur_node->cdata = tmp;
|
nuclear@0
|
314
|
nuclear@0
|
315 pdata->buf = 0;
|
nuclear@0
|
316 pdata->buf_size = 0;
|
nuclear@0
|
317 }
|
nuclear@0
|
318
|
nuclear@0
|
319 static void abort_parsing(XML_Parser p)
|
nuclear@0
|
320 {
|
nuclear@0
|
321 perror("abort XML parsing");
|
nuclear@0
|
322
|
nuclear@0
|
323 XML_SetElementHandler(p, 0, 0);
|
nuclear@0
|
324 XML_SetCharacterDataHandler(p, 0);
|
nuclear@0
|
325 XML_StopParser(p, 0);
|
nuclear@0
|
326 }
|
nuclear@0
|
327
|
nuclear@0
|
328 int xml_write_tree(struct xml_node *x, const char *fname)
|
nuclear@0
|
329 {
|
nuclear@0
|
330 FILE *fp;
|
nuclear@0
|
331 int res;
|
nuclear@0
|
332
|
nuclear@0
|
333 if(!(fp = fopen(fname, "wb"))) {
|
nuclear@0
|
334 return -1;
|
nuclear@0
|
335 }
|
nuclear@0
|
336 res = xml_write_tree_file(x, fp);
|
nuclear@0
|
337 fclose(fp);
|
nuclear@0
|
338 return res;
|
nuclear@0
|
339 }
|
nuclear@0
|
340
|
nuclear@0
|
341 int xml_write_tree_file(struct xml_node *x, FILE *fp)
|
nuclear@0
|
342 {
|
nuclear@0
|
343 return write_rec(x, fp, 0);
|
nuclear@0
|
344 }
|
nuclear@0
|
345
|
nuclear@0
|
346 static int write_rec(struct xml_node *x, FILE *fp, int lvl)
|
nuclear@0
|
347 {
|
nuclear@0
|
348 struct xml_node *c;
|
nuclear@0
|
349 struct xml_attr *attr;
|
nuclear@0
|
350
|
nuclear@0
|
351 indent(fp, lvl);
|
nuclear@0
|
352 fputc('<', fp);
|
nuclear@0
|
353 fputs(x->name, fp);
|
nuclear@0
|
354
|
nuclear@0
|
355 attr = x->attr;
|
nuclear@0
|
356 while(attr) {
|
nuclear@0
|
357 switch(attr->type) {
|
nuclear@0
|
358 case ATYPE_INT:
|
nuclear@0
|
359 fprintf(fp, " %s=\"%d\"", attr->name, attr->ival);
|
nuclear@0
|
360 break;
|
nuclear@0
|
361
|
nuclear@0
|
362 case ATYPE_FLT:
|
nuclear@0
|
363 fprintf(fp, " %s=\"%.4f\"", attr->name, attr->fval);
|
nuclear@0
|
364 break;
|
nuclear@0
|
365
|
nuclear@0
|
366 case ATYPE_VEC:
|
nuclear@0
|
367 fprintf(fp, " %s=\"%.4f %.4f %.4f %.4f\"", attr->name, attr->vval[0],
|
nuclear@0
|
368 attr->vval[1], attr->vval[2], attr->vval[3]);
|
nuclear@0
|
369 break;
|
nuclear@0
|
370
|
nuclear@0
|
371 case ATYPE_STR:
|
nuclear@0
|
372 default:
|
nuclear@0
|
373 fprintf(fp, " %s=\"%s\"", attr->name, attr->str);
|
nuclear@0
|
374 break;
|
nuclear@0
|
375 }
|
nuclear@0
|
376
|
nuclear@0
|
377 attr = attr->next;
|
nuclear@0
|
378 }
|
nuclear@0
|
379
|
nuclear@0
|
380 if(!x->chld && !x->cdata) {
|
nuclear@0
|
381 fputc('/', fp);
|
nuclear@0
|
382 }
|
nuclear@0
|
383 fprintf(fp, ">\n");
|
nuclear@0
|
384
|
nuclear@0
|
385 if(x->cdata) {
|
nuclear@0
|
386 indent(fp, lvl + 1);
|
nuclear@0
|
387 fprintf(fp, "%s\n", x->cdata);
|
nuclear@0
|
388 }
|
nuclear@0
|
389
|
nuclear@0
|
390 c = x->chld;
|
nuclear@0
|
391 while(c) {
|
nuclear@0
|
392 write_rec(c, fp, lvl + 1);
|
nuclear@0
|
393 c = c->next;
|
nuclear@0
|
394 }
|
nuclear@0
|
395
|
nuclear@0
|
396 if(x->chld || x->cdata) {
|
nuclear@0
|
397 indent(fp, lvl);
|
nuclear@0
|
398 fprintf(fp, "</%s>\n", x->name);
|
nuclear@0
|
399 }
|
nuclear@0
|
400 return 0;
|
nuclear@0
|
401 }
|
nuclear@0
|
402
|
nuclear@0
|
403 void xml_add_child(struct xml_node *x, struct xml_node *chld)
|
nuclear@0
|
404 {
|
nuclear@0
|
405 chld->next = 0;
|
nuclear@0
|
406
|
nuclear@0
|
407 if(x->chld) {
|
nuclear@0
|
408 x->chld_tail->next = chld;
|
nuclear@0
|
409 x->chld_tail = chld;
|
nuclear@0
|
410 } else {
|
nuclear@0
|
411 x->chld = x->chld_tail = chld;
|
nuclear@0
|
412 }
|
nuclear@0
|
413
|
nuclear@0
|
414 chld->up = x;
|
nuclear@0
|
415 x->chld_count++;
|
nuclear@0
|
416 }
|
nuclear@0
|
417
|
nuclear@0
|
418 void xml_remove_subtree(struct xml_node *sub)
|
nuclear@0
|
419 {
|
nuclear@0
|
420 struct xml_node *x;
|
nuclear@0
|
421
|
nuclear@0
|
422 if(sub->up) {
|
nuclear@0
|
423 x = sub->up->chld;
|
nuclear@0
|
424 if(x == sub) {
|
nuclear@0
|
425 sub->up->chld = sub->next;
|
nuclear@0
|
426 } else {
|
nuclear@0
|
427 while(x) {
|
nuclear@0
|
428 if(x->next == sub) {
|
nuclear@0
|
429 x->next = x->next->next;
|
nuclear@0
|
430 break;
|
nuclear@0
|
431 }
|
nuclear@0
|
432 x = x->next;
|
nuclear@0
|
433 }
|
nuclear@0
|
434 }
|
nuclear@0
|
435 }
|
nuclear@0
|
436
|
nuclear@0
|
437 sub->up->chld_count--;
|
nuclear@0
|
438 sub->up = 0;
|
nuclear@0
|
439 }
|
nuclear@0
|
440
|
nuclear@0
|
441 static void indent(FILE *fp, int lvl)
|
nuclear@0
|
442 {
|
nuclear@0
|
443 int i, ind = lvl * IND_SPACES;
|
nuclear@0
|
444
|
nuclear@0
|
445 for(i=0; i<ind; i++) {
|
nuclear@0
|
446 fputc(' ', fp);
|
nuclear@0
|
447 }
|
nuclear@0
|
448 }
|