libtreestore

view src/xmltree.c @ 0:740fec9866b1

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