goat3d
changeset 22:44a20d72f3a6
merged
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 27 Sep 2013 07:14:49 +0300 |
parents | 0e31f2c3f29d f5fdefbb7a1d |
children | b59a3650ed51 |
files | src/goat3d_scene.cc |
diffstat | 20 files changed, 5349 insertions(+), 408 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.clang_complete Fri Sep 27 07:14:49 2013 +0300 1.3 @@ -0,0 +1,3 @@ 1.4 +-Isrc 1.5 +-Ilibs/openctm 1.6 +-Ilibs/tinyxml2
2.1 --- a/.hgignore Fri Sep 27 07:14:27 2013 +0300 2.2 +++ b/.hgignore Fri Sep 27 07:14:49 2013 +0300 2.3 @@ -10,3 +10,7 @@ 2.4 x64/ 2.5 \.tlog$ 2.6 ^tags$ 2.7 +\.xml$ 2.8 +\.ctm$ 2.9 +goatprim$ 2.10 +goatview$
3.1 --- a/Makefile Fri Sep 27 07:14:27 2013 +0300 3.2 +++ b/Makefile Fri Sep 27 07:14:49 2013 +0300 3.3 @@ -9,9 +9,10 @@ 3.4 dep = $(obj:.o=.d) 3.5 3.6 openctm = libs/openctm/libopenctm.a 3.7 +tinyxml2 = libs/tinyxml2/libtinyxml2.a 3.8 3.9 -extinc = -Ilibs/openctm 3.10 -extlibs = $(openctm) 3.11 +extinc = -Ilibs/openctm -Ilibs/tinyxml2 3.12 +extlibs = $(openctm) $(tinyxml2) 3.13 3.14 name = goat3d 3.15 so_major = 0 3.16 @@ -48,6 +49,9 @@ 3.17 $(openctm): 3.18 $(MAKE) -C libs/openctm 3.19 3.20 +$(tinyxml2): 3.21 + $(MAKE) -C libs/tinyxml2 3.22 + 3.23 -include $(dep) 3.24 3.25 %.d: %.cc
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/doc/goatanimfmt Fri Sep 27 07:14:49 2013 +0300 4.3 @@ -0,0 +1,3 @@ 4.4 +goat3d animation file format 4.5 +---------------------------- 4.6 +TODO
5.1 --- a/generators/goatprim/main.c Fri Sep 27 07:14:27 2013 +0300 5.2 +++ b/generators/goatprim/main.c Fri Sep 27 07:14:49 2013 +0300 5.3 @@ -1,78 +1,346 @@ 5.4 #include <stdio.h> 5.5 +#include <stdlib.h> 5.6 +#include <string.h> 5.7 +#include <math.h> 5.8 #include "goat3d.h" 5.9 5.10 -static struct goat3d_mesh *create_box(void); 5.11 +#define DEF_USUB 16 5.12 +#define DEF_VSUB 8 5.13 +#define DEF_SIZE 1.0 5.14 +#define DEF_OUTER 0.25 5.15 +#define DEF_DIFFUSE_R 0.6 5.16 +#define DEF_DIFFUSE_G 0.6 5.17 +#define DEF_DIFFUSE_B 0.6 5.18 +#define DEF_SPECULAR_R 0.8 5.19 +#define DEF_SPECULAR_G 0.8 5.20 +#define DEF_SPECULAR_B 0.8 5.21 +#define DEF_SHININESS 60.0 5.22 5.23 -int main(void) 5.24 +enum { BOX, SPHERE, TORUS }; 5.25 + 5.26 +void gen_box(struct goat3d_mesh *mesh, float size); 5.27 +void gen_sphere(struct goat3d_mesh *mesh, float rad, int usub, int vsub); 5.28 +void gen_sphere_part(struct goat3d_mesh *mesh, float rad, int usub, int vsub, float umax, float vmax); 5.29 +void gen_torus(struct goat3d_mesh *mesh, float inner, float outer, int usub, int vsub); 5.30 +void gen_torus_part(struct goat3d_mesh *mesh, float inner, float outer, 5.31 + int usub, int vsub, float umax, float vmin, float vmax); 5.32 + 5.33 + 5.34 +int main(int argc, char **argv) 5.35 { 5.36 + int i, prim = BOX; 5.37 + int usub = DEF_USUB; 5.38 + int vsub = DEF_VSUB; 5.39 + float size = DEF_SIZE; 5.40 + float outer = DEF_OUTER; 5.41 + float diffuse[] = {DEF_DIFFUSE_R, DEF_DIFFUSE_G, DEF_DIFFUSE_B, 1.0}; 5.42 + float specular[] = {DEF_SPECULAR_R, DEF_SPECULAR_G, DEF_SPECULAR_B, 1.0}; 5.43 + float shininess = DEF_SHININESS; 5.44 struct goat3d *goat; 5.45 struct goat3d_material *mtl; 5.46 struct goat3d_mesh *mesh; 5.47 + const char *fname = 0; 5.48 + 5.49 + for(i=1; i<argc; i++) { 5.50 + if(strcmp(argv[i], "-box") == 0) { 5.51 + prim = BOX; 5.52 + 5.53 + } else if(strcmp(argv[i], "-sphere") == 0) { 5.54 + prim = SPHERE; 5.55 + 5.56 + } else if(strcmp(argv[i], "-torus") == 0) { 5.57 + prim = TORUS; 5.58 + 5.59 + } else if(strcmp(argv[i], "-rad") == 0 || strcmp(argv[i], "-size") == 0 5.60 + || strcmp(argv[i], "-inner") == 0) { 5.61 + if((size = atof(argv[++i])) == 0.0) { 5.62 + fprintf(stderr, "invalid size\n"); 5.63 + return 1; 5.64 + } 5.65 + 5.66 + } else if(strcmp(argv[i], "-outer") == 0) { 5.67 + if((outer = atof(argv[++i])) == 0.0) { 5.68 + fprintf(stderr, "invalid outer radius\n"); 5.69 + return 1; 5.70 + } 5.71 + 5.72 + } else if(strcmp(argv[i], "-usub") == 0) { 5.73 + if(!(usub = atoi(argv[++i]))) { 5.74 + fprintf(stderr, "invalid usub\n"); 5.75 + return 1; 5.76 + } 5.77 + 5.78 + } else if(strcmp(argv[i], "-vsub") == 0) { 5.79 + if(!(vsub = atoi(argv[++i]))) { 5.80 + fprintf(stderr, "invalid vsub\n"); 5.81 + return 1; 5.82 + } 5.83 + 5.84 + } else if(strcmp(argv[i], "-diffuse") == 0) { 5.85 + if(!argv[i + 1] || !argv[i + 2] || !argv[i + 3]) { 5.86 + fprintf(stderr, "-diffuse must be followed by 3 numbers (r, g, b)\n"); 5.87 + return 1; 5.88 + } 5.89 + diffuse[0] = atof(argv[++i]); 5.90 + diffuse[1] = atof(argv[++i]); 5.91 + diffuse[2] = atof(argv[++i]); 5.92 + 5.93 + } else if(strcmp(argv[i], "-specular") == 0) { 5.94 + if(!argv[i + 1] || !argv[i + 2] || !argv[i + 3]) { 5.95 + fprintf(stderr, "-specular must be followed by 3 numbers (r, g, b)\n"); 5.96 + return 1; 5.97 + } 5.98 + specular[0] = atof(argv[++i]); 5.99 + specular[1] = atof(argv[++i]); 5.100 + specular[2] = atof(argv[++i]); 5.101 + 5.102 + } else if(strcmp(argv[i], "-shininess") == 0) { 5.103 + if(!argv[i + 1]) { 5.104 + fprintf(stderr, "-shininess must be followed by a number\n"); 5.105 + return 1; 5.106 + } 5.107 + shininess = atof(argv[++i]); 5.108 + 5.109 + } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-help") == 0) { 5.110 + printf("Usage: %s [filename] [options]\n", argv[0]); 5.111 + printf("Options:\n"); 5.112 + printf(" -box create box (default)\n"); 5.113 + printf(" -sphere create sphere\n"); 5.114 + printf(" -torus create torus\n"); 5.115 + printf(" -size <n>, -rad <n>, -inner <n> (default: %g)\n", DEF_SIZE); 5.116 + printf(" -outer <n> torus outer radius (default: %g)\n", DEF_OUTER); 5.117 + printf(" -usub <n> subdivisions along the horizontal direction (default: %d)\n", DEF_USUB); 5.118 + printf(" -vsub <n> subdivisions along the vertical direction (default: %d)\n", DEF_VSUB); 5.119 + printf(" -diffuse <r> <g> <b> material diffuse color (default: %g %g %g)\n", DEF_DIFFUSE_R, DEF_DIFFUSE_G, DEF_DIFFUSE_B); 5.120 + printf(" -specular <r> <g> <b> material specular color (default: %g %g %g)\n", DEF_SPECULAR_R, DEF_SPECULAR_G, DEF_SPECULAR_B); 5.121 + printf(" -shininess <n> material shininess (default: %g)\n", DEF_SHININESS); 5.122 + printf(" -h, -help print usage information and exit\n"); 5.123 + return 0; 5.124 + 5.125 + } else { 5.126 + if(fname) { 5.127 + fprintf(stderr, "unexpected argument: %s\n", argv[i]); 5.128 + return 1; 5.129 + } 5.130 + fname = argv[i]; 5.131 + } 5.132 + } 5.133 + 5.134 + if(!fname) { 5.135 + fname = "out.xml"; 5.136 + } 5.137 5.138 goat = goat3d_create(); 5.139 + goat3d_set_name(goat, fname); 5.140 5.141 mtl = goat3d_create_mtl(); 5.142 goat3d_set_mtl_name(mtl, "mat"); 5.143 - goat3d_set_mtl_attrib4f(mtl, GOAT3D_MAT_ATTR_DIFFUSE, 1, 0, 0, 1); 5.144 + goat3d_set_mtl_attrib(mtl, GOAT3D_MAT_ATTR_DIFFUSE, diffuse); 5.145 + goat3d_set_mtl_attrib(mtl, GOAT3D_MAT_ATTR_SPECULAR, specular); 5.146 + goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_SHININESS, shininess); 5.147 goat3d_add_mtl(goat, mtl); 5.148 5.149 - mesh = create_box(); 5.150 + mesh = goat3d_create_mesh(); 5.151 + 5.152 + switch(prim) { 5.153 + case BOX: 5.154 + gen_box(mesh, size); 5.155 + break; 5.156 + 5.157 + case SPHERE: 5.158 + gen_sphere(mesh, size, usub, vsub); 5.159 + break; 5.160 + 5.161 + case TORUS: 5.162 + gen_torus(mesh, size, outer, usub, vsub); 5.163 + break; 5.164 + 5.165 + default: 5.166 + return 1; 5.167 + } 5.168 + goat3d_set_mesh_mtl(mesh, mtl); 5.169 goat3d_add_mesh(goat, mesh); 5.170 5.171 goat3d_setopt(goat, GOAT3D_OPT_SAVEXML, 1); 5.172 - goat3d_save(goat, "foo.xml"); 5.173 + goat3d_save(goat, fname); 5.174 5.175 goat3d_free(goat); 5.176 return 0; 5.177 } 5.178 5.179 -static struct goat3d_mesh *create_box(void) 5.180 +void gen_box(struct goat3d_mesh *mesh, float size) 5.181 { 5.182 - struct goat3d_mesh *mesh = goat3d_create_mesh(); 5.183 + float hsz = size / 2.0; 5.184 5.185 goat3d_begin(mesh, GOAT3D_QUADS); 5.186 // +X 5.187 goat3d_normal3f(1, 0, 0); 5.188 - goat3d_vertex3f(-1, -1, 1); 5.189 - goat3d_vertex3f(-1, -1, -1); 5.190 - goat3d_vertex3f(-1, 1, -1); 5.191 - goat3d_vertex3f(-1, 1, 1); 5.192 + goat3d_texcoord2f(0, 0); 5.193 + goat3d_vertex3f(hsz, -hsz, hsz); 5.194 + goat3d_texcoord2f(1, 0); 5.195 + goat3d_vertex3f(hsz, -hsz, -hsz); 5.196 + goat3d_texcoord2f(1, 1); 5.197 + goat3d_vertex3f(hsz, hsz, -hsz); 5.198 + goat3d_texcoord2f(0, 1); 5.199 + goat3d_vertex3f(hsz, hsz, hsz); 5.200 5.201 // -X 5.202 goat3d_normal3f(-1, 0, 0); 5.203 - goat3d_vertex3f(-1, -1, -1); 5.204 - goat3d_vertex3f(-1, -1, 1); 5.205 - goat3d_vertex3f(-1, 1, 1); 5.206 - goat3d_vertex3f(-1, 1, -1); 5.207 + goat3d_texcoord2f(0, 0); 5.208 + goat3d_vertex3f(-hsz, -hsz, -hsz); 5.209 + goat3d_texcoord2f(1, 0); 5.210 + goat3d_vertex3f(-hsz, -hsz, hsz); 5.211 + goat3d_texcoord2f(1, 1); 5.212 + goat3d_vertex3f(-hsz, hsz, hsz); 5.213 + goat3d_texcoord2f(0, 1); 5.214 + goat3d_vertex3f(-hsz, hsz, -hsz); 5.215 5.216 // +Y 5.217 goat3d_normal3f(0, 1, 0); 5.218 - goat3d_vertex3f(-1, 1, 1); 5.219 - goat3d_vertex3f(1, 1, 1); 5.220 - goat3d_vertex3f(1, 1, -1); 5.221 - goat3d_vertex3f(-1, 1, -1); 5.222 + goat3d_texcoord2f(0, 0); 5.223 + goat3d_vertex3f(-hsz, hsz, hsz); 5.224 + goat3d_texcoord2f(1, 0); 5.225 + goat3d_vertex3f(hsz, hsz, hsz); 5.226 + goat3d_texcoord2f(1, 1); 5.227 + goat3d_vertex3f(hsz, hsz, -hsz); 5.228 + goat3d_texcoord2f(0, 1); 5.229 + goat3d_vertex3f(-hsz, hsz, -hsz); 5.230 5.231 // -Y 5.232 goat3d_normal3f(0, -1, 0); 5.233 - goat3d_vertex3f(-1, -1, -1); 5.234 - goat3d_vertex3f(1, -1, -1); 5.235 - goat3d_vertex3f(1, -1, 1); 5.236 - goat3d_vertex3f(-1, -1, 1); 5.237 + goat3d_texcoord2f(0, 0); 5.238 + goat3d_vertex3f(-hsz, -hsz, -hsz); 5.239 + goat3d_texcoord2f(1, 0); 5.240 + goat3d_vertex3f(hsz, -hsz, -hsz); 5.241 + goat3d_texcoord2f(1, 1); 5.242 + goat3d_vertex3f(hsz, -hsz, hsz); 5.243 + goat3d_texcoord2f(0, 1); 5.244 + goat3d_vertex3f(-hsz, -hsz, hsz); 5.245 5.246 // +Z 5.247 goat3d_normal3f(0, 0, 1); 5.248 - goat3d_vertex3f(-1, -1, 1); 5.249 - goat3d_vertex3f(1, -1, 1); 5.250 - goat3d_vertex3f(1, -1, 1); 5.251 - goat3d_vertex3f(-1, -1, 1); 5.252 + goat3d_texcoord2f(0, 0); 5.253 + goat3d_vertex3f(-hsz, -hsz, hsz); 5.254 + goat3d_texcoord2f(1, 0); 5.255 + goat3d_vertex3f(hsz, -hsz, hsz); 5.256 + goat3d_texcoord2f(1, 1); 5.257 + goat3d_vertex3f(hsz, hsz, hsz); 5.258 + goat3d_texcoord2f(0, 1); 5.259 + goat3d_vertex3f(-hsz, hsz, hsz); 5.260 5.261 // -Z 5.262 goat3d_normal3f(0, 0, -1); 5.263 - goat3d_vertex3f(-1, -1, 1); 5.264 - goat3d_vertex3f(1, -1, 1); 5.265 - goat3d_vertex3f(1, -1, -1); 5.266 - goat3d_vertex3f(-1, -1, -1); 5.267 + goat3d_texcoord2f(0, 0); 5.268 + goat3d_vertex3f(hsz, -hsz, -hsz); 5.269 + goat3d_texcoord2f(1, 0); 5.270 + goat3d_vertex3f(-hsz, -hsz, -hsz); 5.271 + goat3d_texcoord2f(1, 1); 5.272 + goat3d_vertex3f(-hsz, hsz, -hsz); 5.273 + goat3d_texcoord2f(0, 1); 5.274 + goat3d_vertex3f(hsz, hsz, -hsz); 5.275 goat3d_end(); 5.276 +} 5.277 5.278 - return mesh; 5.279 +void gen_sphere(struct goat3d_mesh *mesh, float rad, int usub, int vsub) 5.280 +{ 5.281 + gen_sphere_part(mesh, rad, usub, vsub, 1.0, 1.0); 5.282 } 5.283 + 5.284 +#define sphere_vertex(u, v) \ 5.285 + do { \ 5.286 + float x, y, z, theta, phi; \ 5.287 + float costheta, sinphi; \ 5.288 + theta = (u) * 2.0 * M_PI; \ 5.289 + phi = (v) * M_PI; \ 5.290 + costheta = cos(theta); \ 5.291 + sinphi = sin(phi); \ 5.292 + x = costheta * sinphi; \ 5.293 + y = cos(phi); \ 5.294 + z = sin(theta) * sinphi; \ 5.295 + goat3d_normal3f(x, y, z); \ 5.296 + goat3d_texcoord2f(u, v); \ 5.297 + goat3d_vertex3f(rad * x, rad * y, rad * z); \ 5.298 + } while(0) 5.299 + 5.300 +void gen_sphere_part(struct goat3d_mesh *mesh, float rad, int usub, int vsub, float umax, float vmax) 5.301 +{ 5.302 + int i, j; 5.303 + float u, v, du, dv; 5.304 + 5.305 + if(usub < 3) usub = 3; 5.306 + if(vsub < 3) vsub = 3; 5.307 + 5.308 + du = umax / (float)usub; 5.309 + dv = vmax / (float)vsub; 5.310 + 5.311 + goat3d_begin(mesh, GOAT3D_QUADS); 5.312 + 5.313 + u = 0.0; 5.314 + for(i=0; i<usub; i++) { 5.315 + v = 0.0; 5.316 + for(j=0; j<vsub; j++) { 5.317 + sphere_vertex(u, v); 5.318 + sphere_vertex(u + du, v); 5.319 + sphere_vertex(u + du, v + dv); 5.320 + sphere_vertex(u, v + dv); 5.321 + v += dv; 5.322 + } 5.323 + u += du; 5.324 + } 5.325 + goat3d_end(); 5.326 +} 5.327 + 5.328 + 5.329 +void gen_torus(struct goat3d_mesh *mesh, float inner, float outer, int usub, int vsub) 5.330 +{ 5.331 + gen_torus_part(mesh, inner, outer, usub, vsub, 1.0, 0.0, 1.0); 5.332 +} 5.333 + 5.334 +#define torus_vertex(u, v) \ 5.335 + do { \ 5.336 + float rx, ry, rz, cx, cy, cz, theta, phi; \ 5.337 + float costheta, sintheta, sinphi; \ 5.338 + theta = (u) * 2.0 * M_PI; \ 5.339 + phi = (v) * 2.0 * M_PI; \ 5.340 + costheta = cos(theta); \ 5.341 + sintheta = sin(theta); \ 5.342 + sinphi = sin(phi); \ 5.343 + cx = costheta * inner; \ 5.344 + cy = 0.0f; \ 5.345 + cz = sintheta * inner; \ 5.346 + rx = costheta * sinphi; \ 5.347 + ry = cos(phi); \ 5.348 + rz = sintheta * sinphi; \ 5.349 + goat3d_normal3f(rx, ry, rz); \ 5.350 + goat3d_texcoord2f(u, v); \ 5.351 + goat3d_vertex3f(outer * rx + cx, outer * ry + cy, outer * rz + cz); \ 5.352 + } while(0) 5.353 + 5.354 +void gen_torus_part(struct goat3d_mesh *mesh, float inner, float outer, 5.355 + int usub, int vsub, float umax, float vmin, float vmax) 5.356 +{ 5.357 + int i, j; 5.358 + float u, v, du, dv; 5.359 + 5.360 + if(usub < 3) usub = 3; 5.361 + if(vsub < 3) vsub = 3; 5.362 + 5.363 + du = umax / (float)usub; 5.364 + dv = (vmax - vmin) / (float)vsub; 5.365 + 5.366 + goat3d_begin(mesh, GOAT3D_QUADS); 5.367 + 5.368 + u = 0.0; 5.369 + for(i=0; i<usub; i++) { 5.370 + v = vmin; 5.371 + for(j=0; j<vsub; j++) { 5.372 + torus_vertex(u, v); 5.373 + torus_vertex(u + du, v); 5.374 + torus_vertex(u + du, v + dv); 5.375 + torus_vertex(u, v + dv); 5.376 + v += dv; 5.377 + } 5.378 + u += du; 5.379 + } 5.380 + goat3d_end(); 5.381 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/goatview/Makefile Fri Sep 27 07:14:49 2013 +0300 6.3 @@ -0,0 +1,34 @@ 6.4 +src = $(wildcard src/*.c) 6.5 +obj = $(src:.c=.o) 6.6 +dep = $(obj:.o=.d) 6.7 +bin = goatview 6.8 + 6.9 +goat_root = .. 6.10 +libgoat = $(goat_root)/libgoat3d.so.0.1 6.11 + 6.12 +CC = clang 6.13 +CPP = clang -E 6.14 +CFLAGS = -pedantic -Wall -g -I$(goat_root)/src 6.15 +LDFLAGS = $(libgoat) -Wl,-rpath=$(goat_root) $(libgl) 6.16 + 6.17 +ifeq ($(shell uname -s), Darwin) 6.18 + libgl = -framework OpenGL -framework GLUT -lGLEW 6.19 +else 6.20 + libgl = -lGL -lGLU -lglut -lGLEW 6.21 +endif 6.22 + 6.23 +$(bin): $(obj) $(libgoat) 6.24 + $(CC) -o $@ $(obj) $(LDFLAGS) 6.25 + 6.26 +-include $(dep) 6.27 + 6.28 +%.d: %.c 6.29 + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 6.30 + 6.31 +.PHONY: clean 6.32 +clean: 6.33 + rm -f $(obj) $(bin) 6.34 + 6.35 +.PHONY: cleandep 6.36 +cleandep: 6.37 + rm -f $(dep)
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/goatview/src/main.c Fri Sep 27 07:14:49 2013 +0300 7.3 @@ -0,0 +1,208 @@ 7.4 +#include <stdio.h> 7.5 +#include <stdlib.h> 7.6 +#include <assert.h> 7.7 +#ifndef __APPLE__ 7.8 +#include <GL/glut.h> 7.9 +#else 7.10 +#include <GLUT/glut.h> 7.11 +#endif 7.12 +#include "goat3d.h" 7.13 + 7.14 +static void cleanup(void); 7.15 +static void disp(void); 7.16 +static void draw_scene(struct goat3d *g); 7.17 +static void draw_mesh(struct goat3d_mesh *mesh); 7.18 +static void reshape(int x, int y); 7.19 +static void keyb(unsigned char key, int x, int y); 7.20 +static void mouse(int bn, int st, int x, int y); 7.21 +static void motion(int x, int y); 7.22 + 7.23 +static struct goat3d *goat; 7.24 +static float cam_theta, cam_phi, cam_dist = 10; 7.25 + 7.26 +int main(int argc, char **argv) 7.27 +{ 7.28 + glutInitWindowSize(800, 600); 7.29 + glutInit(&argc, argv); 7.30 + 7.31 + if(!argv[1]) { 7.32 + fprintf(stderr, "you must specify a goat3d scene file to open\n"); 7.33 + return 1; 7.34 + } 7.35 + 7.36 + if(!(goat = goat3d_create())) { 7.37 + fprintf(stderr, "failed to create goat3d\n"); 7.38 + return 1; 7.39 + } 7.40 + if(goat3d_load(goat, argv[1]) == -1) { 7.41 + fprintf(stderr, "failed to load goat3d scene: %s\n", argv[1]); 7.42 + goat3d_free(goat); 7.43 + return 1; 7.44 + } 7.45 + 7.46 + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 7.47 + glutCreateWindow(argv[1]); 7.48 + 7.49 + glutDisplayFunc(disp); 7.50 + glutReshapeFunc(reshape); 7.51 + glutKeyboardFunc(keyb); 7.52 + glutMouseFunc(mouse); 7.53 + glutMotionFunc(motion); 7.54 + 7.55 + glEnable(GL_DEPTH_TEST); 7.56 + glEnable(GL_CULL_FACE); 7.57 + glEnable(GL_LIGHTING); 7.58 + glEnable(GL_LIGHT0); 7.59 + 7.60 + glClearColor(0.1, 0.1, 0.1, 1.0); 7.61 + 7.62 + atexit(cleanup); 7.63 + 7.64 + glutMainLoop(); 7.65 + return 0; 7.66 +} 7.67 + 7.68 +static void cleanup(void) 7.69 +{ 7.70 + goat3d_free(goat); 7.71 +} 7.72 + 7.73 +static void disp(void) 7.74 +{ 7.75 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 7.76 + 7.77 + glMatrixMode(GL_MODELVIEW); 7.78 + glLoadIdentity(); 7.79 + glTranslatef(0, 0, -cam_dist); 7.80 + glRotatef(cam_phi, 1, 0, 0); 7.81 + glRotatef(cam_theta, 0, 1, 0); 7.82 + 7.83 + draw_scene(goat); 7.84 + 7.85 + glutSwapBuffers(); 7.86 + assert(glGetError() == GL_NO_ERROR); 7.87 +} 7.88 + 7.89 +static void draw_scene(struct goat3d *g) 7.90 +{ 7.91 + int i, num_meshes; 7.92 + 7.93 + num_meshes = goat3d_get_mesh_count(g); 7.94 + for(i=0; i<num_meshes; i++) { 7.95 + struct goat3d_mesh *mesh = goat3d_get_mesh(g, i); 7.96 + draw_mesh(mesh); 7.97 + } 7.98 +} 7.99 + 7.100 +static void draw_mesh(struct goat3d_mesh *mesh) 7.101 +{ 7.102 + int vnum, fnum; 7.103 + struct goat3d_material *mtl; 7.104 + float *verts, *normals, *texcoords; 7.105 + int *vidx; 7.106 + 7.107 + if((mtl = goat3d_get_mesh_mtl(mesh))) { 7.108 + float white[] = {1, 1, 1, 1}; 7.109 + float black[] = {0, 0, 0, 0}; 7.110 + float zero = 0.0; 7.111 + const float *diffuse, *specular, *shininess; 7.112 + 7.113 + if(!(diffuse = goat3d_get_mtl_attrib(mtl, GOAT3D_MAT_ATTR_DIFFUSE))) { 7.114 + diffuse = white; 7.115 + } 7.116 + if(!(specular = goat3d_get_mtl_attrib(mtl, GOAT3D_MAT_ATTR_SPECULAR))) { 7.117 + specular = black; 7.118 + } 7.119 + if(!(shininess = goat3d_get_mtl_attrib(mtl, GOAT3D_MAT_ATTR_SHININESS))) { 7.120 + shininess = &zero; 7.121 + } 7.122 + 7.123 + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, diffuse); 7.124 + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular); 7.125 + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, *shininess); 7.126 + } 7.127 + 7.128 + vnum = goat3d_get_mesh_attrib_count(mesh, GOAT3D_MESH_ATTR_VERTEX); 7.129 + fnum = goat3d_get_mesh_face_count(mesh); 7.130 + 7.131 + if(!vnum || !fnum) { 7.132 + return; 7.133 + } 7.134 + 7.135 + verts = goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX); 7.136 + normals = goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL); 7.137 + texcoords = goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD); 7.138 + vidx = goat3d_get_mesh_faces(mesh); 7.139 + 7.140 + glEnableClientState(GL_VERTEX_ARRAY); 7.141 + glVertexPointer(3, GL_FLOAT, 0, verts); 7.142 + 7.143 + if(normals) { 7.144 + glEnableClientState(GL_NORMAL_ARRAY); 7.145 + glNormalPointer(GL_FLOAT, 0, normals); 7.146 + } 7.147 + if(texcoords) { 7.148 + glEnableClientState(GL_TEXTURE_COORD_ARRAY); 7.149 + glTexCoordPointer(2, GL_FLOAT, 0, texcoords); 7.150 + } 7.151 + 7.152 + glDrawElements(GL_TRIANGLES, fnum * 3, GL_UNSIGNED_INT, vidx); 7.153 + 7.154 + glDisableClientState(GL_VERTEX_ARRAY); 7.155 + if(normals) { 7.156 + glDisableClientState(GL_NORMAL_ARRAY); 7.157 + } 7.158 + if(texcoords) { 7.159 + glDisableClientState(GL_TEXTURE_COORD_ARRAY); 7.160 + } 7.161 +} 7.162 + 7.163 +static void reshape(int x, int y) 7.164 +{ 7.165 + glViewport(0, 0, x, y); 7.166 + 7.167 + glMatrixMode(GL_PROJECTION); 7.168 + glLoadIdentity(); 7.169 + gluPerspective(50.0, (float)x / (float)y, 0.5, 1000.0); 7.170 +} 7.171 + 7.172 +static void keyb(unsigned char key, int x, int y) 7.173 +{ 7.174 + switch(key) { 7.175 + case 27: 7.176 + exit(0); 7.177 + } 7.178 +} 7.179 + 7.180 +static int bnstate[32]; 7.181 +static int prev_x, prev_y; 7.182 + 7.183 +static void mouse(int bn, int st, int x, int y) 7.184 +{ 7.185 + bnstate[bn - GLUT_LEFT_BUTTON] = (st == GLUT_DOWN); 7.186 + prev_x = x; 7.187 + prev_y = y; 7.188 +} 7.189 + 7.190 +static void motion(int x, int y) 7.191 +{ 7.192 + int dx = x - prev_x; 7.193 + int dy = y - prev_y; 7.194 + prev_x = x; 7.195 + prev_y = y; 7.196 + 7.197 + if(bnstate[0]) { 7.198 + cam_theta += dx * 0.5; 7.199 + cam_phi += dy * 0.5; 7.200 + 7.201 + if(cam_phi < -90) cam_phi = -90; 7.202 + if(cam_phi > 90) cam_phi = 90; 7.203 + glutPostRedisplay(); 7.204 + } 7.205 + if(bnstate[2]) { 7.206 + cam_dist += dy * 0.1; 7.207 + 7.208 + if(cam_dist < 0) cam_dist = 0; 7.209 + glutPostRedisplay(); 7.210 + } 7.211 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/libs/tinyxml2/Makefile Fri Sep 27 07:14:49 2013 +0300 8.3 @@ -0,0 +1,15 @@ 8.4 +obj = tinyxml2.o 8.5 +lib = libtinyxml2.a 8.6 + 8.7 +ifneq ($(shell uname -s), Darwin) 8.8 + pic = -fPIC 8.9 +endif 8.10 + 8.11 +CXXFLAGS = -pedantic -Wall -g $(pic) 8.12 + 8.13 +$(lib): $(obj) 8.14 + $(AR) rcs $@ $(obj) 8.15 + 8.16 +.PHONY: clean 8.17 +clean: 8.18 + rm -f $(obj) $(lib)
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/libs/tinyxml2/tinyxml2.cpp Fri Sep 27 07:14:49 2013 +0300 9.3 @@ -0,0 +1,2101 @@ 9.4 +/* 9.5 +Original code by Lee Thomason (www.grinninglizard.com) 9.6 + 9.7 +This software is provided 'as-is', without any express or implied 9.8 +warranty. In no event will the authors be held liable for any 9.9 +damages arising from the use of this software. 9.10 + 9.11 +Permission is granted to anyone to use this software for any 9.12 +purpose, including commercial applications, and to alter it and 9.13 +redistribute it freely, subject to the following restrictions: 9.14 + 9.15 +1. The origin of this software must not be misrepresented; you must 9.16 +not claim that you wrote the original software. If you use this 9.17 +software in a product, an acknowledgment in the product documentation 9.18 +would be appreciated but is not required. 9.19 + 9.20 +2. Altered source versions must be plainly marked as such, and 9.21 +must not be misrepresented as being the original software. 9.22 + 9.23 +3. This notice may not be removed or altered from any source 9.24 +distribution. 9.25 +*/ 9.26 + 9.27 +#include "tinyxml2.h" 9.28 + 9.29 +#include <new> // yes, this one new style header, is in the Android SDK. 9.30 +# ifdef ANDROID_NDK 9.31 +# include <stddef.h> 9.32 +#else 9.33 +# include <cstddef> 9.34 +#endif 9.35 + 9.36 +static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF 9.37 +static const char LF = LINE_FEED; 9.38 +static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out 9.39 +static const char CR = CARRIAGE_RETURN; 9.40 +static const char SINGLE_QUOTE = '\''; 9.41 +static const char DOUBLE_QUOTE = '\"'; 9.42 + 9.43 +// Bunch of unicode info at: 9.44 +// http://www.unicode.org/faq/utf_bom.html 9.45 +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 9.46 + 9.47 +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; 9.48 +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; 9.49 +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; 9.50 + 9.51 + 9.52 +#define DELETE_NODE( node ) { \ 9.53 + if ( node ) { \ 9.54 + MemPool* pool = node->_memPool; \ 9.55 + node->~XMLNode(); \ 9.56 + pool->Free( node ); \ 9.57 + } \ 9.58 + } 9.59 +#define DELETE_ATTRIBUTE( attrib ) { \ 9.60 + if ( attrib ) { \ 9.61 + MemPool* pool = attrib->_memPool; \ 9.62 + attrib->~XMLAttribute(); \ 9.63 + pool->Free( attrib ); \ 9.64 + } \ 9.65 + } 9.66 + 9.67 +namespace tinyxml2 9.68 +{ 9.69 + 9.70 +struct Entity { 9.71 + const char* pattern; 9.72 + int length; 9.73 + char value; 9.74 +}; 9.75 + 9.76 +static const int NUM_ENTITIES = 5; 9.77 +static const Entity entities[NUM_ENTITIES] = { 9.78 + { "quot", 4, DOUBLE_QUOTE }, 9.79 + { "amp", 3, '&' }, 9.80 + { "apos", 4, SINGLE_QUOTE }, 9.81 + { "lt", 2, '<' }, 9.82 + { "gt", 2, '>' } 9.83 +}; 9.84 + 9.85 + 9.86 +StrPair::~StrPair() 9.87 +{ 9.88 + Reset(); 9.89 +} 9.90 + 9.91 + 9.92 +void StrPair::Reset() 9.93 +{ 9.94 + if ( _flags & NEEDS_DELETE ) { 9.95 + delete [] _start; 9.96 + } 9.97 + _flags = 0; 9.98 + _start = 0; 9.99 + _end = 0; 9.100 +} 9.101 + 9.102 + 9.103 +void StrPair::SetStr( const char* str, int flags ) 9.104 +{ 9.105 + Reset(); 9.106 + size_t len = strlen( str ); 9.107 + _start = new char[ len+1 ]; 9.108 + memcpy( _start, str, len+1 ); 9.109 + _end = _start + len; 9.110 + _flags = flags | NEEDS_DELETE; 9.111 +} 9.112 + 9.113 + 9.114 +char* StrPair::ParseText( char* p, const char* endTag, int strFlags ) 9.115 +{ 9.116 + TIXMLASSERT( endTag && *endTag ); 9.117 + 9.118 + char* start = p; // fixme: hides a member 9.119 + char endChar = *endTag; 9.120 + size_t length = strlen( endTag ); 9.121 + 9.122 + // Inner loop of text parsing. 9.123 + while ( *p ) { 9.124 + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { 9.125 + Set( start, p, strFlags ); 9.126 + return p + length; 9.127 + } 9.128 + ++p; 9.129 + } 9.130 + return 0; 9.131 +} 9.132 + 9.133 + 9.134 +char* StrPair::ParseName( char* p ) 9.135 +{ 9.136 + char* start = p; 9.137 + 9.138 + if ( !start || !(*start) ) { 9.139 + return 0; 9.140 + } 9.141 + 9.142 + while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) { 9.143 + ++p; 9.144 + } 9.145 + 9.146 + if ( p > start ) { 9.147 + Set( start, p, 0 ); 9.148 + return p; 9.149 + } 9.150 + return 0; 9.151 +} 9.152 + 9.153 + 9.154 +void StrPair::CollapseWhitespace() 9.155 +{ 9.156 + // Trim leading space. 9.157 + _start = XMLUtil::SkipWhiteSpace( _start ); 9.158 + 9.159 + if ( _start && *_start ) { 9.160 + char* p = _start; // the read pointer 9.161 + char* q = _start; // the write pointer 9.162 + 9.163 + while( *p ) { 9.164 + if ( XMLUtil::IsWhiteSpace( *p )) { 9.165 + p = XMLUtil::SkipWhiteSpace( p ); 9.166 + if ( *p == 0 ) { 9.167 + break; // don't write to q; this trims the trailing space. 9.168 + } 9.169 + *q = ' '; 9.170 + ++q; 9.171 + } 9.172 + *q = *p; 9.173 + ++q; 9.174 + ++p; 9.175 + } 9.176 + *q = 0; 9.177 + } 9.178 +} 9.179 + 9.180 + 9.181 +const char* StrPair::GetStr() 9.182 +{ 9.183 + if ( _flags & NEEDS_FLUSH ) { 9.184 + *_end = 0; 9.185 + _flags ^= NEEDS_FLUSH; 9.186 + 9.187 + if ( _flags ) { 9.188 + char* p = _start; // the read pointer 9.189 + char* q = _start; // the write pointer 9.190 + 9.191 + while( p < _end ) { 9.192 + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { 9.193 + // CR-LF pair becomes LF 9.194 + // CR alone becomes LF 9.195 + // LF-CR becomes LF 9.196 + if ( *(p+1) == LF ) { 9.197 + p += 2; 9.198 + } 9.199 + else { 9.200 + ++p; 9.201 + } 9.202 + *q++ = LF; 9.203 + } 9.204 + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { 9.205 + if ( *(p+1) == CR ) { 9.206 + p += 2; 9.207 + } 9.208 + else { 9.209 + ++p; 9.210 + } 9.211 + *q++ = LF; 9.212 + } 9.213 + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { 9.214 + // Entities handled by tinyXML2: 9.215 + // - special entities in the entity table [in/out] 9.216 + // - numeric character reference [in] 9.217 + // 中 or 中 9.218 + 9.219 + if ( *(p+1) == '#' ) { 9.220 + char buf[10] = { 0 }; 9.221 + int len; 9.222 + p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) ); 9.223 + for( int i=0; i<len; ++i ) { 9.224 + *q++ = buf[i]; 9.225 + } 9.226 + TIXMLASSERT( q <= p ); 9.227 + } 9.228 + else { 9.229 + int i=0; 9.230 + for(; i<NUM_ENTITIES; ++i ) { 9.231 + if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0 9.232 + && *(p+entities[i].length+1) == ';' ) { 9.233 + // Found an entity convert; 9.234 + *q = entities[i].value; 9.235 + ++q; 9.236 + p += entities[i].length + 2; 9.237 + break; 9.238 + } 9.239 + } 9.240 + if ( i == NUM_ENTITIES ) { 9.241 + // fixme: treat as error? 9.242 + ++p; 9.243 + ++q; 9.244 + } 9.245 + } 9.246 + } 9.247 + else { 9.248 + *q = *p; 9.249 + ++p; 9.250 + ++q; 9.251 + } 9.252 + } 9.253 + *q = 0; 9.254 + } 9.255 + // The loop below has plenty going on, and this 9.256 + // is a less useful mode. Break it out. 9.257 + if ( _flags & COLLAPSE_WHITESPACE ) { 9.258 + CollapseWhitespace(); 9.259 + } 9.260 + _flags = (_flags & NEEDS_DELETE); 9.261 + } 9.262 + return _start; 9.263 +} 9.264 + 9.265 + 9.266 + 9.267 + 9.268 +// --------- XMLUtil ----------- // 9.269 + 9.270 +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) 9.271 +{ 9.272 + *bom = false; 9.273 + const unsigned char* pu = reinterpret_cast<const unsigned char*>(p); 9.274 + // Check for BOM: 9.275 + if ( *(pu+0) == TIXML_UTF_LEAD_0 9.276 + && *(pu+1) == TIXML_UTF_LEAD_1 9.277 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { 9.278 + *bom = true; 9.279 + p += 3; 9.280 + } 9.281 + return p; 9.282 +} 9.283 + 9.284 + 9.285 +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) 9.286 +{ 9.287 + const unsigned long BYTE_MASK = 0xBF; 9.288 + const unsigned long BYTE_MARK = 0x80; 9.289 + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 9.290 + 9.291 + if (input < 0x80) { 9.292 + *length = 1; 9.293 + } 9.294 + else if ( input < 0x800 ) { 9.295 + *length = 2; 9.296 + } 9.297 + else if ( input < 0x10000 ) { 9.298 + *length = 3; 9.299 + } 9.300 + else if ( input < 0x200000 ) { 9.301 + *length = 4; 9.302 + } 9.303 + else { 9.304 + *length = 0; // This code won't covert this correctly anyway. 9.305 + return; 9.306 + } 9.307 + 9.308 + output += *length; 9.309 + 9.310 + // Scary scary fall throughs. 9.311 + switch (*length) { 9.312 + case 4: 9.313 + --output; 9.314 + *output = (char)((input | BYTE_MARK) & BYTE_MASK); 9.315 + input >>= 6; 9.316 + case 3: 9.317 + --output; 9.318 + *output = (char)((input | BYTE_MARK) & BYTE_MASK); 9.319 + input >>= 6; 9.320 + case 2: 9.321 + --output; 9.322 + *output = (char)((input | BYTE_MARK) & BYTE_MASK); 9.323 + input >>= 6; 9.324 + case 1: 9.325 + --output; 9.326 + *output = (char)(input | FIRST_BYTE_MARK[*length]); 9.327 + default: 9.328 + break; 9.329 + } 9.330 +} 9.331 + 9.332 + 9.333 +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) 9.334 +{ 9.335 + // Presume an entity, and pull it out. 9.336 + *length = 0; 9.337 + 9.338 + if ( *(p+1) == '#' && *(p+2) ) { 9.339 + unsigned long ucs = 0; 9.340 + ptrdiff_t delta = 0; 9.341 + unsigned mult = 1; 9.342 + 9.343 + if ( *(p+2) == 'x' ) { 9.344 + // Hexadecimal. 9.345 + if ( !*(p+3) ) { 9.346 + return 0; 9.347 + } 9.348 + 9.349 + const char* q = p+3; 9.350 + q = strchr( q, ';' ); 9.351 + 9.352 + if ( !q || !*q ) { 9.353 + return 0; 9.354 + } 9.355 + 9.356 + delta = q-p; 9.357 + --q; 9.358 + 9.359 + while ( *q != 'x' ) { 9.360 + if ( *q >= '0' && *q <= '9' ) { 9.361 + ucs += mult * (*q - '0'); 9.362 + } 9.363 + else if ( *q >= 'a' && *q <= 'f' ) { 9.364 + ucs += mult * (*q - 'a' + 10); 9.365 + } 9.366 + else if ( *q >= 'A' && *q <= 'F' ) { 9.367 + ucs += mult * (*q - 'A' + 10 ); 9.368 + } 9.369 + else { 9.370 + return 0; 9.371 + } 9.372 + mult *= 16; 9.373 + --q; 9.374 + } 9.375 + } 9.376 + else { 9.377 + // Decimal. 9.378 + if ( !*(p+2) ) { 9.379 + return 0; 9.380 + } 9.381 + 9.382 + const char* q = p+2; 9.383 + q = strchr( q, ';' ); 9.384 + 9.385 + if ( !q || !*q ) { 9.386 + return 0; 9.387 + } 9.388 + 9.389 + delta = q-p; 9.390 + --q; 9.391 + 9.392 + while ( *q != '#' ) { 9.393 + if ( *q >= '0' && *q <= '9' ) { 9.394 + ucs += mult * (*q - '0'); 9.395 + } 9.396 + else { 9.397 + return 0; 9.398 + } 9.399 + mult *= 10; 9.400 + --q; 9.401 + } 9.402 + } 9.403 + // convert the UCS to UTF-8 9.404 + ConvertUTF32ToUTF8( ucs, value, length ); 9.405 + return p + delta + 1; 9.406 + } 9.407 + return p+1; 9.408 +} 9.409 + 9.410 + 9.411 +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) 9.412 +{ 9.413 + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); 9.414 +} 9.415 + 9.416 + 9.417 +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) 9.418 +{ 9.419 + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); 9.420 +} 9.421 + 9.422 + 9.423 +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) 9.424 +{ 9.425 + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 ); 9.426 +} 9.427 + 9.428 + 9.429 +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) 9.430 +{ 9.431 + TIXML_SNPRINTF( buffer, bufferSize, "%f", v ); 9.432 +} 9.433 + 9.434 + 9.435 +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) 9.436 +{ 9.437 + TIXML_SNPRINTF( buffer, bufferSize, "%f", v ); 9.438 +} 9.439 + 9.440 + 9.441 +bool XMLUtil::ToInt( const char* str, int* value ) 9.442 +{ 9.443 + if ( TIXML_SSCANF( str, "%d", value ) == 1 ) { 9.444 + return true; 9.445 + } 9.446 + return false; 9.447 +} 9.448 + 9.449 +bool XMLUtil::ToUnsigned( const char* str, unsigned *value ) 9.450 +{ 9.451 + if ( TIXML_SSCANF( str, "%u", value ) == 1 ) { 9.452 + return true; 9.453 + } 9.454 + return false; 9.455 +} 9.456 + 9.457 +bool XMLUtil::ToBool( const char* str, bool* value ) 9.458 +{ 9.459 + int ival = 0; 9.460 + if ( ToInt( str, &ival )) { 9.461 + *value = (ival==0) ? false : true; 9.462 + return true; 9.463 + } 9.464 + if ( StringEqual( str, "true" ) ) { 9.465 + *value = true; 9.466 + return true; 9.467 + } 9.468 + else if ( StringEqual( str, "false" ) ) { 9.469 + *value = false; 9.470 + return true; 9.471 + } 9.472 + return false; 9.473 +} 9.474 + 9.475 + 9.476 +bool XMLUtil::ToFloat( const char* str, float* value ) 9.477 +{ 9.478 + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { 9.479 + return true; 9.480 + } 9.481 + return false; 9.482 +} 9.483 + 9.484 +bool XMLUtil::ToDouble( const char* str, double* value ) 9.485 +{ 9.486 + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { 9.487 + return true; 9.488 + } 9.489 + return false; 9.490 +} 9.491 + 9.492 + 9.493 +char* XMLDocument::Identify( char* p, XMLNode** node ) 9.494 +{ 9.495 + XMLNode* returnNode = 0; 9.496 + char* start = p; 9.497 + p = XMLUtil::SkipWhiteSpace( p ); 9.498 + if( !p || !*p ) { 9.499 + return p; 9.500 + } 9.501 + 9.502 + // What is this thing? 9.503 + // - Elements start with a letter or underscore, but xml is reserved. 9.504 + // - Comments: <!-- 9.505 + // - Declaration: <? 9.506 + // - Everything else is unknown to tinyxml. 9.507 + // 9.508 + 9.509 + static const char* xmlHeader = { "<?" }; 9.510 + static const char* commentHeader = { "<!--" }; 9.511 + static const char* dtdHeader = { "<!" }; 9.512 + static const char* cdataHeader = { "<![CDATA[" }; 9.513 + static const char* elementHeader = { "<" }; // and a header for everything else; check last. 9.514 + 9.515 + static const int xmlHeaderLen = 2; 9.516 + static const int commentHeaderLen = 4; 9.517 + static const int dtdHeaderLen = 2; 9.518 + static const int cdataHeaderLen = 9; 9.519 + static const int elementHeaderLen = 1; 9.520 + 9.521 +#if defined(_MSC_VER) 9.522 +#pragma warning ( push ) 9.523 +#pragma warning ( disable : 4127 ) 9.524 +#endif 9.525 + TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool 9.526 + TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool 9.527 +#if defined(_MSC_VER) 9.528 +#pragma warning (pop) 9.529 +#endif 9.530 + if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) { 9.531 + returnNode = new (_commentPool.Alloc()) XMLDeclaration( this ); 9.532 + returnNode->_memPool = &_commentPool; 9.533 + p += xmlHeaderLen; 9.534 + } 9.535 + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { 9.536 + returnNode = new (_commentPool.Alloc()) XMLComment( this ); 9.537 + returnNode->_memPool = &_commentPool; 9.538 + p += commentHeaderLen; 9.539 + } 9.540 + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { 9.541 + XMLText* text = new (_textPool.Alloc()) XMLText( this ); 9.542 + returnNode = text; 9.543 + returnNode->_memPool = &_textPool; 9.544 + p += cdataHeaderLen; 9.545 + text->SetCData( true ); 9.546 + } 9.547 + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { 9.548 + returnNode = new (_commentPool.Alloc()) XMLUnknown( this ); 9.549 + returnNode->_memPool = &_commentPool; 9.550 + p += dtdHeaderLen; 9.551 + } 9.552 + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { 9.553 + returnNode = new (_elementPool.Alloc()) XMLElement( this ); 9.554 + returnNode->_memPool = &_elementPool; 9.555 + p += elementHeaderLen; 9.556 + } 9.557 + else { 9.558 + returnNode = new (_textPool.Alloc()) XMLText( this ); 9.559 + returnNode->_memPool = &_textPool; 9.560 + p = start; // Back it up, all the text counts. 9.561 + } 9.562 + 9.563 + *node = returnNode; 9.564 + return p; 9.565 +} 9.566 + 9.567 + 9.568 +bool XMLDocument::Accept( XMLVisitor* visitor ) const 9.569 +{ 9.570 + if ( visitor->VisitEnter( *this ) ) { 9.571 + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { 9.572 + if ( !node->Accept( visitor ) ) { 9.573 + break; 9.574 + } 9.575 + } 9.576 + } 9.577 + return visitor->VisitExit( *this ); 9.578 +} 9.579 + 9.580 + 9.581 +// --------- XMLNode ----------- // 9.582 + 9.583 +XMLNode::XMLNode( XMLDocument* doc ) : 9.584 + _document( doc ), 9.585 + _parent( 0 ), 9.586 + _firstChild( 0 ), _lastChild( 0 ), 9.587 + _prev( 0 ), _next( 0 ), 9.588 + _memPool( 0 ) 9.589 +{ 9.590 +} 9.591 + 9.592 + 9.593 +XMLNode::~XMLNode() 9.594 +{ 9.595 + DeleteChildren(); 9.596 + if ( _parent ) { 9.597 + _parent->Unlink( this ); 9.598 + } 9.599 +} 9.600 + 9.601 + 9.602 +void XMLNode::SetValue( const char* str, bool staticMem ) 9.603 +{ 9.604 + if ( staticMem ) { 9.605 + _value.SetInternedStr( str ); 9.606 + } 9.607 + else { 9.608 + _value.SetStr( str ); 9.609 + } 9.610 +} 9.611 + 9.612 + 9.613 +void XMLNode::DeleteChildren() 9.614 +{ 9.615 + while( _firstChild ) { 9.616 + XMLNode* node = _firstChild; 9.617 + Unlink( node ); 9.618 + 9.619 + DELETE_NODE( node ); 9.620 + } 9.621 + _firstChild = _lastChild = 0; 9.622 +} 9.623 + 9.624 + 9.625 +void XMLNode::Unlink( XMLNode* child ) 9.626 +{ 9.627 + TIXMLASSERT( child->_parent == this ); 9.628 + if ( child == _firstChild ) { 9.629 + _firstChild = _firstChild->_next; 9.630 + } 9.631 + if ( child == _lastChild ) { 9.632 + _lastChild = _lastChild->_prev; 9.633 + } 9.634 + 9.635 + if ( child->_prev ) { 9.636 + child->_prev->_next = child->_next; 9.637 + } 9.638 + if ( child->_next ) { 9.639 + child->_next->_prev = child->_prev; 9.640 + } 9.641 + child->_parent = 0; 9.642 +} 9.643 + 9.644 + 9.645 +void XMLNode::DeleteChild( XMLNode* node ) 9.646 +{ 9.647 + TIXMLASSERT( node->_parent == this ); 9.648 + DELETE_NODE( node ); 9.649 +} 9.650 + 9.651 + 9.652 +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) 9.653 +{ 9.654 + if ( _lastChild ) { 9.655 + TIXMLASSERT( _firstChild ); 9.656 + TIXMLASSERT( _lastChild->_next == 0 ); 9.657 + _lastChild->_next = addThis; 9.658 + addThis->_prev = _lastChild; 9.659 + _lastChild = addThis; 9.660 + 9.661 + addThis->_next = 0; 9.662 + } 9.663 + else { 9.664 + TIXMLASSERT( _firstChild == 0 ); 9.665 + _firstChild = _lastChild = addThis; 9.666 + 9.667 + addThis->_prev = 0; 9.668 + addThis->_next = 0; 9.669 + } 9.670 + addThis->_parent = this; 9.671 + addThis->_memPool->SetTracked(); 9.672 + return addThis; 9.673 +} 9.674 + 9.675 + 9.676 +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) 9.677 +{ 9.678 + if ( _firstChild ) { 9.679 + TIXMLASSERT( _lastChild ); 9.680 + TIXMLASSERT( _firstChild->_prev == 0 ); 9.681 + 9.682 + _firstChild->_prev = addThis; 9.683 + addThis->_next = _firstChild; 9.684 + _firstChild = addThis; 9.685 + 9.686 + addThis->_prev = 0; 9.687 + } 9.688 + else { 9.689 + TIXMLASSERT( _lastChild == 0 ); 9.690 + _firstChild = _lastChild = addThis; 9.691 + 9.692 + addThis->_prev = 0; 9.693 + addThis->_next = 0; 9.694 + } 9.695 + addThis->_parent = this; 9.696 + addThis->_memPool->SetTracked(); 9.697 + return addThis; 9.698 +} 9.699 + 9.700 + 9.701 +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) 9.702 +{ 9.703 + TIXMLASSERT( afterThis->_parent == this ); 9.704 + if ( afterThis->_parent != this ) { 9.705 + return 0; 9.706 + } 9.707 + 9.708 + if ( afterThis->_next == 0 ) { 9.709 + // The last node or the only node. 9.710 + return InsertEndChild( addThis ); 9.711 + } 9.712 + addThis->_prev = afterThis; 9.713 + addThis->_next = afterThis->_next; 9.714 + afterThis->_next->_prev = addThis; 9.715 + afterThis->_next = addThis; 9.716 + addThis->_parent = this; 9.717 + addThis->_memPool->SetTracked(); 9.718 + return addThis; 9.719 +} 9.720 + 9.721 + 9.722 + 9.723 + 9.724 +const XMLElement* XMLNode::FirstChildElement( const char* value ) const 9.725 +{ 9.726 + for( XMLNode* node=_firstChild; node; node=node->_next ) { 9.727 + XMLElement* element = node->ToElement(); 9.728 + if ( element ) { 9.729 + if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { 9.730 + return element; 9.731 + } 9.732 + } 9.733 + } 9.734 + return 0; 9.735 +} 9.736 + 9.737 + 9.738 +const XMLElement* XMLNode::LastChildElement( const char* value ) const 9.739 +{ 9.740 + for( XMLNode* node=_lastChild; node; node=node->_prev ) { 9.741 + XMLElement* element = node->ToElement(); 9.742 + if ( element ) { 9.743 + if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) { 9.744 + return element; 9.745 + } 9.746 + } 9.747 + } 9.748 + return 0; 9.749 +} 9.750 + 9.751 + 9.752 +const XMLElement* XMLNode::NextSiblingElement( const char* value ) const 9.753 +{ 9.754 + for( XMLNode* element=this->_next; element; element = element->_next ) { 9.755 + if ( element->ToElement() 9.756 + && (!value || XMLUtil::StringEqual( value, element->Value() ))) { 9.757 + return element->ToElement(); 9.758 + } 9.759 + } 9.760 + return 0; 9.761 +} 9.762 + 9.763 + 9.764 +const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const 9.765 +{ 9.766 + for( XMLNode* element=_prev; element; element = element->_prev ) { 9.767 + if ( element->ToElement() 9.768 + && (!value || XMLUtil::StringEqual( value, element->Value() ))) { 9.769 + return element->ToElement(); 9.770 + } 9.771 + } 9.772 + return 0; 9.773 +} 9.774 + 9.775 + 9.776 +char* XMLNode::ParseDeep( char* p, StrPair* parentEnd ) 9.777 +{ 9.778 + // This is a recursive method, but thinking about it "at the current level" 9.779 + // it is a pretty simple flat list: 9.780 + // <foo/> 9.781 + // <!-- comment --> 9.782 + // 9.783 + // With a special case: 9.784 + // <foo> 9.785 + // </foo> 9.786 + // <!-- comment --> 9.787 + // 9.788 + // Where the closing element (/foo) *must* be the next thing after the opening 9.789 + // element, and the names must match. BUT the tricky bit is that the closing 9.790 + // element will be read by the child. 9.791 + // 9.792 + // 'endTag' is the end tag for this node, it is returned by a call to a child. 9.793 + // 'parentEnd' is the end tag for the parent, which is filled in and returned. 9.794 + 9.795 + while( p && *p ) { 9.796 + XMLNode* node = 0; 9.797 + 9.798 + p = _document->Identify( p, &node ); 9.799 + if ( p == 0 || node == 0 ) { 9.800 + break; 9.801 + } 9.802 + 9.803 + StrPair endTag; 9.804 + p = node->ParseDeep( p, &endTag ); 9.805 + if ( !p ) { 9.806 + DELETE_NODE( node ); 9.807 + node = 0; 9.808 + if ( !_document->Error() ) { 9.809 + _document->SetError( XML_ERROR_PARSING, 0, 0 ); 9.810 + } 9.811 + break; 9.812 + } 9.813 + 9.814 + // We read the end tag. Return it to the parent. 9.815 + if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) { 9.816 + if ( parentEnd ) { 9.817 + *parentEnd = static_cast<XMLElement*>(node)->_value; 9.818 + } 9.819 + node->_memPool->SetTracked(); // created and then immediately deleted. 9.820 + DELETE_NODE( node ); 9.821 + return p; 9.822 + } 9.823 + 9.824 + // Handle an end tag returned to this level. 9.825 + // And handle a bunch of annoying errors. 9.826 + XMLElement* ele = node->ToElement(); 9.827 + if ( ele ) { 9.828 + if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) { 9.829 + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); 9.830 + p = 0; 9.831 + } 9.832 + else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) { 9.833 + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); 9.834 + p = 0; 9.835 + } 9.836 + else if ( !endTag.Empty() ) { 9.837 + if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) { 9.838 + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 ); 9.839 + p = 0; 9.840 + } 9.841 + } 9.842 + } 9.843 + if ( p == 0 ) { 9.844 + DELETE_NODE( node ); 9.845 + node = 0; 9.846 + } 9.847 + if ( node ) { 9.848 + this->InsertEndChild( node ); 9.849 + } 9.850 + } 9.851 + return 0; 9.852 +} 9.853 + 9.854 +// --------- XMLText ---------- // 9.855 +char* XMLText::ParseDeep( char* p, StrPair* ) 9.856 +{ 9.857 + const char* start = p; 9.858 + if ( this->CData() ) { 9.859 + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); 9.860 + if ( !p ) { 9.861 + _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 ); 9.862 + } 9.863 + return p; 9.864 + } 9.865 + else { 9.866 + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; 9.867 + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { 9.868 + flags |= StrPair::COLLAPSE_WHITESPACE; 9.869 + } 9.870 + 9.871 + p = _value.ParseText( p, "<", flags ); 9.872 + if ( !p ) { 9.873 + _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 ); 9.874 + } 9.875 + if ( p && *p ) { 9.876 + return p-1; 9.877 + } 9.878 + } 9.879 + return 0; 9.880 +} 9.881 + 9.882 + 9.883 +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const 9.884 +{ 9.885 + if ( !doc ) { 9.886 + doc = _document; 9.887 + } 9.888 + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? 9.889 + text->SetCData( this->CData() ); 9.890 + return text; 9.891 +} 9.892 + 9.893 + 9.894 +bool XMLText::ShallowEqual( const XMLNode* compare ) const 9.895 +{ 9.896 + return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() )); 9.897 +} 9.898 + 9.899 + 9.900 +bool XMLText::Accept( XMLVisitor* visitor ) const 9.901 +{ 9.902 + return visitor->Visit( *this ); 9.903 +} 9.904 + 9.905 + 9.906 +// --------- XMLComment ---------- // 9.907 + 9.908 +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) 9.909 +{ 9.910 +} 9.911 + 9.912 + 9.913 +XMLComment::~XMLComment() 9.914 +{ 9.915 +} 9.916 + 9.917 + 9.918 +char* XMLComment::ParseDeep( char* p, StrPair* ) 9.919 +{ 9.920 + // Comment parses as text. 9.921 + const char* start = p; 9.922 + p = _value.ParseText( p, "-->", StrPair::COMMENT ); 9.923 + if ( p == 0 ) { 9.924 + _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 ); 9.925 + } 9.926 + return p; 9.927 +} 9.928 + 9.929 + 9.930 +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const 9.931 +{ 9.932 + if ( !doc ) { 9.933 + doc = _document; 9.934 + } 9.935 + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? 9.936 + return comment; 9.937 +} 9.938 + 9.939 + 9.940 +bool XMLComment::ShallowEqual( const XMLNode* compare ) const 9.941 +{ 9.942 + return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() )); 9.943 +} 9.944 + 9.945 + 9.946 +bool XMLComment::Accept( XMLVisitor* visitor ) const 9.947 +{ 9.948 + return visitor->Visit( *this ); 9.949 +} 9.950 + 9.951 + 9.952 +// --------- XMLDeclaration ---------- // 9.953 + 9.954 +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) 9.955 +{ 9.956 +} 9.957 + 9.958 + 9.959 +XMLDeclaration::~XMLDeclaration() 9.960 +{ 9.961 + //printf( "~XMLDeclaration\n" ); 9.962 +} 9.963 + 9.964 + 9.965 +char* XMLDeclaration::ParseDeep( char* p, StrPair* ) 9.966 +{ 9.967 + // Declaration parses as text. 9.968 + const char* start = p; 9.969 + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION ); 9.970 + if ( p == 0 ) { 9.971 + _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 ); 9.972 + } 9.973 + return p; 9.974 +} 9.975 + 9.976 + 9.977 +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const 9.978 +{ 9.979 + if ( !doc ) { 9.980 + doc = _document; 9.981 + } 9.982 + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? 9.983 + return dec; 9.984 +} 9.985 + 9.986 + 9.987 +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const 9.988 +{ 9.989 + return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() )); 9.990 +} 9.991 + 9.992 + 9.993 + 9.994 +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const 9.995 +{ 9.996 + return visitor->Visit( *this ); 9.997 +} 9.998 + 9.999 +// --------- XMLUnknown ---------- // 9.1000 + 9.1001 +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) 9.1002 +{ 9.1003 +} 9.1004 + 9.1005 + 9.1006 +XMLUnknown::~XMLUnknown() 9.1007 +{ 9.1008 +} 9.1009 + 9.1010 + 9.1011 +char* XMLUnknown::ParseDeep( char* p, StrPair* ) 9.1012 +{ 9.1013 + // Unknown parses as text. 9.1014 + const char* start = p; 9.1015 + 9.1016 + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION ); 9.1017 + if ( !p ) { 9.1018 + _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 ); 9.1019 + } 9.1020 + return p; 9.1021 +} 9.1022 + 9.1023 + 9.1024 +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const 9.1025 +{ 9.1026 + if ( !doc ) { 9.1027 + doc = _document; 9.1028 + } 9.1029 + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? 9.1030 + return text; 9.1031 +} 9.1032 + 9.1033 + 9.1034 +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const 9.1035 +{ 9.1036 + return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() )); 9.1037 +} 9.1038 + 9.1039 + 9.1040 +bool XMLUnknown::Accept( XMLVisitor* visitor ) const 9.1041 +{ 9.1042 + return visitor->Visit( *this ); 9.1043 +} 9.1044 + 9.1045 +// --------- XMLAttribute ---------- // 9.1046 +char* XMLAttribute::ParseDeep( char* p, bool processEntities ) 9.1047 +{ 9.1048 + // Parse using the name rules: bug fix, was using ParseText before 9.1049 + p = _name.ParseName( p ); 9.1050 + if ( !p || !*p ) { 9.1051 + return 0; 9.1052 + } 9.1053 + 9.1054 + // Skip white space before = 9.1055 + p = XMLUtil::SkipWhiteSpace( p ); 9.1056 + if ( !p || *p != '=' ) { 9.1057 + return 0; 9.1058 + } 9.1059 + 9.1060 + ++p; // move up to opening quote 9.1061 + p = XMLUtil::SkipWhiteSpace( p ); 9.1062 + if ( *p != '\"' && *p != '\'' ) { 9.1063 + return 0; 9.1064 + } 9.1065 + 9.1066 + char endTag[2] = { *p, 0 }; 9.1067 + ++p; // move past opening quote 9.1068 + 9.1069 + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES ); 9.1070 + return p; 9.1071 +} 9.1072 + 9.1073 + 9.1074 +void XMLAttribute::SetName( const char* n ) 9.1075 +{ 9.1076 + _name.SetStr( n ); 9.1077 +} 9.1078 + 9.1079 + 9.1080 +XMLError XMLAttribute::QueryIntValue( int* value ) const 9.1081 +{ 9.1082 + if ( XMLUtil::ToInt( Value(), value )) { 9.1083 + return XML_NO_ERROR; 9.1084 + } 9.1085 + return XML_WRONG_ATTRIBUTE_TYPE; 9.1086 +} 9.1087 + 9.1088 + 9.1089 +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const 9.1090 +{ 9.1091 + if ( XMLUtil::ToUnsigned( Value(), value )) { 9.1092 + return XML_NO_ERROR; 9.1093 + } 9.1094 + return XML_WRONG_ATTRIBUTE_TYPE; 9.1095 +} 9.1096 + 9.1097 + 9.1098 +XMLError XMLAttribute::QueryBoolValue( bool* value ) const 9.1099 +{ 9.1100 + if ( XMLUtil::ToBool( Value(), value )) { 9.1101 + return XML_NO_ERROR; 9.1102 + } 9.1103 + return XML_WRONG_ATTRIBUTE_TYPE; 9.1104 +} 9.1105 + 9.1106 + 9.1107 +XMLError XMLAttribute::QueryFloatValue( float* value ) const 9.1108 +{ 9.1109 + if ( XMLUtil::ToFloat( Value(), value )) { 9.1110 + return XML_NO_ERROR; 9.1111 + } 9.1112 + return XML_WRONG_ATTRIBUTE_TYPE; 9.1113 +} 9.1114 + 9.1115 + 9.1116 +XMLError XMLAttribute::QueryDoubleValue( double* value ) const 9.1117 +{ 9.1118 + if ( XMLUtil::ToDouble( Value(), value )) { 9.1119 + return XML_NO_ERROR; 9.1120 + } 9.1121 + return XML_WRONG_ATTRIBUTE_TYPE; 9.1122 +} 9.1123 + 9.1124 + 9.1125 +void XMLAttribute::SetAttribute( const char* v ) 9.1126 +{ 9.1127 + _value.SetStr( v ); 9.1128 +} 9.1129 + 9.1130 + 9.1131 +void XMLAttribute::SetAttribute( int v ) 9.1132 +{ 9.1133 + char buf[BUF_SIZE]; 9.1134 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1135 + _value.SetStr( buf ); 9.1136 +} 9.1137 + 9.1138 + 9.1139 +void XMLAttribute::SetAttribute( unsigned v ) 9.1140 +{ 9.1141 + char buf[BUF_SIZE]; 9.1142 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1143 + _value.SetStr( buf ); 9.1144 +} 9.1145 + 9.1146 + 9.1147 +void XMLAttribute::SetAttribute( bool v ) 9.1148 +{ 9.1149 + char buf[BUF_SIZE]; 9.1150 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1151 + _value.SetStr( buf ); 9.1152 +} 9.1153 + 9.1154 +void XMLAttribute::SetAttribute( double v ) 9.1155 +{ 9.1156 + char buf[BUF_SIZE]; 9.1157 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1158 + _value.SetStr( buf ); 9.1159 +} 9.1160 + 9.1161 +void XMLAttribute::SetAttribute( float v ) 9.1162 +{ 9.1163 + char buf[BUF_SIZE]; 9.1164 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1165 + _value.SetStr( buf ); 9.1166 +} 9.1167 + 9.1168 + 9.1169 +// --------- XMLElement ---------- // 9.1170 +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), 9.1171 + _closingType( 0 ), 9.1172 + _rootAttribute( 0 ) 9.1173 +{ 9.1174 +} 9.1175 + 9.1176 + 9.1177 +XMLElement::~XMLElement() 9.1178 +{ 9.1179 + while( _rootAttribute ) { 9.1180 + XMLAttribute* next = _rootAttribute->_next; 9.1181 + DELETE_ATTRIBUTE( _rootAttribute ); 9.1182 + _rootAttribute = next; 9.1183 + } 9.1184 +} 9.1185 + 9.1186 + 9.1187 +XMLAttribute* XMLElement::FindAttribute( const char* name ) 9.1188 +{ 9.1189 + XMLAttribute* a = 0; 9.1190 + for( a=_rootAttribute; a; a = a->_next ) { 9.1191 + if ( XMLUtil::StringEqual( a->Name(), name ) ) { 9.1192 + return a; 9.1193 + } 9.1194 + } 9.1195 + return 0; 9.1196 +} 9.1197 + 9.1198 + 9.1199 +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const 9.1200 +{ 9.1201 + XMLAttribute* a = 0; 9.1202 + for( a=_rootAttribute; a; a = a->_next ) { 9.1203 + if ( XMLUtil::StringEqual( a->Name(), name ) ) { 9.1204 + return a; 9.1205 + } 9.1206 + } 9.1207 + return 0; 9.1208 +} 9.1209 + 9.1210 + 9.1211 +const char* XMLElement::Attribute( const char* name, const char* value ) const 9.1212 +{ 9.1213 + const XMLAttribute* a = FindAttribute( name ); 9.1214 + if ( !a ) { 9.1215 + return 0; 9.1216 + } 9.1217 + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { 9.1218 + return a->Value(); 9.1219 + } 9.1220 + return 0; 9.1221 +} 9.1222 + 9.1223 + 9.1224 +const char* XMLElement::GetText() const 9.1225 +{ 9.1226 + if ( FirstChild() && FirstChild()->ToText() ) { 9.1227 + return FirstChild()->ToText()->Value(); 9.1228 + } 9.1229 + return 0; 9.1230 +} 9.1231 + 9.1232 + 9.1233 +XMLError XMLElement::QueryIntText( int* ival ) const 9.1234 +{ 9.1235 + if ( FirstChild() && FirstChild()->ToText() ) { 9.1236 + const char* t = FirstChild()->ToText()->Value(); 9.1237 + if ( XMLUtil::ToInt( t, ival ) ) { 9.1238 + return XML_SUCCESS; 9.1239 + } 9.1240 + return XML_CAN_NOT_CONVERT_TEXT; 9.1241 + } 9.1242 + return XML_NO_TEXT_NODE; 9.1243 +} 9.1244 + 9.1245 + 9.1246 +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const 9.1247 +{ 9.1248 + if ( FirstChild() && FirstChild()->ToText() ) { 9.1249 + const char* t = FirstChild()->ToText()->Value(); 9.1250 + if ( XMLUtil::ToUnsigned( t, uval ) ) { 9.1251 + return XML_SUCCESS; 9.1252 + } 9.1253 + return XML_CAN_NOT_CONVERT_TEXT; 9.1254 + } 9.1255 + return XML_NO_TEXT_NODE; 9.1256 +} 9.1257 + 9.1258 + 9.1259 +XMLError XMLElement::QueryBoolText( bool* bval ) const 9.1260 +{ 9.1261 + if ( FirstChild() && FirstChild()->ToText() ) { 9.1262 + const char* t = FirstChild()->ToText()->Value(); 9.1263 + if ( XMLUtil::ToBool( t, bval ) ) { 9.1264 + return XML_SUCCESS; 9.1265 + } 9.1266 + return XML_CAN_NOT_CONVERT_TEXT; 9.1267 + } 9.1268 + return XML_NO_TEXT_NODE; 9.1269 +} 9.1270 + 9.1271 + 9.1272 +XMLError XMLElement::QueryDoubleText( double* dval ) const 9.1273 +{ 9.1274 + if ( FirstChild() && FirstChild()->ToText() ) { 9.1275 + const char* t = FirstChild()->ToText()->Value(); 9.1276 + if ( XMLUtil::ToDouble( t, dval ) ) { 9.1277 + return XML_SUCCESS; 9.1278 + } 9.1279 + return XML_CAN_NOT_CONVERT_TEXT; 9.1280 + } 9.1281 + return XML_NO_TEXT_NODE; 9.1282 +} 9.1283 + 9.1284 + 9.1285 +XMLError XMLElement::QueryFloatText( float* fval ) const 9.1286 +{ 9.1287 + if ( FirstChild() && FirstChild()->ToText() ) { 9.1288 + const char* t = FirstChild()->ToText()->Value(); 9.1289 + if ( XMLUtil::ToFloat( t, fval ) ) { 9.1290 + return XML_SUCCESS; 9.1291 + } 9.1292 + return XML_CAN_NOT_CONVERT_TEXT; 9.1293 + } 9.1294 + return XML_NO_TEXT_NODE; 9.1295 +} 9.1296 + 9.1297 + 9.1298 + 9.1299 +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) 9.1300 +{ 9.1301 + XMLAttribute* last = 0; 9.1302 + XMLAttribute* attrib = 0; 9.1303 + for( attrib = _rootAttribute; 9.1304 + attrib; 9.1305 + last = attrib, attrib = attrib->_next ) { 9.1306 + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { 9.1307 + break; 9.1308 + } 9.1309 + } 9.1310 + if ( !attrib ) { 9.1311 + attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); 9.1312 + attrib->_memPool = &_document->_attributePool; 9.1313 + if ( last ) { 9.1314 + last->_next = attrib; 9.1315 + } 9.1316 + else { 9.1317 + _rootAttribute = attrib; 9.1318 + } 9.1319 + attrib->SetName( name ); 9.1320 + attrib->_memPool->SetTracked(); // always created and linked. 9.1321 + } 9.1322 + return attrib; 9.1323 +} 9.1324 + 9.1325 + 9.1326 +void XMLElement::DeleteAttribute( const char* name ) 9.1327 +{ 9.1328 + XMLAttribute* prev = 0; 9.1329 + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { 9.1330 + if ( XMLUtil::StringEqual( name, a->Name() ) ) { 9.1331 + if ( prev ) { 9.1332 + prev->_next = a->_next; 9.1333 + } 9.1334 + else { 9.1335 + _rootAttribute = a->_next; 9.1336 + } 9.1337 + DELETE_ATTRIBUTE( a ); 9.1338 + break; 9.1339 + } 9.1340 + prev = a; 9.1341 + } 9.1342 +} 9.1343 + 9.1344 + 9.1345 +char* XMLElement::ParseAttributes( char* p ) 9.1346 +{ 9.1347 + const char* start = p; 9.1348 + XMLAttribute* prevAttribute = 0; 9.1349 + 9.1350 + // Read the attributes. 9.1351 + while( p ) { 9.1352 + p = XMLUtil::SkipWhiteSpace( p ); 9.1353 + if ( !p || !(*p) ) { 9.1354 + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() ); 9.1355 + return 0; 9.1356 + } 9.1357 + 9.1358 + // attribute. 9.1359 + if (XMLUtil::IsNameStartChar( *p ) ) { 9.1360 + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); 9.1361 + attrib->_memPool = &_document->_attributePool; 9.1362 + attrib->_memPool->SetTracked(); 9.1363 + 9.1364 + p = attrib->ParseDeep( p, _document->ProcessEntities() ); 9.1365 + if ( !p || Attribute( attrib->Name() ) ) { 9.1366 + DELETE_ATTRIBUTE( attrib ); 9.1367 + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p ); 9.1368 + return 0; 9.1369 + } 9.1370 + // There is a minor bug here: if the attribute in the source xml 9.1371 + // document is duplicated, it will not be detected and the 9.1372 + // attribute will be doubly added. However, tracking the 'prevAttribute' 9.1373 + // avoids re-scanning the attribute list. Preferring performance for 9.1374 + // now, may reconsider in the future. 9.1375 + if ( prevAttribute ) { 9.1376 + prevAttribute->_next = attrib; 9.1377 + } 9.1378 + else { 9.1379 + _rootAttribute = attrib; 9.1380 + } 9.1381 + prevAttribute = attrib; 9.1382 + } 9.1383 + // end of the tag 9.1384 + else if ( *p == '/' && *(p+1) == '>' ) { 9.1385 + _closingType = CLOSED; 9.1386 + return p+2; // done; sealed element. 9.1387 + } 9.1388 + // end of the tag 9.1389 + else if ( *p == '>' ) { 9.1390 + ++p; 9.1391 + break; 9.1392 + } 9.1393 + else { 9.1394 + _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p ); 9.1395 + return 0; 9.1396 + } 9.1397 + } 9.1398 + return p; 9.1399 +} 9.1400 + 9.1401 + 9.1402 +// 9.1403 +// <ele></ele> 9.1404 +// <ele>foo<b>bar</b></ele> 9.1405 +// 9.1406 +char* XMLElement::ParseDeep( char* p, StrPair* strPair ) 9.1407 +{ 9.1408 + // Read the element name. 9.1409 + p = XMLUtil::SkipWhiteSpace( p ); 9.1410 + if ( !p ) { 9.1411 + return 0; 9.1412 + } 9.1413 + 9.1414 + // The closing element is the </element> form. It is 9.1415 + // parsed just like a regular element then deleted from 9.1416 + // the DOM. 9.1417 + if ( *p == '/' ) { 9.1418 + _closingType = CLOSING; 9.1419 + ++p; 9.1420 + } 9.1421 + 9.1422 + p = _value.ParseName( p ); 9.1423 + if ( _value.Empty() ) { 9.1424 + return 0; 9.1425 + } 9.1426 + 9.1427 + p = ParseAttributes( p ); 9.1428 + if ( !p || !*p || _closingType ) { 9.1429 + return p; 9.1430 + } 9.1431 + 9.1432 + p = XMLNode::ParseDeep( p, strPair ); 9.1433 + return p; 9.1434 +} 9.1435 + 9.1436 + 9.1437 + 9.1438 +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const 9.1439 +{ 9.1440 + if ( !doc ) { 9.1441 + doc = _document; 9.1442 + } 9.1443 + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? 9.1444 + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { 9.1445 + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? 9.1446 + } 9.1447 + return element; 9.1448 +} 9.1449 + 9.1450 + 9.1451 +bool XMLElement::ShallowEqual( const XMLNode* compare ) const 9.1452 +{ 9.1453 + const XMLElement* other = compare->ToElement(); 9.1454 + if ( other && XMLUtil::StringEqual( other->Value(), Value() )) { 9.1455 + 9.1456 + const XMLAttribute* a=FirstAttribute(); 9.1457 + const XMLAttribute* b=other->FirstAttribute(); 9.1458 + 9.1459 + while ( a && b ) { 9.1460 + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { 9.1461 + return false; 9.1462 + } 9.1463 + a = a->Next(); 9.1464 + b = b->Next(); 9.1465 + } 9.1466 + if ( a || b ) { 9.1467 + // different count 9.1468 + return false; 9.1469 + } 9.1470 + return true; 9.1471 + } 9.1472 + return false; 9.1473 +} 9.1474 + 9.1475 + 9.1476 +bool XMLElement::Accept( XMLVisitor* visitor ) const 9.1477 +{ 9.1478 + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { 9.1479 + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { 9.1480 + if ( !node->Accept( visitor ) ) { 9.1481 + break; 9.1482 + } 9.1483 + } 9.1484 + } 9.1485 + return visitor->VisitExit( *this ); 9.1486 +} 9.1487 + 9.1488 + 9.1489 +// --------- XMLDocument ----------- // 9.1490 +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) : 9.1491 + XMLNode( 0 ), 9.1492 + _writeBOM( false ), 9.1493 + _processEntities( processEntities ), 9.1494 + _errorID( XML_NO_ERROR ), 9.1495 + _whitespace( whitespace ), 9.1496 + _errorStr1( 0 ), 9.1497 + _errorStr2( 0 ), 9.1498 + _charBuffer( 0 ) 9.1499 +{ 9.1500 + _document = this; // avoid warning about 'this' in initializer list 9.1501 +} 9.1502 + 9.1503 + 9.1504 +XMLDocument::~XMLDocument() 9.1505 +{ 9.1506 + DeleteChildren(); 9.1507 + delete [] _charBuffer; 9.1508 + 9.1509 +#if 0 9.1510 + _textPool.Trace( "text" ); 9.1511 + _elementPool.Trace( "element" ); 9.1512 + _commentPool.Trace( "comment" ); 9.1513 + _attributePool.Trace( "attribute" ); 9.1514 +#endif 9.1515 + 9.1516 +#ifdef DEBUG 9.1517 + if ( Error() == false ) { 9.1518 + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); 9.1519 + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); 9.1520 + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); 9.1521 + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); 9.1522 + } 9.1523 +#endif 9.1524 +} 9.1525 + 9.1526 + 9.1527 +void XMLDocument::Clear() 9.1528 +{ 9.1529 + DeleteChildren(); 9.1530 + 9.1531 + _errorID = XML_NO_ERROR; 9.1532 + _errorStr1 = 0; 9.1533 + _errorStr2 = 0; 9.1534 + 9.1535 + delete [] _charBuffer; 9.1536 + _charBuffer = 0; 9.1537 +} 9.1538 + 9.1539 + 9.1540 +XMLElement* XMLDocument::NewElement( const char* name ) 9.1541 +{ 9.1542 + XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this ); 9.1543 + ele->_memPool = &_elementPool; 9.1544 + ele->SetName( name ); 9.1545 + return ele; 9.1546 +} 9.1547 + 9.1548 + 9.1549 +XMLComment* XMLDocument::NewComment( const char* str ) 9.1550 +{ 9.1551 + XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this ); 9.1552 + comment->_memPool = &_commentPool; 9.1553 + comment->SetValue( str ); 9.1554 + return comment; 9.1555 +} 9.1556 + 9.1557 + 9.1558 +XMLText* XMLDocument::NewText( const char* str ) 9.1559 +{ 9.1560 + XMLText* text = new (_textPool.Alloc()) XMLText( this ); 9.1561 + text->_memPool = &_textPool; 9.1562 + text->SetValue( str ); 9.1563 + return text; 9.1564 +} 9.1565 + 9.1566 + 9.1567 +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) 9.1568 +{ 9.1569 + XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this ); 9.1570 + dec->_memPool = &_commentPool; 9.1571 + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); 9.1572 + return dec; 9.1573 +} 9.1574 + 9.1575 + 9.1576 +XMLUnknown* XMLDocument::NewUnknown( const char* str ) 9.1577 +{ 9.1578 + XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this ); 9.1579 + unk->_memPool = &_commentPool; 9.1580 + unk->SetValue( str ); 9.1581 + return unk; 9.1582 +} 9.1583 + 9.1584 + 9.1585 +XMLError XMLDocument::LoadFile( const char* filename ) 9.1586 +{ 9.1587 + Clear(); 9.1588 + FILE* fp = 0; 9.1589 + 9.1590 +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) 9.1591 + errno_t err = fopen_s(&fp, filename, "rb" ); 9.1592 + if ( !fp || err) { 9.1593 +#else 9.1594 + fp = fopen( filename, "rb" ); 9.1595 + if ( !fp) { 9.1596 +#endif 9.1597 + SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 ); 9.1598 + return _errorID; 9.1599 + } 9.1600 + LoadFile( fp ); 9.1601 + fclose( fp ); 9.1602 + return _errorID; 9.1603 +} 9.1604 + 9.1605 + 9.1606 +XMLError XMLDocument::LoadFile( FILE* fp ) 9.1607 +{ 9.1608 + Clear(); 9.1609 + 9.1610 + fseek( fp, 0, SEEK_END ); 9.1611 + size_t size = ftell( fp ); 9.1612 + fseek( fp, 0, SEEK_SET ); 9.1613 + 9.1614 + if ( size == 0 ) { 9.1615 + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 9.1616 + return _errorID; 9.1617 + } 9.1618 + 9.1619 + _charBuffer = new char[size+1]; 9.1620 + size_t read = fread( _charBuffer, 1, size, fp ); 9.1621 + if ( read != size ) { 9.1622 + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); 9.1623 + return _errorID; 9.1624 + } 9.1625 + 9.1626 + _charBuffer[size] = 0; 9.1627 + 9.1628 + const char* p = _charBuffer; 9.1629 + p = XMLUtil::SkipWhiteSpace( p ); 9.1630 + p = XMLUtil::ReadBOM( p, &_writeBOM ); 9.1631 + if ( !p || !*p ) { 9.1632 + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 9.1633 + return _errorID; 9.1634 + } 9.1635 + 9.1636 + ParseDeep( _charBuffer + (p-_charBuffer), 0 ); 9.1637 + return _errorID; 9.1638 +} 9.1639 + 9.1640 + 9.1641 +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) 9.1642 +{ 9.1643 + FILE* fp = 0; 9.1644 +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) 9.1645 + errno_t err = fopen_s(&fp, filename, "w" ); 9.1646 + if ( !fp || err) { 9.1647 +#else 9.1648 + fp = fopen( filename, "w" ); 9.1649 + if ( !fp) { 9.1650 +#endif 9.1651 + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 ); 9.1652 + return _errorID; 9.1653 + } 9.1654 + SaveFile(fp, compact); 9.1655 + fclose( fp ); 9.1656 + return _errorID; 9.1657 +} 9.1658 + 9.1659 + 9.1660 +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) 9.1661 +{ 9.1662 + XMLPrinter stream( fp, compact ); 9.1663 + Print( &stream ); 9.1664 + return _errorID; 9.1665 +} 9.1666 + 9.1667 + 9.1668 +XMLError XMLDocument::Parse( const char* p, size_t len ) 9.1669 +{ 9.1670 + const char* start = p; 9.1671 + Clear(); 9.1672 + 9.1673 + if ( !p || !*p ) { 9.1674 + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 9.1675 + return _errorID; 9.1676 + } 9.1677 + if ( len == (size_t)(-1) ) { 9.1678 + len = strlen( p ); 9.1679 + } 9.1680 + _charBuffer = new char[ len+1 ]; 9.1681 + memcpy( _charBuffer, p, len ); 9.1682 + _charBuffer[len] = 0; 9.1683 + 9.1684 + p = XMLUtil::SkipWhiteSpace( p ); 9.1685 + p = XMLUtil::ReadBOM( p, &_writeBOM ); 9.1686 + if ( !p || !*p ) { 9.1687 + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); 9.1688 + return _errorID; 9.1689 + } 9.1690 + 9.1691 + ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc. 9.1692 + ParseDeep( _charBuffer+delta, 0 ); 9.1693 + return _errorID; 9.1694 +} 9.1695 + 9.1696 + 9.1697 +void XMLDocument::Print( XMLPrinter* streamer ) const 9.1698 +{ 9.1699 + XMLPrinter stdStreamer( stdout ); 9.1700 + if ( !streamer ) { 9.1701 + streamer = &stdStreamer; 9.1702 + } 9.1703 + Accept( streamer ); 9.1704 +} 9.1705 + 9.1706 + 9.1707 +void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 ) 9.1708 +{ 9.1709 + _errorID = error; 9.1710 + _errorStr1 = str1; 9.1711 + _errorStr2 = str2; 9.1712 +} 9.1713 + 9.1714 + 9.1715 +void XMLDocument::PrintError() const 9.1716 +{ 9.1717 + if ( _errorID ) { 9.1718 + static const int LEN = 20; 9.1719 + char buf1[LEN] = { 0 }; 9.1720 + char buf2[LEN] = { 0 }; 9.1721 + 9.1722 + if ( _errorStr1 ) { 9.1723 + TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 ); 9.1724 + } 9.1725 + if ( _errorStr2 ) { 9.1726 + TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 ); 9.1727 + } 9.1728 + 9.1729 + printf( "XMLDocument error id=%d str1=%s str2=%s\n", 9.1730 + _errorID, buf1, buf2 ); 9.1731 + } 9.1732 +} 9.1733 + 9.1734 + 9.1735 +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : 9.1736 + _elementJustOpened( false ), 9.1737 + _firstElement( true ), 9.1738 + _fp( file ), 9.1739 + _depth( depth ), 9.1740 + _textDepth( -1 ), 9.1741 + _processEntities( true ), 9.1742 + _compactMode( compact ) 9.1743 +{ 9.1744 + for( int i=0; i<ENTITY_RANGE; ++i ) { 9.1745 + _entityFlag[i] = false; 9.1746 + _restrictedEntityFlag[i] = false; 9.1747 + } 9.1748 + for( int i=0; i<NUM_ENTITIES; ++i ) { 9.1749 + TIXMLASSERT( entities[i].value < ENTITY_RANGE ); 9.1750 + if ( entities[i].value < ENTITY_RANGE ) { 9.1751 + _entityFlag[ (int)entities[i].value ] = true; 9.1752 + } 9.1753 + } 9.1754 + _restrictedEntityFlag[(int)'&'] = true; 9.1755 + _restrictedEntityFlag[(int)'<'] = true; 9.1756 + _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice 9.1757 + _buffer.Push( 0 ); 9.1758 +} 9.1759 + 9.1760 + 9.1761 +void XMLPrinter::Print( const char* format, ... ) 9.1762 +{ 9.1763 + va_list va; 9.1764 + va_start( va, format ); 9.1765 + 9.1766 + if ( _fp ) { 9.1767 + vfprintf( _fp, format, va ); 9.1768 + } 9.1769 + else { 9.1770 + // This seems brutally complex. Haven't figured out a better 9.1771 + // way on windows. 9.1772 +#ifdef _MSC_VER 9.1773 + int len = -1; 9.1774 + int expand = 1000; 9.1775 + while ( len < 0 ) { 9.1776 + len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va ); 9.1777 + if ( len < 0 ) { 9.1778 + expand *= 3/2; 9.1779 + _accumulator.PushArr( expand ); 9.1780 + } 9.1781 + } 9.1782 + char* p = _buffer.PushArr( len ) - 1; 9.1783 + memcpy( p, _accumulator.Mem(), len+1 ); 9.1784 +#else 9.1785 + int len = vsnprintf( 0, 0, format, va ); 9.1786 + // Close out and re-start the va-args 9.1787 + va_end( va ); 9.1788 + va_start( va, format ); 9.1789 + char* p = _buffer.PushArr( len ) - 1; 9.1790 + vsnprintf( p, len+1, format, va ); 9.1791 +#endif 9.1792 + } 9.1793 + va_end( va ); 9.1794 +} 9.1795 + 9.1796 + 9.1797 +void XMLPrinter::PrintSpace( int depth ) 9.1798 +{ 9.1799 + for( int i=0; i<depth; ++i ) { 9.1800 + Print( " " ); 9.1801 + } 9.1802 +} 9.1803 + 9.1804 + 9.1805 +void XMLPrinter::PrintString( const char* p, bool restricted ) 9.1806 +{ 9.1807 + // Look for runs of bytes between entities to print. 9.1808 + const char* q = p; 9.1809 + const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag; 9.1810 + 9.1811 + if ( _processEntities ) { 9.1812 + while ( *q ) { 9.1813 + // Remember, char is sometimes signed. (How many times has that bitten me?) 9.1814 + if ( *q > 0 && *q < ENTITY_RANGE ) { 9.1815 + // Check for entities. If one is found, flush 9.1816 + // the stream up until the entity, write the 9.1817 + // entity, and keep looking. 9.1818 + if ( flag[(unsigned)(*q)] ) { 9.1819 + while ( p < q ) { 9.1820 + Print( "%c", *p ); 9.1821 + ++p; 9.1822 + } 9.1823 + for( int i=0; i<NUM_ENTITIES; ++i ) { 9.1824 + if ( entities[i].value == *q ) { 9.1825 + Print( "&%s;", entities[i].pattern ); 9.1826 + break; 9.1827 + } 9.1828 + } 9.1829 + ++p; 9.1830 + } 9.1831 + } 9.1832 + ++q; 9.1833 + } 9.1834 + } 9.1835 + // Flush the remaining string. This will be the entire 9.1836 + // string if an entity wasn't found. 9.1837 + if ( !_processEntities || (q-p > 0) ) { 9.1838 + Print( "%s", p ); 9.1839 + } 9.1840 +} 9.1841 + 9.1842 + 9.1843 +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) 9.1844 +{ 9.1845 + if ( writeBOM ) { 9.1846 + static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; 9.1847 + Print( "%s", bom ); 9.1848 + } 9.1849 + if ( writeDec ) { 9.1850 + PushDeclaration( "xml version=\"1.0\"" ); 9.1851 + } 9.1852 +} 9.1853 + 9.1854 + 9.1855 +void XMLPrinter::OpenElement( const char* name ) 9.1856 +{ 9.1857 + if ( _elementJustOpened ) { 9.1858 + SealElement(); 9.1859 + } 9.1860 + _stack.Push( name ); 9.1861 + 9.1862 + if ( _textDepth < 0 && !_firstElement && !_compactMode ) { 9.1863 + Print( "\n" ); 9.1864 + } 9.1865 + if ( !_compactMode ) { 9.1866 + PrintSpace( _depth ); 9.1867 + } 9.1868 + 9.1869 + Print( "<%s", name ); 9.1870 + _elementJustOpened = true; 9.1871 + _firstElement = false; 9.1872 + ++_depth; 9.1873 +} 9.1874 + 9.1875 + 9.1876 +void XMLPrinter::PushAttribute( const char* name, const char* value ) 9.1877 +{ 9.1878 + TIXMLASSERT( _elementJustOpened ); 9.1879 + Print( " %s=\"", name ); 9.1880 + PrintString( value, false ); 9.1881 + Print( "\"" ); 9.1882 +} 9.1883 + 9.1884 + 9.1885 +void XMLPrinter::PushAttribute( const char* name, int v ) 9.1886 +{ 9.1887 + char buf[BUF_SIZE]; 9.1888 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1889 + PushAttribute( name, buf ); 9.1890 +} 9.1891 + 9.1892 + 9.1893 +void XMLPrinter::PushAttribute( const char* name, unsigned v ) 9.1894 +{ 9.1895 + char buf[BUF_SIZE]; 9.1896 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1897 + PushAttribute( name, buf ); 9.1898 +} 9.1899 + 9.1900 + 9.1901 +void XMLPrinter::PushAttribute( const char* name, bool v ) 9.1902 +{ 9.1903 + char buf[BUF_SIZE]; 9.1904 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1905 + PushAttribute( name, buf ); 9.1906 +} 9.1907 + 9.1908 + 9.1909 +void XMLPrinter::PushAttribute( const char* name, double v ) 9.1910 +{ 9.1911 + char buf[BUF_SIZE]; 9.1912 + XMLUtil::ToStr( v, buf, BUF_SIZE ); 9.1913 + PushAttribute( name, buf ); 9.1914 +} 9.1915 + 9.1916 + 9.1917 +void XMLPrinter::CloseElement() 9.1918 +{ 9.1919 + --_depth; 9.1920 + const char* name = _stack.Pop(); 9.1921 + 9.1922 + if ( _elementJustOpened ) { 9.1923 + Print( "/>" ); 9.1924 + } 9.1925 + else { 9.1926 + if ( _textDepth < 0 && !_compactMode) { 9.1927 + Print( "\n" ); 9.1928 + PrintSpace( _depth ); 9.1929 + } 9.1930 + Print( "</%s>", name ); 9.1931 + } 9.1932 + 9.1933 + if ( _textDepth == _depth ) { 9.1934 + _textDepth = -1; 9.1935 + } 9.1936 + if ( _depth == 0 && !_compactMode) { 9.1937 + Print( "\n" ); 9.1938 + } 9.1939 + _elementJustOpened = false; 9.1940 +} 9.1941 + 9.1942 + 9.1943 +void XMLPrinter::SealElement() 9.1944 +{ 9.1945 + _elementJustOpened = false; 9.1946 + Print( ">" ); 9.1947 +} 9.1948 + 9.1949 + 9.1950 +void XMLPrinter::PushText( const char* text, bool cdata ) 9.1951 +{ 9.1952 + _textDepth = _depth-1; 9.1953 + 9.1954 + if ( _elementJustOpened ) { 9.1955 + SealElement(); 9.1956 + } 9.1957 + if ( cdata ) { 9.1958 + Print( "<![CDATA[" ); 9.1959 + Print( "%s", text ); 9.1960 + Print( "]]>" ); 9.1961 + } 9.1962 + else { 9.1963 + PrintString( text, true ); 9.1964 + } 9.1965 +} 9.1966 + 9.1967 +void XMLPrinter::PushText( int value ) 9.1968 +{ 9.1969 + char buf[BUF_SIZE]; 9.1970 + XMLUtil::ToStr( value, buf, BUF_SIZE ); 9.1971 + PushText( buf, false ); 9.1972 +} 9.1973 + 9.1974 + 9.1975 +void XMLPrinter::PushText( unsigned value ) 9.1976 +{ 9.1977 + char buf[BUF_SIZE]; 9.1978 + XMLUtil::ToStr( value, buf, BUF_SIZE ); 9.1979 + PushText( buf, false ); 9.1980 +} 9.1981 + 9.1982 + 9.1983 +void XMLPrinter::PushText( bool value ) 9.1984 +{ 9.1985 + char buf[BUF_SIZE]; 9.1986 + XMLUtil::ToStr( value, buf, BUF_SIZE ); 9.1987 + PushText( buf, false ); 9.1988 +} 9.1989 + 9.1990 + 9.1991 +void XMLPrinter::PushText( float value ) 9.1992 +{ 9.1993 + char buf[BUF_SIZE]; 9.1994 + XMLUtil::ToStr( value, buf, BUF_SIZE ); 9.1995 + PushText( buf, false ); 9.1996 +} 9.1997 + 9.1998 + 9.1999 +void XMLPrinter::PushText( double value ) 9.2000 +{ 9.2001 + char buf[BUF_SIZE]; 9.2002 + XMLUtil::ToStr( value, buf, BUF_SIZE ); 9.2003 + PushText( buf, false ); 9.2004 +} 9.2005 + 9.2006 + 9.2007 +void XMLPrinter::PushComment( const char* comment ) 9.2008 +{ 9.2009 + if ( _elementJustOpened ) { 9.2010 + SealElement(); 9.2011 + } 9.2012 + if ( _textDepth < 0 && !_firstElement && !_compactMode) { 9.2013 + Print( "\n" ); 9.2014 + PrintSpace( _depth ); 9.2015 + } 9.2016 + _firstElement = false; 9.2017 + Print( "<!--%s-->", comment ); 9.2018 +} 9.2019 + 9.2020 + 9.2021 +void XMLPrinter::PushDeclaration( const char* value ) 9.2022 +{ 9.2023 + if ( _elementJustOpened ) { 9.2024 + SealElement(); 9.2025 + } 9.2026 + if ( _textDepth < 0 && !_firstElement && !_compactMode) { 9.2027 + Print( "\n" ); 9.2028 + PrintSpace( _depth ); 9.2029 + } 9.2030 + _firstElement = false; 9.2031 + Print( "<?%s?>", value ); 9.2032 +} 9.2033 + 9.2034 + 9.2035 +void XMLPrinter::PushUnknown( const char* value ) 9.2036 +{ 9.2037 + if ( _elementJustOpened ) { 9.2038 + SealElement(); 9.2039 + } 9.2040 + if ( _textDepth < 0 && !_firstElement && !_compactMode) { 9.2041 + Print( "\n" ); 9.2042 + PrintSpace( _depth ); 9.2043 + } 9.2044 + _firstElement = false; 9.2045 + Print( "<!%s>", value ); 9.2046 +} 9.2047 + 9.2048 + 9.2049 +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) 9.2050 +{ 9.2051 + _processEntities = doc.ProcessEntities(); 9.2052 + if ( doc.HasBOM() ) { 9.2053 + PushHeader( true, false ); 9.2054 + } 9.2055 + return true; 9.2056 +} 9.2057 + 9.2058 + 9.2059 +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) 9.2060 +{ 9.2061 + OpenElement( element.Name() ); 9.2062 + while ( attribute ) { 9.2063 + PushAttribute( attribute->Name(), attribute->Value() ); 9.2064 + attribute = attribute->Next(); 9.2065 + } 9.2066 + return true; 9.2067 +} 9.2068 + 9.2069 + 9.2070 +bool XMLPrinter::VisitExit( const XMLElement& ) 9.2071 +{ 9.2072 + CloseElement(); 9.2073 + return true; 9.2074 +} 9.2075 + 9.2076 + 9.2077 +bool XMLPrinter::Visit( const XMLText& text ) 9.2078 +{ 9.2079 + PushText( text.Value(), text.CData() ); 9.2080 + return true; 9.2081 +} 9.2082 + 9.2083 + 9.2084 +bool XMLPrinter::Visit( const XMLComment& comment ) 9.2085 +{ 9.2086 + PushComment( comment.Value() ); 9.2087 + return true; 9.2088 +} 9.2089 + 9.2090 +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) 9.2091 +{ 9.2092 + PushDeclaration( declaration.Value() ); 9.2093 + return true; 9.2094 +} 9.2095 + 9.2096 + 9.2097 +bool XMLPrinter::Visit( const XMLUnknown& unknown ) 9.2098 +{ 9.2099 + PushUnknown( unknown.Value() ); 9.2100 + return true; 9.2101 +} 9.2102 + 9.2103 +} // namespace tinyxml2 9.2104 +
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/libs/tinyxml2/tinyxml2.h Fri Sep 27 07:14:49 2013 +0300 10.3 @@ -0,0 +1,1987 @@ 10.4 +/* 10.5 +Original code by Lee Thomason (www.grinninglizard.com) 10.6 + 10.7 +This software is provided 'as-is', without any express or implied 10.8 +warranty. In no event will the authors be held liable for any 10.9 +damages arising from the use of this software. 10.10 + 10.11 +Permission is granted to anyone to use this software for any 10.12 +purpose, including commercial applications, and to alter it and 10.13 +redistribute it freely, subject to the following restrictions: 10.14 + 10.15 +1. The origin of this software must not be misrepresented; you must 10.16 +not claim that you wrote the original software. If you use this 10.17 +software in a product, an acknowledgment in the product documentation 10.18 +would be appreciated but is not required. 10.19 + 10.20 + 10.21 +2. Altered source versions must be plainly marked as such, and 10.22 +must not be misrepresented as being the original software. 10.23 + 10.24 +3. This notice may not be removed or altered from any source 10.25 +distribution. 10.26 +*/ 10.27 + 10.28 +#ifndef TINYXML2_INCLUDED 10.29 +#define TINYXML2_INCLUDED 10.30 + 10.31 +#if defined(ANDROID_NDK) || defined(__BORLANDC__) 10.32 +# include <ctype.h> 10.33 +# include <limits.h> 10.34 +# include <stdio.h> 10.35 +# include <stdlib.h> 10.36 +# include <string.h> 10.37 +# include <stdarg.h> 10.38 +#else 10.39 +# include <cctype> 10.40 +# include <climits> 10.41 +# include <cstdio> 10.42 +# include <cstdlib> 10.43 +# include <cstring> 10.44 +# include <cstdarg> 10.45 +#endif 10.46 + 10.47 +/* 10.48 + TODO: intern strings instead of allocation. 10.49 +*/ 10.50 +/* 10.51 + gcc: 10.52 + g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe 10.53 + 10.54 + Formatting, Artistic Style: 10.55 + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h 10.56 +*/ 10.57 + 10.58 +#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) 10.59 +# ifndef DEBUG 10.60 +# define DEBUG 10.61 +# endif 10.62 +#endif 10.63 + 10.64 +#ifdef _MSC_VER 10.65 +# pragma warning(push) 10.66 +# pragma warning(disable: 4251) 10.67 +#endif 10.68 + 10.69 +#ifdef _WIN32 10.70 +# ifdef TINYXML2_EXPORT 10.71 +# define TINYXML2_LIB __declspec(dllexport) 10.72 +# elif defined(TINYXML2_IMPORT) 10.73 +# define TINYXML2_LIB __declspec(dllimport) 10.74 +# else 10.75 +# define TINYXML2_LIB 10.76 +# endif 10.77 +#else 10.78 +# define TINYXML2_LIB 10.79 +#endif 10.80 + 10.81 + 10.82 +#if defined(DEBUG) 10.83 +# if defined(_MSC_VER) 10.84 +# define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak() 10.85 +# elif defined (ANDROID_NDK) 10.86 +# include <android/log.h> 10.87 +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } 10.88 +# else 10.89 +# include <assert.h> 10.90 +# define TIXMLASSERT assert 10.91 +# endif 10.92 +# else 10.93 +# define TIXMLASSERT( x ) {} 10.94 +#endif 10.95 + 10.96 + 10.97 +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) 10.98 +// Microsoft visual studio, version 2005 and higher. 10.99 +/*int _snprintf_s( 10.100 + char *buffer, 10.101 + size_t sizeOfBuffer, 10.102 + size_t count, 10.103 + const char *format [, 10.104 + argument] ... 10.105 +);*/ 10.106 +inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) 10.107 +{ 10.108 + va_list va; 10.109 + va_start( va, format ); 10.110 + int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); 10.111 + va_end( va ); 10.112 + return result; 10.113 +} 10.114 +#define TIXML_SSCANF sscanf_s 10.115 +#else 10.116 +// GCC version 3 and higher 10.117 +//#warning( "Using sn* functions." ) 10.118 +#define TIXML_SNPRINTF snprintf 10.119 +#define TIXML_SSCANF sscanf 10.120 +#endif 10.121 + 10.122 +static const int TIXML2_MAJOR_VERSION = 1; 10.123 +static const int TIXML2_MINOR_VERSION = 0; 10.124 +static const int TIXML2_PATCH_VERSION = 11; 10.125 + 10.126 +namespace tinyxml2 10.127 +{ 10.128 +class XMLDocument; 10.129 +class XMLElement; 10.130 +class XMLAttribute; 10.131 +class XMLComment; 10.132 +class XMLText; 10.133 +class XMLDeclaration; 10.134 +class XMLUnknown; 10.135 +class XMLPrinter; 10.136 + 10.137 +/* 10.138 + A class that wraps strings. Normally stores the start and end 10.139 + pointers into the XML file itself, and will apply normalization 10.140 + and entity translation if actually read. Can also store (and memory 10.141 + manage) a traditional char[] 10.142 +*/ 10.143 +class StrPair 10.144 +{ 10.145 +public: 10.146 + enum { 10.147 + NEEDS_ENTITY_PROCESSING = 0x01, 10.148 + NEEDS_NEWLINE_NORMALIZATION = 0x02, 10.149 + COLLAPSE_WHITESPACE = 0x04, 10.150 + 10.151 + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, 10.152 + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, 10.153 + ATTRIBUTE_NAME = 0, 10.154 + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, 10.155 + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, 10.156 + COMMENT = NEEDS_NEWLINE_NORMALIZATION 10.157 + }; 10.158 + 10.159 + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} 10.160 + ~StrPair(); 10.161 + 10.162 + void Set( char* start, char* end, int flags ) { 10.163 + Reset(); 10.164 + _start = start; 10.165 + _end = end; 10.166 + _flags = flags | NEEDS_FLUSH; 10.167 + } 10.168 + 10.169 + const char* GetStr(); 10.170 + 10.171 + bool Empty() const { 10.172 + return _start == _end; 10.173 + } 10.174 + 10.175 + void SetInternedStr( const char* str ) { 10.176 + Reset(); 10.177 + _start = const_cast<char*>(str); 10.178 + } 10.179 + 10.180 + void SetStr( const char* str, int flags=0 ); 10.181 + 10.182 + char* ParseText( char* in, const char* endTag, int strFlags ); 10.183 + char* ParseName( char* in ); 10.184 + 10.185 +private: 10.186 + void Reset(); 10.187 + void CollapseWhitespace(); 10.188 + 10.189 + enum { 10.190 + NEEDS_FLUSH = 0x100, 10.191 + NEEDS_DELETE = 0x200 10.192 + }; 10.193 + 10.194 + // After parsing, if *_end != 0, it can be set to zero. 10.195 + int _flags; 10.196 + char* _start; 10.197 + char* _end; 10.198 +}; 10.199 + 10.200 + 10.201 +/* 10.202 + A dynamic array of Plain Old Data. Doesn't support constructors, etc. 10.203 + Has a small initial memory pool, so that low or no usage will not 10.204 + cause a call to new/delete 10.205 +*/ 10.206 +template <class T, int INIT> 10.207 +class DynArray 10.208 +{ 10.209 +public: 10.210 + DynArray< T, INIT >() { 10.211 + _mem = _pool; 10.212 + _allocated = INIT; 10.213 + _size = 0; 10.214 + } 10.215 + 10.216 + ~DynArray() { 10.217 + if ( _mem != _pool ) { 10.218 + delete [] _mem; 10.219 + } 10.220 + } 10.221 + 10.222 + void Push( T t ) { 10.223 + EnsureCapacity( _size+1 ); 10.224 + _mem[_size++] = t; 10.225 + } 10.226 + 10.227 + T* PushArr( int count ) { 10.228 + EnsureCapacity( _size+count ); 10.229 + T* ret = &_mem[_size]; 10.230 + _size += count; 10.231 + return ret; 10.232 + } 10.233 + 10.234 + T Pop() { 10.235 + return _mem[--_size]; 10.236 + } 10.237 + 10.238 + void PopArr( int count ) { 10.239 + TIXMLASSERT( _size >= count ); 10.240 + _size -= count; 10.241 + } 10.242 + 10.243 + bool Empty() const { 10.244 + return _size == 0; 10.245 + } 10.246 + 10.247 + T& operator[](int i) { 10.248 + TIXMLASSERT( i>= 0 && i < _size ); 10.249 + return _mem[i]; 10.250 + } 10.251 + 10.252 + const T& operator[](int i) const { 10.253 + TIXMLASSERT( i>= 0 && i < _size ); 10.254 + return _mem[i]; 10.255 + } 10.256 + 10.257 + int Size() const { 10.258 + return _size; 10.259 + } 10.260 + 10.261 + int Capacity() const { 10.262 + return _allocated; 10.263 + } 10.264 + 10.265 + const T* Mem() const { 10.266 + return _mem; 10.267 + } 10.268 + 10.269 + T* Mem() { 10.270 + return _mem; 10.271 + } 10.272 + 10.273 +private: 10.274 + void EnsureCapacity( int cap ) { 10.275 + if ( cap > _allocated ) { 10.276 + int newAllocated = cap * 2; 10.277 + T* newMem = new T[newAllocated]; 10.278 + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs 10.279 + if ( _mem != _pool ) { 10.280 + delete [] _mem; 10.281 + } 10.282 + _mem = newMem; 10.283 + _allocated = newAllocated; 10.284 + } 10.285 + } 10.286 + 10.287 + T* _mem; 10.288 + T _pool[INIT]; 10.289 + int _allocated; // objects allocated 10.290 + int _size; // number objects in use 10.291 +}; 10.292 + 10.293 + 10.294 +/* 10.295 + Parent virtual class of a pool for fast allocation 10.296 + and deallocation of objects. 10.297 +*/ 10.298 +class MemPool 10.299 +{ 10.300 +public: 10.301 + MemPool() {} 10.302 + virtual ~MemPool() {} 10.303 + 10.304 + virtual int ItemSize() const = 0; 10.305 + virtual void* Alloc() = 0; 10.306 + virtual void Free( void* ) = 0; 10.307 + virtual void SetTracked() = 0; 10.308 +}; 10.309 + 10.310 + 10.311 +/* 10.312 + Template child class to create pools of the correct type. 10.313 +*/ 10.314 +template< int SIZE > 10.315 +class MemPoolT : public MemPool 10.316 +{ 10.317 +public: 10.318 + MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} 10.319 + ~MemPoolT() { 10.320 + // Delete the blocks. 10.321 + for( int i=0; i<_blockPtrs.Size(); ++i ) { 10.322 + delete _blockPtrs[i]; 10.323 + } 10.324 + } 10.325 + 10.326 + virtual int ItemSize() const { 10.327 + return SIZE; 10.328 + } 10.329 + int CurrentAllocs() const { 10.330 + return _currentAllocs; 10.331 + } 10.332 + 10.333 + virtual void* Alloc() { 10.334 + if ( !_root ) { 10.335 + // Need a new block. 10.336 + Block* block = new Block(); 10.337 + _blockPtrs.Push( block ); 10.338 + 10.339 + for( int i=0; i<COUNT-1; ++i ) { 10.340 + block->chunk[i].next = &block->chunk[i+1]; 10.341 + } 10.342 + block->chunk[COUNT-1].next = 0; 10.343 + _root = block->chunk; 10.344 + } 10.345 + void* result = _root; 10.346 + _root = _root->next; 10.347 + 10.348 + ++_currentAllocs; 10.349 + if ( _currentAllocs > _maxAllocs ) { 10.350 + _maxAllocs = _currentAllocs; 10.351 + } 10.352 + _nAllocs++; 10.353 + _nUntracked++; 10.354 + return result; 10.355 + } 10.356 + virtual void Free( void* mem ) { 10.357 + if ( !mem ) { 10.358 + return; 10.359 + } 10.360 + --_currentAllocs; 10.361 + Chunk* chunk = (Chunk*)mem; 10.362 +#ifdef DEBUG 10.363 + memset( chunk, 0xfe, sizeof(Chunk) ); 10.364 +#endif 10.365 + chunk->next = _root; 10.366 + _root = chunk; 10.367 + } 10.368 + void Trace( const char* name ) { 10.369 + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", 10.370 + name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() ); 10.371 + } 10.372 + 10.373 + void SetTracked() { 10.374 + _nUntracked--; 10.375 + } 10.376 + 10.377 + int Untracked() const { 10.378 + return _nUntracked; 10.379 + } 10.380 + 10.381 + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. 10.382 + // The test file is large, 170k. 10.383 + // Release: VS2010 gcc(no opt) 10.384 + // 1k: 4000 10.385 + // 2k: 4000 10.386 + // 4k: 3900 21000 10.387 + // 16k: 5200 10.388 + // 32k: 4300 10.389 + // 64k: 4000 21000 10.390 + enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private 10.391 + 10.392 +private: 10.393 + union Chunk { 10.394 + Chunk* next; 10.395 + char mem[SIZE]; 10.396 + }; 10.397 + struct Block { 10.398 + Chunk chunk[COUNT]; 10.399 + }; 10.400 + DynArray< Block*, 10 > _blockPtrs; 10.401 + Chunk* _root; 10.402 + 10.403 + int _currentAllocs; 10.404 + int _nAllocs; 10.405 + int _maxAllocs; 10.406 + int _nUntracked; 10.407 +}; 10.408 + 10.409 + 10.410 + 10.411 +/** 10.412 + Implements the interface to the "Visitor pattern" (see the Accept() method.) 10.413 + If you call the Accept() method, it requires being passed a XMLVisitor 10.414 + class to handle callbacks. For nodes that contain other nodes (Document, Element) 10.415 + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs 10.416 + are simply called with Visit(). 10.417 + 10.418 + If you return 'true' from a Visit method, recursive parsing will continue. If you return 10.419 + false, <b>no children of this node or its siblings</b> will be visited. 10.420 + 10.421 + All flavors of Visit methods have a default implementation that returns 'true' (continue 10.422 + visiting). You need to only override methods that are interesting to you. 10.423 + 10.424 + Generally Accept() is called on the XMLDocument, although all nodes support visiting. 10.425 + 10.426 + You should never change the document from a callback. 10.427 + 10.428 + @sa XMLNode::Accept() 10.429 +*/ 10.430 +class TINYXML2_LIB XMLVisitor 10.431 +{ 10.432 +public: 10.433 + virtual ~XMLVisitor() {} 10.434 + 10.435 + /// Visit a document. 10.436 + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { 10.437 + return true; 10.438 + } 10.439 + /// Visit a document. 10.440 + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { 10.441 + return true; 10.442 + } 10.443 + 10.444 + /// Visit an element. 10.445 + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { 10.446 + return true; 10.447 + } 10.448 + /// Visit an element. 10.449 + virtual bool VisitExit( const XMLElement& /*element*/ ) { 10.450 + return true; 10.451 + } 10.452 + 10.453 + /// Visit a declaration. 10.454 + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { 10.455 + return true; 10.456 + } 10.457 + /// Visit a text node. 10.458 + virtual bool Visit( const XMLText& /*text*/ ) { 10.459 + return true; 10.460 + } 10.461 + /// Visit a comment node. 10.462 + virtual bool Visit( const XMLComment& /*comment*/ ) { 10.463 + return true; 10.464 + } 10.465 + /// Visit an unknown node. 10.466 + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { 10.467 + return true; 10.468 + } 10.469 +}; 10.470 + 10.471 + 10.472 +/* 10.473 + Utility functionality. 10.474 +*/ 10.475 +class XMLUtil 10.476 +{ 10.477 +public: 10.478 + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't 10.479 + // correct, but simple, and usually works. 10.480 + static const char* SkipWhiteSpace( const char* p ) { 10.481 + while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<const unsigned char*>(p) ) ) { 10.482 + ++p; 10.483 + } 10.484 + return p; 10.485 + } 10.486 + static char* SkipWhiteSpace( char* p ) { 10.487 + while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<unsigned char*>(p) ) ) { 10.488 + ++p; 10.489 + } 10.490 + return p; 10.491 + } 10.492 + static bool IsWhiteSpace( char p ) { 10.493 + return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) ); 10.494 + } 10.495 + 10.496 + inline static bool IsNameStartChar( unsigned char ch ) { 10.497 + return ( ( ch < 128 ) ? isalpha( ch ) : 1 ) 10.498 + || ch == ':' 10.499 + || ch == '_'; 10.500 + } 10.501 + 10.502 + inline static bool IsNameChar( unsigned char ch ) { 10.503 + return IsNameStartChar( ch ) 10.504 + || isdigit( ch ) 10.505 + || ch == '.' 10.506 + || ch == '-'; 10.507 + } 10.508 + 10.509 + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { 10.510 + int n = 0; 10.511 + if ( p == q ) { 10.512 + return true; 10.513 + } 10.514 + while( *p && *q && *p == *q && n<nChar ) { 10.515 + ++p; 10.516 + ++q; 10.517 + ++n; 10.518 + } 10.519 + if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) { 10.520 + return true; 10.521 + } 10.522 + return false; 10.523 + } 10.524 + 10.525 + inline static int IsUTF8Continuation( const char p ) { 10.526 + return p & 0x80; 10.527 + } 10.528 + 10.529 + static const char* ReadBOM( const char* p, bool* hasBOM ); 10.530 + // p is the starting location, 10.531 + // the UTF-8 value of the entity will be placed in value, and length filled in. 10.532 + static const char* GetCharacterRef( const char* p, char* value, int* length ); 10.533 + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); 10.534 + 10.535 + // converts primitive types to strings 10.536 + static void ToStr( int v, char* buffer, int bufferSize ); 10.537 + static void ToStr( unsigned v, char* buffer, int bufferSize ); 10.538 + static void ToStr( bool v, char* buffer, int bufferSize ); 10.539 + static void ToStr( float v, char* buffer, int bufferSize ); 10.540 + static void ToStr( double v, char* buffer, int bufferSize ); 10.541 + 10.542 + // converts strings to primitive types 10.543 + static bool ToInt( const char* str, int* value ); 10.544 + static bool ToUnsigned( const char* str, unsigned* value ); 10.545 + static bool ToBool( const char* str, bool* value ); 10.546 + static bool ToFloat( const char* str, float* value ); 10.547 + static bool ToDouble( const char* str, double* value ); 10.548 +}; 10.549 + 10.550 + 10.551 +/** XMLNode is a base class for every object that is in the 10.552 + XML Document Object Model (DOM), except XMLAttributes. 10.553 + Nodes have siblings, a parent, and children which can 10.554 + be navigated. A node is always in a XMLDocument. 10.555 + The type of a XMLNode can be queried, and it can 10.556 + be cast to its more defined type. 10.557 + 10.558 + A XMLDocument allocates memory for all its Nodes. 10.559 + When the XMLDocument gets deleted, all its Nodes 10.560 + will also be deleted. 10.561 + 10.562 + @verbatim 10.563 + A Document can contain: Element (container or leaf) 10.564 + Comment (leaf) 10.565 + Unknown (leaf) 10.566 + Declaration( leaf ) 10.567 + 10.568 + An Element can contain: Element (container or leaf) 10.569 + Text (leaf) 10.570 + Attributes (not on tree) 10.571 + Comment (leaf) 10.572 + Unknown (leaf) 10.573 + 10.574 + @endverbatim 10.575 +*/ 10.576 +class TINYXML2_LIB XMLNode 10.577 +{ 10.578 + friend class XMLDocument; 10.579 + friend class XMLElement; 10.580 +public: 10.581 + 10.582 + /// Get the XMLDocument that owns this XMLNode. 10.583 + const XMLDocument* GetDocument() const { 10.584 + return _document; 10.585 + } 10.586 + /// Get the XMLDocument that owns this XMLNode. 10.587 + XMLDocument* GetDocument() { 10.588 + return _document; 10.589 + } 10.590 + 10.591 + /// Safely cast to an Element, or null. 10.592 + virtual XMLElement* ToElement() { 10.593 + return 0; 10.594 + } 10.595 + /// Safely cast to Text, or null. 10.596 + virtual XMLText* ToText() { 10.597 + return 0; 10.598 + } 10.599 + /// Safely cast to a Comment, or null. 10.600 + virtual XMLComment* ToComment() { 10.601 + return 0; 10.602 + } 10.603 + /// Safely cast to a Document, or null. 10.604 + virtual XMLDocument* ToDocument() { 10.605 + return 0; 10.606 + } 10.607 + /// Safely cast to a Declaration, or null. 10.608 + virtual XMLDeclaration* ToDeclaration() { 10.609 + return 0; 10.610 + } 10.611 + /// Safely cast to an Unknown, or null. 10.612 + virtual XMLUnknown* ToUnknown() { 10.613 + return 0; 10.614 + } 10.615 + 10.616 + virtual const XMLElement* ToElement() const { 10.617 + return 0; 10.618 + } 10.619 + virtual const XMLText* ToText() const { 10.620 + return 0; 10.621 + } 10.622 + virtual const XMLComment* ToComment() const { 10.623 + return 0; 10.624 + } 10.625 + virtual const XMLDocument* ToDocument() const { 10.626 + return 0; 10.627 + } 10.628 + virtual const XMLDeclaration* ToDeclaration() const { 10.629 + return 0; 10.630 + } 10.631 + virtual const XMLUnknown* ToUnknown() const { 10.632 + return 0; 10.633 + } 10.634 + 10.635 + /** The meaning of 'value' changes for the specific type. 10.636 + @verbatim 10.637 + Document: empty 10.638 + Element: name of the element 10.639 + Comment: the comment text 10.640 + Unknown: the tag contents 10.641 + Text: the text string 10.642 + @endverbatim 10.643 + */ 10.644 + const char* Value() const { 10.645 + return _value.GetStr(); 10.646 + } 10.647 + 10.648 + /** Set the Value of an XML node. 10.649 + @sa Value() 10.650 + */ 10.651 + void SetValue( const char* val, bool staticMem=false ); 10.652 + 10.653 + /// Get the parent of this node on the DOM. 10.654 + const XMLNode* Parent() const { 10.655 + return _parent; 10.656 + } 10.657 + 10.658 + XMLNode* Parent() { 10.659 + return _parent; 10.660 + } 10.661 + 10.662 + /// Returns true if this node has no children. 10.663 + bool NoChildren() const { 10.664 + return !_firstChild; 10.665 + } 10.666 + 10.667 + /// Get the first child node, or null if none exists. 10.668 + const XMLNode* FirstChild() const { 10.669 + return _firstChild; 10.670 + } 10.671 + 10.672 + XMLNode* FirstChild() { 10.673 + return _firstChild; 10.674 + } 10.675 + 10.676 + /** Get the first child element, or optionally the first child 10.677 + element with the specified name. 10.678 + */ 10.679 + const XMLElement* FirstChildElement( const char* value=0 ) const; 10.680 + 10.681 + XMLElement* FirstChildElement( const char* value=0 ) { 10.682 + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value )); 10.683 + } 10.684 + 10.685 + /// Get the last child node, or null if none exists. 10.686 + const XMLNode* LastChild() const { 10.687 + return _lastChild; 10.688 + } 10.689 + 10.690 + XMLNode* LastChild() { 10.691 + return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); 10.692 + } 10.693 + 10.694 + /** Get the last child element or optionally the last child 10.695 + element with the specified name. 10.696 + */ 10.697 + const XMLElement* LastChildElement( const char* value=0 ) const; 10.698 + 10.699 + XMLElement* LastChildElement( const char* value=0 ) { 10.700 + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) ); 10.701 + } 10.702 + 10.703 + /// Get the previous (left) sibling node of this node. 10.704 + const XMLNode* PreviousSibling() const { 10.705 + return _prev; 10.706 + } 10.707 + 10.708 + XMLNode* PreviousSibling() { 10.709 + return _prev; 10.710 + } 10.711 + 10.712 + /// Get the previous (left) sibling element of this node, with an optionally supplied name. 10.713 + const XMLElement* PreviousSiblingElement( const char* value=0 ) const ; 10.714 + 10.715 + XMLElement* PreviousSiblingElement( const char* value=0 ) { 10.716 + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); 10.717 + } 10.718 + 10.719 + /// Get the next (right) sibling node of this node. 10.720 + const XMLNode* NextSibling() const { 10.721 + return _next; 10.722 + } 10.723 + 10.724 + XMLNode* NextSibling() { 10.725 + return _next; 10.726 + } 10.727 + 10.728 + /// Get the next (right) sibling element of this node, with an optionally supplied name. 10.729 + const XMLElement* NextSiblingElement( const char* value=0 ) const; 10.730 + 10.731 + XMLElement* NextSiblingElement( const char* value=0 ) { 10.732 + return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); 10.733 + } 10.734 + 10.735 + /** 10.736 + Add a child node as the last (right) child. 10.737 + */ 10.738 + XMLNode* InsertEndChild( XMLNode* addThis ); 10.739 + 10.740 + XMLNode* LinkEndChild( XMLNode* addThis ) { 10.741 + return InsertEndChild( addThis ); 10.742 + } 10.743 + /** 10.744 + Add a child node as the first (left) child. 10.745 + */ 10.746 + XMLNode* InsertFirstChild( XMLNode* addThis ); 10.747 + /** 10.748 + Add a node after the specified child node. 10.749 + */ 10.750 + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); 10.751 + 10.752 + /** 10.753 + Delete all the children of this node. 10.754 + */ 10.755 + void DeleteChildren(); 10.756 + 10.757 + /** 10.758 + Delete a child of this node. 10.759 + */ 10.760 + void DeleteChild( XMLNode* node ); 10.761 + 10.762 + /** 10.763 + Make a copy of this node, but not its children. 10.764 + You may pass in a Document pointer that will be 10.765 + the owner of the new Node. If the 'document' is 10.766 + null, then the node returned will be allocated 10.767 + from the current Document. (this->GetDocument()) 10.768 + 10.769 + Note: if called on a XMLDocument, this will return null. 10.770 + */ 10.771 + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; 10.772 + 10.773 + /** 10.774 + Test if 2 nodes are the same, but don't test children. 10.775 + The 2 nodes do not need to be in the same Document. 10.776 + 10.777 + Note: if called on a XMLDocument, this will return false. 10.778 + */ 10.779 + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; 10.780 + 10.781 + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the 10.782 + XML tree will be conditionally visited and the host will be called back 10.783 + via the XMLVisitor interface. 10.784 + 10.785 + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse 10.786 + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this 10.787 + interface versus any other.) 10.788 + 10.789 + The interface has been based on ideas from: 10.790 + 10.791 + - http://www.saxproject.org/ 10.792 + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern 10.793 + 10.794 + Which are both good references for "visiting". 10.795 + 10.796 + An example of using Accept(): 10.797 + @verbatim 10.798 + XMLPrinter printer; 10.799 + tinyxmlDoc.Accept( &printer ); 10.800 + const char* xmlcstr = printer.CStr(); 10.801 + @endverbatim 10.802 + */ 10.803 + virtual bool Accept( XMLVisitor* visitor ) const = 0; 10.804 + 10.805 + // internal 10.806 + virtual char* ParseDeep( char*, StrPair* ); 10.807 + 10.808 +protected: 10.809 + XMLNode( XMLDocument* ); 10.810 + virtual ~XMLNode(); 10.811 + XMLNode( const XMLNode& ); // not supported 10.812 + XMLNode& operator=( const XMLNode& ); // not supported 10.813 + 10.814 + XMLDocument* _document; 10.815 + XMLNode* _parent; 10.816 + mutable StrPair _value; 10.817 + 10.818 + XMLNode* _firstChild; 10.819 + XMLNode* _lastChild; 10.820 + 10.821 + XMLNode* _prev; 10.822 + XMLNode* _next; 10.823 + 10.824 +private: 10.825 + MemPool* _memPool; 10.826 + void Unlink( XMLNode* child ); 10.827 +}; 10.828 + 10.829 + 10.830 +/** XML text. 10.831 + 10.832 + Note that a text node can have child element nodes, for example: 10.833 + @verbatim 10.834 + <root>This is <b>bold</b></root> 10.835 + @endverbatim 10.836 + 10.837 + A text node can have 2 ways to output the next. "normal" output 10.838 + and CDATA. It will default to the mode it was parsed from the XML file and 10.839 + you generally want to leave it alone, but you can change the output mode with 10.840 + SetCData() and query it with CData(). 10.841 +*/ 10.842 +class TINYXML2_LIB XMLText : public XMLNode 10.843 +{ 10.844 + friend class XMLBase; 10.845 + friend class XMLDocument; 10.846 +public: 10.847 + virtual bool Accept( XMLVisitor* visitor ) const; 10.848 + 10.849 + virtual XMLText* ToText() { 10.850 + return this; 10.851 + } 10.852 + virtual const XMLText* ToText() const { 10.853 + return this; 10.854 + } 10.855 + 10.856 + /// Declare whether this should be CDATA or standard text. 10.857 + void SetCData( bool isCData ) { 10.858 + _isCData = isCData; 10.859 + } 10.860 + /// Returns true if this is a CDATA text element. 10.861 + bool CData() const { 10.862 + return _isCData; 10.863 + } 10.864 + 10.865 + char* ParseDeep( char*, StrPair* endTag ); 10.866 + virtual XMLNode* ShallowClone( XMLDocument* document ) const; 10.867 + virtual bool ShallowEqual( const XMLNode* compare ) const; 10.868 + 10.869 +protected: 10.870 + XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} 10.871 + virtual ~XMLText() {} 10.872 + XMLText( const XMLText& ); // not supported 10.873 + XMLText& operator=( const XMLText& ); // not supported 10.874 + 10.875 +private: 10.876 + bool _isCData; 10.877 +}; 10.878 + 10.879 + 10.880 +/** An XML Comment. */ 10.881 +class TINYXML2_LIB XMLComment : public XMLNode 10.882 +{ 10.883 + friend class XMLDocument; 10.884 +public: 10.885 + virtual XMLComment* ToComment() { 10.886 + return this; 10.887 + } 10.888 + virtual const XMLComment* ToComment() const { 10.889 + return this; 10.890 + } 10.891 + 10.892 + virtual bool Accept( XMLVisitor* visitor ) const; 10.893 + 10.894 + char* ParseDeep( char*, StrPair* endTag ); 10.895 + virtual XMLNode* ShallowClone( XMLDocument* document ) const; 10.896 + virtual bool ShallowEqual( const XMLNode* compare ) const; 10.897 + 10.898 +protected: 10.899 + XMLComment( XMLDocument* doc ); 10.900 + virtual ~XMLComment(); 10.901 + XMLComment( const XMLComment& ); // not supported 10.902 + XMLComment& operator=( const XMLComment& ); // not supported 10.903 + 10.904 +private: 10.905 +}; 10.906 + 10.907 + 10.908 +/** In correct XML the declaration is the first entry in the file. 10.909 + @verbatim 10.910 + <?xml version="1.0" standalone="yes"?> 10.911 + @endverbatim 10.912 + 10.913 + TinyXML-2 will happily read or write files without a declaration, 10.914 + however. 10.915 + 10.916 + The text of the declaration isn't interpreted. It is parsed 10.917 + and written as a string. 10.918 +*/ 10.919 +class TINYXML2_LIB XMLDeclaration : public XMLNode 10.920 +{ 10.921 + friend class XMLDocument; 10.922 +public: 10.923 + virtual XMLDeclaration* ToDeclaration() { 10.924 + return this; 10.925 + } 10.926 + virtual const XMLDeclaration* ToDeclaration() const { 10.927 + return this; 10.928 + } 10.929 + 10.930 + virtual bool Accept( XMLVisitor* visitor ) const; 10.931 + 10.932 + char* ParseDeep( char*, StrPair* endTag ); 10.933 + virtual XMLNode* ShallowClone( XMLDocument* document ) const; 10.934 + virtual bool ShallowEqual( const XMLNode* compare ) const; 10.935 + 10.936 +protected: 10.937 + XMLDeclaration( XMLDocument* doc ); 10.938 + virtual ~XMLDeclaration(); 10.939 + XMLDeclaration( const XMLDeclaration& ); // not supported 10.940 + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported 10.941 +}; 10.942 + 10.943 + 10.944 +/** Any tag that TinyXML-2 doesn't recognize is saved as an 10.945 + unknown. It is a tag of text, but should not be modified. 10.946 + It will be written back to the XML, unchanged, when the file 10.947 + is saved. 10.948 + 10.949 + DTD tags get thrown into XMLUnknowns. 10.950 +*/ 10.951 +class TINYXML2_LIB XMLUnknown : public XMLNode 10.952 +{ 10.953 + friend class XMLDocument; 10.954 +public: 10.955 + virtual XMLUnknown* ToUnknown() { 10.956 + return this; 10.957 + } 10.958 + virtual const XMLUnknown* ToUnknown() const { 10.959 + return this; 10.960 + } 10.961 + 10.962 + virtual bool Accept( XMLVisitor* visitor ) const; 10.963 + 10.964 + char* ParseDeep( char*, StrPair* endTag ); 10.965 + virtual XMLNode* ShallowClone( XMLDocument* document ) const; 10.966 + virtual bool ShallowEqual( const XMLNode* compare ) const; 10.967 + 10.968 +protected: 10.969 + XMLUnknown( XMLDocument* doc ); 10.970 + virtual ~XMLUnknown(); 10.971 + XMLUnknown( const XMLUnknown& ); // not supported 10.972 + XMLUnknown& operator=( const XMLUnknown& ); // not supported 10.973 +}; 10.974 + 10.975 + 10.976 +enum XMLError { 10.977 + XML_NO_ERROR = 0, 10.978 + XML_SUCCESS = 0, 10.979 + 10.980 + XML_NO_ATTRIBUTE, 10.981 + XML_WRONG_ATTRIBUTE_TYPE, 10.982 + 10.983 + XML_ERROR_FILE_NOT_FOUND, 10.984 + XML_ERROR_FILE_COULD_NOT_BE_OPENED, 10.985 + XML_ERROR_FILE_READ_ERROR, 10.986 + XML_ERROR_ELEMENT_MISMATCH, 10.987 + XML_ERROR_PARSING_ELEMENT, 10.988 + XML_ERROR_PARSING_ATTRIBUTE, 10.989 + XML_ERROR_IDENTIFYING_TAG, 10.990 + XML_ERROR_PARSING_TEXT, 10.991 + XML_ERROR_PARSING_CDATA, 10.992 + XML_ERROR_PARSING_COMMENT, 10.993 + XML_ERROR_PARSING_DECLARATION, 10.994 + XML_ERROR_PARSING_UNKNOWN, 10.995 + XML_ERROR_EMPTY_DOCUMENT, 10.996 + XML_ERROR_MISMATCHED_ELEMENT, 10.997 + XML_ERROR_PARSING, 10.998 + 10.999 + XML_CAN_NOT_CONVERT_TEXT, 10.1000 + XML_NO_TEXT_NODE 10.1001 +}; 10.1002 + 10.1003 + 10.1004 +/** An attribute is a name-value pair. Elements have an arbitrary 10.1005 + number of attributes, each with a unique name. 10.1006 + 10.1007 + @note The attributes are not XMLNodes. You may only query the 10.1008 + Next() attribute in a list. 10.1009 +*/ 10.1010 +class TINYXML2_LIB XMLAttribute 10.1011 +{ 10.1012 + friend class XMLElement; 10.1013 +public: 10.1014 + /// The name of the attribute. 10.1015 + const char* Name() const { 10.1016 + return _name.GetStr(); 10.1017 + } 10.1018 + /// The value of the attribute. 10.1019 + const char* Value() const { 10.1020 + return _value.GetStr(); 10.1021 + } 10.1022 + /// The next attribute in the list. 10.1023 + const XMLAttribute* Next() const { 10.1024 + return _next; 10.1025 + } 10.1026 + 10.1027 + /** IntValue interprets the attribute as an integer, and returns the value. 10.1028 + If the value isn't an integer, 0 will be returned. There is no error checking; 10.1029 + use QueryIntValue() if you need error checking. 10.1030 + */ 10.1031 + int IntValue() const { 10.1032 + int i=0; 10.1033 + QueryIntValue( &i ); 10.1034 + return i; 10.1035 + } 10.1036 + /// Query as an unsigned integer. See IntValue() 10.1037 + unsigned UnsignedValue() const { 10.1038 + unsigned i=0; 10.1039 + QueryUnsignedValue( &i ); 10.1040 + return i; 10.1041 + } 10.1042 + /// Query as a boolean. See IntValue() 10.1043 + bool BoolValue() const { 10.1044 + bool b=false; 10.1045 + QueryBoolValue( &b ); 10.1046 + return b; 10.1047 + } 10.1048 + /// Query as a double. See IntValue() 10.1049 + double DoubleValue() const { 10.1050 + double d=0; 10.1051 + QueryDoubleValue( &d ); 10.1052 + return d; 10.1053 + } 10.1054 + /// Query as a float. See IntValue() 10.1055 + float FloatValue() const { 10.1056 + float f=0; 10.1057 + QueryFloatValue( &f ); 10.1058 + return f; 10.1059 + } 10.1060 + 10.1061 + /** QueryIntValue interprets the attribute as an integer, and returns the value 10.1062 + in the provided parameter. The function will return XML_NO_ERROR on success, 10.1063 + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. 10.1064 + */ 10.1065 + XMLError QueryIntValue( int* value ) const; 10.1066 + /// See QueryIntValue 10.1067 + XMLError QueryUnsignedValue( unsigned int* value ) const; 10.1068 + /// See QueryIntValue 10.1069 + XMLError QueryBoolValue( bool* value ) const; 10.1070 + /// See QueryIntValue 10.1071 + XMLError QueryDoubleValue( double* value ) const; 10.1072 + /// See QueryIntValue 10.1073 + XMLError QueryFloatValue( float* value ) const; 10.1074 + 10.1075 + /// Set the attribute to a string value. 10.1076 + void SetAttribute( const char* value ); 10.1077 + /// Set the attribute to value. 10.1078 + void SetAttribute( int value ); 10.1079 + /// Set the attribute to value. 10.1080 + void SetAttribute( unsigned value ); 10.1081 + /// Set the attribute to value. 10.1082 + void SetAttribute( bool value ); 10.1083 + /// Set the attribute to value. 10.1084 + void SetAttribute( double value ); 10.1085 + /// Set the attribute to value. 10.1086 + void SetAttribute( float value ); 10.1087 + 10.1088 +private: 10.1089 + enum { BUF_SIZE = 200 }; 10.1090 + 10.1091 + XMLAttribute() : _next( 0 ), _memPool( 0 ) {} 10.1092 + virtual ~XMLAttribute() {} 10.1093 + 10.1094 + XMLAttribute( const XMLAttribute& ); // not supported 10.1095 + void operator=( const XMLAttribute& ); // not supported 10.1096 + void SetName( const char* name ); 10.1097 + 10.1098 + char* ParseDeep( char* p, bool processEntities ); 10.1099 + 10.1100 + mutable StrPair _name; 10.1101 + mutable StrPair _value; 10.1102 + XMLAttribute* _next; 10.1103 + MemPool* _memPool; 10.1104 +}; 10.1105 + 10.1106 + 10.1107 +/** The element is a container class. It has a value, the element name, 10.1108 + and can contain other elements, text, comments, and unknowns. 10.1109 + Elements also contain an arbitrary number of attributes. 10.1110 +*/ 10.1111 +class TINYXML2_LIB XMLElement : public XMLNode 10.1112 +{ 10.1113 + friend class XMLBase; 10.1114 + friend class XMLDocument; 10.1115 +public: 10.1116 + /// Get the name of an element (which is the Value() of the node.) 10.1117 + const char* Name() const { 10.1118 + return Value(); 10.1119 + } 10.1120 + /// Set the name of the element. 10.1121 + void SetName( const char* str, bool staticMem=false ) { 10.1122 + SetValue( str, staticMem ); 10.1123 + } 10.1124 + 10.1125 + virtual XMLElement* ToElement() { 10.1126 + return this; 10.1127 + } 10.1128 + virtual const XMLElement* ToElement() const { 10.1129 + return this; 10.1130 + } 10.1131 + virtual bool Accept( XMLVisitor* visitor ) const; 10.1132 + 10.1133 + /** Given an attribute name, Attribute() returns the value 10.1134 + for the attribute of that name, or null if none 10.1135 + exists. For example: 10.1136 + 10.1137 + @verbatim 10.1138 + const char* value = ele->Attribute( "foo" ); 10.1139 + @endverbatim 10.1140 + 10.1141 + The 'value' parameter is normally null. However, if specified, 10.1142 + the attribute will only be returned if the 'name' and 'value' 10.1143 + match. This allow you to write code: 10.1144 + 10.1145 + @verbatim 10.1146 + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); 10.1147 + @endverbatim 10.1148 + 10.1149 + rather than: 10.1150 + @verbatim 10.1151 + if ( ele->Attribute( "foo" ) ) { 10.1152 + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); 10.1153 + } 10.1154 + @endverbatim 10.1155 + */ 10.1156 + const char* Attribute( const char* name, const char* value=0 ) const; 10.1157 + 10.1158 + /** Given an attribute name, IntAttribute() returns the value 10.1159 + of the attribute interpreted as an integer. 0 will be 10.1160 + returned if there is an error. For a method with error 10.1161 + checking, see QueryIntAttribute() 10.1162 + */ 10.1163 + int IntAttribute( const char* name ) const { 10.1164 + int i=0; 10.1165 + QueryIntAttribute( name, &i ); 10.1166 + return i; 10.1167 + } 10.1168 + /// See IntAttribute() 10.1169 + unsigned UnsignedAttribute( const char* name ) const { 10.1170 + unsigned i=0; 10.1171 + QueryUnsignedAttribute( name, &i ); 10.1172 + return i; 10.1173 + } 10.1174 + /// See IntAttribute() 10.1175 + bool BoolAttribute( const char* name ) const { 10.1176 + bool b=false; 10.1177 + QueryBoolAttribute( name, &b ); 10.1178 + return b; 10.1179 + } 10.1180 + /// See IntAttribute() 10.1181 + double DoubleAttribute( const char* name ) const { 10.1182 + double d=0; 10.1183 + QueryDoubleAttribute( name, &d ); 10.1184 + return d; 10.1185 + } 10.1186 + /// See IntAttribute() 10.1187 + float FloatAttribute( const char* name ) const { 10.1188 + float f=0; 10.1189 + QueryFloatAttribute( name, &f ); 10.1190 + return f; 10.1191 + } 10.1192 + 10.1193 + /** Given an attribute name, QueryIntAttribute() returns 10.1194 + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion 10.1195 + can't be performed, or XML_NO_ATTRIBUTE if the attribute 10.1196 + doesn't exist. If successful, the result of the conversion 10.1197 + will be written to 'value'. If not successful, nothing will 10.1198 + be written to 'value'. This allows you to provide default 10.1199 + value: 10.1200 + 10.1201 + @verbatim 10.1202 + int value = 10; 10.1203 + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 10.1204 + @endverbatim 10.1205 + */ 10.1206 + XMLError QueryIntAttribute( const char* name, int* value ) const { 10.1207 + const XMLAttribute* a = FindAttribute( name ); 10.1208 + if ( !a ) { 10.1209 + return XML_NO_ATTRIBUTE; 10.1210 + } 10.1211 + return a->QueryIntValue( value ); 10.1212 + } 10.1213 + /// See QueryIntAttribute() 10.1214 + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { 10.1215 + const XMLAttribute* a = FindAttribute( name ); 10.1216 + if ( !a ) { 10.1217 + return XML_NO_ATTRIBUTE; 10.1218 + } 10.1219 + return a->QueryUnsignedValue( value ); 10.1220 + } 10.1221 + /// See QueryIntAttribute() 10.1222 + XMLError QueryBoolAttribute( const char* name, bool* value ) const { 10.1223 + const XMLAttribute* a = FindAttribute( name ); 10.1224 + if ( !a ) { 10.1225 + return XML_NO_ATTRIBUTE; 10.1226 + } 10.1227 + return a->QueryBoolValue( value ); 10.1228 + } 10.1229 + /// See QueryIntAttribute() 10.1230 + XMLError QueryDoubleAttribute( const char* name, double* value ) const { 10.1231 + const XMLAttribute* a = FindAttribute( name ); 10.1232 + if ( !a ) { 10.1233 + return XML_NO_ATTRIBUTE; 10.1234 + } 10.1235 + return a->QueryDoubleValue( value ); 10.1236 + } 10.1237 + /// See QueryIntAttribute() 10.1238 + XMLError QueryFloatAttribute( const char* name, float* value ) const { 10.1239 + const XMLAttribute* a = FindAttribute( name ); 10.1240 + if ( !a ) { 10.1241 + return XML_NO_ATTRIBUTE; 10.1242 + } 10.1243 + return a->QueryFloatValue( value ); 10.1244 + } 10.1245 + 10.1246 + 10.1247 + /** Given an attribute name, QueryAttribute() returns 10.1248 + XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion 10.1249 + can't be performed, or XML_NO_ATTRIBUTE if the attribute 10.1250 + doesn't exist. It is overloaded for the primitive types, 10.1251 + and is a generally more convenient replacement of 10.1252 + QueryIntAttribute() and related functions. 10.1253 + 10.1254 + If successful, the result of the conversion 10.1255 + will be written to 'value'. If not successful, nothing will 10.1256 + be written to 'value'. This allows you to provide default 10.1257 + value: 10.1258 + 10.1259 + @verbatim 10.1260 + int value = 10; 10.1261 + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 10.1262 + @endverbatim 10.1263 + */ 10.1264 + int QueryAttribute( const char* name, int* value ) const { 10.1265 + return QueryIntAttribute( name, value ); 10.1266 + } 10.1267 + 10.1268 + int QueryAttribute( const char* name, unsigned int* value ) const { 10.1269 + return QueryUnsignedAttribute( name, value ); 10.1270 + } 10.1271 + 10.1272 + int QueryAttribute( const char* name, bool* value ) const { 10.1273 + return QueryBoolAttribute( name, value ); 10.1274 + } 10.1275 + 10.1276 + int QueryAttribute( const char* name, double* value ) const { 10.1277 + return QueryDoubleAttribute( name, value ); 10.1278 + } 10.1279 + 10.1280 + int QueryAttribute( const char* name, float* value ) const { 10.1281 + return QueryFloatAttribute( name, value ); 10.1282 + } 10.1283 + 10.1284 + /// Sets the named attribute to value. 10.1285 + void SetAttribute( const char* name, const char* value ) { 10.1286 + XMLAttribute* a = FindOrCreateAttribute( name ); 10.1287 + a->SetAttribute( value ); 10.1288 + } 10.1289 + /// Sets the named attribute to value. 10.1290 + void SetAttribute( const char* name, int value ) { 10.1291 + XMLAttribute* a = FindOrCreateAttribute( name ); 10.1292 + a->SetAttribute( value ); 10.1293 + } 10.1294 + /// Sets the named attribute to value. 10.1295 + void SetAttribute( const char* name, unsigned value ) { 10.1296 + XMLAttribute* a = FindOrCreateAttribute( name ); 10.1297 + a->SetAttribute( value ); 10.1298 + } 10.1299 + /// Sets the named attribute to value. 10.1300 + void SetAttribute( const char* name, bool value ) { 10.1301 + XMLAttribute* a = FindOrCreateAttribute( name ); 10.1302 + a->SetAttribute( value ); 10.1303 + } 10.1304 + /// Sets the named attribute to value. 10.1305 + void SetAttribute( const char* name, double value ) { 10.1306 + XMLAttribute* a = FindOrCreateAttribute( name ); 10.1307 + a->SetAttribute( value ); 10.1308 + } 10.1309 + 10.1310 + /** 10.1311 + Delete an attribute. 10.1312 + */ 10.1313 + void DeleteAttribute( const char* name ); 10.1314 + 10.1315 + /// Return the first attribute in the list. 10.1316 + const XMLAttribute* FirstAttribute() const { 10.1317 + return _rootAttribute; 10.1318 + } 10.1319 + /// Query a specific attribute in the list. 10.1320 + const XMLAttribute* FindAttribute( const char* name ) const; 10.1321 + 10.1322 + /** Convenience function for easy access to the text inside an element. Although easy 10.1323 + and concise, GetText() is limited compared to getting the XMLText child 10.1324 + and accessing it directly. 10.1325 + 10.1326 + If the first child of 'this' is a XMLText, the GetText() 10.1327 + returns the character string of the Text node, else null is returned. 10.1328 + 10.1329 + This is a convenient method for getting the text of simple contained text: 10.1330 + @verbatim 10.1331 + <foo>This is text</foo> 10.1332 + const char* str = fooElement->GetText(); 10.1333 + @endverbatim 10.1334 + 10.1335 + 'str' will be a pointer to "This is text". 10.1336 + 10.1337 + Note that this function can be misleading. If the element foo was created from 10.1338 + this XML: 10.1339 + @verbatim 10.1340 + <foo><b>This is text</b></foo> 10.1341 + @endverbatim 10.1342 + 10.1343 + then the value of str would be null. The first child node isn't a text node, it is 10.1344 + another element. From this XML: 10.1345 + @verbatim 10.1346 + <foo>This is <b>text</b></foo> 10.1347 + @endverbatim 10.1348 + GetText() will return "This is ". 10.1349 + */ 10.1350 + const char* GetText() const; 10.1351 + 10.1352 + /** 10.1353 + Convenience method to query the value of a child text node. This is probably best 10.1354 + shown by example. Given you have a document is this form: 10.1355 + @verbatim 10.1356 + <point> 10.1357 + <x>1</x> 10.1358 + <y>1.4</y> 10.1359 + </point> 10.1360 + @endverbatim 10.1361 + 10.1362 + The QueryIntText() and similar functions provide a safe and easier way to get to the 10.1363 + "value" of x and y. 10.1364 + 10.1365 + @verbatim 10.1366 + int x = 0; 10.1367 + float y = 0; // types of x and y are contrived for example 10.1368 + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); 10.1369 + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); 10.1370 + xElement->QueryIntText( &x ); 10.1371 + yElement->QueryFloatText( &y ); 10.1372 + @endverbatim 10.1373 + 10.1374 + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted 10.1375 + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. 10.1376 + 10.1377 + */ 10.1378 + XMLError QueryIntText( int* ival ) const; 10.1379 + /// See QueryIntText() 10.1380 + XMLError QueryUnsignedText( unsigned* uval ) const; 10.1381 + /// See QueryIntText() 10.1382 + XMLError QueryBoolText( bool* bval ) const; 10.1383 + /// See QueryIntText() 10.1384 + XMLError QueryDoubleText( double* dval ) const; 10.1385 + /// See QueryIntText() 10.1386 + XMLError QueryFloatText( float* fval ) const; 10.1387 + 10.1388 + // internal: 10.1389 + enum { 10.1390 + OPEN, // <foo> 10.1391 + CLOSED, // <foo/> 10.1392 + CLOSING // </foo> 10.1393 + }; 10.1394 + int ClosingType() const { 10.1395 + return _closingType; 10.1396 + } 10.1397 + char* ParseDeep( char* p, StrPair* endTag ); 10.1398 + virtual XMLNode* ShallowClone( XMLDocument* document ) const; 10.1399 + virtual bool ShallowEqual( const XMLNode* compare ) const; 10.1400 + 10.1401 +private: 10.1402 + XMLElement( XMLDocument* doc ); 10.1403 + virtual ~XMLElement(); 10.1404 + XMLElement( const XMLElement& ); // not supported 10.1405 + void operator=( const XMLElement& ); // not supported 10.1406 + 10.1407 + XMLAttribute* FindAttribute( const char* name ); 10.1408 + XMLAttribute* FindOrCreateAttribute( const char* name ); 10.1409 + //void LinkAttribute( XMLAttribute* attrib ); 10.1410 + char* ParseAttributes( char* p ); 10.1411 + 10.1412 + int _closingType; 10.1413 + // The attribute list is ordered; there is no 'lastAttribute' 10.1414 + // because the list needs to be scanned for dupes before adding 10.1415 + // a new attribute. 10.1416 + XMLAttribute* _rootAttribute; 10.1417 +}; 10.1418 + 10.1419 + 10.1420 +enum Whitespace { 10.1421 + PRESERVE_WHITESPACE, 10.1422 + COLLAPSE_WHITESPACE 10.1423 +}; 10.1424 + 10.1425 + 10.1426 +/** A Document binds together all the functionality. 10.1427 + It can be saved, loaded, and printed to the screen. 10.1428 + All Nodes are connected and allocated to a Document. 10.1429 + If the Document is deleted, all its Nodes are also deleted. 10.1430 +*/ 10.1431 +class TINYXML2_LIB XMLDocument : public XMLNode 10.1432 +{ 10.1433 + friend class XMLElement; 10.1434 +public: 10.1435 + /// constructor 10.1436 + XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE ); 10.1437 + ~XMLDocument(); 10.1438 + 10.1439 + virtual XMLDocument* ToDocument() { 10.1440 + return this; 10.1441 + } 10.1442 + virtual const XMLDocument* ToDocument() const { 10.1443 + return this; 10.1444 + } 10.1445 + 10.1446 + /** 10.1447 + Parse an XML file from a character string. 10.1448 + Returns XML_NO_ERROR (0) on success, or 10.1449 + an errorID. 10.1450 + 10.1451 + You may optionally pass in the 'nBytes', which is 10.1452 + the number of bytes which will be parsed. If not 10.1453 + specified, TinyXML-2 will assume 'xml' points to a 10.1454 + null terminated string. 10.1455 + */ 10.1456 + XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) ); 10.1457 + 10.1458 + /** 10.1459 + Load an XML file from disk. 10.1460 + Returns XML_NO_ERROR (0) on success, or 10.1461 + an errorID. 10.1462 + */ 10.1463 + XMLError LoadFile( const char* filename ); 10.1464 + 10.1465 + /** 10.1466 + Load an XML file from disk. You are responsible 10.1467 + for providing and closing the FILE*. 10.1468 + 10.1469 + Returns XML_NO_ERROR (0) on success, or 10.1470 + an errorID. 10.1471 + */ 10.1472 + XMLError LoadFile( FILE* ); 10.1473 + 10.1474 + /** 10.1475 + Save the XML file to disk. 10.1476 + Returns XML_NO_ERROR (0) on success, or 10.1477 + an errorID. 10.1478 + */ 10.1479 + XMLError SaveFile( const char* filename, bool compact = false ); 10.1480 + 10.1481 + /** 10.1482 + Save the XML file to disk. You are responsible 10.1483 + for providing and closing the FILE*. 10.1484 + 10.1485 + Returns XML_NO_ERROR (0) on success, or 10.1486 + an errorID. 10.1487 + */ 10.1488 + XMLError SaveFile( FILE* fp, bool compact = false ); 10.1489 + 10.1490 + bool ProcessEntities() const { 10.1491 + return _processEntities; 10.1492 + } 10.1493 + Whitespace WhitespaceMode() const { 10.1494 + return _whitespace; 10.1495 + } 10.1496 + 10.1497 + /** 10.1498 + Returns true if this document has a leading Byte Order Mark of UTF8. 10.1499 + */ 10.1500 + bool HasBOM() const { 10.1501 + return _writeBOM; 10.1502 + } 10.1503 + /** Sets whether to write the BOM when writing the file. 10.1504 + */ 10.1505 + void SetBOM( bool useBOM ) { 10.1506 + _writeBOM = useBOM; 10.1507 + } 10.1508 + 10.1509 + /** Return the root element of DOM. Equivalent to FirstChildElement(). 10.1510 + To get the first node, use FirstChild(). 10.1511 + */ 10.1512 + XMLElement* RootElement() { 10.1513 + return FirstChildElement(); 10.1514 + } 10.1515 + const XMLElement* RootElement() const { 10.1516 + return FirstChildElement(); 10.1517 + } 10.1518 + 10.1519 + /** Print the Document. If the Printer is not provided, it will 10.1520 + print to stdout. If you provide Printer, this can print to a file: 10.1521 + @verbatim 10.1522 + XMLPrinter printer( fp ); 10.1523 + doc.Print( &printer ); 10.1524 + @endverbatim 10.1525 + 10.1526 + Or you can use a printer to print to memory: 10.1527 + @verbatim 10.1528 + XMLPrinter printer; 10.1529 + doc.Print( &printer ); 10.1530 + // printer.CStr() has a const char* to the XML 10.1531 + @endverbatim 10.1532 + */ 10.1533 + void Print( XMLPrinter* streamer=0 ) const; 10.1534 + virtual bool Accept( XMLVisitor* visitor ) const; 10.1535 + 10.1536 + /** 10.1537 + Create a new Element associated with 10.1538 + this Document. The memory for the Element 10.1539 + is managed by the Document. 10.1540 + */ 10.1541 + XMLElement* NewElement( const char* name ); 10.1542 + /** 10.1543 + Create a new Comment associated with 10.1544 + this Document. The memory for the Comment 10.1545 + is managed by the Document. 10.1546 + */ 10.1547 + XMLComment* NewComment( const char* comment ); 10.1548 + /** 10.1549 + Create a new Text associated with 10.1550 + this Document. The memory for the Text 10.1551 + is managed by the Document. 10.1552 + */ 10.1553 + XMLText* NewText( const char* text ); 10.1554 + /** 10.1555 + Create a new Declaration associated with 10.1556 + this Document. The memory for the object 10.1557 + is managed by the Document. 10.1558 + 10.1559 + If the 'text' param is null, the standard 10.1560 + declaration is used.: 10.1561 + @verbatim 10.1562 + <?xml version="1.0" encoding="UTF-8"?> 10.1563 + @endverbatim 10.1564 + */ 10.1565 + XMLDeclaration* NewDeclaration( const char* text=0 ); 10.1566 + /** 10.1567 + Create a new Unknown associated with 10.1568 + this Document. The memory for the object 10.1569 + is managed by the Document. 10.1570 + */ 10.1571 + XMLUnknown* NewUnknown( const char* text ); 10.1572 + 10.1573 + /** 10.1574 + Delete a node associated with this document. 10.1575 + It will be unlinked from the DOM. 10.1576 + */ 10.1577 + void DeleteNode( XMLNode* node ) { 10.1578 + node->_parent->DeleteChild( node ); 10.1579 + } 10.1580 + 10.1581 + void SetError( XMLError error, const char* str1, const char* str2 ); 10.1582 + 10.1583 + /// Return true if there was an error parsing the document. 10.1584 + bool Error() const { 10.1585 + return _errorID != XML_NO_ERROR; 10.1586 + } 10.1587 + /// Return the errorID. 10.1588 + XMLError ErrorID() const { 10.1589 + return _errorID; 10.1590 + } 10.1591 + /// Return a possibly helpful diagnostic location or string. 10.1592 + const char* GetErrorStr1() const { 10.1593 + return _errorStr1; 10.1594 + } 10.1595 + /// Return a possibly helpful secondary diagnostic location or string. 10.1596 + const char* GetErrorStr2() const { 10.1597 + return _errorStr2; 10.1598 + } 10.1599 + /// If there is an error, print it to stdout. 10.1600 + void PrintError() const; 10.1601 + 10.1602 + /// Clear the document, resetting it to the initial state. 10.1603 + void Clear(); 10.1604 + 10.1605 + // internal 10.1606 + char* Identify( char* p, XMLNode** node ); 10.1607 + 10.1608 + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { 10.1609 + return 0; 10.1610 + } 10.1611 + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { 10.1612 + return false; 10.1613 + } 10.1614 + 10.1615 +private: 10.1616 + XMLDocument( const XMLDocument& ); // not supported 10.1617 + void operator=( const XMLDocument& ); // not supported 10.1618 + 10.1619 + bool _writeBOM; 10.1620 + bool _processEntities; 10.1621 + XMLError _errorID; 10.1622 + Whitespace _whitespace; 10.1623 + const char* _errorStr1; 10.1624 + const char* _errorStr2; 10.1625 + char* _charBuffer; 10.1626 + 10.1627 + MemPoolT< sizeof(XMLElement) > _elementPool; 10.1628 + MemPoolT< sizeof(XMLAttribute) > _attributePool; 10.1629 + MemPoolT< sizeof(XMLText) > _textPool; 10.1630 + MemPoolT< sizeof(XMLComment) > _commentPool; 10.1631 +}; 10.1632 + 10.1633 + 10.1634 +/** 10.1635 + A XMLHandle is a class that wraps a node pointer with null checks; this is 10.1636 + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 10.1637 + DOM structure. It is a separate utility class. 10.1638 + 10.1639 + Take an example: 10.1640 + @verbatim 10.1641 + <Document> 10.1642 + <Element attributeA = "valueA"> 10.1643 + <Child attributeB = "value1" /> 10.1644 + <Child attributeB = "value2" /> 10.1645 + </Element> 10.1646 + </Document> 10.1647 + @endverbatim 10.1648 + 10.1649 + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very 10.1650 + easy to write a *lot* of code that looks like: 10.1651 + 10.1652 + @verbatim 10.1653 + XMLElement* root = document.FirstChildElement( "Document" ); 10.1654 + if ( root ) 10.1655 + { 10.1656 + XMLElement* element = root->FirstChildElement( "Element" ); 10.1657 + if ( element ) 10.1658 + { 10.1659 + XMLElement* child = element->FirstChildElement( "Child" ); 10.1660 + if ( child ) 10.1661 + { 10.1662 + XMLElement* child2 = child->NextSiblingElement( "Child" ); 10.1663 + if ( child2 ) 10.1664 + { 10.1665 + // Finally do something useful. 10.1666 + @endverbatim 10.1667 + 10.1668 + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity 10.1669 + of such code. A XMLHandle checks for null pointers so it is perfectly safe 10.1670 + and correct to use: 10.1671 + 10.1672 + @verbatim 10.1673 + XMLHandle docHandle( &document ); 10.1674 + XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement(); 10.1675 + if ( child2 ) 10.1676 + { 10.1677 + // do something useful 10.1678 + @endverbatim 10.1679 + 10.1680 + Which is MUCH more concise and useful. 10.1681 + 10.1682 + It is also safe to copy handles - internally they are nothing more than node pointers. 10.1683 + @verbatim 10.1684 + XMLHandle handleCopy = handle; 10.1685 + @endverbatim 10.1686 + 10.1687 + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. 10.1688 +*/ 10.1689 +class TINYXML2_LIB XMLHandle 10.1690 +{ 10.1691 +public: 10.1692 + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. 10.1693 + XMLHandle( XMLNode* node ) { 10.1694 + _node = node; 10.1695 + } 10.1696 + /// Create a handle from a node. 10.1697 + XMLHandle( XMLNode& node ) { 10.1698 + _node = &node; 10.1699 + } 10.1700 + /// Copy constructor 10.1701 + XMLHandle( const XMLHandle& ref ) { 10.1702 + _node = ref._node; 10.1703 + } 10.1704 + /// Assignment 10.1705 + XMLHandle& operator=( const XMLHandle& ref ) { 10.1706 + _node = ref._node; 10.1707 + return *this; 10.1708 + } 10.1709 + 10.1710 + /// Get the first child of this handle. 10.1711 + XMLHandle FirstChild() { 10.1712 + return XMLHandle( _node ? _node->FirstChild() : 0 ); 10.1713 + } 10.1714 + /// Get the first child element of this handle. 10.1715 + XMLHandle FirstChildElement( const char* value=0 ) { 10.1716 + return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 ); 10.1717 + } 10.1718 + /// Get the last child of this handle. 10.1719 + XMLHandle LastChild() { 10.1720 + return XMLHandle( _node ? _node->LastChild() : 0 ); 10.1721 + } 10.1722 + /// Get the last child element of this handle. 10.1723 + XMLHandle LastChildElement( const char* _value=0 ) { 10.1724 + return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 ); 10.1725 + } 10.1726 + /// Get the previous sibling of this handle. 10.1727 + XMLHandle PreviousSibling() { 10.1728 + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); 10.1729 + } 10.1730 + /// Get the previous sibling element of this handle. 10.1731 + XMLHandle PreviousSiblingElement( const char* _value=0 ) { 10.1732 + return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); 10.1733 + } 10.1734 + /// Get the next sibling of this handle. 10.1735 + XMLHandle NextSibling() { 10.1736 + return XMLHandle( _node ? _node->NextSibling() : 0 ); 10.1737 + } 10.1738 + /// Get the next sibling element of this handle. 10.1739 + XMLHandle NextSiblingElement( const char* _value=0 ) { 10.1740 + return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); 10.1741 + } 10.1742 + 10.1743 + /// Safe cast to XMLNode. This can return null. 10.1744 + XMLNode* ToNode() { 10.1745 + return _node; 10.1746 + } 10.1747 + /// Safe cast to XMLElement. This can return null. 10.1748 + XMLElement* ToElement() { 10.1749 + return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 ); 10.1750 + } 10.1751 + /// Safe cast to XMLText. This can return null. 10.1752 + XMLText* ToText() { 10.1753 + return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 ); 10.1754 + } 10.1755 + /// Safe cast to XMLUnknown. This can return null. 10.1756 + XMLUnknown* ToUnknown() { 10.1757 + return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 ); 10.1758 + } 10.1759 + /// Safe cast to XMLDeclaration. This can return null. 10.1760 + XMLDeclaration* ToDeclaration() { 10.1761 + return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 ); 10.1762 + } 10.1763 + 10.1764 +private: 10.1765 + XMLNode* _node; 10.1766 +}; 10.1767 + 10.1768 + 10.1769 +/** 10.1770 + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the 10.1771 + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. 10.1772 +*/ 10.1773 +class TINYXML2_LIB XMLConstHandle 10.1774 +{ 10.1775 +public: 10.1776 + XMLConstHandle( const XMLNode* node ) { 10.1777 + _node = node; 10.1778 + } 10.1779 + XMLConstHandle( const XMLNode& node ) { 10.1780 + _node = &node; 10.1781 + } 10.1782 + XMLConstHandle( const XMLConstHandle& ref ) { 10.1783 + _node = ref._node; 10.1784 + } 10.1785 + 10.1786 + XMLConstHandle& operator=( const XMLConstHandle& ref ) { 10.1787 + _node = ref._node; 10.1788 + return *this; 10.1789 + } 10.1790 + 10.1791 + const XMLConstHandle FirstChild() const { 10.1792 + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); 10.1793 + } 10.1794 + const XMLConstHandle FirstChildElement( const char* value=0 ) const { 10.1795 + return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 ); 10.1796 + } 10.1797 + const XMLConstHandle LastChild() const { 10.1798 + return XMLConstHandle( _node ? _node->LastChild() : 0 ); 10.1799 + } 10.1800 + const XMLConstHandle LastChildElement( const char* _value=0 ) const { 10.1801 + return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 ); 10.1802 + } 10.1803 + const XMLConstHandle PreviousSibling() const { 10.1804 + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); 10.1805 + } 10.1806 + const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { 10.1807 + return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 ); 10.1808 + } 10.1809 + const XMLConstHandle NextSibling() const { 10.1810 + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); 10.1811 + } 10.1812 + const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { 10.1813 + return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 ); 10.1814 + } 10.1815 + 10.1816 + 10.1817 + const XMLNode* ToNode() const { 10.1818 + return _node; 10.1819 + } 10.1820 + const XMLElement* ToElement() const { 10.1821 + return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 ); 10.1822 + } 10.1823 + const XMLText* ToText() const { 10.1824 + return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 ); 10.1825 + } 10.1826 + const XMLUnknown* ToUnknown() const { 10.1827 + return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 ); 10.1828 + } 10.1829 + const XMLDeclaration* ToDeclaration() const { 10.1830 + return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 ); 10.1831 + } 10.1832 + 10.1833 +private: 10.1834 + const XMLNode* _node; 10.1835 +}; 10.1836 + 10.1837 + 10.1838 +/** 10.1839 + Printing functionality. The XMLPrinter gives you more 10.1840 + options than the XMLDocument::Print() method. 10.1841 + 10.1842 + It can: 10.1843 + -# Print to memory. 10.1844 + -# Print to a file you provide. 10.1845 + -# Print XML without a XMLDocument. 10.1846 + 10.1847 + Print to Memory 10.1848 + 10.1849 + @verbatim 10.1850 + XMLPrinter printer; 10.1851 + doc.Print( &printer ); 10.1852 + SomeFunction( printer.CStr() ); 10.1853 + @endverbatim 10.1854 + 10.1855 + Print to a File 10.1856 + 10.1857 + You provide the file pointer. 10.1858 + @verbatim 10.1859 + XMLPrinter printer( fp ); 10.1860 + doc.Print( &printer ); 10.1861 + @endverbatim 10.1862 + 10.1863 + Print without a XMLDocument 10.1864 + 10.1865 + When loading, an XML parser is very useful. However, sometimes 10.1866 + when saving, it just gets in the way. The code is often set up 10.1867 + for streaming, and constructing the DOM is just overhead. 10.1868 + 10.1869 + The Printer supports the streaming case. The following code 10.1870 + prints out a trivially simple XML file without ever creating 10.1871 + an XML document. 10.1872 + 10.1873 + @verbatim 10.1874 + XMLPrinter printer( fp ); 10.1875 + printer.OpenElement( "foo" ); 10.1876 + printer.PushAttribute( "foo", "bar" ); 10.1877 + printer.CloseElement(); 10.1878 + @endverbatim 10.1879 +*/ 10.1880 +class TINYXML2_LIB XMLPrinter : public XMLVisitor 10.1881 +{ 10.1882 +public: 10.1883 + /** Construct the printer. If the FILE* is specified, 10.1884 + this will print to the FILE. Else it will print 10.1885 + to memory, and the result is available in CStr(). 10.1886 + If 'compact' is set to true, then output is created 10.1887 + with only required whitespace and newlines. 10.1888 + */ 10.1889 + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); 10.1890 + ~XMLPrinter() {} 10.1891 + 10.1892 + /** If streaming, write the BOM and declaration. */ 10.1893 + void PushHeader( bool writeBOM, bool writeDeclaration ); 10.1894 + /** If streaming, start writing an element. 10.1895 + The element must be closed with CloseElement() 10.1896 + */ 10.1897 + void OpenElement( const char* name ); 10.1898 + /// If streaming, add an attribute to an open element. 10.1899 + void PushAttribute( const char* name, const char* value ); 10.1900 + void PushAttribute( const char* name, int value ); 10.1901 + void PushAttribute( const char* name, unsigned value ); 10.1902 + void PushAttribute( const char* name, bool value ); 10.1903 + void PushAttribute( const char* name, double value ); 10.1904 + /// If streaming, close the Element. 10.1905 + void CloseElement(); 10.1906 + 10.1907 + /// Add a text node. 10.1908 + void PushText( const char* text, bool cdata=false ); 10.1909 + /// Add a text node from an integer. 10.1910 + void PushText( int value ); 10.1911 + /// Add a text node from an unsigned. 10.1912 + void PushText( unsigned value ); 10.1913 + /// Add a text node from a bool. 10.1914 + void PushText( bool value ); 10.1915 + /// Add a text node from a float. 10.1916 + void PushText( float value ); 10.1917 + /// Add a text node from a double. 10.1918 + void PushText( double value ); 10.1919 + 10.1920 + /// Add a comment 10.1921 + void PushComment( const char* comment ); 10.1922 + 10.1923 + void PushDeclaration( const char* value ); 10.1924 + void PushUnknown( const char* value ); 10.1925 + 10.1926 + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); 10.1927 + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { 10.1928 + return true; 10.1929 + } 10.1930 + 10.1931 + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); 10.1932 + virtual bool VisitExit( const XMLElement& element ); 10.1933 + 10.1934 + virtual bool Visit( const XMLText& text ); 10.1935 + virtual bool Visit( const XMLComment& comment ); 10.1936 + virtual bool Visit( const XMLDeclaration& declaration ); 10.1937 + virtual bool Visit( const XMLUnknown& unknown ); 10.1938 + 10.1939 + /** 10.1940 + If in print to memory mode, return a pointer to 10.1941 + the XML file in memory. 10.1942 + */ 10.1943 + const char* CStr() const { 10.1944 + return _buffer.Mem(); 10.1945 + } 10.1946 + /** 10.1947 + If in print to memory mode, return the size 10.1948 + of the XML file in memory. (Note the size returned 10.1949 + includes the terminating null.) 10.1950 + */ 10.1951 + int CStrSize() const { 10.1952 + return _buffer.Size(); 10.1953 + } 10.1954 + 10.1955 +private: 10.1956 + void SealElement(); 10.1957 + void PrintSpace( int depth ); 10.1958 + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. 10.1959 + void Print( const char* format, ... ); 10.1960 + 10.1961 + bool _elementJustOpened; 10.1962 + bool _firstElement; 10.1963 + FILE* _fp; 10.1964 + int _depth; 10.1965 + int _textDepth; 10.1966 + bool _processEntities; 10.1967 + bool _compactMode; 10.1968 + 10.1969 + enum { 10.1970 + ENTITY_RANGE = 64, 10.1971 + BUF_SIZE = 200 10.1972 + }; 10.1973 + bool _entityFlag[ENTITY_RANGE]; 10.1974 + bool _restrictedEntityFlag[ENTITY_RANGE]; 10.1975 + 10.1976 + DynArray< const char*, 10 > _stack; 10.1977 + DynArray< char, 20 > _buffer; 10.1978 +#ifdef _MSC_VER 10.1979 + DynArray< char, 20 > _accumulator; 10.1980 +#endif 10.1981 +}; 10.1982 + 10.1983 + 10.1984 +} // tinyxml2 10.1985 + 10.1986 +#if defined(_MSC_VER) 10.1987 +# pragma warning(pop) 10.1988 +#endif 10.1989 + 10.1990 +#endif // TINYXML2_INCLUDED
11.1 --- a/src/goat3d.cc Fri Sep 27 07:14:27 2013 +0300 11.2 +++ b/src/goat3d.cc Fri Sep 27 07:14:49 2013 +0300 11.3 @@ -243,15 +243,7 @@ 11.4 return (int)mesh->faces.size(); 11.5 } 11.6 11.7 -#if __cplusplus >= 201103L 11.8 -#define MOVE(x) std::move(x) 11.9 -#else 11.10 -#define MOVE(x) x 11.11 -#endif 11.12 - 11.13 -#define VECDATA(type, data, num) \ 11.14 - MOVE(std::vector<type>((type*)(data), (type*)(data) + (num))) 11.15 - 11.16 +// VECDATA is in goat3d_impl.h 11.17 void goat3d_set_mesh_attribs(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib, const void *data, int vnum) 11.18 { 11.19 if(attrib == GOAT3D_MESH_ATTR_VERTEX) { 11.20 @@ -360,42 +352,44 @@ 11.21 11.22 void goat3d_end(void) 11.23 { 11.24 - static int tri_offs[] = {0, 1, 2}; 11.25 - static int quad_offs[] = {0, 1, 2, 0, 2, 3}; 11.26 - int *index_offs; 11.27 - 11.28 - int num_faces, in_face_verts, out_face_verts; 11.29 switch(im_prim) { 11.30 case GOAT3D_TRIANGLES: 11.31 - in_face_verts = 3; 11.32 - out_face_verts = 3; 11.33 - index_offs = tri_offs; 11.34 + { 11.35 + int num_faces = (int)im_mesh->vertices.size() / 3; 11.36 + im_mesh->faces.resize(num_faces); 11.37 + 11.38 + int vidx = 0; 11.39 + for(int i=0; i<num_faces; i++) { 11.40 + im_mesh->faces[i].v[0] = vidx++; 11.41 + im_mesh->faces[i].v[1] = vidx++; 11.42 + im_mesh->faces[i].v[2] = vidx++; 11.43 + } 11.44 + } 11.45 break; 11.46 11.47 case GOAT3D_QUADS: 11.48 - in_face_verts = 4; 11.49 - out_face_verts = 6; 11.50 - index_offs = quad_offs; 11.51 + { 11.52 + int num_quads = (int)im_mesh->vertices.size() / 4; 11.53 + im_mesh->faces.resize(num_quads * 2); 11.54 + 11.55 + int vidx = 0; 11.56 + for(int i=0; i<num_quads; i++) { 11.57 + im_mesh->faces[i * 2].v[0] = vidx; 11.58 + im_mesh->faces[i * 2].v[1] = vidx + 1; 11.59 + im_mesh->faces[i * 2].v[2] = vidx + 2; 11.60 + 11.61 + im_mesh->faces[i * 2 + 1].v[0] = vidx; 11.62 + im_mesh->faces[i * 2 + 1].v[1] = vidx + 2; 11.63 + im_mesh->faces[i * 2 + 1].v[2] = vidx + 3; 11.64 + 11.65 + vidx += 4; 11.66 + } 11.67 + } 11.68 break; 11.69 11.70 default: 11.71 return; 11.72 }; 11.73 - 11.74 - num_faces = (int)im_mesh->vertices.size() / in_face_verts; 11.75 - if(!num_faces) { 11.76 - return; 11.77 - } 11.78 - 11.79 - im_mesh->faces.resize(num_faces); 11.80 - 11.81 - int vidx = 0; 11.82 - for(int i=0; i<num_faces; i++) { 11.83 - for(int j=0; j<out_face_verts; j++) { 11.84 - im_mesh->faces[i].v[j] = vidx + index_offs[j]; 11.85 - } 11.86 - vidx += 4; 11.87 - } 11.88 } 11.89 11.90 void goat3d_vertex3f(float x, float y, float z) 11.91 @@ -424,21 +418,25 @@ 11.92 void goat3d_normal3f(float x, float y, float z) 11.93 { 11.94 im_norm = Vector3(x, y, z); 11.95 + im_use[GOAT3D_MESH_ATTR_NORMAL] = true; 11.96 } 11.97 11.98 void goat3d_tangent3f(float x, float y, float z) 11.99 { 11.100 im_tang = Vector3(x, y, z); 11.101 + im_use[GOAT3D_MESH_ATTR_TANGENT] = true; 11.102 } 11.103 11.104 void goat3d_texcoord2f(float x, float y) 11.105 { 11.106 im_texcoord = Vector2(x, y); 11.107 + im_use[GOAT3D_MESH_ATTR_TEXCOORD] = true; 11.108 } 11.109 11.110 void goat3d_skin_weight4f(float x, float y, float z, float w) 11.111 { 11.112 im_skinw = Vector4(x, y, z, w); 11.113 + im_use[GOAT3D_MESH_ATTR_SKIN_WEIGHT] = true; 11.114 } 11.115 11.116 void goat3d_skin_matrix4i(int x, int y, int z, int w) 11.117 @@ -447,16 +445,18 @@ 11.118 im_skinmat.y = y; 11.119 im_skinmat.z = z; 11.120 im_skinmat.w = w; 11.121 + im_use[GOAT3D_MESH_ATTR_SKIN_MATRIX] = true; 11.122 } 11.123 11.124 void goat3d_color3f(float x, float y, float z) 11.125 { 11.126 - im_color = Vector4(x, y, z, 1.0f); 11.127 + goat3d_color4f(x, y, z, 1.0f); 11.128 } 11.129 11.130 void goat3d_color4f(float x, float y, float z, float w) 11.131 { 11.132 im_color = Vector4(x, y, z, w); 11.133 + im_use[GOAT3D_MESH_ATTR_COLOR] = true; 11.134 } 11.135 11.136 void goat3d_add_mesh(struct goat3d *g, struct goat3d_mesh *mesh) 11.137 @@ -464,6 +464,16 @@ 11.138 g->scn->add_mesh(mesh); 11.139 } 11.140 11.141 +int goat3d_get_mesh_count(struct goat3d *g) 11.142 +{ 11.143 + return g->scn->get_mesh_count(); 11.144 +} 11.145 + 11.146 +struct goat3d_mesh *goat3d_get_mesh(struct goat3d *g, int idx) 11.147 +{ 11.148 + return (goat3d_mesh*)g->scn->get_mesh(idx); 11.149 +} 11.150 + 11.151 11.152 } // extern "C" 11.153
12.1 --- a/src/goat3d.h Fri Sep 27 07:14:27 2013 +0300 12.2 +++ b/src/goat3d.h Fri Sep 27 07:14:49 2013 +0300 12.3 @@ -155,6 +155,9 @@ 12.4 12.5 void goat3d_add_mesh(struct goat3d *g, struct goat3d_mesh *mesh); 12.6 12.7 +int goat3d_get_mesh_count(struct goat3d *g); 12.8 +struct goat3d_mesh *goat3d_get_mesh(struct goat3d *g, int idx); 12.9 + 12.10 #ifdef __cplusplus 12.11 } 12.12 #endif
13.1 --- a/src/goat3d_impl.h Fri Sep 27 07:14:27 2013 +0300 13.2 +++ b/src/goat3d_impl.h Fri Sep 27 07:14:49 2013 +0300 13.3 @@ -12,6 +12,16 @@ 13.4 13.5 extern int goat_log_level; 13.6 13.7 +#if __cplusplus >= 201103L 13.8 +#define MOVE(x) std::move(x) 13.9 +#else 13.10 +#define MOVE(x) x 13.11 +#endif 13.12 + 13.13 +#define VECDATA(type, data, num) \ 13.14 + MOVE(std::vector<type>((type*)(data), (type*)(data) + (num))) 13.15 + 13.16 + 13.17 class Scene { 13.18 private: 13.19 std::string name;
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/src/goat3d_readxml.cc Fri Sep 27 07:14:49 2013 +0300 14.3 @@ -0,0 +1,175 @@ 14.4 +#include <stdio.h> 14.5 +#include "goat3d.h" 14.6 +#include "goat3d_impl.h" 14.7 +#include "tinyxml2.h" 14.8 +#include "log.h" 14.9 + 14.10 +using namespace tinyxml2; 14.11 + 14.12 +static Material *read_material(Scene *scn, XMLElement *xml_mtl); 14.13 +static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr); 14.14 +static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh); 14.15 +static std::string get_name(XMLElement *node, int idx); 14.16 + 14.17 +bool Scene::loadxml(goat3d_io *io) 14.18 +{ 14.19 + long bytes = io->seek(0, SEEK_END, io->cls); 14.20 + io->seek(0, SEEK_SET, io->cls); 14.21 + 14.22 + char *buf = new char[bytes]; 14.23 + if(io->read(buf, bytes, io->cls) < bytes) { 14.24 + logmsg(LOG_ERROR, "failed to read XML scene file\n"); 14.25 + return false; 14.26 + } 14.27 + 14.28 + XMLDocument xml; 14.29 + XMLError err = xml.Parse(buf, bytes); 14.30 + if(err) { 14.31 + logmsg(LOG_ERROR, "failed to parse XML scene file: %s\n%s\n", xml.GetErrorStr1(), 14.32 + xml.GetErrorStr2()); 14.33 + return false; 14.34 + } 14.35 + 14.36 + XMLElement *root = xml.RootElement(); 14.37 + if(strcmp(root->Name(), "scene") != 0) { 14.38 + logmsg(LOG_ERROR, "invalid XML file, root node is not <scene>\n"); 14.39 + return false; 14.40 + } 14.41 + 14.42 + XMLElement *elem; 14.43 + 14.44 + // get all materials 14.45 + elem = root->FirstChildElement("mtl"); 14.46 + while(elem) { 14.47 + Material *mtl = read_material(this, elem); 14.48 + if(mtl) { 14.49 + add_material(mtl); 14.50 + } 14.51 + elem = elem->NextSiblingElement("mtl"); 14.52 + } 14.53 + 14.54 + // get all meshes 14.55 + elem = root->FirstChildElement("mesh"); 14.56 + while(elem) { 14.57 + Mesh *mesh = read_mesh(this, elem); 14.58 + if(mesh) { 14.59 + add_mesh(mesh); 14.60 + } 14.61 + elem = elem->NextSiblingElement("mesh"); 14.62 + } 14.63 + 14.64 + return false; 14.65 +} 14.66 + 14.67 + 14.68 +static Material *read_material(Scene *scn, XMLElement *xml_mtl) 14.69 +{ 14.70 + Material *mtl = new Material; 14.71 + mtl->name = get_name(xml_mtl, scn->get_material_count()); 14.72 + 14.73 + // get all the material attributes in turn 14.74 + XMLElement *elem = xml_mtl->FirstChildElement("attr"); 14.75 + while(elem) { 14.76 + MaterialAttrib attr; 14.77 + const char *name = read_material_attrib(&attr, elem); 14.78 + if(name) { 14.79 + (*mtl)[name] = attr; 14.80 + } 14.81 + 14.82 + elem = elem->NextSiblingElement("attr"); 14.83 + } 14.84 + 14.85 + return mtl; 14.86 +} 14.87 + 14.88 +static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr) 14.89 +{ 14.90 + const char *name; 14.91 + 14.92 + XMLElement *elem; 14.93 + if((elem = xml_attr->FirstChildElement("name"))) { 14.94 + if(!(name = elem->Attribute("string"))) { 14.95 + return 0; 14.96 + } 14.97 + } 14.98 + 14.99 + if((elem = xml_attr->FirstChildElement("val"))) { 14.100 + if(elem->QueryFloatAttribute("float", &attr->value.x) != XML_NO_ERROR) { 14.101 + // try a float3 14.102 + const char *valstr = elem->Attribute("float3"); 14.103 + if(!valstr || sscanf(valstr, "%f %f %f", &attr->value.x, &attr->value.y, 14.104 + &attr->value.z) != 3) { 14.105 + // try a float4 14.106 + valstr = elem->Attribute("float4"); 14.107 + if(!valstr || sscanf(valstr, "%f %f %f %f", &attr->value.x, &attr->value.y, 14.108 + &attr->value.z, &attr->value.w) != 4) { 14.109 + // no valid val attribute found 14.110 + return 0; 14.111 + } 14.112 + } 14.113 + } 14.114 + } 14.115 + 14.116 + if((elem = xml_attr->FirstChildElement("map"))) { 14.117 + const char *tex = elem->Attribute("string"); 14.118 + if(tex) { 14.119 + attr->map = std::string(tex); 14.120 + } 14.121 + } 14.122 + 14.123 + return name; 14.124 +} 14.125 + 14.126 +static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh) 14.127 +{ 14.128 + Mesh *mesh = new Mesh; 14.129 + mesh->name = get_name(xml_mesh, scn->get_mesh_count()); 14.130 + 14.131 + XMLElement *elem; 14.132 + if((elem = xml_mesh->FirstChildElement("material"))) { 14.133 + int idx; 14.134 + if(elem->QueryIntAttribute("int", &idx) == XML_NO_ERROR) { 14.135 + mesh->material = scn->get_material(idx); 14.136 + } else { 14.137 + // try string 14.138 + const char *mtlstr = elem->Attribute("string"); 14.139 + if(mtlstr) { 14.140 + mesh->material = scn->get_material(mtlstr); 14.141 + } 14.142 + } 14.143 + } 14.144 + 14.145 + /* reading mesh data from XML is not supported, only MESH_FILE can be used to 14.146 + * specify an external mesh file to be loaded 14.147 + */ 14.148 + 14.149 + if((elem = xml_mesh->FirstChildElement("file"))) { 14.150 + const char *fname = elem->Attribute("string"); 14.151 + if(fname) { 14.152 + if(!mesh->load(fname)) { 14.153 + delete mesh; 14.154 + return 0; 14.155 + } 14.156 + } 14.157 + } 14.158 + 14.159 + return mesh; 14.160 +} 14.161 + 14.162 +static std::string get_name(XMLElement *node, int idx) 14.163 +{ 14.164 + char buf[64]; 14.165 + const char *name = 0; 14.166 + 14.167 + XMLElement *elem; 14.168 + if((elem = node->FirstChildElement("name"))) { 14.169 + name = elem->Attribute("string"); 14.170 + } 14.171 + 14.172 + if(!name) { 14.173 + sprintf(buf, "mesh%04d", idx); 14.174 + name = buf; 14.175 + } 14.176 + 14.177 + return std::string(name); 14.178 +}
15.1 --- a/src/goat3d_scene.cc Fri Sep 27 07:14:27 2013 +0300 15.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 15.3 @@ -1,258 +0,0 @@ 15.4 -#include <stdarg.h> 15.5 -#include "goat3d.h" 15.6 -#include "goat3d_impl.h" 15.7 -#include "chunk.h" 15.8 - 15.9 -Scene::Scene() 15.10 - : name("unnamed"), ambient(0.05, 0.05, 0.05) 15.11 -{ 15.12 -} 15.13 - 15.14 -Scene::~Scene() 15.15 -{ 15.16 - clear(); 15.17 -} 15.18 - 15.19 -void Scene::clear() 15.20 -{ 15.21 - for(size_t i=0; i<materials.size(); i++) { 15.22 - delete materials[i]; 15.23 - } 15.24 - materials.clear(); 15.25 - 15.26 - for(size_t i=0; i<meshes.size(); i++) { 15.27 - delete meshes[i]; 15.28 - } 15.29 - meshes.clear(); 15.30 - 15.31 - for(size_t i=0; i<lights.size(); i++) { 15.32 - delete lights[i]; 15.33 - } 15.34 - lights.clear(); 15.35 - 15.36 - for(size_t i=0; i<cameras.size(); i++) { 15.37 - delete cameras[i]; 15.38 - } 15.39 - cameras.clear(); 15.40 - 15.41 - for(size_t i=0; i<nodes.size(); i++) { 15.42 - delete_node_tree(nodes[i]); 15.43 - } 15.44 - nodes.clear(); 15.45 - 15.46 - name = "unnamed"; 15.47 -} 15.48 - 15.49 -void Scene::set_name(const char *name) 15.50 -{ 15.51 - this->name = name; 15.52 -} 15.53 - 15.54 -const char *Scene::get_name() const 15.55 -{ 15.56 - return name.c_str(); 15.57 -} 15.58 - 15.59 -void Scene::set_ambient(const Vector3 &amb) 15.60 -{ 15.61 - ambient = amb; 15.62 -} 15.63 - 15.64 -const Vector3 &Scene::get_ambient() const 15.65 -{ 15.66 - return ambient; 15.67 -} 15.68 - 15.69 -void Scene::add_material(Material *mat) 15.70 -{ 15.71 - materials.push_back(mat); 15.72 -} 15.73 - 15.74 -Material *Scene::get_material(int idx) const 15.75 -{ 15.76 - return idx >=0 && idx < (int)materials.size() ? materials[idx] : 0; 15.77 -} 15.78 - 15.79 -Material *Scene::get_material(const char *name) const 15.80 -{ 15.81 - for(size_t i=0; i<materials.size(); i++) { 15.82 - if(materials[i]->name == std::string(name)) { 15.83 - return materials[i]; 15.84 - } 15.85 - } 15.86 - return 0; 15.87 -} 15.88 - 15.89 -int Scene::get_material_count() const 15.90 -{ 15.91 - return (int)materials.size(); 15.92 -} 15.93 - 15.94 - 15.95 -void Scene::add_mesh(Mesh *mesh) 15.96 -{ 15.97 - meshes.push_back(mesh); 15.98 -} 15.99 - 15.100 -Mesh *Scene::get_mesh(int idx) const 15.101 -{ 15.102 - return idx >= 0 && idx < (int)meshes.size() ? meshes[idx] : 0; 15.103 -} 15.104 - 15.105 -Mesh *Scene::get_mesh(const char *name) const 15.106 -{ 15.107 - for(size_t i=0; i<meshes.size(); i++) { 15.108 - if(meshes[i]->name == std::string(name)) { 15.109 - return meshes[i]; 15.110 - } 15.111 - } 15.112 - return 0; 15.113 -} 15.114 - 15.115 -int Scene::get_mesh_count() const 15.116 -{ 15.117 - return (int)meshes.size(); 15.118 -} 15.119 - 15.120 - 15.121 -void Scene::add_light(Light *light) 15.122 -{ 15.123 - lights.push_back(light); 15.124 -} 15.125 - 15.126 -Light *Scene::get_light(int idx) const 15.127 -{ 15.128 - return idx >= 0 && idx < (int)lights.size() ? lights[idx] : 0; 15.129 -} 15.130 - 15.131 -Light *Scene::get_light(const char *name) const 15.132 -{ 15.133 - for(size_t i=0; i<lights.size(); i++) { 15.134 - if(lights[i]->name == std::string(name)) { 15.135 - return lights[i]; 15.136 - } 15.137 - } 15.138 - return 0; 15.139 -} 15.140 - 15.141 -int Scene::get_light_count() const 15.142 -{ 15.143 - return (int)lights.size(); 15.144 -} 15.145 - 15.146 - 15.147 -void Scene::add_camera(Camera *cam) 15.148 -{ 15.149 - cameras.push_back(cam); 15.150 -} 15.151 - 15.152 -Camera *Scene::get_camera(int idx) const 15.153 -{ 15.154 - return idx >= 0 && idx < (int)cameras.size() ? cameras[idx] : 0; 15.155 -} 15.156 - 15.157 -Camera *Scene::get_camera(const char *name) const 15.158 -{ 15.159 - for(size_t i=0; i<cameras.size(); i++) { 15.160 - if(cameras[i]->name == std::string(name)) { 15.161 - return cameras[i]; 15.162 - } 15.163 - } 15.164 - return 0; 15.165 -} 15.166 - 15.167 -int Scene::get_camera_count() const 15.168 -{ 15.169 - return (int)cameras.size(); 15.170 -} 15.171 - 15.172 - 15.173 -void Scene::add_node(Node *node) 15.174 -{ 15.175 - nodes.push_back(node); 15.176 -} 15.177 - 15.178 -Node *Scene::get_node(int idx) const 15.179 -{ 15.180 - return idx >= 0 && idx < (int)nodes.size() ? nodes[idx] : 0; 15.181 -} 15.182 - 15.183 -Node *Scene::get_node(const char *name) const 15.184 -{ 15.185 - for(size_t i=0; i<nodes.size(); i++) { 15.186 - if(strcmp(nodes[i]->get_name(), name) == 0) { 15.187 - return nodes[i]; 15.188 - } 15.189 - } 15.190 - return 0; 15.191 -} 15.192 - 15.193 -int Scene::get_node_count() const 15.194 -{ 15.195 - return (int)nodes.size(); 15.196 -} 15.197 - 15.198 - 15.199 -bool Scene::load(goat3d_io *io) 15.200 -{ 15.201 - return false; 15.202 -} 15.203 - 15.204 -bool Scene::loadxml(goat3d_io *io) 15.205 -{ 15.206 - return false; 15.207 -} 15.208 - 15.209 -// Scene::save is defined in goat3d_write.cc 15.210 - 15.211 - 15.212 -void io_fprintf(goat3d_io *io, const char *fmt, ...) 15.213 -{ 15.214 - va_list ap; 15.215 - 15.216 - va_start(ap, fmt); 15.217 - io_vfprintf(io, fmt, ap); 15.218 - va_end(ap); 15.219 -} 15.220 - 15.221 - 15.222 -void io_vfprintf(goat3d_io *io, const char *fmt, va_list ap) 15.223 -{ 15.224 - char smallbuf[256]; 15.225 - char *buf = smallbuf; 15.226 - int sz = sizeof smallbuf; 15.227 - 15.228 - int retsz = vsnprintf(buf, sz - 1, fmt, ap); 15.229 - 15.230 - if(retsz >= sz) { 15.231 - /* C99 mandates that snprintf with a short count should return the 15.232 - * number of characters that *would* be printed. 15.233 - */ 15.234 - buf = new char[retsz + 1]; 15.235 - 15.236 - vsnprintf(buf, retsz, fmt, ap); 15.237 - 15.238 - } else if(retsz <= 0) { 15.239 - /* SUSv2 and microsoft specify that snprintf with a short count 15.240 - * returns an arbitrary value <= 0. So let's try allocating 15.241 - * bigger and bigger arrays until we find the correct size. 15.242 - */ 15.243 - sz = sizeof smallbuf; 15.244 - do { 15.245 - sz *= 2; 15.246 - if(buf != smallbuf) { 15.247 - delete [] buf; 15.248 - } 15.249 - buf = new char[sz + 1]; 15.250 - 15.251 - retsz = vsnprintf(buf, sz, fmt, ap); 15.252 - } while(retsz <= 0); 15.253 - } 15.254 - 15.255 - io->write(buf, retsz, io->cls); 15.256 - 15.257 - if(buf != smallbuf) { 15.258 - delete [] buf; 15.259 - } 15.260 - 15.261 -}
16.1 --- a/src/goat3d_writexml.cc Fri Sep 27 07:14:27 2013 +0300 16.2 +++ b/src/goat3d_writexml.cc Fri Sep 27 07:14:49 2013 +0300 16.3 @@ -1,11 +1,9 @@ 16.4 #include <stdarg.h> 16.5 #include "goat3d_impl.h" 16.6 -#include "chunk.h" 16.7 -#include "openctm.h" 16.8 +#include "log.h" 16.9 16.10 static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level); 16.11 static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level); 16.12 -static void write_ctm_mesh(const Mesh *mesh, const char *fname); 16.13 static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level); 16.14 static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level); 16.15 static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level); 16.16 @@ -17,7 +15,8 @@ 16.17 16.18 // write environment stuff 16.19 xmlout(io, 1, "<env>\n"); 16.20 - xmlout(io, 1, "</env>\n"); 16.21 + xmlout(io, 2, "<ambient float3=\"%g %g %g\"/>\n", ambient.x, ambient.y, ambient.z); 16.22 + xmlout(io, 1, "</env>\n\n"); 16.23 16.24 for(size_t i=0; i<materials.size(); i++) { 16.25 write_material(this, io, materials[i], 1); 16.26 @@ -49,14 +48,14 @@ 16.27 xmlout(io, level + 2, "<name string=\"%s\"/>\n", mat->get_attrib_name(i)); 16.28 16.29 const MaterialAttrib &attr = (*mat)[i]; 16.30 - xmlout(io, level + 2, "<val float4=\"%.3f %.3f %.3f %.3f\"/>\n", attr.value.x, 16.31 + xmlout(io, level + 2, "<val float4=\"%g %g %g %g\"/>\n", attr.value.x, 16.32 attr.value.y, attr.value.z, attr.value.w); 16.33 if(!attr.map.empty()) { 16.34 xmlout(io, level + 2, "<map string=\"%s\"/>\n", attr.map.c_str()); 16.35 } 16.36 xmlout(io, level + 1, "</attr>\n"); 16.37 } 16.38 - xmlout(io, level, "</mtl>\n"); 16.39 + xmlout(io, level, "</mtl>\n\n"); 16.40 return true; 16.41 } 16.42 16.43 @@ -71,85 +70,21 @@ 16.44 char *mesh_filename = (char*)alloca(strlen(prefix) + 32); 16.45 sprintf(mesh_filename, "%s-mesh%04d.ctm", prefix, idx); 16.46 16.47 - write_ctm_mesh(mesh, mesh_filename); 16.48 + if(!mesh->save(mesh_filename)) { 16.49 + return false; 16.50 + } 16.51 16.52 // then refer to that filename in the XML tags 16.53 xmlout(io, level, "<mesh>\n"); 16.54 xmlout(io, level + 1, "<name string=\"%s\"/>\n", mesh->name.c_str()); 16.55 - xmlout(io, level + 1, "<material string=\"%s\"/>\n", mesh->material->name.c_str()); 16.56 + if(mesh->material) { 16.57 + xmlout(io, level + 1, "<material string=\"%s\"/>\n", mesh->material->name.c_str()); 16.58 + } 16.59 xmlout(io, level + 1, "<file string=\"%s\"/>\n", mesh_filename); 16.60 - xmlout(io, level, "</mesh>\n"); 16.61 + xmlout(io, level, "</mesh>\n\n"); 16.62 return true; 16.63 } 16.64 16.65 -static void write_ctm_mesh(const Mesh *mesh, const char *fname) 16.66 -{ 16.67 - int vnum = (int)mesh->vertices.size(); 16.68 - 16.69 - CTMcontext ctm = ctmNewContext(CTM_EXPORT); 16.70 - 16.71 - // vertices, normals, and face-vertex indices 16.72 - ctmDefineMesh(ctm, &mesh->vertices[0].x, vnum, (CTMuint*)mesh->faces[0].v, 16.73 - mesh->faces.size(), mesh->normals.empty() ? 0 : &mesh->normals[0].x); 16.74 - 16.75 - // texture coordinates 16.76 - if(!mesh->texcoords.empty()) { 16.77 - ctmAddUVMap(ctm, &mesh->texcoords[0].x, "texcoord", 0); 16.78 - } 16.79 - 16.80 - // vertex colors 16.81 - if(!mesh->colors.empty()) { 16.82 - ctmAddAttribMap(ctm, &mesh->colors[0].x, "color"); 16.83 - } 16.84 - 16.85 - // skin weights 16.86 - if(!mesh->skin_weights.empty()) { 16.87 - ctmAddAttribMap(ctm, &mesh->skin_weights[0].x, "skin_weight"); 16.88 - } 16.89 - 16.90 - // if either of the non-float4 attributes are present we need to make a tmp array 16.91 - CTMfloat *attr_array = 0; 16.92 - if(!mesh->tangents.empty() || !mesh->skin_matrices.empty()) { 16.93 - attr_array = new CTMfloat[vnum * 4 * sizeof *attr_array]; 16.94 - } 16.95 - 16.96 - // tangents 16.97 - if(!mesh->tangents.empty()) { 16.98 - CTMfloat *ptr = attr_array; 16.99 - 16.100 - for(int i=0; i<vnum; i++) { 16.101 - *ptr++ = mesh->tangents[i].x; 16.102 - *ptr++ = mesh->tangents[i].y; 16.103 - *ptr++ = mesh->tangents[i].z; 16.104 - *ptr++ = 1.0; 16.105 - } 16.106 - ctmAddAttribMap(ctm, attr_array, "tangent"); 16.107 - } 16.108 - 16.109 - // skin matrix indices (4 per vertex) 16.110 - if(!mesh->skin_matrices.empty()) { 16.111 - CTMfloat *ptr = attr_array; 16.112 - 16.113 - for(int i=0; i<vnum; i++) { 16.114 - *ptr++ = (float)mesh->skin_matrices[i].x; 16.115 - *ptr++ = (float)mesh->skin_matrices[i].y; 16.116 - *ptr++ = (float)mesh->skin_matrices[i].z; 16.117 - *ptr++ = (float)mesh->skin_matrices[i].w; 16.118 - } 16.119 - ctmAddAttribMap(ctm, attr_array, "skin_matrix"); 16.120 - } 16.121 - 16.122 - delete [] attr_array; 16.123 - 16.124 - /* TODO find a way to specify the nodes participating in the skinning of this mesh 16.125 - * probably in the comment field? 16.126 - */ 16.127 - 16.128 - ctmSave(ctm, fname); 16.129 - 16.130 - ctmFreeContext(ctm); 16.131 -} 16.132 - 16.133 static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level) 16.134 { 16.135 return true;
17.1 --- a/src/log.cc Fri Sep 27 07:14:27 2013 +0300 17.2 +++ b/src/log.cc Fri Sep 27 07:14:49 2013 +0300 17.3 @@ -6,14 +6,13 @@ 17.4 17.5 void logmsg(int prio, const char *fmt, ...) 17.6 { 17.7 - fprintf(stderr, "goat3d error: "); 17.8 - 17.9 va_list ap; 17.10 17.11 - if(prio < goat_log_level) { 17.12 + if(goat_log_level < prio) { 17.13 return; 17.14 } 17.15 17.16 + fprintf(stderr, "goat3d: "); 17.17 va_start(ap, fmt); 17.18 vfprintf(stderr, fmt, ap); 17.19 va_end(ap);
18.1 --- a/src/mesh.cc Fri Sep 27 07:14:27 2013 +0300 18.2 +++ b/src/mesh.cc Fri Sep 27 07:14:49 2013 +0300 18.3 @@ -1,10 +1,182 @@ 18.4 +#include "goat3d_impl.h" 18.5 #include "mesh.h" 18.6 +#include "openctm.h" 18.7 +#include "log.h" 18.8 18.9 Mesh::Mesh() 18.10 { 18.11 material = 0; 18.12 } 18.13 18.14 +bool Mesh::load(const char *fname) 18.15 +{ 18.16 + CTMcontext ctm = ctmNewContext(CTM_IMPORT); 18.17 + 18.18 + ctmLoad(ctm, fname); 18.19 + if(ctmGetError(ctm) != CTM_NONE) { 18.20 + logmsg(LOG_ERROR, "failed to load ctm mesh: %s\n", fname); 18.21 + ctmFreeContext(ctm); 18.22 + return false; 18.23 + } 18.24 + 18.25 + int vnum = ctmGetInteger(ctm, CTM_VERTEX_COUNT); 18.26 + int fnum = ctmGetInteger(ctm, CTM_TRIANGLE_COUNT); 18.27 + 18.28 + const CTMfloat *vertices = ctmGetFloatArray(ctm, CTM_VERTICES); 18.29 + if(!vertices) { 18.30 + logmsg(LOG_ERROR, "failed to load ctm mesh: %s: no vertices found!\n", fname); 18.31 + ctmFreeContext(ctm); 18.32 + return false; 18.33 + } 18.34 + 18.35 + const CTMuint *indices = ctmGetIntegerArray(ctm, CTM_INDICES); 18.36 + if(!indices) { 18.37 + logmsg(LOG_ERROR, "failed to load ctm mesh: %s: no faces found!\n", fname); 18.38 + ctmFreeContext(ctm); 18.39 + return false; 18.40 + } 18.41 + 18.42 + const CTMfloat *normals = ctmGetFloatArray(ctm, CTM_NORMALS); 18.43 + const CTMfloat *texcoords = ctmGetFloatArray(ctm, CTM_UV_MAP_1); 18.44 + 18.45 + CTMenum tangent_id = ctmGetNamedAttribMap(ctm, "tangent"); 18.46 + const CTMfloat *tangents = tangent_id ? ctmGetFloatArray(ctm, tangent_id) : 0; 18.47 + 18.48 + CTMenum skinweight_id = ctmGetNamedAttribMap(ctm, "skin_weight"); 18.49 + const CTMfloat *skinweights = skinweight_id ? ctmGetFloatArray(ctm, skinweight_id) : 0; 18.50 + 18.51 + CTMenum skinmat_id = ctmGetNamedAttribMap(ctm, "skin_matrix"); 18.52 + const CTMuint *skinmats = skinmat_id ? ctmGetIntegerArray(ctm, skinmat_id) : 0; 18.53 + 18.54 + CTMenum color_id = ctmGetNamedAttribMap(ctm, "color"); 18.55 + const CTMfloat *colors = color_id ? ctmGetFloatArray(ctm, color_id) : 0; 18.56 + 18.57 + // now put everything we found into our vectors 18.58 + this->vertices = VECDATA(Vector3, vertices, vnum); 18.59 + 18.60 + if(texcoords) { 18.61 + this->texcoords = VECDATA(Vector2, texcoords, vnum); 18.62 + } 18.63 + if(normals) { 18.64 + this->normals = VECDATA(Vector3, normals, vnum); 18.65 + } 18.66 + if(skinweights) { 18.67 + this->skin_weights = VECDATA(Vector4, skinweights, vnum); 18.68 + } 18.69 + if(colors) { 18.70 + this->colors = VECDATA(Vector4, colors, vnum); 18.71 + } 18.72 + 18.73 + // the rest need converting 18.74 + if(tangents) { 18.75 + this->tangents.clear(); 18.76 + this->tangents.resize(vnum); 18.77 + 18.78 + for(int i=0; i<vnum; i++) { 18.79 + for(int j=0; j<3; j++) { 18.80 + this->tangents[i][j] = tangents[j]; 18.81 + } 18.82 + tangents += 4; 18.83 + } 18.84 + } 18.85 + if(skinmats) { 18.86 + this->skin_matrices.clear(); 18.87 + this->skin_matrices.resize(vnum); 18.88 + 18.89 + for(int i=0; i<vnum; i++) { 18.90 + this->skin_matrices[i].x = skinmats[0]; 18.91 + this->skin_matrices[i].y = skinmats[1]; 18.92 + this->skin_matrices[i].z = skinmats[2]; 18.93 + this->skin_matrices[i].w = skinmats[3]; 18.94 + } 18.95 + } 18.96 + 18.97 + // grab the face data 18.98 + this->faces.clear(); 18.99 + this->faces.resize(fnum); 18.100 + 18.101 + for(int i=0; i<fnum; i++) { 18.102 + for(int j=0; j<3; j++) { 18.103 + this->faces[i].v[j] = indices[j]; 18.104 + } 18.105 + indices += 3; 18.106 + } 18.107 + 18.108 + 18.109 + ctmFreeContext(ctm); 18.110 + return true; 18.111 +} 18.112 + 18.113 +bool Mesh::save(const char *fname) const 18.114 +{ 18.115 + int vnum = (int)vertices.size(); 18.116 + 18.117 + CTMcontext ctm = ctmNewContext(CTM_EXPORT); 18.118 + 18.119 + // vertices, normals, and face-vertex indices 18.120 + ctmDefineMesh(ctm, &vertices[0].x, vnum, (CTMuint*)faces[0].v, faces.size(), 18.121 + normals.empty() ? 0 : &normals[0].x); 18.122 + 18.123 + // texture coordinates 18.124 + if(!texcoords.empty()) { 18.125 + ctmAddUVMap(ctm, &texcoords[0].x, "texcoord", 0); 18.126 + } 18.127 + 18.128 + // vertex colors 18.129 + if(!colors.empty()) { 18.130 + ctmAddAttribMap(ctm, &colors[0].x, "color"); 18.131 + } 18.132 + 18.133 + // skin weights 18.134 + if(!skin_weights.empty()) { 18.135 + ctmAddAttribMap(ctm, &skin_weights[0].x, "skin_weight"); 18.136 + } 18.137 + 18.138 + // if either of the non-float4 attributes are present we need to make a tmp array 18.139 + CTMfloat *attr_array = 0; 18.140 + if(!tangents.empty() || !skin_matrices.empty()) { 18.141 + attr_array = new CTMfloat[vnum * 4 * sizeof *attr_array]; 18.142 + } 18.143 + 18.144 + // tangents 18.145 + if(!tangents.empty()) { 18.146 + CTMfloat *ptr = attr_array; 18.147 + 18.148 + for(int i=0; i<vnum; i++) { 18.149 + *ptr++ = tangents[i].x; 18.150 + *ptr++ = tangents[i].y; 18.151 + *ptr++ = tangents[i].z; 18.152 + *ptr++ = 1.0; 18.153 + } 18.154 + ctmAddAttribMap(ctm, attr_array, "tangent"); 18.155 + } 18.156 + 18.157 + // skin matrix indices (4 per vertex) 18.158 + if(!skin_matrices.empty()) { 18.159 + CTMfloat *ptr = attr_array; 18.160 + 18.161 + for(int i=0; i<vnum; i++) { 18.162 + *ptr++ = (float)skin_matrices[i].x; 18.163 + *ptr++ = (float)skin_matrices[i].y; 18.164 + *ptr++ = (float)skin_matrices[i].z; 18.165 + *ptr++ = (float)skin_matrices[i].w; 18.166 + } 18.167 + ctmAddAttribMap(ctm, attr_array, "skin_matrix"); 18.168 + } 18.169 + 18.170 + delete [] attr_array; 18.171 + 18.172 + /* TODO find a way to specify the nodes participating in the skinning of this mesh 18.173 + * probably in the comment field? 18.174 + */ 18.175 + 18.176 + logmsg(LOG_INFO, "saving CTM mesh file: %s\n", fname); 18.177 + ctmSave(ctm, fname); 18.178 + 18.179 + ctmFreeContext(ctm); 18.180 + return true; 18.181 +} 18.182 + 18.183 void Mesh::set_material(Material *mat) 18.184 { 18.185 material = mat;
19.1 --- a/src/mesh.h Fri Sep 27 07:14:27 2013 +0300 19.2 +++ b/src/mesh.h Fri Sep 27 07:14:49 2013 +0300 19.3 @@ -32,6 +32,9 @@ 19.4 19.5 Mesh(); 19.6 19.7 + bool load(const char *fname); 19.8 + bool save(const char *fname) const; 19.9 + 19.10 void set_material(Material *mat); 19.11 Material *get_material(); 19.12 const Material *get_material() const;
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/src/scene.cc Fri Sep 27 07:14:49 2013 +0300 20.3 @@ -0,0 +1,265 @@ 20.4 +#include <stdarg.h> 20.5 +#include "goat3d.h" 20.6 +#include "goat3d_impl.h" 20.7 +#include "chunk.h" 20.8 + 20.9 +Scene::Scene() 20.10 + : name("unnamed"), ambient(0.05, 0.05, 0.05) 20.11 +{ 20.12 +} 20.13 + 20.14 +Scene::~Scene() 20.15 +{ 20.16 + clear(); 20.17 +} 20.18 + 20.19 +void Scene::clear() 20.20 +{ 20.21 + for(size_t i=0; i<materials.size(); i++) { 20.22 + delete materials[i]; 20.23 + } 20.24 + materials.clear(); 20.25 + 20.26 + for(size_t i=0; i<meshes.size(); i++) { 20.27 + delete meshes[i]; 20.28 + } 20.29 + meshes.clear(); 20.30 + 20.31 + for(size_t i=0; i<lights.size(); i++) { 20.32 + delete lights[i]; 20.33 + } 20.34 + lights.clear(); 20.35 + 20.36 + for(size_t i=0; i<cameras.size(); i++) { 20.37 + delete cameras[i]; 20.38 + } 20.39 + cameras.clear(); 20.40 + 20.41 + for(size_t i=0; i<nodes.size(); i++) { 20.42 + delete_node_tree(nodes[i]); 20.43 + } 20.44 + nodes.clear(); 20.45 + 20.46 + name = "unnamed"; 20.47 +} 20.48 + 20.49 +void Scene::set_name(const char *name) 20.50 +{ 20.51 + this->name = name; 20.52 +} 20.53 + 20.54 +const char *Scene::get_name() const 20.55 +{ 20.56 + return name.c_str(); 20.57 +} 20.58 + 20.59 +void Scene::set_ambient(const Vector3 &amb) 20.60 +{ 20.61 + ambient = amb; 20.62 +} 20.63 + 20.64 +const Vector3 &Scene::get_ambient() const 20.65 +{ 20.66 + return ambient; 20.67 +} 20.68 + 20.69 +void Scene::add_material(Material *mat) 20.70 +{ 20.71 + if(mat->name.empty()) { 20.72 + char buf[64]; 20.73 + sprintf(buf, "material%04d", (int)materials.size()); 20.74 + mat->name = std::string(buf); 20.75 + } 20.76 + materials.push_back(mat); 20.77 +} 20.78 + 20.79 +Material *Scene::get_material(int idx) const 20.80 +{ 20.81 + return idx >=0 && idx < (int)materials.size() ? materials[idx] : 0; 20.82 +} 20.83 + 20.84 +Material *Scene::get_material(const char *name) const 20.85 +{ 20.86 + for(size_t i=0; i<materials.size(); i++) { 20.87 + if(materials[i]->name == std::string(name)) { 20.88 + return materials[i]; 20.89 + } 20.90 + } 20.91 + return 0; 20.92 +} 20.93 + 20.94 +int Scene::get_material_count() const 20.95 +{ 20.96 + return (int)materials.size(); 20.97 +} 20.98 + 20.99 + 20.100 +void Scene::add_mesh(Mesh *mesh) 20.101 +{ 20.102 + if(mesh->name.empty()) { 20.103 + char buf[64]; 20.104 + sprintf(buf, "mesh%04d", (int)meshes.size()); 20.105 + mesh->name = std::string(buf); 20.106 + } 20.107 + meshes.push_back(mesh); 20.108 +} 20.109 + 20.110 +Mesh *Scene::get_mesh(int idx) const 20.111 +{ 20.112 + return idx >= 0 && idx < (int)meshes.size() ? meshes[idx] : 0; 20.113 +} 20.114 + 20.115 +Mesh *Scene::get_mesh(const char *name) const 20.116 +{ 20.117 + for(size_t i=0; i<meshes.size(); i++) { 20.118 + if(meshes[i]->name == std::string(name)) { 20.119 + return meshes[i]; 20.120 + } 20.121 + } 20.122 + return 0; 20.123 +} 20.124 + 20.125 +int Scene::get_mesh_count() const 20.126 +{ 20.127 + return (int)meshes.size(); 20.128 +} 20.129 + 20.130 + 20.131 +void Scene::add_light(Light *light) 20.132 +{ 20.133 + lights.push_back(light); 20.134 +} 20.135 + 20.136 +Light *Scene::get_light(int idx) const 20.137 +{ 20.138 + return idx >= 0 && idx < (int)lights.size() ? lights[idx] : 0; 20.139 +} 20.140 + 20.141 +Light *Scene::get_light(const char *name) const 20.142 +{ 20.143 + for(size_t i=0; i<lights.size(); i++) { 20.144 + if(lights[i]->name == std::string(name)) { 20.145 + return lights[i]; 20.146 + } 20.147 + } 20.148 + return 0; 20.149 +} 20.150 + 20.151 +int Scene::get_light_count() const 20.152 +{ 20.153 + return (int)lights.size(); 20.154 +} 20.155 + 20.156 + 20.157 +void Scene::add_camera(Camera *cam) 20.158 +{ 20.159 + cameras.push_back(cam); 20.160 +} 20.161 + 20.162 +Camera *Scene::get_camera(int idx) const 20.163 +{ 20.164 + return idx >= 0 && idx < (int)cameras.size() ? cameras[idx] : 0; 20.165 +} 20.166 + 20.167 +Camera *Scene::get_camera(const char *name) const 20.168 +{ 20.169 + for(size_t i=0; i<cameras.size(); i++) { 20.170 + if(cameras[i]->name == std::string(name)) { 20.171 + return cameras[i]; 20.172 + } 20.173 + } 20.174 + return 0; 20.175 +} 20.176 + 20.177 +int Scene::get_camera_count() const 20.178 +{ 20.179 + return (int)cameras.size(); 20.180 +} 20.181 + 20.182 + 20.183 +void Scene::add_node(Node *node) 20.184 +{ 20.185 + nodes.push_back(node); 20.186 +} 20.187 + 20.188 +Node *Scene::get_node(int idx) const 20.189 +{ 20.190 + return idx >= 0 && idx < (int)nodes.size() ? nodes[idx] : 0; 20.191 +} 20.192 + 20.193 +Node *Scene::get_node(const char *name) const 20.194 +{ 20.195 + for(size_t i=0; i<nodes.size(); i++) { 20.196 + if(strcmp(nodes[i]->get_name(), name) == 0) { 20.197 + return nodes[i]; 20.198 + } 20.199 + } 20.200 + return 0; 20.201 +} 20.202 + 20.203 +int Scene::get_node_count() const 20.204 +{ 20.205 + return (int)nodes.size(); 20.206 +} 20.207 + 20.208 + 20.209 +bool Scene::load(goat3d_io *io) 20.210 +{ 20.211 + return false; 20.212 +} 20.213 + 20.214 +// Scene::loadxml is defined in goat3d_readxml.cc 20.215 +// Scene::save is defined in goat3d_write.cc 20.216 +// Scene::savexml is defined in goat3d_writexml.cc 20.217 + 20.218 + 20.219 +void io_fprintf(goat3d_io *io, const char *fmt, ...) 20.220 +{ 20.221 + va_list ap; 20.222 + 20.223 + va_start(ap, fmt); 20.224 + io_vfprintf(io, fmt, ap); 20.225 + va_end(ap); 20.226 +} 20.227 + 20.228 + 20.229 +void io_vfprintf(goat3d_io *io, const char *fmt, va_list ap) 20.230 +{ 20.231 + char smallbuf[256]; 20.232 + char *buf = smallbuf; 20.233 + int sz = sizeof smallbuf; 20.234 + 20.235 + int retsz = vsnprintf(buf, sz - 1, fmt, ap); 20.236 + 20.237 + if(retsz >= sz) { 20.238 + /* C99 mandates that snprintf with a short count should return the 20.239 + * number of characters that *would* be printed. 20.240 + */ 20.241 + buf = new char[retsz + 1]; 20.242 + 20.243 + vsnprintf(buf, retsz, fmt, ap); 20.244 + 20.245 + } else if(retsz <= 0) { 20.246 + /* SUSv2 and microsoft specify that snprintf with a short count 20.247 + * returns an arbitrary value <= 0. So let's try allocating 20.248 + * bigger and bigger arrays until we find the correct size. 20.249 + */ 20.250 + sz = sizeof smallbuf; 20.251 + do { 20.252 + sz *= 2; 20.253 + if(buf != smallbuf) { 20.254 + delete [] buf; 20.255 + } 20.256 + buf = new char[sz + 1]; 20.257 + 20.258 + retsz = vsnprintf(buf, sz, fmt, ap); 20.259 + } while(retsz <= 0); 20.260 + } 20.261 + 20.262 + io->write(buf, retsz, io->cls); 20.263 + 20.264 + if(buf != smallbuf) { 20.265 + delete [] buf; 20.266 + } 20.267 + 20.268 +}