libtreestore
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/xmltree.c Fri Apr 11 08:56:46 2014 +0300 1.3 @@ -0,0 +1,448 @@ 1.4 +/* 1.5 +This file is part of the s-ray renderer <http://code.google.com/p/sray>. 1.6 +Copyright (C) 2009 John Tsiombikas <nuclear@member.fsf.org> 1.7 + 1.8 +This program is free software: you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation, either version 3 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 1.20 +*/ 1.21 +/* TODO list 1.22 + * - fix cdata handling. make a nodes's cdata into a number of ordered children 1.23 + */ 1.24 +#include <stdio.h> 1.25 +#include <stdlib.h> 1.26 +#include <string.h> 1.27 +#include <ctype.h> 1.28 +#include <assert.h> 1.29 +#include <expat.h> 1.30 +#include "xmltree.h" 1.31 + 1.32 +#ifdef _MSC_VER 1.33 +typedef int ssize_t; 1.34 +#endif 1.35 + 1.36 +struct parse_data { 1.37 + XML_Parser parser; 1.38 + struct xml_node *cur_node; 1.39 + 1.40 + char *buf; 1.41 + int buf_size; 1.42 +}; 1.43 + 1.44 +static void start(void *udata, const char *name, const char **atts); 1.45 +static void end(void *udata, const char *name); 1.46 +static void cdata(void *udata, const char *text, int len); 1.47 +static void finish_cdata(struct parse_data *pdata); 1.48 +static void abort_parsing(XML_Parser p); 1.49 +static int write_rec(struct xml_node *x, FILE *fp, int lvl); 1.50 + 1.51 +#define IND_SPACES 4 1.52 +static void indent(FILE *fp, int lvl); 1.53 + 1.54 +struct xml_attr *xml_create_attr(const char *name, const char *val) 1.55 +{ 1.56 + struct xml_attr *attr; 1.57 + 1.58 + if(!(attr = malloc(sizeof *attr))) { 1.59 + return 0; 1.60 + } 1.61 + memset(attr, 0, sizeof *attr); 1.62 + 1.63 + if(name) { 1.64 + if(!(attr->name = malloc(strlen(name) + 1))) { 1.65 + free(attr); 1.66 + return 0; 1.67 + } 1.68 + strcpy(attr->name, name); 1.69 + } 1.70 + 1.71 + if(val) { 1.72 + if(!(attr->str = malloc(strlen(val) + 1))) { 1.73 + free(attr->name); 1.74 + free(attr); 1.75 + return 0; 1.76 + } 1.77 + strcpy(attr->str, val); 1.78 + 1.79 + if(isdigit(val[0]) || ((val[0] == '+' || val[0] == '-') && isdigit(val[1]))) { 1.80 + int i; 1.81 + attr->type = strchr(val, '.') ? ATYPE_FLT : ATYPE_INT; 1.82 + attr->ival = atoi(val); 1.83 + attr->fval = atof(val); 1.84 + 1.85 + attr->vval[0] = attr->vval[1] = attr->vval[2] = attr->vval[3] = 1.0; 1.86 + 1.87 + for(i=0; i<4; i++) { 1.88 + if(!*val) break; 1.89 + attr->vval[i] = atof(val); 1.90 + 1.91 + while(*val && !isspace(*val)) val++; 1.92 + while(*val && isspace(*val)) val++; 1.93 + } 1.94 + 1.95 + if(i > 1) { 1.96 + attr->type = ATYPE_VEC; 1.97 + } 1.98 + } 1.99 + } 1.100 + 1.101 + return attr; 1.102 +} 1.103 + 1.104 +void xml_free_attr(struct xml_attr *attr) 1.105 +{ 1.106 + free(attr->name); 1.107 + free(attr->str); 1.108 + free(attr); 1.109 +} 1.110 + 1.111 +void xml_free_attr_list(struct xml_attr *alist) 1.112 +{ 1.113 + while(alist) { 1.114 + struct xml_attr *tmp = alist; 1.115 + alist = alist->next; 1.116 + 1.117 + xml_free_attr(tmp); 1.118 + } 1.119 +} 1.120 + 1.121 +struct xml_attr *xml_get_attr(struct xml_node *node, const char *attr_name) 1.122 +{ 1.123 + struct xml_attr *attr; 1.124 + 1.125 + attr = node->attr; 1.126 + while(attr) { 1.127 + if(strcmp(attr->name, attr_name) == 0) { 1.128 + return attr; 1.129 + } 1.130 + attr = attr->next; 1.131 + } 1.132 + return 0; 1.133 +} 1.134 + 1.135 +struct xml_node *xml_create_tree(void) 1.136 +{ 1.137 + struct xml_node *x; 1.138 + 1.139 + if(!(x = malloc(sizeof *x))) { 1.140 + return 0; 1.141 + } 1.142 + memset(x, 0, sizeof *x); 1.143 + 1.144 + return x; 1.145 +} 1.146 + 1.147 +void xml_free_tree(struct xml_node *x) 1.148 +{ 1.149 + while(x->chld) { 1.150 + void *tmp = x->chld; 1.151 + 1.152 + x->chld = x->chld->next; 1.153 + xml_free_tree(tmp); 1.154 + } 1.155 + 1.156 + while(x->attr) { 1.157 + struct xml_attr *tmp = x->attr; 1.158 + x->attr = x->attr->next; 1.159 + 1.160 + free(tmp->name); 1.161 + free(tmp->str); 1.162 + free(tmp); 1.163 + } 1.164 + 1.165 + free(x->cdata); 1.166 + free(x->name); 1.167 + free(x); 1.168 +} 1.169 + 1.170 +struct xml_node *xml_read_tree(const char *fname) 1.171 +{ 1.172 + FILE *fp; 1.173 + struct xml_node *xml; 1.174 + 1.175 + if(!(fp = fopen(fname, "rb"))) { 1.176 + return 0; 1.177 + } 1.178 + xml = xml_read_tree_file(fp); 1.179 + fclose(fp); 1.180 + return xml; 1.181 +} 1.182 + 1.183 +struct xml_node *xml_read_tree_file(FILE *fp) 1.184 +{ 1.185 + struct parse_data pdata; 1.186 + struct xml_node node, *tree; 1.187 + XML_Parser p; 1.188 + ssize_t rdsz; 1.189 + void *buf; 1.190 + 1.191 + memset(&node, 0, sizeof node); 1.192 + 1.193 + if(!(p = XML_ParserCreate(0))) { 1.194 + return 0; 1.195 + } 1.196 + XML_SetElementHandler(p, start, end); 1.197 + XML_SetCharacterDataHandler(p, cdata); 1.198 + XML_SetUserData(p, &pdata); 1.199 + 1.200 + memset(&pdata, 0, sizeof pdata); 1.201 + pdata.parser = p; 1.202 + pdata.cur_node = &node; 1.203 + 1.204 + do { 1.205 + if(!(buf = XML_GetBuffer(p, 4096))) { 1.206 + break; 1.207 + } 1.208 + 1.209 + if((rdsz = fread(buf, 1, 4096, fp)) == -1) { 1.210 + break; 1.211 + } 1.212 + 1.213 + if(!XML_ParseBuffer(p, rdsz, rdsz < 4096)) { 1.214 + fprintf(stderr, "XML parsing error: %d: %s\n", (int)XML_GetCurrentLineNumber(p), 1.215 + XML_ErrorString(XML_GetErrorCode(p))); 1.216 + break; 1.217 + } 1.218 + } while(rdsz == 4096); 1.219 + 1.220 + tree = node.chld; 1.221 + if(tree) { 1.222 + assert(tree->next == 0); 1.223 + } 1.224 + 1.225 + if(pdata.cur_node != &node) { /* aborted */ 1.226 + xml_free_tree(tree); 1.227 + tree = 0; 1.228 + } 1.229 + 1.230 + if(pdata.buf) { 1.231 + free(pdata.buf); 1.232 + } 1.233 + 1.234 + XML_ParserFree(p); 1.235 + return tree; 1.236 +} 1.237 + 1.238 +static void start(void *udata, const char *name, const char **atts) 1.239 +{ 1.240 + struct xml_node *node = 0; 1.241 + struct parse_data *pdata = udata; 1.242 + 1.243 + finish_cdata(pdata); 1.244 + 1.245 + if(!(node = malloc(sizeof *node))) { 1.246 + goto err; 1.247 + } 1.248 + memset(node, 0, sizeof *node); 1.249 + 1.250 + if(!(node->name = malloc(strlen(name) + 1))) { 1.251 + goto err; 1.252 + } 1.253 + strcpy(node->name, name); 1.254 + 1.255 + while(*atts) { 1.256 + struct xml_attr *attr; 1.257 + 1.258 + if(!(attr = xml_create_attr(atts[0], atts[1]))) { 1.259 + goto err; 1.260 + } 1.261 + attr->next = node->attr; 1.262 + node->attr = attr; 1.263 + 1.264 + atts += 2; 1.265 + } 1.266 + 1.267 + xml_add_child(pdata->cur_node, node); 1.268 + pdata->cur_node = node; 1.269 + return; 1.270 + 1.271 +err: 1.272 + if(node) { 1.273 + free(node->name); 1.274 + xml_free_attr_list(node->attr); 1.275 + } 1.276 + free(node); 1.277 + abort_parsing(pdata->parser); 1.278 +} 1.279 + 1.280 +static void end(void *udata, const char *name) 1.281 +{ 1.282 + struct parse_data *pdata = udata; 1.283 + 1.284 + finish_cdata(pdata); 1.285 + 1.286 + pdata->cur_node = pdata->cur_node->up; 1.287 +} 1.288 + 1.289 +static void cdata(void *udata, const char *text, int len) 1.290 +{ 1.291 + char *tmp; 1.292 + struct parse_data *pdata = udata; 1.293 + 1.294 + if(!(tmp = realloc(pdata->buf, pdata->buf_size + len))) { 1.295 + abort_parsing(pdata->parser); 1.296 + return; 1.297 + } 1.298 + memcpy(tmp + pdata->buf_size, text, len); 1.299 + pdata->buf = tmp; 1.300 + pdata->buf_size += len; 1.301 +} 1.302 + 1.303 +static void finish_cdata(struct parse_data *pdata) 1.304 +{ 1.305 + char *tmp; 1.306 + 1.307 + if(!pdata->buf) { 1.308 + return; 1.309 + } 1.310 + 1.311 + if(!(tmp = realloc(pdata->buf, pdata->buf_size + 1))) { 1.312 + abort_parsing(pdata->parser); 1.313 + return; 1.314 + } 1.315 + tmp[pdata->buf_size] = 0; 1.316 + pdata->cur_node->cdata = tmp; 1.317 + 1.318 + pdata->buf = 0; 1.319 + pdata->buf_size = 0; 1.320 +} 1.321 + 1.322 +static void abort_parsing(XML_Parser p) 1.323 +{ 1.324 + perror("abort XML parsing"); 1.325 + 1.326 + XML_SetElementHandler(p, 0, 0); 1.327 + XML_SetCharacterDataHandler(p, 0); 1.328 + XML_StopParser(p, 0); 1.329 +} 1.330 + 1.331 +int xml_write_tree(struct xml_node *x, const char *fname) 1.332 +{ 1.333 + FILE *fp; 1.334 + int res; 1.335 + 1.336 + if(!(fp = fopen(fname, "wb"))) { 1.337 + return -1; 1.338 + } 1.339 + res = xml_write_tree_file(x, fp); 1.340 + fclose(fp); 1.341 + return res; 1.342 +} 1.343 + 1.344 +int xml_write_tree_file(struct xml_node *x, FILE *fp) 1.345 +{ 1.346 + return write_rec(x, fp, 0); 1.347 +} 1.348 + 1.349 +static int write_rec(struct xml_node *x, FILE *fp, int lvl) 1.350 +{ 1.351 + struct xml_node *c; 1.352 + struct xml_attr *attr; 1.353 + 1.354 + indent(fp, lvl); 1.355 + fputc('<', fp); 1.356 + fputs(x->name, fp); 1.357 + 1.358 + attr = x->attr; 1.359 + while(attr) { 1.360 + switch(attr->type) { 1.361 + case ATYPE_INT: 1.362 + fprintf(fp, " %s=\"%d\"", attr->name, attr->ival); 1.363 + break; 1.364 + 1.365 + case ATYPE_FLT: 1.366 + fprintf(fp, " %s=\"%.4f\"", attr->name, attr->fval); 1.367 + break; 1.368 + 1.369 + case ATYPE_VEC: 1.370 + fprintf(fp, " %s=\"%.4f %.4f %.4f %.4f\"", attr->name, attr->vval[0], 1.371 + attr->vval[1], attr->vval[2], attr->vval[3]); 1.372 + break; 1.373 + 1.374 + case ATYPE_STR: 1.375 + default: 1.376 + fprintf(fp, " %s=\"%s\"", attr->name, attr->str); 1.377 + break; 1.378 + } 1.379 + 1.380 + attr = attr->next; 1.381 + } 1.382 + 1.383 + if(!x->chld && !x->cdata) { 1.384 + fputc('/', fp); 1.385 + } 1.386 + fprintf(fp, ">\n"); 1.387 + 1.388 + if(x->cdata) { 1.389 + indent(fp, lvl + 1); 1.390 + fprintf(fp, "%s\n", x->cdata); 1.391 + } 1.392 + 1.393 + c = x->chld; 1.394 + while(c) { 1.395 + write_rec(c, fp, lvl + 1); 1.396 + c = c->next; 1.397 + } 1.398 + 1.399 + if(x->chld || x->cdata) { 1.400 + indent(fp, lvl); 1.401 + fprintf(fp, "</%s>\n", x->name); 1.402 + } 1.403 + return 0; 1.404 +} 1.405 + 1.406 +void xml_add_child(struct xml_node *x, struct xml_node *chld) 1.407 +{ 1.408 + chld->next = 0; 1.409 + 1.410 + if(x->chld) { 1.411 + x->chld_tail->next = chld; 1.412 + x->chld_tail = chld; 1.413 + } else { 1.414 + x->chld = x->chld_tail = chld; 1.415 + } 1.416 + 1.417 + chld->up = x; 1.418 + x->chld_count++; 1.419 +} 1.420 + 1.421 +void xml_remove_subtree(struct xml_node *sub) 1.422 +{ 1.423 + struct xml_node *x; 1.424 + 1.425 + if(sub->up) { 1.426 + x = sub->up->chld; 1.427 + if(x == sub) { 1.428 + sub->up->chld = sub->next; 1.429 + } else { 1.430 + while(x) { 1.431 + if(x->next == sub) { 1.432 + x->next = x->next->next; 1.433 + break; 1.434 + } 1.435 + x = x->next; 1.436 + } 1.437 + } 1.438 + } 1.439 + 1.440 + sub->up->chld_count--; 1.441 + sub->up = 0; 1.442 +} 1.443 + 1.444 +static void indent(FILE *fp, int lvl) 1.445 +{ 1.446 + int i, ind = lvl * IND_SPACES; 1.447 + 1.448 + for(i=0; i<ind; i++) { 1.449 + fputc(' ', fp); 1.450 + } 1.451 +}