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 +                    //   &#20013; or &#x4e2d;
   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 +}