goat3d

changeset 19:b35427826b60

- added XML format reading support - wrote a rudimentary version of goatview
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 27 Sep 2013 06:58:37 +0300
parents bdfc8dd14965
children f5fdefbb7a1d
files .clang_complete .hgignore Makefile doc/goatanimfmt goatview/Makefile goatview/src/main.c libs/tinyxml2/Makefile libs/tinyxml2/tinyxml2.cpp libs/tinyxml2/tinyxml2.h src/goat3d.cc src/goat3d.h src/goat3d_impl.h src/goat3d_readxml.cc src/goat3d_writexml.cc src/mesh.cc src/mesh.h src/scene.cc
diffstat 17 files changed, 4723 insertions(+), 88 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.clang_complete	Fri Sep 27 06:58:37 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 03:17:36 2013 +0300
     2.2 +++ b/.hgignore	Fri Sep 27 06:58:37 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 03:17:36 2013 +0300
     3.2 +++ b/Makefile	Fri Sep 27 06:58:37 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 06:58:37 2013 +0300
     4.3 @@ -0,0 +1,3 @@
     4.4 +goat3d animation file format
     4.5 +----------------------------
     4.6 +TODO
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/goatview/Makefile	Fri Sep 27 06:58:37 2013 +0300
     5.3 @@ -0,0 +1,34 @@
     5.4 +src = $(wildcard src/*.c)
     5.5 +obj = $(src:.c=.o)
     5.6 +dep = $(obj:.o=.d)
     5.7 +bin = goatview
     5.8 +
     5.9 +goat_root = ..
    5.10 +libgoat = $(goat_root)/libgoat3d.so.0.1
    5.11 +
    5.12 +CC = clang
    5.13 +CPP = clang -E
    5.14 +CFLAGS = -pedantic -Wall -g -I$(goat_root)/src
    5.15 +LDFLAGS = $(libgoat) -Wl,-rpath=$(goat_root) $(libgl)
    5.16 +
    5.17 +ifeq ($(shell uname -s), Darwin)
    5.18 +	libgl = -framework OpenGL -framework GLUT -lGLEW
    5.19 +else
    5.20 +	libgl = -lGL -lGLU -lglut -lGLEW
    5.21 +endif
    5.22 +
    5.23 +$(bin): $(obj) $(libgoat)
    5.24 +	$(CC) -o $@ $(obj) $(LDFLAGS)
    5.25 +
    5.26 +-include $(dep)
    5.27 +
    5.28 +%.d: %.c
    5.29 +	@$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
    5.30 +
    5.31 +.PHONY: clean
    5.32 +clean:
    5.33 +	rm -f $(obj) $(bin)
    5.34 +
    5.35 +.PHONY: cleandep
    5.36 +cleandep:
    5.37 +	rm -f $(dep)
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/goatview/src/main.c	Fri Sep 27 06:58:37 2013 +0300
     6.3 @@ -0,0 +1,191 @@
     6.4 +#include <stdio.h>
     6.5 +#include <stdlib.h>
     6.6 +#include <assert.h>
     6.7 +#ifndef __APPLE__
     6.8 +#include <GL/glut.h>
     6.9 +#else
    6.10 +#include <GLUT/glut.h>
    6.11 +#endif
    6.12 +#include "goat3d.h"
    6.13 +
    6.14 +static void cleanup(void);
    6.15 +static void disp(void);
    6.16 +static void draw_scene(struct goat3d *g);
    6.17 +static void draw_mesh(struct goat3d_mesh *mesh);
    6.18 +static void reshape(int x, int y);
    6.19 +static void keyb(unsigned char key, int x, int y);
    6.20 +static void mouse(int bn, int st, int x, int y);
    6.21 +static void motion(int x, int y);
    6.22 +
    6.23 +static struct goat3d *goat;
    6.24 +static float cam_theta, cam_phi, cam_dist = 10;
    6.25 +
    6.26 +int main(int argc, char **argv)
    6.27 +{
    6.28 +	glutInitWindowSize(800, 600);
    6.29 +	glutInit(&argc, argv);
    6.30 +
    6.31 +	if(!argv[1]) {
    6.32 +		fprintf(stderr, "you must specify a goat3d scene file to open\n");
    6.33 +		return 1;
    6.34 +	}
    6.35 +
    6.36 +	if(!(goat = goat3d_create())) {
    6.37 +		fprintf(stderr, "failed to create goat3d\n");
    6.38 +		return 1;
    6.39 +	}
    6.40 +	if(goat3d_load(goat, argv[1]) == -1) {
    6.41 +		fprintf(stderr, "failed to load goat3d scene: %s\n", argv[1]);
    6.42 +		goat3d_free(goat);
    6.43 +		return 1;
    6.44 +	}
    6.45 +
    6.46 +	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    6.47 +	glutCreateWindow(argv[1]);
    6.48 +
    6.49 +	glutDisplayFunc(disp);
    6.50 +	glutReshapeFunc(reshape);
    6.51 +	glutKeyboardFunc(keyb);
    6.52 +	glutMouseFunc(mouse);
    6.53 +	glutMotionFunc(motion);
    6.54 +
    6.55 +	glEnable(GL_DEPTH_TEST);
    6.56 +	glEnable(GL_CULL_FACE);
    6.57 +	glEnable(GL_LIGHTING);
    6.58 +	glEnable(GL_LIGHT0);
    6.59 +
    6.60 +	glClearColor(0.1, 0.1, 0.1, 1.0);
    6.61 +
    6.62 +	atexit(cleanup);
    6.63 +
    6.64 +	glutMainLoop();
    6.65 +	return 0;
    6.66 +}
    6.67 +
    6.68 +static void cleanup(void)
    6.69 +{
    6.70 +	goat3d_free(goat);
    6.71 +}
    6.72 +
    6.73 +static void disp(void)
    6.74 +{
    6.75 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    6.76 +
    6.77 +	glMatrixMode(GL_MODELVIEW);
    6.78 +	glLoadIdentity();
    6.79 +	glTranslatef(0, 0, -cam_dist);
    6.80 +	glRotatef(cam_phi, 1, 0, 0);
    6.81 +	glRotatef(cam_theta, 0, 1, 0);
    6.82 +
    6.83 +	draw_scene(goat);
    6.84 +
    6.85 +	glutSwapBuffers();
    6.86 +	assert(glGetError() == GL_NO_ERROR);
    6.87 +}
    6.88 +
    6.89 +static void draw_scene(struct goat3d *g)
    6.90 +{
    6.91 +	int i, num_meshes;
    6.92 +
    6.93 +	num_meshes = goat3d_get_mesh_count(g);
    6.94 +	for(i=0; i<num_meshes; i++) {
    6.95 +		struct goat3d_mesh *mesh = goat3d_get_mesh(g, i);
    6.96 +		draw_mesh(mesh);
    6.97 +	}
    6.98 +}
    6.99 +
   6.100 +static void draw_mesh(struct goat3d_mesh *mesh)
   6.101 +{
   6.102 +	int vnum, fnum;
   6.103 +	struct goat3d_material *mtl;
   6.104 +	float *verts, *normals, *texcoords;
   6.105 +	int *vidx;
   6.106 +
   6.107 +	if((mtl = goat3d_get_mesh_mtl(mesh))) {
   6.108 +		/* TODO */
   6.109 +	}
   6.110 +
   6.111 +	vnum = goat3d_get_mesh_attrib_count(mesh, GOAT3D_MESH_ATTR_VERTEX);
   6.112 +	fnum = goat3d_get_mesh_face_count(mesh);
   6.113 +
   6.114 +	if(!vnum || !fnum) {
   6.115 +		return;
   6.116 +	}
   6.117 +
   6.118 +	verts = goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_VERTEX);
   6.119 +	normals = goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_NORMAL);
   6.120 +	texcoords = goat3d_get_mesh_attribs(mesh, GOAT3D_MESH_ATTR_TEXCOORD);
   6.121 +	vidx = goat3d_get_mesh_faces(mesh);
   6.122 +
   6.123 +	glEnableClientState(GL_VERTEX_ARRAY);
   6.124 +	glVertexPointer(3, GL_FLOAT, 0, verts);
   6.125 +
   6.126 +	if(normals) {
   6.127 +		glEnableClientState(GL_NORMAL_ARRAY);
   6.128 +		glNormalPointer(GL_FLOAT, 0, normals);
   6.129 +	}
   6.130 +	if(texcoords) {
   6.131 +		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
   6.132 +		glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
   6.133 +	}
   6.134 +
   6.135 +	glDrawElements(GL_TRIANGLES, fnum * 3, GL_UNSIGNED_INT, vidx);
   6.136 +
   6.137 +	glDisableClientState(GL_VERTEX_ARRAY);
   6.138 +	if(normals) {
   6.139 +		glDisableClientState(GL_NORMAL_ARRAY);
   6.140 +	}
   6.141 +	if(texcoords) {
   6.142 +		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
   6.143 +	}
   6.144 +}
   6.145 +
   6.146 +static void reshape(int x, int y)
   6.147 +{
   6.148 +	glViewport(0, 0, x, y);
   6.149 +
   6.150 +	glMatrixMode(GL_PROJECTION);
   6.151 +	glLoadIdentity();
   6.152 +	gluPerspective(50.0, (float)x / (float)y, 0.5, 1000.0);
   6.153 +}
   6.154 +
   6.155 +static void keyb(unsigned char key, int x, int y)
   6.156 +{
   6.157 +	switch(key) {
   6.158 +	case 27:
   6.159 +		exit(0);
   6.160 +	}
   6.161 +}
   6.162 +
   6.163 +static int bnstate[32];
   6.164 +static int prev_x, prev_y;
   6.165 +
   6.166 +static void mouse(int bn, int st, int x, int y)
   6.167 +{
   6.168 +	bnstate[bn - GLUT_LEFT_BUTTON] = (st == GLUT_DOWN);
   6.169 +	prev_x = x;
   6.170 +	prev_y = y;
   6.171 +}
   6.172 +
   6.173 +static void motion(int x, int y)
   6.174 +{
   6.175 +	int dx = x - prev_x;
   6.176 +	int dy = y - prev_y;
   6.177 +	prev_x = x;
   6.178 +	prev_y = y;
   6.179 +
   6.180 +	if(bnstate[0]) {
   6.181 +		cam_theta += dx * 0.5;
   6.182 +		cam_phi += dy * 0.5;
   6.183 +
   6.184 +		if(cam_phi < -90) cam_phi = -90;
   6.185 +		if(cam_phi > 90) cam_phi = 90;
   6.186 +		glutPostRedisplay();
   6.187 +	}
   6.188 +	if(bnstate[2]) {
   6.189 +		cam_dist += dy * 0.1;
   6.190 +
   6.191 +		if(cam_dist < 0) cam_dist = 0;
   6.192 +		glutPostRedisplay();
   6.193 +	}
   6.194 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/libs/tinyxml2/Makefile	Fri Sep 27 06:58:37 2013 +0300
     7.3 @@ -0,0 +1,15 @@
     7.4 +obj = tinyxml2.o
     7.5 +lib = libtinyxml2.a
     7.6 +
     7.7 +ifneq ($(shell uname -s), Darwin)
     7.8 +	pic = -fPIC
     7.9 +endif
    7.10 +
    7.11 +CXXFLAGS = -pedantic -Wall -g $(pic)
    7.12 +
    7.13 +$(lib): $(obj)
    7.14 +	$(AR) rcs $@ $(obj)
    7.15 +
    7.16 +.PHONY: clean
    7.17 +clean:
    7.18 +	rm -f $(obj) $(lib)
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/libs/tinyxml2/tinyxml2.cpp	Fri Sep 27 06:58:37 2013 +0300
     8.3 @@ -0,0 +1,2101 @@
     8.4 +/*
     8.5 +Original code by Lee Thomason (www.grinninglizard.com)
     8.6 +
     8.7 +This software is provided 'as-is', without any express or implied
     8.8 +warranty. In no event will the authors be held liable for any
     8.9 +damages arising from the use of this software.
    8.10 +
    8.11 +Permission is granted to anyone to use this software for any
    8.12 +purpose, including commercial applications, and to alter it and
    8.13 +redistribute it freely, subject to the following restrictions:
    8.14 +
    8.15 +1. The origin of this software must not be misrepresented; you must
    8.16 +not claim that you wrote the original software. If you use this
    8.17 +software in a product, an acknowledgment in the product documentation
    8.18 +would be appreciated but is not required.
    8.19 +
    8.20 +2. Altered source versions must be plainly marked as such, and
    8.21 +must not be misrepresented as being the original software.
    8.22 +
    8.23 +3. This notice may not be removed or altered from any source
    8.24 +distribution.
    8.25 +*/
    8.26 +
    8.27 +#include "tinyxml2.h"
    8.28 +
    8.29 +#include <new>		// yes, this one new style header, is in the Android SDK.
    8.30 +#   ifdef ANDROID_NDK
    8.31 +#   include <stddef.h>
    8.32 +#else
    8.33 +#   include <cstddef>
    8.34 +#endif
    8.35 +
    8.36 +static const char LINE_FEED				= (char)0x0a;			// all line endings are normalized to LF
    8.37 +static const char LF = LINE_FEED;
    8.38 +static const char CARRIAGE_RETURN		= (char)0x0d;			// CR gets filtered out
    8.39 +static const char CR = CARRIAGE_RETURN;
    8.40 +static const char SINGLE_QUOTE			= '\'';
    8.41 +static const char DOUBLE_QUOTE			= '\"';
    8.42 +
    8.43 +// Bunch of unicode info at:
    8.44 +//		http://www.unicode.org/faq/utf_bom.html
    8.45 +//	ef bb bf (Microsoft "lead bytes") - designates UTF-8
    8.46 +
    8.47 +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
    8.48 +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
    8.49 +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
    8.50 +
    8.51 +
    8.52 +#define DELETE_NODE( node )	{			\
    8.53 +        if ( node ) {						\
    8.54 +            MemPool* pool = node->_memPool;	\
    8.55 +            node->~XMLNode();				\
    8.56 +            pool->Free( node );				\
    8.57 +        }									\
    8.58 +    }
    8.59 +#define DELETE_ATTRIBUTE( attrib ) {		\
    8.60 +        if ( attrib ) {							\
    8.61 +            MemPool* pool = attrib->_memPool;	\
    8.62 +            attrib->~XMLAttribute();			\
    8.63 +            pool->Free( attrib );				\
    8.64 +        }										\
    8.65 +    }
    8.66 +
    8.67 +namespace tinyxml2
    8.68 +{
    8.69 +
    8.70 +struct Entity {
    8.71 +    const char* pattern;
    8.72 +    int length;
    8.73 +    char value;
    8.74 +};
    8.75 +
    8.76 +static const int NUM_ENTITIES = 5;
    8.77 +static const Entity entities[NUM_ENTITIES] = {
    8.78 +    { "quot", 4,	DOUBLE_QUOTE },
    8.79 +    { "amp", 3,		'&'  },
    8.80 +    { "apos", 4,	SINGLE_QUOTE },
    8.81 +    { "lt",	2, 		'<'	 },
    8.82 +    { "gt",	2,		'>'	 }
    8.83 +};
    8.84 +
    8.85 +
    8.86 +StrPair::~StrPair()
    8.87 +{
    8.88 +    Reset();
    8.89 +}
    8.90 +
    8.91 +
    8.92 +void StrPair::Reset()
    8.93 +{
    8.94 +    if ( _flags & NEEDS_DELETE ) {
    8.95 +        delete [] _start;
    8.96 +    }
    8.97 +    _flags = 0;
    8.98 +    _start = 0;
    8.99 +    _end = 0;
   8.100 +}
   8.101 +
   8.102 +
   8.103 +void StrPair::SetStr( const char* str, int flags )
   8.104 +{
   8.105 +    Reset();
   8.106 +    size_t len = strlen( str );
   8.107 +    _start = new char[ len+1 ];
   8.108 +    memcpy( _start, str, len+1 );
   8.109 +    _end = _start + len;
   8.110 +    _flags = flags | NEEDS_DELETE;
   8.111 +}
   8.112 +
   8.113 +
   8.114 +char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
   8.115 +{
   8.116 +    TIXMLASSERT( endTag && *endTag );
   8.117 +
   8.118 +    char* start = p;	// fixme: hides a member
   8.119 +    char  endChar = *endTag;
   8.120 +    size_t length = strlen( endTag );
   8.121 +
   8.122 +    // Inner loop of text parsing.
   8.123 +    while ( *p ) {
   8.124 +        if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
   8.125 +            Set( start, p, strFlags );
   8.126 +            return p + length;
   8.127 +        }
   8.128 +        ++p;
   8.129 +    }
   8.130 +    return 0;
   8.131 +}
   8.132 +
   8.133 +
   8.134 +char* StrPair::ParseName( char* p )
   8.135 +{
   8.136 +    char* start = p;
   8.137 +
   8.138 +    if ( !start || !(*start) ) {
   8.139 +        return 0;
   8.140 +    }
   8.141 +
   8.142 +    while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
   8.143 +        ++p;
   8.144 +    }
   8.145 +
   8.146 +    if ( p > start ) {
   8.147 +        Set( start, p, 0 );
   8.148 +        return p;
   8.149 +    }
   8.150 +    return 0;
   8.151 +}
   8.152 +
   8.153 +
   8.154 +void StrPair::CollapseWhitespace()
   8.155 +{
   8.156 +    // Trim leading space.
   8.157 +    _start = XMLUtil::SkipWhiteSpace( _start );
   8.158 +
   8.159 +    if ( _start && *_start ) {
   8.160 +        char* p = _start;	// the read pointer
   8.161 +        char* q = _start;	// the write pointer
   8.162 +
   8.163 +        while( *p ) {
   8.164 +            if ( XMLUtil::IsWhiteSpace( *p )) {
   8.165 +                p = XMLUtil::SkipWhiteSpace( p );
   8.166 +                if ( *p == 0 ) {
   8.167 +                    break;    // don't write to q; this trims the trailing space.
   8.168 +                }
   8.169 +                *q = ' ';
   8.170 +                ++q;
   8.171 +            }
   8.172 +            *q = *p;
   8.173 +            ++q;
   8.174 +            ++p;
   8.175 +        }
   8.176 +        *q = 0;
   8.177 +    }
   8.178 +}
   8.179 +
   8.180 +
   8.181 +const char* StrPair::GetStr()
   8.182 +{
   8.183 +    if ( _flags & NEEDS_FLUSH ) {
   8.184 +        *_end = 0;
   8.185 +        _flags ^= NEEDS_FLUSH;
   8.186 +
   8.187 +        if ( _flags ) {
   8.188 +            char* p = _start;	// the read pointer
   8.189 +            char* q = _start;	// the write pointer
   8.190 +
   8.191 +            while( p < _end ) {
   8.192 +                if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
   8.193 +                    // CR-LF pair becomes LF
   8.194 +                    // CR alone becomes LF
   8.195 +                    // LF-CR becomes LF
   8.196 +                    if ( *(p+1) == LF ) {
   8.197 +                        p += 2;
   8.198 +                    }
   8.199 +                    else {
   8.200 +                        ++p;
   8.201 +                    }
   8.202 +                    *q++ = LF;
   8.203 +                }
   8.204 +                else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
   8.205 +                    if ( *(p+1) == CR ) {
   8.206 +                        p += 2;
   8.207 +                    }
   8.208 +                    else {
   8.209 +                        ++p;
   8.210 +                    }
   8.211 +                    *q++ = LF;
   8.212 +                }
   8.213 +                else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
   8.214 +                    // Entities handled by tinyXML2:
   8.215 +                    // - special entities in the entity table [in/out]
   8.216 +                    // - numeric character reference [in]
   8.217 +                    //   &#20013; or &#x4e2d;
   8.218 +
   8.219 +                    if ( *(p+1) == '#' ) {
   8.220 +                        char buf[10] = { 0 };
   8.221 +                        int len;
   8.222 +                        p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
   8.223 +                        for( int i=0; i<len; ++i ) {
   8.224 +                            *q++ = buf[i];
   8.225 +                        }
   8.226 +                        TIXMLASSERT( q <= p );
   8.227 +                    }
   8.228 +                    else {
   8.229 +                        int i=0;
   8.230 +                        for(; i<NUM_ENTITIES; ++i ) {
   8.231 +                            if (    strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
   8.232 +                                    && *(p+entities[i].length+1) == ';' ) {
   8.233 +                                // Found an entity convert;
   8.234 +                                *q = entities[i].value;
   8.235 +                                ++q;
   8.236 +                                p += entities[i].length + 2;
   8.237 +                                break;
   8.238 +                            }
   8.239 +                        }
   8.240 +                        if ( i == NUM_ENTITIES ) {
   8.241 +                            // fixme: treat as error?
   8.242 +                            ++p;
   8.243 +                            ++q;
   8.244 +                        }
   8.245 +                    }
   8.246 +                }
   8.247 +                else {
   8.248 +                    *q = *p;
   8.249 +                    ++p;
   8.250 +                    ++q;
   8.251 +                }
   8.252 +            }
   8.253 +            *q = 0;
   8.254 +        }
   8.255 +        // The loop below has plenty going on, and this
   8.256 +        // is a less useful mode. Break it out.
   8.257 +        if ( _flags & COLLAPSE_WHITESPACE ) {
   8.258 +            CollapseWhitespace();
   8.259 +        }
   8.260 +        _flags = (_flags & NEEDS_DELETE);
   8.261 +    }
   8.262 +    return _start;
   8.263 +}
   8.264 +
   8.265 +
   8.266 +
   8.267 +
   8.268 +// --------- XMLUtil ----------- //
   8.269 +
   8.270 +const char* XMLUtil::ReadBOM( const char* p, bool* bom )
   8.271 +{
   8.272 +    *bom = false;
   8.273 +    const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
   8.274 +    // Check for BOM:
   8.275 +    if (    *(pu+0) == TIXML_UTF_LEAD_0
   8.276 +            && *(pu+1) == TIXML_UTF_LEAD_1
   8.277 +            && *(pu+2) == TIXML_UTF_LEAD_2 ) {
   8.278 +        *bom = true;
   8.279 +        p += 3;
   8.280 +    }
   8.281 +    return p;
   8.282 +}
   8.283 +
   8.284 +
   8.285 +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
   8.286 +{
   8.287 +    const unsigned long BYTE_MASK = 0xBF;
   8.288 +    const unsigned long BYTE_MARK = 0x80;
   8.289 +    const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
   8.290 +
   8.291 +    if (input < 0x80) {
   8.292 +        *length = 1;
   8.293 +    }
   8.294 +    else if ( input < 0x800 ) {
   8.295 +        *length = 2;
   8.296 +    }
   8.297 +    else if ( input < 0x10000 ) {
   8.298 +        *length = 3;
   8.299 +    }
   8.300 +    else if ( input < 0x200000 ) {
   8.301 +        *length = 4;
   8.302 +    }
   8.303 +    else {
   8.304 +        *length = 0;    // This code won't covert this correctly anyway.
   8.305 +        return;
   8.306 +    }
   8.307 +
   8.308 +    output += *length;
   8.309 +
   8.310 +    // Scary scary fall throughs.
   8.311 +    switch (*length) {
   8.312 +        case 4:
   8.313 +            --output;
   8.314 +            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
   8.315 +            input >>= 6;
   8.316 +        case 3:
   8.317 +            --output;
   8.318 +            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
   8.319 +            input >>= 6;
   8.320 +        case 2:
   8.321 +            --output;
   8.322 +            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
   8.323 +            input >>= 6;
   8.324 +        case 1:
   8.325 +            --output;
   8.326 +            *output = (char)(input | FIRST_BYTE_MARK[*length]);
   8.327 +        default:
   8.328 +            break;
   8.329 +    }
   8.330 +}
   8.331 +
   8.332 +
   8.333 +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
   8.334 +{
   8.335 +    // Presume an entity, and pull it out.
   8.336 +    *length = 0;
   8.337 +
   8.338 +    if ( *(p+1) == '#' && *(p+2) ) {
   8.339 +        unsigned long ucs = 0;
   8.340 +        ptrdiff_t delta = 0;
   8.341 +        unsigned mult = 1;
   8.342 +
   8.343 +        if ( *(p+2) == 'x' ) {
   8.344 +            // Hexadecimal.
   8.345 +            if ( !*(p+3) ) {
   8.346 +                return 0;
   8.347 +            }
   8.348 +
   8.349 +            const char* q = p+3;
   8.350 +            q = strchr( q, ';' );
   8.351 +
   8.352 +            if ( !q || !*q ) {
   8.353 +                return 0;
   8.354 +            }
   8.355 +
   8.356 +            delta = q-p;
   8.357 +            --q;
   8.358 +
   8.359 +            while ( *q != 'x' ) {
   8.360 +                if ( *q >= '0' && *q <= '9' ) {
   8.361 +                    ucs += mult * (*q - '0');
   8.362 +                }
   8.363 +                else if ( *q >= 'a' && *q <= 'f' ) {
   8.364 +                    ucs += mult * (*q - 'a' + 10);
   8.365 +                }
   8.366 +                else if ( *q >= 'A' && *q <= 'F' ) {
   8.367 +                    ucs += mult * (*q - 'A' + 10 );
   8.368 +                }
   8.369 +                else {
   8.370 +                    return 0;
   8.371 +                }
   8.372 +                mult *= 16;
   8.373 +                --q;
   8.374 +            }
   8.375 +        }
   8.376 +        else {
   8.377 +            // Decimal.
   8.378 +            if ( !*(p+2) ) {
   8.379 +                return 0;
   8.380 +            }
   8.381 +
   8.382 +            const char* q = p+2;
   8.383 +            q = strchr( q, ';' );
   8.384 +
   8.385 +            if ( !q || !*q ) {
   8.386 +                return 0;
   8.387 +            }
   8.388 +
   8.389 +            delta = q-p;
   8.390 +            --q;
   8.391 +
   8.392 +            while ( *q != '#' ) {
   8.393 +                if ( *q >= '0' && *q <= '9' ) {
   8.394 +                    ucs += mult * (*q - '0');
   8.395 +                }
   8.396 +                else {
   8.397 +                    return 0;
   8.398 +                }
   8.399 +                mult *= 10;
   8.400 +                --q;
   8.401 +            }
   8.402 +        }
   8.403 +        // convert the UCS to UTF-8
   8.404 +        ConvertUTF32ToUTF8( ucs, value, length );
   8.405 +        return p + delta + 1;
   8.406 +    }
   8.407 +    return p+1;
   8.408 +}
   8.409 +
   8.410 +
   8.411 +void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
   8.412 +{
   8.413 +    TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
   8.414 +}
   8.415 +
   8.416 +
   8.417 +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
   8.418 +{
   8.419 +    TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
   8.420 +}
   8.421 +
   8.422 +
   8.423 +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
   8.424 +{
   8.425 +    TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
   8.426 +}
   8.427 +
   8.428 +
   8.429 +void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
   8.430 +{
   8.431 +    TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
   8.432 +}
   8.433 +
   8.434 +
   8.435 +void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
   8.436 +{
   8.437 +    TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
   8.438 +}
   8.439 +
   8.440 +
   8.441 +bool XMLUtil::ToInt( const char* str, int* value )
   8.442 +{
   8.443 +    if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
   8.444 +        return true;
   8.445 +    }
   8.446 +    return false;
   8.447 +}
   8.448 +
   8.449 +bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
   8.450 +{
   8.451 +    if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
   8.452 +        return true;
   8.453 +    }
   8.454 +    return false;
   8.455 +}
   8.456 +
   8.457 +bool XMLUtil::ToBool( const char* str, bool* value )
   8.458 +{
   8.459 +    int ival = 0;
   8.460 +    if ( ToInt( str, &ival )) {
   8.461 +        *value = (ival==0) ? false : true;
   8.462 +        return true;
   8.463 +    }
   8.464 +    if ( StringEqual( str, "true" ) ) {
   8.465 +        *value = true;
   8.466 +        return true;
   8.467 +    }
   8.468 +    else if ( StringEqual( str, "false" ) ) {
   8.469 +        *value = false;
   8.470 +        return true;
   8.471 +    }
   8.472 +    return false;
   8.473 +}
   8.474 +
   8.475 +
   8.476 +bool XMLUtil::ToFloat( const char* str, float* value )
   8.477 +{
   8.478 +    if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
   8.479 +        return true;
   8.480 +    }
   8.481 +    return false;
   8.482 +}
   8.483 +
   8.484 +bool XMLUtil::ToDouble( const char* str, double* value )
   8.485 +{
   8.486 +    if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
   8.487 +        return true;
   8.488 +    }
   8.489 +    return false;
   8.490 +}
   8.491 +
   8.492 +
   8.493 +char* XMLDocument::Identify( char* p, XMLNode** node )
   8.494 +{
   8.495 +    XMLNode* returnNode = 0;
   8.496 +    char* start = p;
   8.497 +    p = XMLUtil::SkipWhiteSpace( p );
   8.498 +    if( !p || !*p ) {
   8.499 +        return p;
   8.500 +    }
   8.501 +
   8.502 +    // What is this thing?
   8.503 +    // - Elements start with a letter or underscore, but xml is reserved.
   8.504 +    // - Comments: <!--
   8.505 +    // - Declaration: <?
   8.506 +    // - Everything else is unknown to tinyxml.
   8.507 +    //
   8.508 +
   8.509 +    static const char* xmlHeader		= { "<?" };
   8.510 +    static const char* commentHeader	= { "<!--" };
   8.511 +    static const char* dtdHeader		= { "<!" };
   8.512 +    static const char* cdataHeader		= { "<![CDATA[" };
   8.513 +    static const char* elementHeader	= { "<" };	// and a header for everything else; check last.
   8.514 +
   8.515 +    static const int xmlHeaderLen		= 2;
   8.516 +    static const int commentHeaderLen	= 4;
   8.517 +    static const int dtdHeaderLen		= 2;
   8.518 +    static const int cdataHeaderLen		= 9;
   8.519 +    static const int elementHeaderLen	= 1;
   8.520 +
   8.521 +#if defined(_MSC_VER)
   8.522 +#pragma warning ( push )
   8.523 +#pragma warning ( disable : 4127 )
   8.524 +#endif
   8.525 +    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );		// use same memory pool
   8.526 +    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );	// use same memory pool
   8.527 +#if defined(_MSC_VER)
   8.528 +#pragma warning (pop)
   8.529 +#endif
   8.530 +    if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
   8.531 +        returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
   8.532 +        returnNode->_memPool = &_commentPool;
   8.533 +        p += xmlHeaderLen;
   8.534 +    }
   8.535 +    else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
   8.536 +        returnNode = new (_commentPool.Alloc()) XMLComment( this );
   8.537 +        returnNode->_memPool = &_commentPool;
   8.538 +        p += commentHeaderLen;
   8.539 +    }
   8.540 +    else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
   8.541 +        XMLText* text = new (_textPool.Alloc()) XMLText( this );
   8.542 +        returnNode = text;
   8.543 +        returnNode->_memPool = &_textPool;
   8.544 +        p += cdataHeaderLen;
   8.545 +        text->SetCData( true );
   8.546 +    }
   8.547 +    else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
   8.548 +        returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
   8.549 +        returnNode->_memPool = &_commentPool;
   8.550 +        p += dtdHeaderLen;
   8.551 +    }
   8.552 +    else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
   8.553 +        returnNode = new (_elementPool.Alloc()) XMLElement( this );
   8.554 +        returnNode->_memPool = &_elementPool;
   8.555 +        p += elementHeaderLen;
   8.556 +    }
   8.557 +    else {
   8.558 +        returnNode = new (_textPool.Alloc()) XMLText( this );
   8.559 +        returnNode->_memPool = &_textPool;
   8.560 +        p = start;	// Back it up, all the text counts.
   8.561 +    }
   8.562 +
   8.563 +    *node = returnNode;
   8.564 +    return p;
   8.565 +}
   8.566 +
   8.567 +
   8.568 +bool XMLDocument::Accept( XMLVisitor* visitor ) const
   8.569 +{
   8.570 +    if ( visitor->VisitEnter( *this ) ) {
   8.571 +        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
   8.572 +            if ( !node->Accept( visitor ) ) {
   8.573 +                break;
   8.574 +            }
   8.575 +        }
   8.576 +    }
   8.577 +    return visitor->VisitExit( *this );
   8.578 +}
   8.579 +
   8.580 +
   8.581 +// --------- XMLNode ----------- //
   8.582 +
   8.583 +XMLNode::XMLNode( XMLDocument* doc ) :
   8.584 +    _document( doc ),
   8.585 +    _parent( 0 ),
   8.586 +    _firstChild( 0 ), _lastChild( 0 ),
   8.587 +    _prev( 0 ), _next( 0 ),
   8.588 +    _memPool( 0 )
   8.589 +{
   8.590 +}
   8.591 +
   8.592 +
   8.593 +XMLNode::~XMLNode()
   8.594 +{
   8.595 +    DeleteChildren();
   8.596 +    if ( _parent ) {
   8.597 +        _parent->Unlink( this );
   8.598 +    }
   8.599 +}
   8.600 +
   8.601 +
   8.602 +void XMLNode::SetValue( const char* str, bool staticMem )
   8.603 +{
   8.604 +    if ( staticMem ) {
   8.605 +        _value.SetInternedStr( str );
   8.606 +    }
   8.607 +    else {
   8.608 +        _value.SetStr( str );
   8.609 +    }
   8.610 +}
   8.611 +
   8.612 +
   8.613 +void XMLNode::DeleteChildren()
   8.614 +{
   8.615 +    while( _firstChild ) {
   8.616 +        XMLNode* node = _firstChild;
   8.617 +        Unlink( node );
   8.618 +
   8.619 +        DELETE_NODE( node );
   8.620 +    }
   8.621 +    _firstChild = _lastChild = 0;
   8.622 +}
   8.623 +
   8.624 +
   8.625 +void XMLNode::Unlink( XMLNode* child )
   8.626 +{
   8.627 +    TIXMLASSERT( child->_parent == this );
   8.628 +    if ( child == _firstChild ) {
   8.629 +        _firstChild = _firstChild->_next;
   8.630 +    }
   8.631 +    if ( child == _lastChild ) {
   8.632 +        _lastChild = _lastChild->_prev;
   8.633 +    }
   8.634 +
   8.635 +    if ( child->_prev ) {
   8.636 +        child->_prev->_next = child->_next;
   8.637 +    }
   8.638 +    if ( child->_next ) {
   8.639 +        child->_next->_prev = child->_prev;
   8.640 +    }
   8.641 +    child->_parent = 0;
   8.642 +}
   8.643 +
   8.644 +
   8.645 +void XMLNode::DeleteChild( XMLNode* node )
   8.646 +{
   8.647 +    TIXMLASSERT( node->_parent == this );
   8.648 +    DELETE_NODE( node );
   8.649 +}
   8.650 +
   8.651 +
   8.652 +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
   8.653 +{
   8.654 +    if ( _lastChild ) {
   8.655 +        TIXMLASSERT( _firstChild );
   8.656 +        TIXMLASSERT( _lastChild->_next == 0 );
   8.657 +        _lastChild->_next = addThis;
   8.658 +        addThis->_prev = _lastChild;
   8.659 +        _lastChild = addThis;
   8.660 +
   8.661 +        addThis->_next = 0;
   8.662 +    }
   8.663 +    else {
   8.664 +        TIXMLASSERT( _firstChild == 0 );
   8.665 +        _firstChild = _lastChild = addThis;
   8.666 +
   8.667 +        addThis->_prev = 0;
   8.668 +        addThis->_next = 0;
   8.669 +    }
   8.670 +    addThis->_parent = this;
   8.671 +    addThis->_memPool->SetTracked();
   8.672 +    return addThis;
   8.673 +}
   8.674 +
   8.675 +
   8.676 +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
   8.677 +{
   8.678 +    if ( _firstChild ) {
   8.679 +        TIXMLASSERT( _lastChild );
   8.680 +        TIXMLASSERT( _firstChild->_prev == 0 );
   8.681 +
   8.682 +        _firstChild->_prev = addThis;
   8.683 +        addThis->_next = _firstChild;
   8.684 +        _firstChild = addThis;
   8.685 +
   8.686 +        addThis->_prev = 0;
   8.687 +    }
   8.688 +    else {
   8.689 +        TIXMLASSERT( _lastChild == 0 );
   8.690 +        _firstChild = _lastChild = addThis;
   8.691 +
   8.692 +        addThis->_prev = 0;
   8.693 +        addThis->_next = 0;
   8.694 +    }
   8.695 +    addThis->_parent = this;
   8.696 +    addThis->_memPool->SetTracked();
   8.697 +    return addThis;
   8.698 +}
   8.699 +
   8.700 +
   8.701 +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
   8.702 +{
   8.703 +    TIXMLASSERT( afterThis->_parent == this );
   8.704 +    if ( afterThis->_parent != this ) {
   8.705 +        return 0;
   8.706 +    }
   8.707 +
   8.708 +    if ( afterThis->_next == 0 ) {
   8.709 +        // The last node or the only node.
   8.710 +        return InsertEndChild( addThis );
   8.711 +    }
   8.712 +    addThis->_prev = afterThis;
   8.713 +    addThis->_next = afterThis->_next;
   8.714 +    afterThis->_next->_prev = addThis;
   8.715 +    afterThis->_next = addThis;
   8.716 +    addThis->_parent = this;
   8.717 +    addThis->_memPool->SetTracked();
   8.718 +    return addThis;
   8.719 +}
   8.720 +
   8.721 +
   8.722 +
   8.723 +
   8.724 +const XMLElement* XMLNode::FirstChildElement( const char* value ) const
   8.725 +{
   8.726 +    for( XMLNode* node=_firstChild; node; node=node->_next ) {
   8.727 +        XMLElement* element = node->ToElement();
   8.728 +        if ( element ) {
   8.729 +            if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
   8.730 +                return element;
   8.731 +            }
   8.732 +        }
   8.733 +    }
   8.734 +    return 0;
   8.735 +}
   8.736 +
   8.737 +
   8.738 +const XMLElement* XMLNode::LastChildElement( const char* value ) const
   8.739 +{
   8.740 +    for( XMLNode* node=_lastChild; node; node=node->_prev ) {
   8.741 +        XMLElement* element = node->ToElement();
   8.742 +        if ( element ) {
   8.743 +            if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
   8.744 +                return element;
   8.745 +            }
   8.746 +        }
   8.747 +    }
   8.748 +    return 0;
   8.749 +}
   8.750 +
   8.751 +
   8.752 +const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
   8.753 +{
   8.754 +    for( XMLNode* element=this->_next; element; element = element->_next ) {
   8.755 +        if (    element->ToElement()
   8.756 +                && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
   8.757 +            return element->ToElement();
   8.758 +        }
   8.759 +    }
   8.760 +    return 0;
   8.761 +}
   8.762 +
   8.763 +
   8.764 +const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
   8.765 +{
   8.766 +    for( XMLNode* element=_prev; element; element = element->_prev ) {
   8.767 +        if (    element->ToElement()
   8.768 +                && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
   8.769 +            return element->ToElement();
   8.770 +        }
   8.771 +    }
   8.772 +    return 0;
   8.773 +}
   8.774 +
   8.775 +
   8.776 +char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
   8.777 +{
   8.778 +    // This is a recursive method, but thinking about it "at the current level"
   8.779 +    // it is a pretty simple flat list:
   8.780 +    //		<foo/>
   8.781 +    //		<!-- comment -->
   8.782 +    //
   8.783 +    // With a special case:
   8.784 +    //		<foo>
   8.785 +    //		</foo>
   8.786 +    //		<!-- comment -->
   8.787 +    //
   8.788 +    // Where the closing element (/foo) *must* be the next thing after the opening
   8.789 +    // element, and the names must match. BUT the tricky bit is that the closing
   8.790 +    // element will be read by the child.
   8.791 +    //
   8.792 +    // 'endTag' is the end tag for this node, it is returned by a call to a child.
   8.793 +    // 'parentEnd' is the end tag for the parent, which is filled in and returned.
   8.794 +
   8.795 +    while( p && *p ) {
   8.796 +        XMLNode* node = 0;
   8.797 +
   8.798 +        p = _document->Identify( p, &node );
   8.799 +        if ( p == 0 || node == 0 ) {
   8.800 +            break;
   8.801 +        }
   8.802 +
   8.803 +        StrPair endTag;
   8.804 +        p = node->ParseDeep( p, &endTag );
   8.805 +        if ( !p ) {
   8.806 +            DELETE_NODE( node );
   8.807 +            node = 0;
   8.808 +            if ( !_document->Error() ) {
   8.809 +                _document->SetError( XML_ERROR_PARSING, 0, 0 );
   8.810 +            }
   8.811 +            break;
   8.812 +        }
   8.813 +
   8.814 +        // We read the end tag. Return it to the parent.
   8.815 +        if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
   8.816 +            if ( parentEnd ) {
   8.817 +                *parentEnd = static_cast<XMLElement*>(node)->_value;
   8.818 +            }
   8.819 +			node->_memPool->SetTracked();	// created and then immediately deleted.
   8.820 +            DELETE_NODE( node );
   8.821 +            return p;
   8.822 +        }
   8.823 +
   8.824 +        // Handle an end tag returned to this level.
   8.825 +        // And handle a bunch of annoying errors.
   8.826 +        XMLElement* ele = node->ToElement();
   8.827 +        if ( ele ) {
   8.828 +            if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
   8.829 +                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
   8.830 +                p = 0;
   8.831 +            }
   8.832 +            else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
   8.833 +                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
   8.834 +                p = 0;
   8.835 +            }
   8.836 +            else if ( !endTag.Empty() ) {
   8.837 +                if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
   8.838 +                    _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
   8.839 +                    p = 0;
   8.840 +                }
   8.841 +            }
   8.842 +        }
   8.843 +        if ( p == 0 ) {
   8.844 +            DELETE_NODE( node );
   8.845 +            node = 0;
   8.846 +        }
   8.847 +        if ( node ) {
   8.848 +            this->InsertEndChild( node );
   8.849 +        }
   8.850 +    }
   8.851 +    return 0;
   8.852 +}
   8.853 +
   8.854 +// --------- XMLText ---------- //
   8.855 +char* XMLText::ParseDeep( char* p, StrPair* )
   8.856 +{
   8.857 +    const char* start = p;
   8.858 +    if ( this->CData() ) {
   8.859 +        p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
   8.860 +        if ( !p ) {
   8.861 +            _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
   8.862 +        }
   8.863 +        return p;
   8.864 +    }
   8.865 +    else {
   8.866 +        int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
   8.867 +        if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
   8.868 +            flags |= StrPair::COLLAPSE_WHITESPACE;
   8.869 +        }
   8.870 +
   8.871 +        p = _value.ParseText( p, "<", flags );
   8.872 +        if ( !p ) {
   8.873 +            _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
   8.874 +        }
   8.875 +        if ( p && *p ) {
   8.876 +            return p-1;
   8.877 +        }
   8.878 +    }
   8.879 +    return 0;
   8.880 +}
   8.881 +
   8.882 +
   8.883 +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
   8.884 +{
   8.885 +    if ( !doc ) {
   8.886 +        doc = _document;
   8.887 +    }
   8.888 +    XMLText* text = doc->NewText( Value() );	// fixme: this will always allocate memory. Intern?
   8.889 +    text->SetCData( this->CData() );
   8.890 +    return text;
   8.891 +}
   8.892 +
   8.893 +
   8.894 +bool XMLText::ShallowEqual( const XMLNode* compare ) const
   8.895 +{
   8.896 +    return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
   8.897 +}
   8.898 +
   8.899 +
   8.900 +bool XMLText::Accept( XMLVisitor* visitor ) const
   8.901 +{
   8.902 +    return visitor->Visit( *this );
   8.903 +}
   8.904 +
   8.905 +
   8.906 +// --------- XMLComment ---------- //
   8.907 +
   8.908 +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
   8.909 +{
   8.910 +}
   8.911 +
   8.912 +
   8.913 +XMLComment::~XMLComment()
   8.914 +{
   8.915 +}
   8.916 +
   8.917 +
   8.918 +char* XMLComment::ParseDeep( char* p, StrPair* )
   8.919 +{
   8.920 +    // Comment parses as text.
   8.921 +    const char* start = p;
   8.922 +    p = _value.ParseText( p, "-->", StrPair::COMMENT );
   8.923 +    if ( p == 0 ) {
   8.924 +        _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
   8.925 +    }
   8.926 +    return p;
   8.927 +}
   8.928 +
   8.929 +
   8.930 +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
   8.931 +{
   8.932 +    if ( !doc ) {
   8.933 +        doc = _document;
   8.934 +    }
   8.935 +    XMLComment* comment = doc->NewComment( Value() );	// fixme: this will always allocate memory. Intern?
   8.936 +    return comment;
   8.937 +}
   8.938 +
   8.939 +
   8.940 +bool XMLComment::ShallowEqual( const XMLNode* compare ) const
   8.941 +{
   8.942 +    return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
   8.943 +}
   8.944 +
   8.945 +
   8.946 +bool XMLComment::Accept( XMLVisitor* visitor ) const
   8.947 +{
   8.948 +    return visitor->Visit( *this );
   8.949 +}
   8.950 +
   8.951 +
   8.952 +// --------- XMLDeclaration ---------- //
   8.953 +
   8.954 +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
   8.955 +{
   8.956 +}
   8.957 +
   8.958 +
   8.959 +XMLDeclaration::~XMLDeclaration()
   8.960 +{
   8.961 +    //printf( "~XMLDeclaration\n" );
   8.962 +}
   8.963 +
   8.964 +
   8.965 +char* XMLDeclaration::ParseDeep( char* p, StrPair* )
   8.966 +{
   8.967 +    // Declaration parses as text.
   8.968 +    const char* start = p;
   8.969 +    p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
   8.970 +    if ( p == 0 ) {
   8.971 +        _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
   8.972 +    }
   8.973 +    return p;
   8.974 +}
   8.975 +
   8.976 +
   8.977 +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
   8.978 +{
   8.979 +    if ( !doc ) {
   8.980 +        doc = _document;
   8.981 +    }
   8.982 +    XMLDeclaration* dec = doc->NewDeclaration( Value() );	// fixme: this will always allocate memory. Intern?
   8.983 +    return dec;
   8.984 +}
   8.985 +
   8.986 +
   8.987 +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
   8.988 +{
   8.989 +    return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
   8.990 +}
   8.991 +
   8.992 +
   8.993 +
   8.994 +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
   8.995 +{
   8.996 +    return visitor->Visit( *this );
   8.997 +}
   8.998 +
   8.999 +// --------- XMLUnknown ---------- //
  8.1000 +
  8.1001 +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
  8.1002 +{
  8.1003 +}
  8.1004 +
  8.1005 +
  8.1006 +XMLUnknown::~XMLUnknown()
  8.1007 +{
  8.1008 +}
  8.1009 +
  8.1010 +
  8.1011 +char* XMLUnknown::ParseDeep( char* p, StrPair* )
  8.1012 +{
  8.1013 +    // Unknown parses as text.
  8.1014 +    const char* start = p;
  8.1015 +
  8.1016 +    p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
  8.1017 +    if ( !p ) {
  8.1018 +        _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
  8.1019 +    }
  8.1020 +    return p;
  8.1021 +}
  8.1022 +
  8.1023 +
  8.1024 +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
  8.1025 +{
  8.1026 +    if ( !doc ) {
  8.1027 +        doc = _document;
  8.1028 +    }
  8.1029 +    XMLUnknown* text = doc->NewUnknown( Value() );	// fixme: this will always allocate memory. Intern?
  8.1030 +    return text;
  8.1031 +}
  8.1032 +
  8.1033 +
  8.1034 +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
  8.1035 +{
  8.1036 +    return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
  8.1037 +}
  8.1038 +
  8.1039 +
  8.1040 +bool XMLUnknown::Accept( XMLVisitor* visitor ) const
  8.1041 +{
  8.1042 +    return visitor->Visit( *this );
  8.1043 +}
  8.1044 +
  8.1045 +// --------- XMLAttribute ---------- //
  8.1046 +char* XMLAttribute::ParseDeep( char* p, bool processEntities )
  8.1047 +{
  8.1048 +    // Parse using the name rules: bug fix, was using ParseText before
  8.1049 +    p = _name.ParseName( p );
  8.1050 +    if ( !p || !*p ) {
  8.1051 +        return 0;
  8.1052 +    }
  8.1053 +
  8.1054 +    // Skip white space before =
  8.1055 +    p = XMLUtil::SkipWhiteSpace( p );
  8.1056 +    if ( !p || *p != '=' ) {
  8.1057 +        return 0;
  8.1058 +    }
  8.1059 +
  8.1060 +    ++p;	// move up to opening quote
  8.1061 +    p = XMLUtil::SkipWhiteSpace( p );
  8.1062 +    if ( *p != '\"' && *p != '\'' ) {
  8.1063 +        return 0;
  8.1064 +    }
  8.1065 +
  8.1066 +    char endTag[2] = { *p, 0 };
  8.1067 +    ++p;	// move past opening quote
  8.1068 +
  8.1069 +    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
  8.1070 +    return p;
  8.1071 +}
  8.1072 +
  8.1073 +
  8.1074 +void XMLAttribute::SetName( const char* n )
  8.1075 +{
  8.1076 +    _name.SetStr( n );
  8.1077 +}
  8.1078 +
  8.1079 +
  8.1080 +XMLError XMLAttribute::QueryIntValue( int* value ) const
  8.1081 +{
  8.1082 +    if ( XMLUtil::ToInt( Value(), value )) {
  8.1083 +        return XML_NO_ERROR;
  8.1084 +    }
  8.1085 +    return XML_WRONG_ATTRIBUTE_TYPE;
  8.1086 +}
  8.1087 +
  8.1088 +
  8.1089 +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
  8.1090 +{
  8.1091 +    if ( XMLUtil::ToUnsigned( Value(), value )) {
  8.1092 +        return XML_NO_ERROR;
  8.1093 +    }
  8.1094 +    return XML_WRONG_ATTRIBUTE_TYPE;
  8.1095 +}
  8.1096 +
  8.1097 +
  8.1098 +XMLError XMLAttribute::QueryBoolValue( bool* value ) const
  8.1099 +{
  8.1100 +    if ( XMLUtil::ToBool( Value(), value )) {
  8.1101 +        return XML_NO_ERROR;
  8.1102 +    }
  8.1103 +    return XML_WRONG_ATTRIBUTE_TYPE;
  8.1104 +}
  8.1105 +
  8.1106 +
  8.1107 +XMLError XMLAttribute::QueryFloatValue( float* value ) const
  8.1108 +{
  8.1109 +    if ( XMLUtil::ToFloat( Value(), value )) {
  8.1110 +        return XML_NO_ERROR;
  8.1111 +    }
  8.1112 +    return XML_WRONG_ATTRIBUTE_TYPE;
  8.1113 +}
  8.1114 +
  8.1115 +
  8.1116 +XMLError XMLAttribute::QueryDoubleValue( double* value ) const
  8.1117 +{
  8.1118 +    if ( XMLUtil::ToDouble( Value(), value )) {
  8.1119 +        return XML_NO_ERROR;
  8.1120 +    }
  8.1121 +    return XML_WRONG_ATTRIBUTE_TYPE;
  8.1122 +}
  8.1123 +
  8.1124 +
  8.1125 +void XMLAttribute::SetAttribute( const char* v )
  8.1126 +{
  8.1127 +    _value.SetStr( v );
  8.1128 +}
  8.1129 +
  8.1130 +
  8.1131 +void XMLAttribute::SetAttribute( int v )
  8.1132 +{
  8.1133 +    char buf[BUF_SIZE];
  8.1134 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1135 +    _value.SetStr( buf );
  8.1136 +}
  8.1137 +
  8.1138 +
  8.1139 +void XMLAttribute::SetAttribute( unsigned v )
  8.1140 +{
  8.1141 +    char buf[BUF_SIZE];
  8.1142 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1143 +    _value.SetStr( buf );
  8.1144 +}
  8.1145 +
  8.1146 +
  8.1147 +void XMLAttribute::SetAttribute( bool v )
  8.1148 +{
  8.1149 +    char buf[BUF_SIZE];
  8.1150 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1151 +    _value.SetStr( buf );
  8.1152 +}
  8.1153 +
  8.1154 +void XMLAttribute::SetAttribute( double v )
  8.1155 +{
  8.1156 +    char buf[BUF_SIZE];
  8.1157 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1158 +    _value.SetStr( buf );
  8.1159 +}
  8.1160 +
  8.1161 +void XMLAttribute::SetAttribute( float v )
  8.1162 +{
  8.1163 +    char buf[BUF_SIZE];
  8.1164 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1165 +    _value.SetStr( buf );
  8.1166 +}
  8.1167 +
  8.1168 +
  8.1169 +// --------- XMLElement ---------- //
  8.1170 +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
  8.1171 +    _closingType( 0 ),
  8.1172 +    _rootAttribute( 0 )
  8.1173 +{
  8.1174 +}
  8.1175 +
  8.1176 +
  8.1177 +XMLElement::~XMLElement()
  8.1178 +{
  8.1179 +    while( _rootAttribute ) {
  8.1180 +        XMLAttribute* next = _rootAttribute->_next;
  8.1181 +        DELETE_ATTRIBUTE( _rootAttribute );
  8.1182 +        _rootAttribute = next;
  8.1183 +    }
  8.1184 +}
  8.1185 +
  8.1186 +
  8.1187 +XMLAttribute* XMLElement::FindAttribute( const char* name )
  8.1188 +{
  8.1189 +    XMLAttribute* a = 0;
  8.1190 +    for( a=_rootAttribute; a; a = a->_next ) {
  8.1191 +        if ( XMLUtil::StringEqual( a->Name(), name ) ) {
  8.1192 +            return a;
  8.1193 +        }
  8.1194 +    }
  8.1195 +    return 0;
  8.1196 +}
  8.1197 +
  8.1198 +
  8.1199 +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
  8.1200 +{
  8.1201 +    XMLAttribute* a = 0;
  8.1202 +    for( a=_rootAttribute; a; a = a->_next ) {
  8.1203 +        if ( XMLUtil::StringEqual( a->Name(), name ) ) {
  8.1204 +            return a;
  8.1205 +        }
  8.1206 +    }
  8.1207 +    return 0;
  8.1208 +}
  8.1209 +
  8.1210 +
  8.1211 +const char* XMLElement::Attribute( const char* name, const char* value ) const
  8.1212 +{
  8.1213 +    const XMLAttribute* a = FindAttribute( name );
  8.1214 +    if ( !a ) {
  8.1215 +        return 0;
  8.1216 +    }
  8.1217 +    if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
  8.1218 +        return a->Value();
  8.1219 +    }
  8.1220 +    return 0;
  8.1221 +}
  8.1222 +
  8.1223 +
  8.1224 +const char* XMLElement::GetText() const
  8.1225 +{
  8.1226 +    if ( FirstChild() && FirstChild()->ToText() ) {
  8.1227 +        return FirstChild()->ToText()->Value();
  8.1228 +    }
  8.1229 +    return 0;
  8.1230 +}
  8.1231 +
  8.1232 +
  8.1233 +XMLError XMLElement::QueryIntText( int* ival ) const
  8.1234 +{
  8.1235 +    if ( FirstChild() && FirstChild()->ToText() ) {
  8.1236 +        const char* t = FirstChild()->ToText()->Value();
  8.1237 +        if ( XMLUtil::ToInt( t, ival ) ) {
  8.1238 +            return XML_SUCCESS;
  8.1239 +        }
  8.1240 +        return XML_CAN_NOT_CONVERT_TEXT;
  8.1241 +    }
  8.1242 +    return XML_NO_TEXT_NODE;
  8.1243 +}
  8.1244 +
  8.1245 +
  8.1246 +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
  8.1247 +{
  8.1248 +    if ( FirstChild() && FirstChild()->ToText() ) {
  8.1249 +        const char* t = FirstChild()->ToText()->Value();
  8.1250 +        if ( XMLUtil::ToUnsigned( t, uval ) ) {
  8.1251 +            return XML_SUCCESS;
  8.1252 +        }
  8.1253 +        return XML_CAN_NOT_CONVERT_TEXT;
  8.1254 +    }
  8.1255 +    return XML_NO_TEXT_NODE;
  8.1256 +}
  8.1257 +
  8.1258 +
  8.1259 +XMLError XMLElement::QueryBoolText( bool* bval ) const
  8.1260 +{
  8.1261 +    if ( FirstChild() && FirstChild()->ToText() ) {
  8.1262 +        const char* t = FirstChild()->ToText()->Value();
  8.1263 +        if ( XMLUtil::ToBool( t, bval ) ) {
  8.1264 +            return XML_SUCCESS;
  8.1265 +        }
  8.1266 +        return XML_CAN_NOT_CONVERT_TEXT;
  8.1267 +    }
  8.1268 +    return XML_NO_TEXT_NODE;
  8.1269 +}
  8.1270 +
  8.1271 +
  8.1272 +XMLError XMLElement::QueryDoubleText( double* dval ) const
  8.1273 +{
  8.1274 +    if ( FirstChild() && FirstChild()->ToText() ) {
  8.1275 +        const char* t = FirstChild()->ToText()->Value();
  8.1276 +        if ( XMLUtil::ToDouble( t, dval ) ) {
  8.1277 +            return XML_SUCCESS;
  8.1278 +        }
  8.1279 +        return XML_CAN_NOT_CONVERT_TEXT;
  8.1280 +    }
  8.1281 +    return XML_NO_TEXT_NODE;
  8.1282 +}
  8.1283 +
  8.1284 +
  8.1285 +XMLError XMLElement::QueryFloatText( float* fval ) const
  8.1286 +{
  8.1287 +    if ( FirstChild() && FirstChild()->ToText() ) {
  8.1288 +        const char* t = FirstChild()->ToText()->Value();
  8.1289 +        if ( XMLUtil::ToFloat( t, fval ) ) {
  8.1290 +            return XML_SUCCESS;
  8.1291 +        }
  8.1292 +        return XML_CAN_NOT_CONVERT_TEXT;
  8.1293 +    }
  8.1294 +    return XML_NO_TEXT_NODE;
  8.1295 +}
  8.1296 +
  8.1297 +
  8.1298 +
  8.1299 +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
  8.1300 +{
  8.1301 +    XMLAttribute* last = 0;
  8.1302 +    XMLAttribute* attrib = 0;
  8.1303 +    for( attrib = _rootAttribute;
  8.1304 +            attrib;
  8.1305 +            last = attrib, attrib = attrib->_next ) {
  8.1306 +        if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
  8.1307 +            break;
  8.1308 +        }
  8.1309 +    }
  8.1310 +    if ( !attrib ) {
  8.1311 +        attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
  8.1312 +        attrib->_memPool = &_document->_attributePool;
  8.1313 +        if ( last ) {
  8.1314 +            last->_next = attrib;
  8.1315 +        }
  8.1316 +        else {
  8.1317 +            _rootAttribute = attrib;
  8.1318 +        }
  8.1319 +        attrib->SetName( name );
  8.1320 +        attrib->_memPool->SetTracked(); // always created and linked.
  8.1321 +    }
  8.1322 +    return attrib;
  8.1323 +}
  8.1324 +
  8.1325 +
  8.1326 +void XMLElement::DeleteAttribute( const char* name )
  8.1327 +{
  8.1328 +    XMLAttribute* prev = 0;
  8.1329 +    for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
  8.1330 +        if ( XMLUtil::StringEqual( name, a->Name() ) ) {
  8.1331 +            if ( prev ) {
  8.1332 +                prev->_next = a->_next;
  8.1333 +            }
  8.1334 +            else {
  8.1335 +                _rootAttribute = a->_next;
  8.1336 +            }
  8.1337 +            DELETE_ATTRIBUTE( a );
  8.1338 +            break;
  8.1339 +        }
  8.1340 +        prev = a;
  8.1341 +    }
  8.1342 +}
  8.1343 +
  8.1344 +
  8.1345 +char* XMLElement::ParseAttributes( char* p )
  8.1346 +{
  8.1347 +    const char* start = p;
  8.1348 +    XMLAttribute* prevAttribute = 0;
  8.1349 +
  8.1350 +    // Read the attributes.
  8.1351 +    while( p ) {
  8.1352 +        p = XMLUtil::SkipWhiteSpace( p );
  8.1353 +        if ( !p || !(*p) ) {
  8.1354 +            _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
  8.1355 +            return 0;
  8.1356 +        }
  8.1357 +
  8.1358 +        // attribute.
  8.1359 +        if (XMLUtil::IsNameStartChar( *p ) ) {
  8.1360 +            XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
  8.1361 +            attrib->_memPool = &_document->_attributePool;
  8.1362 +			attrib->_memPool->SetTracked();
  8.1363 +
  8.1364 +            p = attrib->ParseDeep( p, _document->ProcessEntities() );
  8.1365 +            if ( !p || Attribute( attrib->Name() ) ) {
  8.1366 +                DELETE_ATTRIBUTE( attrib );
  8.1367 +                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
  8.1368 +                return 0;
  8.1369 +            }
  8.1370 +            // There is a minor bug here: if the attribute in the source xml
  8.1371 +            // document is duplicated, it will not be detected and the
  8.1372 +            // attribute will be doubly added. However, tracking the 'prevAttribute'
  8.1373 +            // avoids re-scanning the attribute list. Preferring performance for
  8.1374 +            // now, may reconsider in the future.
  8.1375 +            if ( prevAttribute ) {
  8.1376 +                prevAttribute->_next = attrib;
  8.1377 +            }
  8.1378 +            else {
  8.1379 +                _rootAttribute = attrib;
  8.1380 +            }
  8.1381 +            prevAttribute = attrib;
  8.1382 +        }
  8.1383 +        // end of the tag
  8.1384 +        else if ( *p == '/' && *(p+1) == '>' ) {
  8.1385 +            _closingType = CLOSED;
  8.1386 +            return p+2;	// done; sealed element.
  8.1387 +        }
  8.1388 +        // end of the tag
  8.1389 +        else if ( *p == '>' ) {
  8.1390 +            ++p;
  8.1391 +            break;
  8.1392 +        }
  8.1393 +        else {
  8.1394 +            _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
  8.1395 +            return 0;
  8.1396 +        }
  8.1397 +    }
  8.1398 +    return p;
  8.1399 +}
  8.1400 +
  8.1401 +
  8.1402 +//
  8.1403 +//	<ele></ele>
  8.1404 +//	<ele>foo<b>bar</b></ele>
  8.1405 +//
  8.1406 +char* XMLElement::ParseDeep( char* p, StrPair* strPair )
  8.1407 +{
  8.1408 +    // Read the element name.
  8.1409 +    p = XMLUtil::SkipWhiteSpace( p );
  8.1410 +    if ( !p ) {
  8.1411 +        return 0;
  8.1412 +    }
  8.1413 +
  8.1414 +    // The closing element is the </element> form. It is
  8.1415 +    // parsed just like a regular element then deleted from
  8.1416 +    // the DOM.
  8.1417 +    if ( *p == '/' ) {
  8.1418 +        _closingType = CLOSING;
  8.1419 +        ++p;
  8.1420 +    }
  8.1421 +
  8.1422 +    p = _value.ParseName( p );
  8.1423 +    if ( _value.Empty() ) {
  8.1424 +        return 0;
  8.1425 +    }
  8.1426 +
  8.1427 +    p = ParseAttributes( p );
  8.1428 +    if ( !p || !*p || _closingType ) {
  8.1429 +        return p;
  8.1430 +    }
  8.1431 +
  8.1432 +    p = XMLNode::ParseDeep( p, strPair );
  8.1433 +    return p;
  8.1434 +}
  8.1435 +
  8.1436 +
  8.1437 +
  8.1438 +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
  8.1439 +{
  8.1440 +    if ( !doc ) {
  8.1441 +        doc = _document;
  8.1442 +    }
  8.1443 +    XMLElement* element = doc->NewElement( Value() );					// fixme: this will always allocate memory. Intern?
  8.1444 +    for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
  8.1445 +        element->SetAttribute( a->Name(), a->Value() );					// fixme: this will always allocate memory. Intern?
  8.1446 +    }
  8.1447 +    return element;
  8.1448 +}
  8.1449 +
  8.1450 +
  8.1451 +bool XMLElement::ShallowEqual( const XMLNode* compare ) const
  8.1452 +{
  8.1453 +    const XMLElement* other = compare->ToElement();
  8.1454 +    if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
  8.1455 +
  8.1456 +        const XMLAttribute* a=FirstAttribute();
  8.1457 +        const XMLAttribute* b=other->FirstAttribute();
  8.1458 +
  8.1459 +        while ( a && b ) {
  8.1460 +            if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
  8.1461 +                return false;
  8.1462 +            }
  8.1463 +            a = a->Next();
  8.1464 +            b = b->Next();
  8.1465 +        }
  8.1466 +        if ( a || b ) {
  8.1467 +            // different count
  8.1468 +            return false;
  8.1469 +        }
  8.1470 +        return true;
  8.1471 +    }
  8.1472 +    return false;
  8.1473 +}
  8.1474 +
  8.1475 +
  8.1476 +bool XMLElement::Accept( XMLVisitor* visitor ) const
  8.1477 +{
  8.1478 +    if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
  8.1479 +        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
  8.1480 +            if ( !node->Accept( visitor ) ) {
  8.1481 +                break;
  8.1482 +            }
  8.1483 +        }
  8.1484 +    }
  8.1485 +    return visitor->VisitExit( *this );
  8.1486 +}
  8.1487 +
  8.1488 +
  8.1489 +// --------- XMLDocument ----------- //
  8.1490 +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
  8.1491 +    XMLNode( 0 ),
  8.1492 +    _writeBOM( false ),
  8.1493 +    _processEntities( processEntities ),
  8.1494 +    _errorID( XML_NO_ERROR ),
  8.1495 +    _whitespace( whitespace ),
  8.1496 +    _errorStr1( 0 ),
  8.1497 +    _errorStr2( 0 ),
  8.1498 +    _charBuffer( 0 )
  8.1499 +{
  8.1500 +    _document = this;	// avoid warning about 'this' in initializer list
  8.1501 +}
  8.1502 +
  8.1503 +
  8.1504 +XMLDocument::~XMLDocument()
  8.1505 +{
  8.1506 +    DeleteChildren();
  8.1507 +    delete [] _charBuffer;
  8.1508 +
  8.1509 +#if 0
  8.1510 +    _textPool.Trace( "text" );
  8.1511 +    _elementPool.Trace( "element" );
  8.1512 +    _commentPool.Trace( "comment" );
  8.1513 +    _attributePool.Trace( "attribute" );
  8.1514 +#endif
  8.1515 +
  8.1516 +#ifdef DEBUG
  8.1517 +	if ( Error() == false ) {
  8.1518 +		TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
  8.1519 +		TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
  8.1520 +		TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
  8.1521 +		TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
  8.1522 +	}
  8.1523 +#endif
  8.1524 +}
  8.1525 +
  8.1526 +
  8.1527 +void XMLDocument::Clear()
  8.1528 +{
  8.1529 +    DeleteChildren();
  8.1530 +
  8.1531 +    _errorID = XML_NO_ERROR;
  8.1532 +    _errorStr1 = 0;
  8.1533 +    _errorStr2 = 0;
  8.1534 +
  8.1535 +    delete [] _charBuffer;
  8.1536 +    _charBuffer = 0;
  8.1537 +}
  8.1538 +
  8.1539 +
  8.1540 +XMLElement* XMLDocument::NewElement( const char* name )
  8.1541 +{
  8.1542 +    XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
  8.1543 +    ele->_memPool = &_elementPool;
  8.1544 +    ele->SetName( name );
  8.1545 +    return ele;
  8.1546 +}
  8.1547 +
  8.1548 +
  8.1549 +XMLComment* XMLDocument::NewComment( const char* str )
  8.1550 +{
  8.1551 +    XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
  8.1552 +    comment->_memPool = &_commentPool;
  8.1553 +    comment->SetValue( str );
  8.1554 +    return comment;
  8.1555 +}
  8.1556 +
  8.1557 +
  8.1558 +XMLText* XMLDocument::NewText( const char* str )
  8.1559 +{
  8.1560 +    XMLText* text = new (_textPool.Alloc()) XMLText( this );
  8.1561 +    text->_memPool = &_textPool;
  8.1562 +    text->SetValue( str );
  8.1563 +    return text;
  8.1564 +}
  8.1565 +
  8.1566 +
  8.1567 +XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
  8.1568 +{
  8.1569 +    XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
  8.1570 +    dec->_memPool = &_commentPool;
  8.1571 +    dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
  8.1572 +    return dec;
  8.1573 +}
  8.1574 +
  8.1575 +
  8.1576 +XMLUnknown* XMLDocument::NewUnknown( const char* str )
  8.1577 +{
  8.1578 +    XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
  8.1579 +    unk->_memPool = &_commentPool;
  8.1580 +    unk->SetValue( str );
  8.1581 +    return unk;
  8.1582 +}
  8.1583 +
  8.1584 +
  8.1585 +XMLError XMLDocument::LoadFile( const char* filename )
  8.1586 +{
  8.1587 +    Clear();
  8.1588 +    FILE* fp = 0;
  8.1589 +
  8.1590 +#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
  8.1591 +    errno_t err = fopen_s(&fp, filename, "rb" );
  8.1592 +    if ( !fp || err) {
  8.1593 +#else
  8.1594 +    fp = fopen( filename, "rb" );
  8.1595 +    if ( !fp) {
  8.1596 +#endif
  8.1597 +        SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
  8.1598 +        return _errorID;
  8.1599 +    }
  8.1600 +    LoadFile( fp );
  8.1601 +    fclose( fp );
  8.1602 +    return _errorID;
  8.1603 +}
  8.1604 +
  8.1605 +
  8.1606 +XMLError XMLDocument::LoadFile( FILE* fp )
  8.1607 +{
  8.1608 +    Clear();
  8.1609 +
  8.1610 +    fseek( fp, 0, SEEK_END );
  8.1611 +    size_t size = ftell( fp );
  8.1612 +    fseek( fp, 0, SEEK_SET );
  8.1613 +
  8.1614 +    if ( size == 0 ) {
  8.1615 +        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  8.1616 +        return _errorID;
  8.1617 +    }
  8.1618 +
  8.1619 +    _charBuffer = new char[size+1];
  8.1620 +    size_t read = fread( _charBuffer, 1, size, fp );
  8.1621 +    if ( read != size ) {
  8.1622 +        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
  8.1623 +        return _errorID;
  8.1624 +    }
  8.1625 +
  8.1626 +    _charBuffer[size] = 0;
  8.1627 +
  8.1628 +    const char* p = _charBuffer;
  8.1629 +    p = XMLUtil::SkipWhiteSpace( p );
  8.1630 +    p = XMLUtil::ReadBOM( p, &_writeBOM );
  8.1631 +    if ( !p || !*p ) {
  8.1632 +        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  8.1633 +        return _errorID;
  8.1634 +    }
  8.1635 +
  8.1636 +    ParseDeep( _charBuffer + (p-_charBuffer), 0 );
  8.1637 +    return _errorID;
  8.1638 +}
  8.1639 +
  8.1640 +
  8.1641 +XMLError XMLDocument::SaveFile( const char* filename, bool compact )
  8.1642 +{
  8.1643 +    FILE* fp = 0;
  8.1644 +#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
  8.1645 +    errno_t err = fopen_s(&fp, filename, "w" );
  8.1646 +    if ( !fp || err) {
  8.1647 +#else
  8.1648 +    fp = fopen( filename, "w" );
  8.1649 +    if ( !fp) {
  8.1650 +#endif
  8.1651 +        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
  8.1652 +        return _errorID;
  8.1653 +    }
  8.1654 +    SaveFile(fp, compact);
  8.1655 +    fclose( fp );
  8.1656 +    return _errorID;
  8.1657 +}
  8.1658 +
  8.1659 +
  8.1660 +XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
  8.1661 +{
  8.1662 +    XMLPrinter stream( fp, compact );
  8.1663 +    Print( &stream );
  8.1664 +    return _errorID;
  8.1665 +}
  8.1666 +
  8.1667 +
  8.1668 +XMLError XMLDocument::Parse( const char* p, size_t len )
  8.1669 +{
  8.1670 +	const char* start = p;
  8.1671 +    Clear();
  8.1672 +
  8.1673 +    if ( !p || !*p ) {
  8.1674 +        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  8.1675 +        return _errorID;
  8.1676 +    }
  8.1677 +    if ( len == (size_t)(-1) ) {
  8.1678 +        len = strlen( p );
  8.1679 +    }
  8.1680 +    _charBuffer = new char[ len+1 ];
  8.1681 +    memcpy( _charBuffer, p, len );
  8.1682 +    _charBuffer[len] = 0;
  8.1683 +
  8.1684 +    p = XMLUtil::SkipWhiteSpace( p );
  8.1685 +    p = XMLUtil::ReadBOM( p, &_writeBOM );
  8.1686 +    if ( !p || !*p ) {
  8.1687 +        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  8.1688 +        return _errorID;
  8.1689 +    }
  8.1690 +
  8.1691 +    ptrdiff_t delta = p - start;	// skip initial whitespace, BOM, etc.
  8.1692 +    ParseDeep( _charBuffer+delta, 0 );
  8.1693 +    return _errorID;
  8.1694 +}
  8.1695 +
  8.1696 +
  8.1697 +void XMLDocument::Print( XMLPrinter* streamer ) const
  8.1698 +{
  8.1699 +    XMLPrinter stdStreamer( stdout );
  8.1700 +    if ( !streamer ) {
  8.1701 +        streamer = &stdStreamer;
  8.1702 +    }
  8.1703 +    Accept( streamer );
  8.1704 +}
  8.1705 +
  8.1706 +
  8.1707 +void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
  8.1708 +{
  8.1709 +    _errorID = error;
  8.1710 +    _errorStr1 = str1;
  8.1711 +    _errorStr2 = str2;
  8.1712 +}
  8.1713 +
  8.1714 +
  8.1715 +void XMLDocument::PrintError() const
  8.1716 +{
  8.1717 +    if ( _errorID ) {
  8.1718 +        static const int LEN = 20;
  8.1719 +        char buf1[LEN] = { 0 };
  8.1720 +        char buf2[LEN] = { 0 };
  8.1721 +
  8.1722 +        if ( _errorStr1 ) {
  8.1723 +            TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
  8.1724 +        }
  8.1725 +        if ( _errorStr2 ) {
  8.1726 +            TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
  8.1727 +        }
  8.1728 +
  8.1729 +        printf( "XMLDocument error id=%d str1=%s str2=%s\n",
  8.1730 +                _errorID, buf1, buf2 );
  8.1731 +    }
  8.1732 +}
  8.1733 +
  8.1734 +
  8.1735 +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
  8.1736 +    _elementJustOpened( false ),
  8.1737 +    _firstElement( true ),
  8.1738 +    _fp( file ),
  8.1739 +    _depth( depth ),
  8.1740 +    _textDepth( -1 ),
  8.1741 +    _processEntities( true ),
  8.1742 +    _compactMode( compact )
  8.1743 +{
  8.1744 +    for( int i=0; i<ENTITY_RANGE; ++i ) {
  8.1745 +        _entityFlag[i] = false;
  8.1746 +        _restrictedEntityFlag[i] = false;
  8.1747 +    }
  8.1748 +    for( int i=0; i<NUM_ENTITIES; ++i ) {
  8.1749 +        TIXMLASSERT( entities[i].value < ENTITY_RANGE );
  8.1750 +        if ( entities[i].value < ENTITY_RANGE ) {
  8.1751 +            _entityFlag[ (int)entities[i].value ] = true;
  8.1752 +        }
  8.1753 +    }
  8.1754 +    _restrictedEntityFlag[(int)'&'] = true;
  8.1755 +    _restrictedEntityFlag[(int)'<'] = true;
  8.1756 +    _restrictedEntityFlag[(int)'>'] = true;	// not required, but consistency is nice
  8.1757 +    _buffer.Push( 0 );
  8.1758 +}
  8.1759 +
  8.1760 +
  8.1761 +void XMLPrinter::Print( const char* format, ... )
  8.1762 +{
  8.1763 +    va_list     va;
  8.1764 +    va_start( va, format );
  8.1765 +
  8.1766 +    if ( _fp ) {
  8.1767 +        vfprintf( _fp, format, va );
  8.1768 +    }
  8.1769 +    else {
  8.1770 +        // This seems brutally complex. Haven't figured out a better
  8.1771 +        // way on windows.
  8.1772 +#ifdef _MSC_VER
  8.1773 +        int len = -1;
  8.1774 +        int expand = 1000;
  8.1775 +        while ( len < 0 ) {
  8.1776 +            len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
  8.1777 +            if ( len < 0 ) {
  8.1778 +                expand *= 3/2;
  8.1779 +                _accumulator.PushArr( expand );
  8.1780 +            }
  8.1781 +        }
  8.1782 +        char* p = _buffer.PushArr( len ) - 1;
  8.1783 +        memcpy( p, _accumulator.Mem(), len+1 );
  8.1784 +#else
  8.1785 +        int len = vsnprintf( 0, 0, format, va );
  8.1786 +        // Close out and re-start the va-args
  8.1787 +        va_end( va );
  8.1788 +        va_start( va, format );
  8.1789 +        char* p = _buffer.PushArr( len ) - 1;
  8.1790 +        vsnprintf( p, len+1, format, va );
  8.1791 +#endif
  8.1792 +    }
  8.1793 +    va_end( va );
  8.1794 +}
  8.1795 +
  8.1796 +
  8.1797 +void XMLPrinter::PrintSpace( int depth )
  8.1798 +{
  8.1799 +    for( int i=0; i<depth; ++i ) {
  8.1800 +        Print( "    " );
  8.1801 +    }
  8.1802 +}
  8.1803 +
  8.1804 +
  8.1805 +void XMLPrinter::PrintString( const char* p, bool restricted )
  8.1806 +{
  8.1807 +    // Look for runs of bytes between entities to print.
  8.1808 +    const char* q = p;
  8.1809 +    const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
  8.1810 +
  8.1811 +    if ( _processEntities ) {
  8.1812 +        while ( *q ) {
  8.1813 +            // Remember, char is sometimes signed. (How many times has that bitten me?)
  8.1814 +            if ( *q > 0 && *q < ENTITY_RANGE ) {
  8.1815 +                // Check for entities. If one is found, flush
  8.1816 +                // the stream up until the entity, write the
  8.1817 +                // entity, and keep looking.
  8.1818 +                if ( flag[(unsigned)(*q)] ) {
  8.1819 +                    while ( p < q ) {
  8.1820 +                        Print( "%c", *p );
  8.1821 +                        ++p;
  8.1822 +                    }
  8.1823 +                    for( int i=0; i<NUM_ENTITIES; ++i ) {
  8.1824 +                        if ( entities[i].value == *q ) {
  8.1825 +                            Print( "&%s;", entities[i].pattern );
  8.1826 +                            break;
  8.1827 +                        }
  8.1828 +                    }
  8.1829 +                    ++p;
  8.1830 +                }
  8.1831 +            }
  8.1832 +            ++q;
  8.1833 +        }
  8.1834 +    }
  8.1835 +    // Flush the remaining string. This will be the entire
  8.1836 +    // string if an entity wasn't found.
  8.1837 +    if ( !_processEntities || (q-p > 0) ) {
  8.1838 +        Print( "%s", p );
  8.1839 +    }
  8.1840 +}
  8.1841 +
  8.1842 +
  8.1843 +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
  8.1844 +{
  8.1845 +    if ( writeBOM ) {
  8.1846 +        static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
  8.1847 +        Print( "%s", bom );
  8.1848 +    }
  8.1849 +    if ( writeDec ) {
  8.1850 +        PushDeclaration( "xml version=\"1.0\"" );
  8.1851 +    }
  8.1852 +}
  8.1853 +
  8.1854 +
  8.1855 +void XMLPrinter::OpenElement( const char* name )
  8.1856 +{
  8.1857 +    if ( _elementJustOpened ) {
  8.1858 +        SealElement();
  8.1859 +    }
  8.1860 +    _stack.Push( name );
  8.1861 +
  8.1862 +    if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
  8.1863 +        Print( "\n" );
  8.1864 +    }
  8.1865 +    if ( !_compactMode ) {
  8.1866 +        PrintSpace( _depth );
  8.1867 +    }
  8.1868 +
  8.1869 +    Print( "<%s", name );
  8.1870 +    _elementJustOpened = true;
  8.1871 +    _firstElement = false;
  8.1872 +    ++_depth;
  8.1873 +}
  8.1874 +
  8.1875 +
  8.1876 +void XMLPrinter::PushAttribute( const char* name, const char* value )
  8.1877 +{
  8.1878 +    TIXMLASSERT( _elementJustOpened );
  8.1879 +    Print( " %s=\"", name );
  8.1880 +    PrintString( value, false );
  8.1881 +    Print( "\"" );
  8.1882 +}
  8.1883 +
  8.1884 +
  8.1885 +void XMLPrinter::PushAttribute( const char* name, int v )
  8.1886 +{
  8.1887 +    char buf[BUF_SIZE];
  8.1888 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1889 +    PushAttribute( name, buf );
  8.1890 +}
  8.1891 +
  8.1892 +
  8.1893 +void XMLPrinter::PushAttribute( const char* name, unsigned v )
  8.1894 +{
  8.1895 +    char buf[BUF_SIZE];
  8.1896 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1897 +    PushAttribute( name, buf );
  8.1898 +}
  8.1899 +
  8.1900 +
  8.1901 +void XMLPrinter::PushAttribute( const char* name, bool v )
  8.1902 +{
  8.1903 +    char buf[BUF_SIZE];
  8.1904 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1905 +    PushAttribute( name, buf );
  8.1906 +}
  8.1907 +
  8.1908 +
  8.1909 +void XMLPrinter::PushAttribute( const char* name, double v )
  8.1910 +{
  8.1911 +    char buf[BUF_SIZE];
  8.1912 +    XMLUtil::ToStr( v, buf, BUF_SIZE );
  8.1913 +    PushAttribute( name, buf );
  8.1914 +}
  8.1915 +
  8.1916 +
  8.1917 +void XMLPrinter::CloseElement()
  8.1918 +{
  8.1919 +    --_depth;
  8.1920 +    const char* name = _stack.Pop();
  8.1921 +
  8.1922 +    if ( _elementJustOpened ) {
  8.1923 +        Print( "/>" );
  8.1924 +    }
  8.1925 +    else {
  8.1926 +        if ( _textDepth < 0 && !_compactMode) {
  8.1927 +            Print( "\n" );
  8.1928 +            PrintSpace( _depth );
  8.1929 +        }
  8.1930 +        Print( "</%s>", name );
  8.1931 +    }
  8.1932 +
  8.1933 +    if ( _textDepth == _depth ) {
  8.1934 +        _textDepth = -1;
  8.1935 +    }
  8.1936 +    if ( _depth == 0 && !_compactMode) {
  8.1937 +        Print( "\n" );
  8.1938 +    }
  8.1939 +    _elementJustOpened = false;
  8.1940 +}
  8.1941 +
  8.1942 +
  8.1943 +void XMLPrinter::SealElement()
  8.1944 +{
  8.1945 +    _elementJustOpened = false;
  8.1946 +    Print( ">" );
  8.1947 +}
  8.1948 +
  8.1949 +
  8.1950 +void XMLPrinter::PushText( const char* text, bool cdata )
  8.1951 +{
  8.1952 +    _textDepth = _depth-1;
  8.1953 +
  8.1954 +    if ( _elementJustOpened ) {
  8.1955 +        SealElement();
  8.1956 +    }
  8.1957 +    if ( cdata ) {
  8.1958 +        Print( "<![CDATA[" );
  8.1959 +        Print( "%s", text );
  8.1960 +        Print( "]]>" );
  8.1961 +    }
  8.1962 +    else {
  8.1963 +        PrintString( text, true );
  8.1964 +    }
  8.1965 +}
  8.1966 +
  8.1967 +void XMLPrinter::PushText( int value )
  8.1968 +{
  8.1969 +    char buf[BUF_SIZE];
  8.1970 +    XMLUtil::ToStr( value, buf, BUF_SIZE );
  8.1971 +    PushText( buf, false );
  8.1972 +}
  8.1973 +
  8.1974 +
  8.1975 +void XMLPrinter::PushText( unsigned value )
  8.1976 +{
  8.1977 +    char buf[BUF_SIZE];
  8.1978 +    XMLUtil::ToStr( value, buf, BUF_SIZE );
  8.1979 +    PushText( buf, false );
  8.1980 +}
  8.1981 +
  8.1982 +
  8.1983 +void XMLPrinter::PushText( bool value )
  8.1984 +{
  8.1985 +    char buf[BUF_SIZE];
  8.1986 +    XMLUtil::ToStr( value, buf, BUF_SIZE );
  8.1987 +    PushText( buf, false );
  8.1988 +}
  8.1989 +
  8.1990 +
  8.1991 +void XMLPrinter::PushText( float value )
  8.1992 +{
  8.1993 +    char buf[BUF_SIZE];
  8.1994 +    XMLUtil::ToStr( value, buf, BUF_SIZE );
  8.1995 +    PushText( buf, false );
  8.1996 +}
  8.1997 +
  8.1998 +
  8.1999 +void XMLPrinter::PushText( double value )
  8.2000 +{
  8.2001 +    char buf[BUF_SIZE];
  8.2002 +    XMLUtil::ToStr( value, buf, BUF_SIZE );
  8.2003 +    PushText( buf, false );
  8.2004 +}
  8.2005 +
  8.2006 +
  8.2007 +void XMLPrinter::PushComment( const char* comment )
  8.2008 +{
  8.2009 +    if ( _elementJustOpened ) {
  8.2010 +        SealElement();
  8.2011 +    }
  8.2012 +    if ( _textDepth < 0 && !_firstElement && !_compactMode) {
  8.2013 +        Print( "\n" );
  8.2014 +        PrintSpace( _depth );
  8.2015 +    }
  8.2016 +    _firstElement = false;
  8.2017 +    Print( "<!--%s-->", comment );
  8.2018 +}
  8.2019 +
  8.2020 +
  8.2021 +void XMLPrinter::PushDeclaration( const char* value )
  8.2022 +{
  8.2023 +    if ( _elementJustOpened ) {
  8.2024 +        SealElement();
  8.2025 +    }
  8.2026 +    if ( _textDepth < 0 && !_firstElement && !_compactMode) {
  8.2027 +        Print( "\n" );
  8.2028 +        PrintSpace( _depth );
  8.2029 +    }
  8.2030 +    _firstElement = false;
  8.2031 +    Print( "<?%s?>", value );
  8.2032 +}
  8.2033 +
  8.2034 +
  8.2035 +void XMLPrinter::PushUnknown( const char* value )
  8.2036 +{
  8.2037 +    if ( _elementJustOpened ) {
  8.2038 +        SealElement();
  8.2039 +    }
  8.2040 +    if ( _textDepth < 0 && !_firstElement && !_compactMode) {
  8.2041 +        Print( "\n" );
  8.2042 +        PrintSpace( _depth );
  8.2043 +    }
  8.2044 +    _firstElement = false;
  8.2045 +    Print( "<!%s>", value );
  8.2046 +}
  8.2047 +
  8.2048 +
  8.2049 +bool XMLPrinter::VisitEnter( const XMLDocument& doc )
  8.2050 +{
  8.2051 +    _processEntities = doc.ProcessEntities();
  8.2052 +    if ( doc.HasBOM() ) {
  8.2053 +        PushHeader( true, false );
  8.2054 +    }
  8.2055 +    return true;
  8.2056 +}
  8.2057 +
  8.2058 +
  8.2059 +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
  8.2060 +{
  8.2061 +    OpenElement( element.Name() );
  8.2062 +    while ( attribute ) {
  8.2063 +        PushAttribute( attribute->Name(), attribute->Value() );
  8.2064 +        attribute = attribute->Next();
  8.2065 +    }
  8.2066 +    return true;
  8.2067 +}
  8.2068 +
  8.2069 +
  8.2070 +bool XMLPrinter::VisitExit( const XMLElement& )
  8.2071 +{
  8.2072 +    CloseElement();
  8.2073 +    return true;
  8.2074 +}
  8.2075 +
  8.2076 +
  8.2077 +bool XMLPrinter::Visit( const XMLText& text )
  8.2078 +{
  8.2079 +    PushText( text.Value(), text.CData() );
  8.2080 +    return true;
  8.2081 +}
  8.2082 +
  8.2083 +
  8.2084 +bool XMLPrinter::Visit( const XMLComment& comment )
  8.2085 +{
  8.2086 +    PushComment( comment.Value() );
  8.2087 +    return true;
  8.2088 +}
  8.2089 +
  8.2090 +bool XMLPrinter::Visit( const XMLDeclaration& declaration )
  8.2091 +{
  8.2092 +    PushDeclaration( declaration.Value() );
  8.2093 +    return true;
  8.2094 +}
  8.2095 +
  8.2096 +
  8.2097 +bool XMLPrinter::Visit( const XMLUnknown& unknown )
  8.2098 +{
  8.2099 +    PushUnknown( unknown.Value() );
  8.2100 +    return true;
  8.2101 +}
  8.2102 +
  8.2103 +}   // namespace tinyxml2
  8.2104 +
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/libs/tinyxml2/tinyxml2.h	Fri Sep 27 06:58:37 2013 +0300
     9.3 @@ -0,0 +1,1987 @@
     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 +
    9.21 +2. Altered source versions must be plainly marked as such, and
    9.22 +must not be misrepresented as being the original software.
    9.23 +
    9.24 +3. This notice may not be removed or altered from any source
    9.25 +distribution.
    9.26 +*/
    9.27 +
    9.28 +#ifndef TINYXML2_INCLUDED
    9.29 +#define TINYXML2_INCLUDED
    9.30 +
    9.31 +#if defined(ANDROID_NDK) || defined(__BORLANDC__)
    9.32 +#   include <ctype.h>
    9.33 +#   include <limits.h>
    9.34 +#   include <stdio.h>
    9.35 +#   include <stdlib.h>
    9.36 +#   include <string.h>
    9.37 +#   include <stdarg.h>
    9.38 +#else
    9.39 +#   include <cctype>
    9.40 +#   include <climits>
    9.41 +#   include <cstdio>
    9.42 +#   include <cstdlib>
    9.43 +#   include <cstring>
    9.44 +#   include <cstdarg>
    9.45 +#endif
    9.46 +
    9.47 +/*
    9.48 +   TODO: intern strings instead of allocation.
    9.49 +*/
    9.50 +/*
    9.51 +	gcc:
    9.52 +        g++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
    9.53 +
    9.54 +    Formatting, Artistic Style:
    9.55 +        AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
    9.56 +*/
    9.57 +
    9.58 +#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
    9.59 +#   ifndef DEBUG
    9.60 +#       define DEBUG
    9.61 +#   endif
    9.62 +#endif
    9.63 +
    9.64 +#ifdef _MSC_VER
    9.65 +#   pragma warning(push)
    9.66 +#   pragma warning(disable: 4251)
    9.67 +#endif
    9.68 +
    9.69 +#ifdef _WIN32
    9.70 +#   ifdef TINYXML2_EXPORT
    9.71 +#       define TINYXML2_LIB __declspec(dllexport)
    9.72 +#   elif defined(TINYXML2_IMPORT)
    9.73 +#       define TINYXML2_LIB __declspec(dllimport)
    9.74 +#   else
    9.75 +#       define TINYXML2_LIB
    9.76 +#   endif
    9.77 +#else
    9.78 +#   define TINYXML2_LIB
    9.79 +#endif
    9.80 +
    9.81 +
    9.82 +#if defined(DEBUG)
    9.83 +#   if defined(_MSC_VER)
    9.84 +#       define TIXMLASSERT( x )           if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
    9.85 +#   elif defined (ANDROID_NDK)
    9.86 +#       include <android/log.h>
    9.87 +#       define TIXMLASSERT( x )           if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
    9.88 +#   else
    9.89 +#       include <assert.h>
    9.90 +#       define TIXMLASSERT                assert
    9.91 +#   endif
    9.92 +#   else
    9.93 +#       define TIXMLASSERT( x )           {}
    9.94 +#endif
    9.95 +
    9.96 +
    9.97 +#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
    9.98 +// Microsoft visual studio, version 2005 and higher.
    9.99 +/*int _snprintf_s(
   9.100 +   char *buffer,
   9.101 +   size_t sizeOfBuffer,
   9.102 +   size_t count,
   9.103 +   const char *format [,
   9.104 +	  argument] ...
   9.105 +);*/
   9.106 +inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
   9.107 +{
   9.108 +    va_list va;
   9.109 +    va_start( va, format );
   9.110 +    int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
   9.111 +    va_end( va );
   9.112 +    return result;
   9.113 +}
   9.114 +#define TIXML_SSCANF   sscanf_s
   9.115 +#else
   9.116 +// GCC version 3 and higher
   9.117 +//#warning( "Using sn* functions." )
   9.118 +#define TIXML_SNPRINTF snprintf
   9.119 +#define TIXML_SSCANF   sscanf
   9.120 +#endif
   9.121 +
   9.122 +static const int TIXML2_MAJOR_VERSION = 1;
   9.123 +static const int TIXML2_MINOR_VERSION = 0;
   9.124 +static const int TIXML2_PATCH_VERSION = 11;
   9.125 +
   9.126 +namespace tinyxml2
   9.127 +{
   9.128 +class XMLDocument;
   9.129 +class XMLElement;
   9.130 +class XMLAttribute;
   9.131 +class XMLComment;
   9.132 +class XMLText;
   9.133 +class XMLDeclaration;
   9.134 +class XMLUnknown;
   9.135 +class XMLPrinter;
   9.136 +
   9.137 +/*
   9.138 +	A class that wraps strings. Normally stores the start and end
   9.139 +	pointers into the XML file itself, and will apply normalization
   9.140 +	and entity translation if actually read. Can also store (and memory
   9.141 +	manage) a traditional char[]
   9.142 +*/
   9.143 +class StrPair
   9.144 +{
   9.145 +public:
   9.146 +    enum {
   9.147 +        NEEDS_ENTITY_PROCESSING			= 0x01,
   9.148 +        NEEDS_NEWLINE_NORMALIZATION		= 0x02,
   9.149 +        COLLAPSE_WHITESPACE	                = 0x04,
   9.150 +
   9.151 +        TEXT_ELEMENT		            	= NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
   9.152 +        TEXT_ELEMENT_LEAVE_ENTITIES		= NEEDS_NEWLINE_NORMALIZATION,
   9.153 +        ATTRIBUTE_NAME		            	= 0,
   9.154 +        ATTRIBUTE_VALUE		            	= NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
   9.155 +        ATTRIBUTE_VALUE_LEAVE_ENTITIES  	= NEEDS_NEWLINE_NORMALIZATION,
   9.156 +        COMMENT				        = NEEDS_NEWLINE_NORMALIZATION
   9.157 +    };
   9.158 +
   9.159 +    StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}
   9.160 +    ~StrPair();
   9.161 +
   9.162 +    void Set( char* start, char* end, int flags ) {
   9.163 +        Reset();
   9.164 +        _start  = start;
   9.165 +        _end    = end;
   9.166 +        _flags  = flags | NEEDS_FLUSH;
   9.167 +    }
   9.168 +
   9.169 +    const char* GetStr();
   9.170 +
   9.171 +    bool Empty() const {
   9.172 +        return _start == _end;
   9.173 +    }
   9.174 +
   9.175 +    void SetInternedStr( const char* str ) {
   9.176 +        Reset();
   9.177 +        _start = const_cast<char*>(str);
   9.178 +    }
   9.179 +
   9.180 +    void SetStr( const char* str, int flags=0 );
   9.181 +
   9.182 +    char* ParseText( char* in, const char* endTag, int strFlags );
   9.183 +    char* ParseName( char* in );
   9.184 +
   9.185 +private:
   9.186 +    void Reset();
   9.187 +    void CollapseWhitespace();
   9.188 +
   9.189 +    enum {
   9.190 +        NEEDS_FLUSH = 0x100,
   9.191 +        NEEDS_DELETE = 0x200
   9.192 +    };
   9.193 +
   9.194 +    // After parsing, if *_end != 0, it can be set to zero.
   9.195 +    int     _flags;
   9.196 +    char*   _start;
   9.197 +    char*   _end;
   9.198 +};
   9.199 +
   9.200 +
   9.201 +/*
   9.202 +	A dynamic array of Plain Old Data. Doesn't support constructors, etc.
   9.203 +	Has a small initial memory pool, so that low or no usage will not
   9.204 +	cause a call to new/delete
   9.205 +*/
   9.206 +template <class T, int INIT>
   9.207 +class DynArray
   9.208 +{
   9.209 +public:
   9.210 +    DynArray< T, INIT >() {
   9.211 +        _mem = _pool;
   9.212 +        _allocated = INIT;
   9.213 +        _size = 0;
   9.214 +    }
   9.215 +
   9.216 +    ~DynArray() {
   9.217 +        if ( _mem != _pool ) {
   9.218 +            delete [] _mem;
   9.219 +        }
   9.220 +    }
   9.221 +
   9.222 +    void Push( T t ) {
   9.223 +        EnsureCapacity( _size+1 );
   9.224 +        _mem[_size++] = t;
   9.225 +    }
   9.226 +
   9.227 +    T* PushArr( int count ) {
   9.228 +        EnsureCapacity( _size+count );
   9.229 +        T* ret = &_mem[_size];
   9.230 +        _size += count;
   9.231 +        return ret;
   9.232 +    }
   9.233 +
   9.234 +    T Pop() {
   9.235 +        return _mem[--_size];
   9.236 +    }
   9.237 +
   9.238 +    void PopArr( int count ) {
   9.239 +        TIXMLASSERT( _size >= count );
   9.240 +        _size -= count;
   9.241 +    }
   9.242 +
   9.243 +    bool Empty() const					{
   9.244 +        return _size == 0;
   9.245 +    }
   9.246 +
   9.247 +    T& operator[](int i)				{
   9.248 +        TIXMLASSERT( i>= 0 && i < _size );
   9.249 +        return _mem[i];
   9.250 +    }
   9.251 +
   9.252 +    const T& operator[](int i) const	{
   9.253 +        TIXMLASSERT( i>= 0 && i < _size );
   9.254 +        return _mem[i];
   9.255 +    }
   9.256 +
   9.257 +    int Size() const					{
   9.258 +        return _size;
   9.259 +    }
   9.260 +
   9.261 +    int Capacity() const				{
   9.262 +        return _allocated;
   9.263 +    }
   9.264 +
   9.265 +    const T* Mem() const				{
   9.266 +        return _mem;
   9.267 +    }
   9.268 +
   9.269 +    T* Mem()							{
   9.270 +        return _mem;
   9.271 +    }
   9.272 +
   9.273 +private:
   9.274 +    void EnsureCapacity( int cap ) {
   9.275 +        if ( cap > _allocated ) {
   9.276 +            int newAllocated = cap * 2;
   9.277 +            T* newMem = new T[newAllocated];
   9.278 +            memcpy( newMem, _mem, sizeof(T)*_size );	// warning: not using constructors, only works for PODs
   9.279 +            if ( _mem != _pool ) {
   9.280 +                delete [] _mem;
   9.281 +            }
   9.282 +            _mem = newMem;
   9.283 +            _allocated = newAllocated;
   9.284 +        }
   9.285 +    }
   9.286 +
   9.287 +    T*  _mem;
   9.288 +    T   _pool[INIT];
   9.289 +    int _allocated;		// objects allocated
   9.290 +    int _size;			// number objects in use
   9.291 +};
   9.292 +
   9.293 +
   9.294 +/*
   9.295 +	Parent virtual class of a pool for fast allocation
   9.296 +	and deallocation of objects.
   9.297 +*/
   9.298 +class MemPool
   9.299 +{
   9.300 +public:
   9.301 +    MemPool() {}
   9.302 +    virtual ~MemPool() {}
   9.303 +
   9.304 +    virtual int ItemSize() const = 0;
   9.305 +    virtual void* Alloc() = 0;
   9.306 +    virtual void Free( void* ) = 0;
   9.307 +    virtual void SetTracked() = 0;
   9.308 +};
   9.309 +
   9.310 +
   9.311 +/*
   9.312 +	Template child class to create pools of the correct type.
   9.313 +*/
   9.314 +template< int SIZE >
   9.315 +class MemPoolT : public MemPool
   9.316 +{
   9.317 +public:
   9.318 +    MemPoolT() : _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0)	{}
   9.319 +    ~MemPoolT() {
   9.320 +        // Delete the blocks.
   9.321 +        for( int i=0; i<_blockPtrs.Size(); ++i ) {
   9.322 +            delete _blockPtrs[i];
   9.323 +        }
   9.324 +    }
   9.325 +
   9.326 +    virtual int ItemSize() const	{
   9.327 +        return SIZE;
   9.328 +    }
   9.329 +    int CurrentAllocs() const		{
   9.330 +        return _currentAllocs;
   9.331 +    }
   9.332 +
   9.333 +    virtual void* Alloc() {
   9.334 +        if ( !_root ) {
   9.335 +            // Need a new block.
   9.336 +            Block* block = new Block();
   9.337 +            _blockPtrs.Push( block );
   9.338 +
   9.339 +            for( int i=0; i<COUNT-1; ++i ) {
   9.340 +                block->chunk[i].next = &block->chunk[i+1];
   9.341 +            }
   9.342 +            block->chunk[COUNT-1].next = 0;
   9.343 +            _root = block->chunk;
   9.344 +        }
   9.345 +        void* result = _root;
   9.346 +        _root = _root->next;
   9.347 +
   9.348 +        ++_currentAllocs;
   9.349 +        if ( _currentAllocs > _maxAllocs ) {
   9.350 +            _maxAllocs = _currentAllocs;
   9.351 +        }
   9.352 +        _nAllocs++;
   9.353 +        _nUntracked++;
   9.354 +        return result;
   9.355 +    }
   9.356 +    virtual void Free( void* mem ) {
   9.357 +        if ( !mem ) {
   9.358 +            return;
   9.359 +        }
   9.360 +        --_currentAllocs;
   9.361 +        Chunk* chunk = (Chunk*)mem;
   9.362 +#ifdef DEBUG
   9.363 +        memset( chunk, 0xfe, sizeof(Chunk) );
   9.364 +#endif
   9.365 +        chunk->next = _root;
   9.366 +        _root = chunk;
   9.367 +    }
   9.368 +    void Trace( const char* name ) {
   9.369 +        printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
   9.370 +                name, _maxAllocs, _maxAllocs*SIZE/1024, _currentAllocs, SIZE, _nAllocs, _blockPtrs.Size() );
   9.371 +    }
   9.372 +
   9.373 +    void SetTracked() {
   9.374 +        _nUntracked--;
   9.375 +    }
   9.376 +
   9.377 +    int Untracked() const {
   9.378 +        return _nUntracked;
   9.379 +    }
   9.380 +
   9.381 +	// This number is perf sensitive. 4k seems like a good tradeoff on my machine.
   9.382 +	// The test file is large, 170k.
   9.383 +	// Release:		VS2010 gcc(no opt)
   9.384 +	//		1k:		4000
   9.385 +	//		2k:		4000
   9.386 +	//		4k:		3900	21000
   9.387 +	//		16k:	5200
   9.388 +	//		32k:	4300
   9.389 +	//		64k:	4000	21000
   9.390 +    enum { COUNT = (4*1024)/SIZE }; // Some compilers do not accept to use COUNT in private part if COUNT is private
   9.391 +
   9.392 +private:
   9.393 +    union Chunk {
   9.394 +        Chunk*  next;
   9.395 +        char    mem[SIZE];
   9.396 +    };
   9.397 +    struct Block {
   9.398 +        Chunk chunk[COUNT];
   9.399 +    };
   9.400 +    DynArray< Block*, 10 > _blockPtrs;
   9.401 +    Chunk* _root;
   9.402 +
   9.403 +    int _currentAllocs;
   9.404 +    int _nAllocs;
   9.405 +    int _maxAllocs;
   9.406 +    int _nUntracked;
   9.407 +};
   9.408 +
   9.409 +
   9.410 +
   9.411 +/**
   9.412 +	Implements the interface to the "Visitor pattern" (see the Accept() method.)
   9.413 +	If you call the Accept() method, it requires being passed a XMLVisitor
   9.414 +	class to handle callbacks. For nodes that contain other nodes (Document, Element)
   9.415 +	you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
   9.416 +	are simply called with Visit().
   9.417 +
   9.418 +	If you return 'true' from a Visit method, recursive parsing will continue. If you return
   9.419 +	false, <b>no children of this node or its siblings</b> will be visited.
   9.420 +
   9.421 +	All flavors of Visit methods have a default implementation that returns 'true' (continue
   9.422 +	visiting). You need to only override methods that are interesting to you.
   9.423 +
   9.424 +	Generally Accept() is called on the XMLDocument, although all nodes support visiting.
   9.425 +
   9.426 +	You should never change the document from a callback.
   9.427 +
   9.428 +	@sa XMLNode::Accept()
   9.429 +*/
   9.430 +class TINYXML2_LIB XMLVisitor
   9.431 +{
   9.432 +public:
   9.433 +    virtual ~XMLVisitor() {}
   9.434 +
   9.435 +    /// Visit a document.
   9.436 +    virtual bool VisitEnter( const XMLDocument& /*doc*/ )			{
   9.437 +        return true;
   9.438 +    }
   9.439 +    /// Visit a document.
   9.440 +    virtual bool VisitExit( const XMLDocument& /*doc*/ )			{
   9.441 +        return true;
   9.442 +    }
   9.443 +
   9.444 +    /// Visit an element.
   9.445 +    virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ )	{
   9.446 +        return true;
   9.447 +    }
   9.448 +    /// Visit an element.
   9.449 +    virtual bool VisitExit( const XMLElement& /*element*/ )			{
   9.450 +        return true;
   9.451 +    }
   9.452 +
   9.453 +    /// Visit a declaration.
   9.454 +    virtual bool Visit( const XMLDeclaration& /*declaration*/ )		{
   9.455 +        return true;
   9.456 +    }
   9.457 +    /// Visit a text node.
   9.458 +    virtual bool Visit( const XMLText& /*text*/ )					{
   9.459 +        return true;
   9.460 +    }
   9.461 +    /// Visit a comment node.
   9.462 +    virtual bool Visit( const XMLComment& /*comment*/ )				{
   9.463 +        return true;
   9.464 +    }
   9.465 +    /// Visit an unknown node.
   9.466 +    virtual bool Visit( const XMLUnknown& /*unknown*/ )				{
   9.467 +        return true;
   9.468 +    }
   9.469 +};
   9.470 +
   9.471 +
   9.472 +/*
   9.473 +	Utility functionality.
   9.474 +*/
   9.475 +class XMLUtil
   9.476 +{
   9.477 +public:
   9.478 +    // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
   9.479 +    // correct, but simple, and usually works.
   9.480 +    static const char* SkipWhiteSpace( const char* p )	{
   9.481 +        while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<const unsigned char*>(p) ) ) {
   9.482 +            ++p;
   9.483 +        }
   9.484 +        return p;
   9.485 +    }
   9.486 +    static char* SkipWhiteSpace( char* p )				{
   9.487 +        while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<unsigned char*>(p) ) )		{
   9.488 +            ++p;
   9.489 +        }
   9.490 +        return p;
   9.491 +    }
   9.492 +    static bool IsWhiteSpace( char p )					{
   9.493 +        return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );
   9.494 +    }
   9.495 +    
   9.496 +    inline static bool IsNameStartChar( unsigned char ch ) {
   9.497 +        return ( ( ch < 128 ) ? isalpha( ch ) : 1 )
   9.498 +               || ch == ':'
   9.499 +               || ch == '_';
   9.500 +    }
   9.501 +    
   9.502 +    inline static bool IsNameChar( unsigned char ch ) {
   9.503 +        return IsNameStartChar( ch )
   9.504 +               || isdigit( ch )
   9.505 +               || ch == '.'
   9.506 +               || ch == '-';
   9.507 +    }
   9.508 +
   9.509 +    inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX )  {
   9.510 +        int n = 0;
   9.511 +        if ( p == q ) {
   9.512 +            return true;
   9.513 +        }
   9.514 +        while( *p && *q && *p == *q && n<nChar ) {
   9.515 +            ++p;
   9.516 +            ++q;
   9.517 +            ++n;
   9.518 +        }
   9.519 +        if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
   9.520 +            return true;
   9.521 +        }
   9.522 +        return false;
   9.523 +    }
   9.524 +    
   9.525 +    inline static int IsUTF8Continuation( const char p ) {
   9.526 +        return p & 0x80;
   9.527 +    }
   9.528 +
   9.529 +    static const char* ReadBOM( const char* p, bool* hasBOM );
   9.530 +    // p is the starting location,
   9.531 +    // the UTF-8 value of the entity will be placed in value, and length filled in.
   9.532 +    static const char* GetCharacterRef( const char* p, char* value, int* length );
   9.533 +    static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
   9.534 +
   9.535 +    // converts primitive types to strings
   9.536 +    static void ToStr( int v, char* buffer, int bufferSize );
   9.537 +    static void ToStr( unsigned v, char* buffer, int bufferSize );
   9.538 +    static void ToStr( bool v, char* buffer, int bufferSize );
   9.539 +    static void ToStr( float v, char* buffer, int bufferSize );
   9.540 +    static void ToStr( double v, char* buffer, int bufferSize );
   9.541 +
   9.542 +    // converts strings to primitive types
   9.543 +    static bool	ToInt( const char* str, int* value );
   9.544 +    static bool ToUnsigned( const char* str, unsigned* value );
   9.545 +    static bool	ToBool( const char* str, bool* value );
   9.546 +    static bool	ToFloat( const char* str, float* value );
   9.547 +    static bool ToDouble( const char* str, double* value );
   9.548 +};
   9.549 +
   9.550 +
   9.551 +/** XMLNode is a base class for every object that is in the
   9.552 +	XML Document Object Model (DOM), except XMLAttributes.
   9.553 +	Nodes have siblings, a parent, and children which can
   9.554 +	be navigated. A node is always in a XMLDocument.
   9.555 +	The type of a XMLNode can be queried, and it can
   9.556 +	be cast to its more defined type.
   9.557 +
   9.558 +	A XMLDocument allocates memory for all its Nodes.
   9.559 +	When the XMLDocument gets deleted, all its Nodes
   9.560 +	will also be deleted.
   9.561 +
   9.562 +	@verbatim
   9.563 +	A Document can contain:	Element	(container or leaf)
   9.564 +							Comment (leaf)
   9.565 +							Unknown (leaf)
   9.566 +							Declaration( leaf )
   9.567 +
   9.568 +	An Element can contain:	Element (container or leaf)
   9.569 +							Text	(leaf)
   9.570 +							Attributes (not on tree)
   9.571 +							Comment (leaf)
   9.572 +							Unknown (leaf)
   9.573 +
   9.574 +	@endverbatim
   9.575 +*/
   9.576 +class TINYXML2_LIB XMLNode
   9.577 +{
   9.578 +    friend class XMLDocument;
   9.579 +    friend class XMLElement;
   9.580 +public:
   9.581 +
   9.582 +    /// Get the XMLDocument that owns this XMLNode.
   9.583 +    const XMLDocument* GetDocument() const	{
   9.584 +        return _document;
   9.585 +    }
   9.586 +    /// Get the XMLDocument that owns this XMLNode.
   9.587 +    XMLDocument* GetDocument()				{
   9.588 +        return _document;
   9.589 +    }
   9.590 +
   9.591 +    /// Safely cast to an Element, or null.
   9.592 +    virtual XMLElement*		ToElement()		{
   9.593 +        return 0;
   9.594 +    }
   9.595 +    /// Safely cast to Text, or null.
   9.596 +    virtual XMLText*		ToText()		{
   9.597 +        return 0;
   9.598 +    }
   9.599 +    /// Safely cast to a Comment, or null.
   9.600 +    virtual XMLComment*		ToComment()		{
   9.601 +        return 0;
   9.602 +    }
   9.603 +    /// Safely cast to a Document, or null.
   9.604 +    virtual XMLDocument*	ToDocument()	{
   9.605 +        return 0;
   9.606 +    }
   9.607 +    /// Safely cast to a Declaration, or null.
   9.608 +    virtual XMLDeclaration*	ToDeclaration()	{
   9.609 +        return 0;
   9.610 +    }
   9.611 +    /// Safely cast to an Unknown, or null.
   9.612 +    virtual XMLUnknown*		ToUnknown()		{
   9.613 +        return 0;
   9.614 +    }
   9.615 +
   9.616 +    virtual const XMLElement*		ToElement() const		{
   9.617 +        return 0;
   9.618 +    }
   9.619 +    virtual const XMLText*			ToText() const			{
   9.620 +        return 0;
   9.621 +    }
   9.622 +    virtual const XMLComment*		ToComment() const		{
   9.623 +        return 0;
   9.624 +    }
   9.625 +    virtual const XMLDocument*		ToDocument() const		{
   9.626 +        return 0;
   9.627 +    }
   9.628 +    virtual const XMLDeclaration*	ToDeclaration() const	{
   9.629 +        return 0;
   9.630 +    }
   9.631 +    virtual const XMLUnknown*		ToUnknown() const		{
   9.632 +        return 0;
   9.633 +    }
   9.634 +
   9.635 +    /** The meaning of 'value' changes for the specific type.
   9.636 +    	@verbatim
   9.637 +    	Document:	empty
   9.638 +    	Element:	name of the element
   9.639 +    	Comment:	the comment text
   9.640 +    	Unknown:	the tag contents
   9.641 +    	Text:		the text string
   9.642 +    	@endverbatim
   9.643 +    */
   9.644 +    const char* Value() const			{
   9.645 +        return _value.GetStr();
   9.646 +    }
   9.647 +
   9.648 +    /** Set the Value of an XML node.
   9.649 +    	@sa Value()
   9.650 +    */
   9.651 +    void SetValue( const char* val, bool staticMem=false );
   9.652 +
   9.653 +    /// Get the parent of this node on the DOM.
   9.654 +    const XMLNode*	Parent() const			{
   9.655 +        return _parent;
   9.656 +    }
   9.657 +
   9.658 +    XMLNode* Parent()						{
   9.659 +        return _parent;
   9.660 +    }
   9.661 +
   9.662 +    /// Returns true if this node has no children.
   9.663 +    bool NoChildren() const					{
   9.664 +        return !_firstChild;
   9.665 +    }
   9.666 +
   9.667 +    /// Get the first child node, or null if none exists.
   9.668 +    const XMLNode*  FirstChild() const		{
   9.669 +        return _firstChild;
   9.670 +    }
   9.671 +
   9.672 +    XMLNode*		FirstChild()			{
   9.673 +        return _firstChild;
   9.674 +    }
   9.675 +
   9.676 +    /** Get the first child element, or optionally the first child
   9.677 +        element with the specified name.
   9.678 +    */
   9.679 +    const XMLElement* FirstChildElement( const char* value=0 ) const;
   9.680 +
   9.681 +    XMLElement* FirstChildElement( const char* value=0 )	{
   9.682 +        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value ));
   9.683 +    }
   9.684 +
   9.685 +    /// Get the last child node, or null if none exists.
   9.686 +    const XMLNode*	LastChild() const						{
   9.687 +        return _lastChild;
   9.688 +    }
   9.689 +
   9.690 +    XMLNode*		LastChild()								{
   9.691 +        return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() );
   9.692 +    }
   9.693 +
   9.694 +    /** Get the last child element or optionally the last child
   9.695 +        element with the specified name.
   9.696 +    */
   9.697 +    const XMLElement* LastChildElement( const char* value=0 ) const;
   9.698 +
   9.699 +    XMLElement* LastChildElement( const char* value=0 )	{
   9.700 +        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) );
   9.701 +    }
   9.702 +
   9.703 +    /// Get the previous (left) sibling node of this node.
   9.704 +    const XMLNode*	PreviousSibling() const					{
   9.705 +        return _prev;
   9.706 +    }
   9.707 +
   9.708 +    XMLNode*	PreviousSibling()							{
   9.709 +        return _prev;
   9.710 +    }
   9.711 +
   9.712 +    /// Get the previous (left) sibling element of this node, with an optionally supplied name.
   9.713 +    const XMLElement*	PreviousSiblingElement( const char* value=0 ) const ;
   9.714 +
   9.715 +    XMLElement*	PreviousSiblingElement( const char* value=0 ) {
   9.716 +        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) );
   9.717 +    }
   9.718 +
   9.719 +    /// Get the next (right) sibling node of this node.
   9.720 +    const XMLNode*	NextSibling() const						{
   9.721 +        return _next;
   9.722 +    }
   9.723 +
   9.724 +    XMLNode*	NextSibling()								{
   9.725 +        return _next;
   9.726 +    }
   9.727 +
   9.728 +    /// Get the next (right) sibling element of this node, with an optionally supplied name.
   9.729 +    const XMLElement*	NextSiblingElement( const char* value=0 ) const;
   9.730 +
   9.731 +    XMLElement*	NextSiblingElement( const char* value=0 )	{
   9.732 +        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) );
   9.733 +    }
   9.734 +
   9.735 +    /**
   9.736 +    	Add a child node as the last (right) child.
   9.737 +    */
   9.738 +    XMLNode* InsertEndChild( XMLNode* addThis );
   9.739 +
   9.740 +    XMLNode* LinkEndChild( XMLNode* addThis )	{
   9.741 +        return InsertEndChild( addThis );
   9.742 +    }
   9.743 +    /**
   9.744 +    	Add a child node as the first (left) child.
   9.745 +    */
   9.746 +    XMLNode* InsertFirstChild( XMLNode* addThis );
   9.747 +    /**
   9.748 +    	Add a node after the specified child node.
   9.749 +    */
   9.750 +    XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
   9.751 +
   9.752 +    /**
   9.753 +    	Delete all the children of this node.
   9.754 +    */
   9.755 +    void DeleteChildren();
   9.756 +
   9.757 +    /**
   9.758 +    	Delete a child of this node.
   9.759 +    */
   9.760 +    void DeleteChild( XMLNode* node );
   9.761 +
   9.762 +    /**
   9.763 +    	Make a copy of this node, but not its children.
   9.764 +    	You may pass in a Document pointer that will be
   9.765 +    	the owner of the new Node. If the 'document' is
   9.766 +    	null, then the node returned will be allocated
   9.767 +    	from the current Document. (this->GetDocument())
   9.768 +
   9.769 +    	Note: if called on a XMLDocument, this will return null.
   9.770 +    */
   9.771 +    virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
   9.772 +
   9.773 +    /**
   9.774 +    	Test if 2 nodes are the same, but don't test children.
   9.775 +    	The 2 nodes do not need to be in the same Document.
   9.776 +
   9.777 +    	Note: if called on a XMLDocument, this will return false.
   9.778 +    */
   9.779 +    virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
   9.780 +
   9.781 +    /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the
   9.782 +    	XML tree will be conditionally visited and the host will be called back
   9.783 +    	via the XMLVisitor interface.
   9.784 +
   9.785 +    	This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse
   9.786 +    	the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this
   9.787 +    	interface versus any other.)
   9.788 +
   9.789 +    	The interface has been based on ideas from:
   9.790 +
   9.791 +    	- http://www.saxproject.org/
   9.792 +    	- http://c2.com/cgi/wiki?HierarchicalVisitorPattern
   9.793 +
   9.794 +    	Which are both good references for "visiting".
   9.795 +
   9.796 +    	An example of using Accept():
   9.797 +    	@verbatim
   9.798 +    	XMLPrinter printer;
   9.799 +    	tinyxmlDoc.Accept( &printer );
   9.800 +    	const char* xmlcstr = printer.CStr();
   9.801 +    	@endverbatim
   9.802 +    */
   9.803 +    virtual bool Accept( XMLVisitor* visitor ) const = 0;
   9.804 +
   9.805 +    // internal
   9.806 +    virtual char* ParseDeep( char*, StrPair* );
   9.807 +
   9.808 +protected:
   9.809 +    XMLNode( XMLDocument* );
   9.810 +    virtual ~XMLNode();
   9.811 +    XMLNode( const XMLNode& );	// not supported
   9.812 +    XMLNode& operator=( const XMLNode& );	// not supported
   9.813 +
   9.814 +    XMLDocument*	_document;
   9.815 +    XMLNode*		_parent;
   9.816 +    mutable StrPair	_value;
   9.817 +
   9.818 +    XMLNode*		_firstChild;
   9.819 +    XMLNode*		_lastChild;
   9.820 +
   9.821 +    XMLNode*		_prev;
   9.822 +    XMLNode*		_next;
   9.823 +
   9.824 +private:
   9.825 +    MemPool*		_memPool;
   9.826 +    void Unlink( XMLNode* child );
   9.827 +};
   9.828 +
   9.829 +
   9.830 +/** XML text.
   9.831 +
   9.832 +	Note that a text node can have child element nodes, for example:
   9.833 +	@verbatim
   9.834 +	<root>This is <b>bold</b></root>
   9.835 +	@endverbatim
   9.836 +
   9.837 +	A text node can have 2 ways to output the next. "normal" output
   9.838 +	and CDATA. It will default to the mode it was parsed from the XML file and
   9.839 +	you generally want to leave it alone, but you can change the output mode with
   9.840 +	SetCData() and query it with CData().
   9.841 +*/
   9.842 +class TINYXML2_LIB XMLText : public XMLNode
   9.843 +{
   9.844 +    friend class XMLBase;
   9.845 +    friend class XMLDocument;
   9.846 +public:
   9.847 +    virtual bool Accept( XMLVisitor* visitor ) const;
   9.848 +
   9.849 +    virtual XMLText* ToText()			{
   9.850 +        return this;
   9.851 +    }
   9.852 +    virtual const XMLText* ToText() const	{
   9.853 +        return this;
   9.854 +    }
   9.855 +
   9.856 +    /// Declare whether this should be CDATA or standard text.
   9.857 +    void SetCData( bool isCData )			{
   9.858 +        _isCData = isCData;
   9.859 +    }
   9.860 +    /// Returns true if this is a CDATA text element.
   9.861 +    bool CData() const						{
   9.862 +        return _isCData;
   9.863 +    }
   9.864 +
   9.865 +    char* ParseDeep( char*, StrPair* endTag );
   9.866 +    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
   9.867 +    virtual bool ShallowEqual( const XMLNode* compare ) const;
   9.868 +
   9.869 +protected:
   9.870 +    XMLText( XMLDocument* doc )	: XMLNode( doc ), _isCData( false )	{}
   9.871 +    virtual ~XMLText()												{}
   9.872 +    XMLText( const XMLText& );	// not supported
   9.873 +    XMLText& operator=( const XMLText& );	// not supported
   9.874 +
   9.875 +private:
   9.876 +    bool _isCData;
   9.877 +};
   9.878 +
   9.879 +
   9.880 +/** An XML Comment. */
   9.881 +class TINYXML2_LIB XMLComment : public XMLNode
   9.882 +{
   9.883 +    friend class XMLDocument;
   9.884 +public:
   9.885 +    virtual XMLComment*	ToComment()					{
   9.886 +        return this;
   9.887 +    }
   9.888 +    virtual const XMLComment* ToComment() const		{
   9.889 +        return this;
   9.890 +    }
   9.891 +
   9.892 +    virtual bool Accept( XMLVisitor* visitor ) const;
   9.893 +
   9.894 +    char* ParseDeep( char*, StrPair* endTag );
   9.895 +    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
   9.896 +    virtual bool ShallowEqual( const XMLNode* compare ) const;
   9.897 +
   9.898 +protected:
   9.899 +    XMLComment( XMLDocument* doc );
   9.900 +    virtual ~XMLComment();
   9.901 +    XMLComment( const XMLComment& );	// not supported
   9.902 +    XMLComment& operator=( const XMLComment& );	// not supported
   9.903 +
   9.904 +private:
   9.905 +};
   9.906 +
   9.907 +
   9.908 +/** In correct XML the declaration is the first entry in the file.
   9.909 +	@verbatim
   9.910 +		<?xml version="1.0" standalone="yes"?>
   9.911 +	@endverbatim
   9.912 +
   9.913 +	TinyXML-2 will happily read or write files without a declaration,
   9.914 +	however.
   9.915 +
   9.916 +	The text of the declaration isn't interpreted. It is parsed
   9.917 +	and written as a string.
   9.918 +*/
   9.919 +class TINYXML2_LIB XMLDeclaration : public XMLNode
   9.920 +{
   9.921 +    friend class XMLDocument;
   9.922 +public:
   9.923 +    virtual XMLDeclaration*	ToDeclaration()					{
   9.924 +        return this;
   9.925 +    }
   9.926 +    virtual const XMLDeclaration* ToDeclaration() const		{
   9.927 +        return this;
   9.928 +    }
   9.929 +
   9.930 +    virtual bool Accept( XMLVisitor* visitor ) const;
   9.931 +
   9.932 +    char* ParseDeep( char*, StrPair* endTag );
   9.933 +    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
   9.934 +    virtual bool ShallowEqual( const XMLNode* compare ) const;
   9.935 +
   9.936 +protected:
   9.937 +    XMLDeclaration( XMLDocument* doc );
   9.938 +    virtual ~XMLDeclaration();
   9.939 +    XMLDeclaration( const XMLDeclaration& );	// not supported
   9.940 +    XMLDeclaration& operator=( const XMLDeclaration& );	// not supported
   9.941 +};
   9.942 +
   9.943 +
   9.944 +/** Any tag that TinyXML-2 doesn't recognize is saved as an
   9.945 +	unknown. It is a tag of text, but should not be modified.
   9.946 +	It will be written back to the XML, unchanged, when the file
   9.947 +	is saved.
   9.948 +
   9.949 +	DTD tags get thrown into XMLUnknowns.
   9.950 +*/
   9.951 +class TINYXML2_LIB XMLUnknown : public XMLNode
   9.952 +{
   9.953 +    friend class XMLDocument;
   9.954 +public:
   9.955 +    virtual XMLUnknown*	ToUnknown()					{
   9.956 +        return this;
   9.957 +    }
   9.958 +    virtual const XMLUnknown* ToUnknown() const		{
   9.959 +        return this;
   9.960 +    }
   9.961 +
   9.962 +    virtual bool Accept( XMLVisitor* visitor ) const;
   9.963 +
   9.964 +    char* ParseDeep( char*, StrPair* endTag );
   9.965 +    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
   9.966 +    virtual bool ShallowEqual( const XMLNode* compare ) const;
   9.967 +
   9.968 +protected:
   9.969 +    XMLUnknown( XMLDocument* doc );
   9.970 +    virtual ~XMLUnknown();
   9.971 +    XMLUnknown( const XMLUnknown& );	// not supported
   9.972 +    XMLUnknown& operator=( const XMLUnknown& );	// not supported
   9.973 +};
   9.974 +
   9.975 +
   9.976 +enum XMLError {
   9.977 +    XML_NO_ERROR = 0,
   9.978 +    XML_SUCCESS = 0,
   9.979 +
   9.980 +    XML_NO_ATTRIBUTE,
   9.981 +    XML_WRONG_ATTRIBUTE_TYPE,
   9.982 +
   9.983 +    XML_ERROR_FILE_NOT_FOUND,
   9.984 +    XML_ERROR_FILE_COULD_NOT_BE_OPENED,
   9.985 +    XML_ERROR_FILE_READ_ERROR,
   9.986 +    XML_ERROR_ELEMENT_MISMATCH,
   9.987 +    XML_ERROR_PARSING_ELEMENT,
   9.988 +    XML_ERROR_PARSING_ATTRIBUTE,
   9.989 +    XML_ERROR_IDENTIFYING_TAG,
   9.990 +    XML_ERROR_PARSING_TEXT,
   9.991 +    XML_ERROR_PARSING_CDATA,
   9.992 +    XML_ERROR_PARSING_COMMENT,
   9.993 +    XML_ERROR_PARSING_DECLARATION,
   9.994 +    XML_ERROR_PARSING_UNKNOWN,
   9.995 +    XML_ERROR_EMPTY_DOCUMENT,
   9.996 +    XML_ERROR_MISMATCHED_ELEMENT,
   9.997 +    XML_ERROR_PARSING,
   9.998 +
   9.999 +    XML_CAN_NOT_CONVERT_TEXT,
  9.1000 +    XML_NO_TEXT_NODE
  9.1001 +};
  9.1002 +
  9.1003 +
  9.1004 +/** An attribute is a name-value pair. Elements have an arbitrary
  9.1005 +	number of attributes, each with a unique name.
  9.1006 +
  9.1007 +	@note The attributes are not XMLNodes. You may only query the
  9.1008 +	Next() attribute in a list.
  9.1009 +*/
  9.1010 +class TINYXML2_LIB XMLAttribute
  9.1011 +{
  9.1012 +    friend class XMLElement;
  9.1013 +public:
  9.1014 +    /// The name of the attribute.
  9.1015 +    const char* Name() const {
  9.1016 +        return _name.GetStr();
  9.1017 +    }
  9.1018 +    /// The value of the attribute.
  9.1019 +    const char* Value() const {
  9.1020 +        return _value.GetStr();
  9.1021 +    }
  9.1022 +    /// The next attribute in the list.
  9.1023 +    const XMLAttribute* Next() const {
  9.1024 +        return _next;
  9.1025 +    }
  9.1026 +
  9.1027 +    /** IntValue interprets the attribute as an integer, and returns the value.
  9.1028 +        If the value isn't an integer, 0 will be returned. There is no error checking;
  9.1029 +    	use QueryIntValue() if you need error checking.
  9.1030 +    */
  9.1031 +    int		 IntValue() const				{
  9.1032 +        int i=0;
  9.1033 +        QueryIntValue( &i );
  9.1034 +        return i;
  9.1035 +    }
  9.1036 +    /// Query as an unsigned integer. See IntValue()
  9.1037 +    unsigned UnsignedValue() const			{
  9.1038 +        unsigned i=0;
  9.1039 +        QueryUnsignedValue( &i );
  9.1040 +        return i;
  9.1041 +    }
  9.1042 +    /// Query as a boolean. See IntValue()
  9.1043 +    bool	 BoolValue() const				{
  9.1044 +        bool b=false;
  9.1045 +        QueryBoolValue( &b );
  9.1046 +        return b;
  9.1047 +    }
  9.1048 +    /// Query as a double. See IntValue()
  9.1049 +    double 	 DoubleValue() const			{
  9.1050 +        double d=0;
  9.1051 +        QueryDoubleValue( &d );
  9.1052 +        return d;
  9.1053 +    }
  9.1054 +    /// Query as a float. See IntValue()
  9.1055 +    float	 FloatValue() const				{
  9.1056 +        float f=0;
  9.1057 +        QueryFloatValue( &f );
  9.1058 +        return f;
  9.1059 +    }
  9.1060 +
  9.1061 +    /** QueryIntValue interprets the attribute as an integer, and returns the value
  9.1062 +    	in the provided parameter. The function will return XML_NO_ERROR on success,
  9.1063 +    	and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
  9.1064 +    */
  9.1065 +    XMLError QueryIntValue( int* value ) const;
  9.1066 +    /// See QueryIntValue
  9.1067 +    XMLError QueryUnsignedValue( unsigned int* value ) const;
  9.1068 +    /// See QueryIntValue
  9.1069 +    XMLError QueryBoolValue( bool* value ) const;
  9.1070 +    /// See QueryIntValue
  9.1071 +    XMLError QueryDoubleValue( double* value ) const;
  9.1072 +    /// See QueryIntValue
  9.1073 +    XMLError QueryFloatValue( float* value ) const;
  9.1074 +
  9.1075 +    /// Set the attribute to a string value.
  9.1076 +    void SetAttribute( const char* value );
  9.1077 +    /// Set the attribute to value.
  9.1078 +    void SetAttribute( int value );
  9.1079 +    /// Set the attribute to value.
  9.1080 +    void SetAttribute( unsigned value );
  9.1081 +    /// Set the attribute to value.
  9.1082 +    void SetAttribute( bool value );
  9.1083 +    /// Set the attribute to value.
  9.1084 +    void SetAttribute( double value );
  9.1085 +    /// Set the attribute to value.
  9.1086 +    void SetAttribute( float value );
  9.1087 +
  9.1088 +private:
  9.1089 +    enum { BUF_SIZE = 200 };
  9.1090 +
  9.1091 +    XMLAttribute() : _next( 0 ), _memPool( 0 ) {}
  9.1092 +    virtual ~XMLAttribute()	{}
  9.1093 +
  9.1094 +    XMLAttribute( const XMLAttribute& );	// not supported
  9.1095 +    void operator=( const XMLAttribute& );	// not supported
  9.1096 +    void SetName( const char* name );
  9.1097 +
  9.1098 +    char* ParseDeep( char* p, bool processEntities );
  9.1099 +
  9.1100 +    mutable StrPair _name;
  9.1101 +    mutable StrPair _value;
  9.1102 +    XMLAttribute*   _next;
  9.1103 +    MemPool*        _memPool;
  9.1104 +};
  9.1105 +
  9.1106 +
  9.1107 +/** The element is a container class. It has a value, the element name,
  9.1108 +	and can contain other elements, text, comments, and unknowns.
  9.1109 +	Elements also contain an arbitrary number of attributes.
  9.1110 +*/
  9.1111 +class TINYXML2_LIB XMLElement : public XMLNode
  9.1112 +{
  9.1113 +    friend class XMLBase;
  9.1114 +    friend class XMLDocument;
  9.1115 +public:
  9.1116 +    /// Get the name of an element (which is the Value() of the node.)
  9.1117 +    const char* Name() const		{
  9.1118 +        return Value();
  9.1119 +    }
  9.1120 +    /// Set the name of the element.
  9.1121 +    void SetName( const char* str, bool staticMem=false )	{
  9.1122 +        SetValue( str, staticMem );
  9.1123 +    }
  9.1124 +
  9.1125 +    virtual XMLElement* ToElement()				{
  9.1126 +        return this;
  9.1127 +    }
  9.1128 +    virtual const XMLElement* ToElement() const {
  9.1129 +        return this;
  9.1130 +    }
  9.1131 +    virtual bool Accept( XMLVisitor* visitor ) const;
  9.1132 +
  9.1133 +    /** Given an attribute name, Attribute() returns the value
  9.1134 +    	for the attribute of that name, or null if none
  9.1135 +    	exists. For example:
  9.1136 +
  9.1137 +    	@verbatim
  9.1138 +    	const char* value = ele->Attribute( "foo" );
  9.1139 +    	@endverbatim
  9.1140 +
  9.1141 +    	The 'value' parameter is normally null. However, if specified,
  9.1142 +    	the attribute will only be returned if the 'name' and 'value'
  9.1143 +    	match. This allow you to write code:
  9.1144 +
  9.1145 +    	@verbatim
  9.1146 +    	if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
  9.1147 +    	@endverbatim
  9.1148 +
  9.1149 +    	rather than:
  9.1150 +    	@verbatim
  9.1151 +    	if ( ele->Attribute( "foo" ) ) {
  9.1152 +    		if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
  9.1153 +    	}
  9.1154 +    	@endverbatim
  9.1155 +    */
  9.1156 +    const char* Attribute( const char* name, const char* value=0 ) const;
  9.1157 +
  9.1158 +    /** Given an attribute name, IntAttribute() returns the value
  9.1159 +    	of the attribute interpreted as an integer. 0 will be
  9.1160 +    	returned if there is an error. For a method with error
  9.1161 +    	checking, see QueryIntAttribute()
  9.1162 +    */
  9.1163 +    int		 IntAttribute( const char* name ) const		{
  9.1164 +        int i=0;
  9.1165 +        QueryIntAttribute( name, &i );
  9.1166 +        return i;
  9.1167 +    }
  9.1168 +    /// See IntAttribute()
  9.1169 +    unsigned UnsignedAttribute( const char* name ) const {
  9.1170 +        unsigned i=0;
  9.1171 +        QueryUnsignedAttribute( name, &i );
  9.1172 +        return i;
  9.1173 +    }
  9.1174 +    /// See IntAttribute()
  9.1175 +    bool	 BoolAttribute( const char* name ) const	{
  9.1176 +        bool b=false;
  9.1177 +        QueryBoolAttribute( name, &b );
  9.1178 +        return b;
  9.1179 +    }
  9.1180 +    /// See IntAttribute()
  9.1181 +    double 	 DoubleAttribute( const char* name ) const	{
  9.1182 +        double d=0;
  9.1183 +        QueryDoubleAttribute( name, &d );
  9.1184 +        return d;
  9.1185 +    }
  9.1186 +    /// See IntAttribute()
  9.1187 +    float	 FloatAttribute( const char* name ) const	{
  9.1188 +        float f=0;
  9.1189 +        QueryFloatAttribute( name, &f );
  9.1190 +        return f;
  9.1191 +    }
  9.1192 +
  9.1193 +    /** Given an attribute name, QueryIntAttribute() returns
  9.1194 +    	XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
  9.1195 +    	can't be performed, or XML_NO_ATTRIBUTE if the attribute
  9.1196 +    	doesn't exist. If successful, the result of the conversion
  9.1197 +    	will be written to 'value'. If not successful, nothing will
  9.1198 +    	be written to 'value'. This allows you to provide default
  9.1199 +    	value:
  9.1200 +
  9.1201 +    	@verbatim
  9.1202 +    	int value = 10;
  9.1203 +    	QueryIntAttribute( "foo", &value );		// if "foo" isn't found, value will still be 10
  9.1204 +    	@endverbatim
  9.1205 +    */
  9.1206 +    XMLError QueryIntAttribute( const char* name, int* value ) const				{
  9.1207 +        const XMLAttribute* a = FindAttribute( name );
  9.1208 +        if ( !a ) {
  9.1209 +            return XML_NO_ATTRIBUTE;
  9.1210 +        }
  9.1211 +        return a->QueryIntValue( value );
  9.1212 +    }
  9.1213 +    /// See QueryIntAttribute()
  9.1214 +    XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const	{
  9.1215 +        const XMLAttribute* a = FindAttribute( name );
  9.1216 +        if ( !a ) {
  9.1217 +            return XML_NO_ATTRIBUTE;
  9.1218 +        }
  9.1219 +        return a->QueryUnsignedValue( value );
  9.1220 +    }
  9.1221 +    /// See QueryIntAttribute()
  9.1222 +    XMLError QueryBoolAttribute( const char* name, bool* value ) const				{
  9.1223 +        const XMLAttribute* a = FindAttribute( name );
  9.1224 +        if ( !a ) {
  9.1225 +            return XML_NO_ATTRIBUTE;
  9.1226 +        }
  9.1227 +        return a->QueryBoolValue( value );
  9.1228 +    }
  9.1229 +    /// See QueryIntAttribute()
  9.1230 +    XMLError QueryDoubleAttribute( const char* name, double* value ) const			{
  9.1231 +        const XMLAttribute* a = FindAttribute( name );
  9.1232 +        if ( !a ) {
  9.1233 +            return XML_NO_ATTRIBUTE;
  9.1234 +        }
  9.1235 +        return a->QueryDoubleValue( value );
  9.1236 +    }
  9.1237 +    /// See QueryIntAttribute()
  9.1238 +    XMLError QueryFloatAttribute( const char* name, float* value ) const			{
  9.1239 +        const XMLAttribute* a = FindAttribute( name );
  9.1240 +        if ( !a ) {
  9.1241 +            return XML_NO_ATTRIBUTE;
  9.1242 +        }
  9.1243 +        return a->QueryFloatValue( value );
  9.1244 +    }
  9.1245 +
  9.1246 +	
  9.1247 +    /** Given an attribute name, QueryAttribute() returns
  9.1248 +    	XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
  9.1249 +    	can't be performed, or XML_NO_ATTRIBUTE if the attribute
  9.1250 +    	doesn't exist. It is overloaded for the primitive types,
  9.1251 +		and is a generally more convenient replacement of
  9.1252 +		QueryIntAttribute() and related functions.
  9.1253 +		
  9.1254 +		If successful, the result of the conversion
  9.1255 +    	will be written to 'value'. If not successful, nothing will
  9.1256 +    	be written to 'value'. This allows you to provide default
  9.1257 +    	value:
  9.1258 +
  9.1259 +    	@verbatim
  9.1260 +    	int value = 10;
  9.1261 +    	QueryAttribute( "foo", &value );		// if "foo" isn't found, value will still be 10
  9.1262 +    	@endverbatim
  9.1263 +    */
  9.1264 +	int QueryAttribute( const char* name, int* value ) const {
  9.1265 +		return QueryIntAttribute( name, value );
  9.1266 +	}
  9.1267 +
  9.1268 +	int QueryAttribute( const char* name, unsigned int* value ) const {
  9.1269 +		return QueryUnsignedAttribute( name, value );
  9.1270 +	}
  9.1271 +
  9.1272 +	int QueryAttribute( const char* name, bool* value ) const {
  9.1273 +		return QueryBoolAttribute( name, value );
  9.1274 +	}
  9.1275 +
  9.1276 +	int QueryAttribute( const char* name, double* value ) const {
  9.1277 +		return QueryDoubleAttribute( name, value );
  9.1278 +	}
  9.1279 +
  9.1280 +	int QueryAttribute( const char* name, float* value ) const {
  9.1281 +		return QueryFloatAttribute( name, value );
  9.1282 +	}
  9.1283 +
  9.1284 +	/// Sets the named attribute to value.
  9.1285 +    void SetAttribute( const char* name, const char* value )	{
  9.1286 +        XMLAttribute* a = FindOrCreateAttribute( name );
  9.1287 +        a->SetAttribute( value );
  9.1288 +    }
  9.1289 +    /// Sets the named attribute to value.
  9.1290 +    void SetAttribute( const char* name, int value )			{
  9.1291 +        XMLAttribute* a = FindOrCreateAttribute( name );
  9.1292 +        a->SetAttribute( value );
  9.1293 +    }
  9.1294 +    /// Sets the named attribute to value.
  9.1295 +    void SetAttribute( const char* name, unsigned value )		{
  9.1296 +        XMLAttribute* a = FindOrCreateAttribute( name );
  9.1297 +        a->SetAttribute( value );
  9.1298 +    }
  9.1299 +    /// Sets the named attribute to value.
  9.1300 +    void SetAttribute( const char* name, bool value )			{
  9.1301 +        XMLAttribute* a = FindOrCreateAttribute( name );
  9.1302 +        a->SetAttribute( value );
  9.1303 +    }
  9.1304 +    /// Sets the named attribute to value.
  9.1305 +    void SetAttribute( const char* name, double value )		{
  9.1306 +        XMLAttribute* a = FindOrCreateAttribute( name );
  9.1307 +        a->SetAttribute( value );
  9.1308 +    }
  9.1309 +
  9.1310 +    /**
  9.1311 +    	Delete an attribute.
  9.1312 +    */
  9.1313 +    void DeleteAttribute( const char* name );
  9.1314 +
  9.1315 +    /// Return the first attribute in the list.
  9.1316 +    const XMLAttribute* FirstAttribute() const {
  9.1317 +        return _rootAttribute;
  9.1318 +    }
  9.1319 +    /// Query a specific attribute in the list.
  9.1320 +    const XMLAttribute* FindAttribute( const char* name ) const;
  9.1321 +
  9.1322 +    /** Convenience function for easy access to the text inside an element. Although easy
  9.1323 +    	and concise, GetText() is limited compared to getting the XMLText child
  9.1324 +    	and accessing it directly.
  9.1325 +
  9.1326 +    	If the first child of 'this' is a XMLText, the GetText()
  9.1327 +    	returns the character string of the Text node, else null is returned.
  9.1328 +
  9.1329 +    	This is a convenient method for getting the text of simple contained text:
  9.1330 +    	@verbatim
  9.1331 +    	<foo>This is text</foo>
  9.1332 +    		const char* str = fooElement->GetText();
  9.1333 +    	@endverbatim
  9.1334 +
  9.1335 +    	'str' will be a pointer to "This is text".
  9.1336 +
  9.1337 +    	Note that this function can be misleading. If the element foo was created from
  9.1338 +    	this XML:
  9.1339 +    	@verbatim
  9.1340 +    		<foo><b>This is text</b></foo>
  9.1341 +    	@endverbatim
  9.1342 +
  9.1343 +    	then the value of str would be null. The first child node isn't a text node, it is
  9.1344 +    	another element. From this XML:
  9.1345 +    	@verbatim
  9.1346 +    		<foo>This is <b>text</b></foo>
  9.1347 +    	@endverbatim
  9.1348 +    	GetText() will return "This is ".
  9.1349 +    */
  9.1350 +    const char* GetText() const;
  9.1351 +
  9.1352 +    /**
  9.1353 +    	Convenience method to query the value of a child text node. This is probably best
  9.1354 +    	shown by example. Given you have a document is this form:
  9.1355 +    	@verbatim
  9.1356 +    		<point>
  9.1357 +    			<x>1</x>
  9.1358 +    			<y>1.4</y>
  9.1359 +    		</point>
  9.1360 +    	@endverbatim
  9.1361 +
  9.1362 +    	The QueryIntText() and similar functions provide a safe and easier way to get to the
  9.1363 +    	"value" of x and y.
  9.1364 +
  9.1365 +    	@verbatim
  9.1366 +    		int x = 0;
  9.1367 +    		float y = 0;	// types of x and y are contrived for example
  9.1368 +    		const XMLElement* xElement = pointElement->FirstChildElement( "x" );
  9.1369 +    		const XMLElement* yElement = pointElement->FirstChildElement( "y" );
  9.1370 +    		xElement->QueryIntText( &x );
  9.1371 +    		yElement->QueryFloatText( &y );
  9.1372 +    	@endverbatim
  9.1373 +
  9.1374 +    	@returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
  9.1375 +    			 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
  9.1376 +
  9.1377 +    */
  9.1378 +    XMLError QueryIntText( int* ival ) const;
  9.1379 +    /// See QueryIntText()
  9.1380 +    XMLError QueryUnsignedText( unsigned* uval ) const;
  9.1381 +    /// See QueryIntText()
  9.1382 +    XMLError QueryBoolText( bool* bval ) const;
  9.1383 +    /// See QueryIntText()
  9.1384 +    XMLError QueryDoubleText( double* dval ) const;
  9.1385 +    /// See QueryIntText()
  9.1386 +    XMLError QueryFloatText( float* fval ) const;
  9.1387 +
  9.1388 +    // internal:
  9.1389 +    enum {
  9.1390 +        OPEN,		// <foo>
  9.1391 +        CLOSED,		// <foo/>
  9.1392 +        CLOSING		// </foo>
  9.1393 +    };
  9.1394 +    int ClosingType() const {
  9.1395 +        return _closingType;
  9.1396 +    }
  9.1397 +    char* ParseDeep( char* p, StrPair* endTag );
  9.1398 +    virtual XMLNode* ShallowClone( XMLDocument* document ) const;
  9.1399 +    virtual bool ShallowEqual( const XMLNode* compare ) const;
  9.1400 +
  9.1401 +private:
  9.1402 +    XMLElement( XMLDocument* doc );
  9.1403 +    virtual ~XMLElement();
  9.1404 +    XMLElement( const XMLElement& );	// not supported
  9.1405 +    void operator=( const XMLElement& );	// not supported
  9.1406 +
  9.1407 +    XMLAttribute* FindAttribute( const char* name );
  9.1408 +    XMLAttribute* FindOrCreateAttribute( const char* name );
  9.1409 +    //void LinkAttribute( XMLAttribute* attrib );
  9.1410 +    char* ParseAttributes( char* p );
  9.1411 +
  9.1412 +    int _closingType;
  9.1413 +    // The attribute list is ordered; there is no 'lastAttribute'
  9.1414 +    // because the list needs to be scanned for dupes before adding
  9.1415 +    // a new attribute.
  9.1416 +    XMLAttribute* _rootAttribute;
  9.1417 +};
  9.1418 +
  9.1419 +
  9.1420 +enum Whitespace {
  9.1421 +    PRESERVE_WHITESPACE,
  9.1422 +    COLLAPSE_WHITESPACE
  9.1423 +};
  9.1424 +
  9.1425 +
  9.1426 +/** A Document binds together all the functionality.
  9.1427 +	It can be saved, loaded, and printed to the screen.
  9.1428 +	All Nodes are connected and allocated to a Document.
  9.1429 +	If the Document is deleted, all its Nodes are also deleted.
  9.1430 +*/
  9.1431 +class TINYXML2_LIB XMLDocument : public XMLNode
  9.1432 +{
  9.1433 +    friend class XMLElement;
  9.1434 +public:
  9.1435 +    /// constructor
  9.1436 +    XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE );
  9.1437 +    ~XMLDocument();
  9.1438 +
  9.1439 +    virtual XMLDocument* ToDocument()				{
  9.1440 +        return this;
  9.1441 +    }
  9.1442 +    virtual const XMLDocument* ToDocument() const	{
  9.1443 +        return this;
  9.1444 +    }
  9.1445 +
  9.1446 +    /**
  9.1447 +    	Parse an XML file from a character string.
  9.1448 +    	Returns XML_NO_ERROR (0) on success, or
  9.1449 +    	an errorID.
  9.1450 +
  9.1451 +    	You may optionally pass in the 'nBytes', which is
  9.1452 +    	the number of bytes which will be parsed. If not
  9.1453 +    	specified, TinyXML-2 will assume 'xml' points to a
  9.1454 +    	null terminated string.
  9.1455 +    */
  9.1456 +    XMLError Parse( const char* xml, size_t nBytes=(size_t)(-1) );
  9.1457 +
  9.1458 +    /**
  9.1459 +    	Load an XML file from disk.
  9.1460 +    	Returns XML_NO_ERROR (0) on success, or
  9.1461 +    	an errorID.
  9.1462 +    */
  9.1463 +    XMLError LoadFile( const char* filename );
  9.1464 +
  9.1465 +    /**
  9.1466 +    	Load an XML file from disk. You are responsible
  9.1467 +    	for providing and closing the FILE*.
  9.1468 +
  9.1469 +    	Returns XML_NO_ERROR (0) on success, or
  9.1470 +    	an errorID.
  9.1471 +    */
  9.1472 +    XMLError LoadFile( FILE* );
  9.1473 +
  9.1474 +    /**
  9.1475 +    	Save the XML file to disk.
  9.1476 +    	Returns XML_NO_ERROR (0) on success, or
  9.1477 +    	an errorID.
  9.1478 +    */
  9.1479 +    XMLError SaveFile( const char* filename, bool compact = false );
  9.1480 +
  9.1481 +    /**
  9.1482 +    	Save the XML file to disk. You are responsible
  9.1483 +    	for providing and closing the FILE*.
  9.1484 +
  9.1485 +    	Returns XML_NO_ERROR (0) on success, or
  9.1486 +    	an errorID.
  9.1487 +    */
  9.1488 +    XMLError SaveFile( FILE* fp, bool compact = false );
  9.1489 +
  9.1490 +    bool ProcessEntities() const		{
  9.1491 +        return _processEntities;
  9.1492 +    }
  9.1493 +    Whitespace WhitespaceMode() const	{
  9.1494 +        return _whitespace;
  9.1495 +    }
  9.1496 +
  9.1497 +    /**
  9.1498 +    	Returns true if this document has a leading Byte Order Mark of UTF8.
  9.1499 +    */
  9.1500 +    bool HasBOM() const {
  9.1501 +        return _writeBOM;
  9.1502 +    }
  9.1503 +    /** Sets whether to write the BOM when writing the file.
  9.1504 +    */
  9.1505 +    void SetBOM( bool useBOM ) {
  9.1506 +        _writeBOM = useBOM;
  9.1507 +    }
  9.1508 +
  9.1509 +    /** Return the root element of DOM. Equivalent to FirstChildElement().
  9.1510 +        To get the first node, use FirstChild().
  9.1511 +    */
  9.1512 +    XMLElement* RootElement()				{
  9.1513 +        return FirstChildElement();
  9.1514 +    }
  9.1515 +    const XMLElement* RootElement() const	{
  9.1516 +        return FirstChildElement();
  9.1517 +    }
  9.1518 +
  9.1519 +    /** Print the Document. If the Printer is not provided, it will
  9.1520 +        print to stdout. If you provide Printer, this can print to a file:
  9.1521 +    	@verbatim
  9.1522 +    	XMLPrinter printer( fp );
  9.1523 +    	doc.Print( &printer );
  9.1524 +    	@endverbatim
  9.1525 +
  9.1526 +    	Or you can use a printer to print to memory:
  9.1527 +    	@verbatim
  9.1528 +    	XMLPrinter printer;
  9.1529 +    	doc.Print( &printer );
  9.1530 +    	// printer.CStr() has a const char* to the XML
  9.1531 +    	@endverbatim
  9.1532 +    */
  9.1533 +    void Print( XMLPrinter* streamer=0 ) const;
  9.1534 +    virtual bool Accept( XMLVisitor* visitor ) const;
  9.1535 +
  9.1536 +    /**
  9.1537 +    	Create a new Element associated with
  9.1538 +    	this Document. The memory for the Element
  9.1539 +    	is managed by the Document.
  9.1540 +    */
  9.1541 +    XMLElement* NewElement( const char* name );
  9.1542 +    /**
  9.1543 +    	Create a new Comment associated with
  9.1544 +    	this Document. The memory for the Comment
  9.1545 +    	is managed by the Document.
  9.1546 +    */
  9.1547 +    XMLComment* NewComment( const char* comment );
  9.1548 +    /**
  9.1549 +    	Create a new Text associated with
  9.1550 +    	this Document. The memory for the Text
  9.1551 +    	is managed by the Document.
  9.1552 +    */
  9.1553 +    XMLText* NewText( const char* text );
  9.1554 +    /**
  9.1555 +    	Create a new Declaration associated with
  9.1556 +    	this Document. The memory for the object
  9.1557 +    	is managed by the Document.
  9.1558 +
  9.1559 +    	If the 'text' param is null, the standard
  9.1560 +    	declaration is used.:
  9.1561 +    	@verbatim
  9.1562 +    		<?xml version="1.0" encoding="UTF-8"?>
  9.1563 +    	@endverbatim
  9.1564 +    */
  9.1565 +    XMLDeclaration* NewDeclaration( const char* text=0 );
  9.1566 +    /**
  9.1567 +    	Create a new Unknown associated with
  9.1568 +    	this Document. The memory for the object
  9.1569 +    	is managed by the Document.
  9.1570 +    */
  9.1571 +    XMLUnknown* NewUnknown( const char* text );
  9.1572 +
  9.1573 +    /**
  9.1574 +    	Delete a node associated with this document.
  9.1575 +    	It will be unlinked from the DOM.
  9.1576 +    */
  9.1577 +    void DeleteNode( XMLNode* node )	{
  9.1578 +        node->_parent->DeleteChild( node );
  9.1579 +    }
  9.1580 +
  9.1581 +    void SetError( XMLError error, const char* str1, const char* str2 );
  9.1582 +
  9.1583 +    /// Return true if there was an error parsing the document.
  9.1584 +    bool Error() const {
  9.1585 +        return _errorID != XML_NO_ERROR;
  9.1586 +    }
  9.1587 +    /// Return the errorID.
  9.1588 +    XMLError  ErrorID() const {
  9.1589 +        return _errorID;
  9.1590 +    }
  9.1591 +    /// Return a possibly helpful diagnostic location or string.
  9.1592 +    const char* GetErrorStr1() const {
  9.1593 +        return _errorStr1;
  9.1594 +    }
  9.1595 +    /// Return a possibly helpful secondary diagnostic location or string.
  9.1596 +    const char* GetErrorStr2() const {
  9.1597 +        return _errorStr2;
  9.1598 +    }
  9.1599 +    /// If there is an error, print it to stdout.
  9.1600 +    void PrintError() const;
  9.1601 +    
  9.1602 +    /// Clear the document, resetting it to the initial state.
  9.1603 +    void Clear();
  9.1604 +
  9.1605 +    // internal
  9.1606 +    char* Identify( char* p, XMLNode** node );
  9.1607 +
  9.1608 +    virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const	{
  9.1609 +        return 0;
  9.1610 +    }
  9.1611 +    virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const	{
  9.1612 +        return false;
  9.1613 +    }
  9.1614 +
  9.1615 +private:
  9.1616 +    XMLDocument( const XMLDocument& );	// not supported
  9.1617 +    void operator=( const XMLDocument& );	// not supported
  9.1618 +
  9.1619 +    bool        _writeBOM;
  9.1620 +    bool        _processEntities;
  9.1621 +    XMLError    _errorID;
  9.1622 +    Whitespace  _whitespace;
  9.1623 +    const char* _errorStr1;
  9.1624 +    const char* _errorStr2;
  9.1625 +    char*       _charBuffer;
  9.1626 +
  9.1627 +    MemPoolT< sizeof(XMLElement) >	 _elementPool;
  9.1628 +    MemPoolT< sizeof(XMLAttribute) > _attributePool;
  9.1629 +    MemPoolT< sizeof(XMLText) >		 _textPool;
  9.1630 +    MemPoolT< sizeof(XMLComment) >	 _commentPool;
  9.1631 +};
  9.1632 +
  9.1633 +
  9.1634 +/**
  9.1635 +	A XMLHandle is a class that wraps a node pointer with null checks; this is
  9.1636 +	an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2
  9.1637 +	DOM structure. It is a separate utility class.
  9.1638 +
  9.1639 +	Take an example:
  9.1640 +	@verbatim
  9.1641 +	<Document>
  9.1642 +		<Element attributeA = "valueA">
  9.1643 +			<Child attributeB = "value1" />
  9.1644 +			<Child attributeB = "value2" />
  9.1645 +		</Element>
  9.1646 +	</Document>
  9.1647 +	@endverbatim
  9.1648 +
  9.1649 +	Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
  9.1650 +	easy to write a *lot* of code that looks like:
  9.1651 +
  9.1652 +	@verbatim
  9.1653 +	XMLElement* root = document.FirstChildElement( "Document" );
  9.1654 +	if ( root )
  9.1655 +	{
  9.1656 +		XMLElement* element = root->FirstChildElement( "Element" );
  9.1657 +		if ( element )
  9.1658 +		{
  9.1659 +			XMLElement* child = element->FirstChildElement( "Child" );
  9.1660 +			if ( child )
  9.1661 +			{
  9.1662 +				XMLElement* child2 = child->NextSiblingElement( "Child" );
  9.1663 +				if ( child2 )
  9.1664 +				{
  9.1665 +					// Finally do something useful.
  9.1666 +	@endverbatim
  9.1667 +
  9.1668 +	And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
  9.1669 +	of such code. A XMLHandle checks for null pointers so it is perfectly safe
  9.1670 +	and correct to use:
  9.1671 +
  9.1672 +	@verbatim
  9.1673 +	XMLHandle docHandle( &document );
  9.1674 +	XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
  9.1675 +	if ( child2 )
  9.1676 +	{
  9.1677 +		// do something useful
  9.1678 +	@endverbatim
  9.1679 +
  9.1680 +	Which is MUCH more concise and useful.
  9.1681 +
  9.1682 +	It is also safe to copy handles - internally they are nothing more than node pointers.
  9.1683 +	@verbatim
  9.1684 +	XMLHandle handleCopy = handle;
  9.1685 +	@endverbatim
  9.1686 +
  9.1687 +	See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
  9.1688 +*/
  9.1689 +class TINYXML2_LIB XMLHandle
  9.1690 +{
  9.1691 +public:
  9.1692 +    /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
  9.1693 +    XMLHandle( XMLNode* node )												{
  9.1694 +        _node = node;
  9.1695 +    }
  9.1696 +    /// Create a handle from a node.
  9.1697 +    XMLHandle( XMLNode& node )												{
  9.1698 +        _node = &node;
  9.1699 +    }
  9.1700 +    /// Copy constructor
  9.1701 +    XMLHandle( const XMLHandle& ref )										{
  9.1702 +        _node = ref._node;
  9.1703 +    }
  9.1704 +    /// Assignment
  9.1705 +    XMLHandle& operator=( const XMLHandle& ref )							{
  9.1706 +        _node = ref._node;
  9.1707 +        return *this;
  9.1708 +    }
  9.1709 +
  9.1710 +    /// Get the first child of this handle.
  9.1711 +    XMLHandle FirstChild() 													{
  9.1712 +        return XMLHandle( _node ? _node->FirstChild() : 0 );
  9.1713 +    }
  9.1714 +    /// Get the first child element of this handle.
  9.1715 +    XMLHandle FirstChildElement( const char* value=0 )						{
  9.1716 +        return XMLHandle( _node ? _node->FirstChildElement( value ) : 0 );
  9.1717 +    }
  9.1718 +    /// Get the last child of this handle.
  9.1719 +    XMLHandle LastChild()													{
  9.1720 +        return XMLHandle( _node ? _node->LastChild() : 0 );
  9.1721 +    }
  9.1722 +    /// Get the last child element of this handle.
  9.1723 +    XMLHandle LastChildElement( const char* _value=0 )						{
  9.1724 +        return XMLHandle( _node ? _node->LastChildElement( _value ) : 0 );
  9.1725 +    }
  9.1726 +    /// Get the previous sibling of this handle.
  9.1727 +    XMLHandle PreviousSibling()												{
  9.1728 +        return XMLHandle( _node ? _node->PreviousSibling() : 0 );
  9.1729 +    }
  9.1730 +    /// Get the previous sibling element of this handle.
  9.1731 +    XMLHandle PreviousSiblingElement( const char* _value=0 )				{
  9.1732 +        return XMLHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 );
  9.1733 +    }
  9.1734 +    /// Get the next sibling of this handle.
  9.1735 +    XMLHandle NextSibling()													{
  9.1736 +        return XMLHandle( _node ? _node->NextSibling() : 0 );
  9.1737 +    }
  9.1738 +    /// Get the next sibling element of this handle.
  9.1739 +    XMLHandle NextSiblingElement( const char* _value=0 )					{
  9.1740 +        return XMLHandle( _node ? _node->NextSiblingElement( _value ) : 0 );
  9.1741 +    }
  9.1742 +
  9.1743 +    /// Safe cast to XMLNode. This can return null.
  9.1744 +    XMLNode* ToNode()							{
  9.1745 +        return _node;
  9.1746 +    }
  9.1747 +    /// Safe cast to XMLElement. This can return null.
  9.1748 +    XMLElement* ToElement() 					{
  9.1749 +        return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 );
  9.1750 +    }
  9.1751 +    /// Safe cast to XMLText. This can return null.
  9.1752 +    XMLText* ToText() 							{
  9.1753 +        return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 );
  9.1754 +    }
  9.1755 +    /// Safe cast to XMLUnknown. This can return null.
  9.1756 +    XMLUnknown* ToUnknown() 					{
  9.1757 +        return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 );
  9.1758 +    }
  9.1759 +    /// Safe cast to XMLDeclaration. This can return null.
  9.1760 +    XMLDeclaration* ToDeclaration() 			{
  9.1761 +        return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 );
  9.1762 +    }
  9.1763 +
  9.1764 +private:
  9.1765 +    XMLNode* _node;
  9.1766 +};
  9.1767 +
  9.1768 +
  9.1769 +/**
  9.1770 +	A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
  9.1771 +	same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
  9.1772 +*/
  9.1773 +class TINYXML2_LIB XMLConstHandle
  9.1774 +{
  9.1775 +public:
  9.1776 +    XMLConstHandle( const XMLNode* node )											{
  9.1777 +        _node = node;
  9.1778 +    }
  9.1779 +    XMLConstHandle( const XMLNode& node )											{
  9.1780 +        _node = &node;
  9.1781 +    }
  9.1782 +    XMLConstHandle( const XMLConstHandle& ref )										{
  9.1783 +        _node = ref._node;
  9.1784 +    }
  9.1785 +
  9.1786 +    XMLConstHandle& operator=( const XMLConstHandle& ref )							{
  9.1787 +        _node = ref._node;
  9.1788 +        return *this;
  9.1789 +    }
  9.1790 +
  9.1791 +    const XMLConstHandle FirstChild() const											{
  9.1792 +        return XMLConstHandle( _node ? _node->FirstChild() : 0 );
  9.1793 +    }
  9.1794 +    const XMLConstHandle FirstChildElement( const char* value=0 ) const				{
  9.1795 +        return XMLConstHandle( _node ? _node->FirstChildElement( value ) : 0 );
  9.1796 +    }
  9.1797 +    const XMLConstHandle LastChild()	const										{
  9.1798 +        return XMLConstHandle( _node ? _node->LastChild() : 0 );
  9.1799 +    }
  9.1800 +    const XMLConstHandle LastChildElement( const char* _value=0 ) const				{
  9.1801 +        return XMLConstHandle( _node ? _node->LastChildElement( _value ) : 0 );
  9.1802 +    }
  9.1803 +    const XMLConstHandle PreviousSibling() const									{
  9.1804 +        return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );
  9.1805 +    }
  9.1806 +    const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const		{
  9.1807 +        return XMLConstHandle( _node ? _node->PreviousSiblingElement( _value ) : 0 );
  9.1808 +    }
  9.1809 +    const XMLConstHandle NextSibling() const										{
  9.1810 +        return XMLConstHandle( _node ? _node->NextSibling() : 0 );
  9.1811 +    }
  9.1812 +    const XMLConstHandle NextSiblingElement( const char* _value=0 ) const			{
  9.1813 +        return XMLConstHandle( _node ? _node->NextSiblingElement( _value ) : 0 );
  9.1814 +    }
  9.1815 +
  9.1816 +
  9.1817 +    const XMLNode* ToNode() const				{
  9.1818 +        return _node;
  9.1819 +    }
  9.1820 +    const XMLElement* ToElement() const			{
  9.1821 +        return ( ( _node && _node->ToElement() ) ? _node->ToElement() : 0 );
  9.1822 +    }
  9.1823 +    const XMLText* ToText() const				{
  9.1824 +        return ( ( _node && _node->ToText() ) ? _node->ToText() : 0 );
  9.1825 +    }
  9.1826 +    const XMLUnknown* ToUnknown() const			{
  9.1827 +        return ( ( _node && _node->ToUnknown() ) ? _node->ToUnknown() : 0 );
  9.1828 +    }
  9.1829 +    const XMLDeclaration* ToDeclaration() const	{
  9.1830 +        return ( ( _node && _node->ToDeclaration() ) ? _node->ToDeclaration() : 0 );
  9.1831 +    }
  9.1832 +
  9.1833 +private:
  9.1834 +    const XMLNode* _node;
  9.1835 +};
  9.1836 +
  9.1837 +
  9.1838 +/**
  9.1839 +	Printing functionality. The XMLPrinter gives you more
  9.1840 +	options than the XMLDocument::Print() method.
  9.1841 +
  9.1842 +	It can:
  9.1843 +	-# Print to memory.
  9.1844 +	-# Print to a file you provide.
  9.1845 +	-# Print XML without a XMLDocument.
  9.1846 +
  9.1847 +	Print to Memory
  9.1848 +
  9.1849 +	@verbatim
  9.1850 +	XMLPrinter printer;
  9.1851 +	doc.Print( &printer );
  9.1852 +	SomeFunction( printer.CStr() );
  9.1853 +	@endverbatim
  9.1854 +
  9.1855 +	Print to a File
  9.1856 +
  9.1857 +	You provide the file pointer.
  9.1858 +	@verbatim
  9.1859 +	XMLPrinter printer( fp );
  9.1860 +	doc.Print( &printer );
  9.1861 +	@endverbatim
  9.1862 +
  9.1863 +	Print without a XMLDocument
  9.1864 +
  9.1865 +	When loading, an XML parser is very useful. However, sometimes
  9.1866 +	when saving, it just gets in the way. The code is often set up
  9.1867 +	for streaming, and constructing the DOM is just overhead.
  9.1868 +
  9.1869 +	The Printer supports the streaming case. The following code
  9.1870 +	prints out a trivially simple XML file without ever creating
  9.1871 +	an XML document.
  9.1872 +
  9.1873 +	@verbatim
  9.1874 +	XMLPrinter printer( fp );
  9.1875 +	printer.OpenElement( "foo" );
  9.1876 +	printer.PushAttribute( "foo", "bar" );
  9.1877 +	printer.CloseElement();
  9.1878 +	@endverbatim
  9.1879 +*/
  9.1880 +class TINYXML2_LIB XMLPrinter : public XMLVisitor
  9.1881 +{
  9.1882 +public:
  9.1883 +    /** Construct the printer. If the FILE* is specified,
  9.1884 +    	this will print to the FILE. Else it will print
  9.1885 +    	to memory, and the result is available in CStr().
  9.1886 +    	If 'compact' is set to true, then output is created
  9.1887 +    	with only required whitespace and newlines.
  9.1888 +    */
  9.1889 +    XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );
  9.1890 +    ~XMLPrinter()	{}
  9.1891 +
  9.1892 +    /** If streaming, write the BOM and declaration. */
  9.1893 +    void PushHeader( bool writeBOM, bool writeDeclaration );
  9.1894 +    /** If streaming, start writing an element.
  9.1895 +        The element must be closed with CloseElement()
  9.1896 +    */
  9.1897 +    void OpenElement( const char* name );
  9.1898 +    /// If streaming, add an attribute to an open element.
  9.1899 +    void PushAttribute( const char* name, const char* value );
  9.1900 +    void PushAttribute( const char* name, int value );
  9.1901 +    void PushAttribute( const char* name, unsigned value );
  9.1902 +    void PushAttribute( const char* name, bool value );
  9.1903 +    void PushAttribute( const char* name, double value );
  9.1904 +    /// If streaming, close the Element.
  9.1905 +    void CloseElement();
  9.1906 +
  9.1907 +    /// Add a text node.
  9.1908 +    void PushText( const char* text, bool cdata=false );
  9.1909 +    /// Add a text node from an integer.
  9.1910 +    void PushText( int value );
  9.1911 +    /// Add a text node from an unsigned.
  9.1912 +    void PushText( unsigned value );
  9.1913 +    /// Add a text node from a bool.
  9.1914 +    void PushText( bool value );
  9.1915 +    /// Add a text node from a float.
  9.1916 +    void PushText( float value );
  9.1917 +    /// Add a text node from a double.
  9.1918 +    void PushText( double value );
  9.1919 +
  9.1920 +    /// Add a comment
  9.1921 +    void PushComment( const char* comment );
  9.1922 +
  9.1923 +    void PushDeclaration( const char* value );
  9.1924 +    void PushUnknown( const char* value );
  9.1925 +
  9.1926 +    virtual bool VisitEnter( const XMLDocument& /*doc*/ );
  9.1927 +    virtual bool VisitExit( const XMLDocument& /*doc*/ )			{
  9.1928 +        return true;
  9.1929 +    }
  9.1930 +
  9.1931 +    virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
  9.1932 +    virtual bool VisitExit( const XMLElement& element );
  9.1933 +
  9.1934 +    virtual bool Visit( const XMLText& text );
  9.1935 +    virtual bool Visit( const XMLComment& comment );
  9.1936 +    virtual bool Visit( const XMLDeclaration& declaration );
  9.1937 +    virtual bool Visit( const XMLUnknown& unknown );
  9.1938 +
  9.1939 +    /**
  9.1940 +    	If in print to memory mode, return a pointer to
  9.1941 +    	the XML file in memory.
  9.1942 +    */
  9.1943 +    const char* CStr() const {
  9.1944 +        return _buffer.Mem();
  9.1945 +    }
  9.1946 +    /**
  9.1947 +    	If in print to memory mode, return the size
  9.1948 +    	of the XML file in memory. (Note the size returned
  9.1949 +    	includes the terminating null.)
  9.1950 +    */
  9.1951 +    int CStrSize() const {
  9.1952 +        return _buffer.Size();
  9.1953 +    }
  9.1954 +
  9.1955 +private:
  9.1956 +    void SealElement();
  9.1957 +    void PrintSpace( int depth );
  9.1958 +    void PrintString( const char*, bool restrictedEntitySet );	// prints out, after detecting entities.
  9.1959 +    void Print( const char* format, ... );
  9.1960 +
  9.1961 +    bool _elementJustOpened;
  9.1962 +    bool _firstElement;
  9.1963 +    FILE* _fp;
  9.1964 +    int _depth;
  9.1965 +    int _textDepth;
  9.1966 +    bool _processEntities;
  9.1967 +    bool _compactMode;
  9.1968 +
  9.1969 +    enum {
  9.1970 +        ENTITY_RANGE = 64,
  9.1971 +        BUF_SIZE = 200
  9.1972 +    };
  9.1973 +    bool _entityFlag[ENTITY_RANGE];
  9.1974 +    bool _restrictedEntityFlag[ENTITY_RANGE];
  9.1975 +
  9.1976 +    DynArray< const char*, 10 > _stack;
  9.1977 +    DynArray< char, 20 > _buffer;
  9.1978 +#ifdef _MSC_VER
  9.1979 +    DynArray< char, 20 > _accumulator;
  9.1980 +#endif
  9.1981 +};
  9.1982 +
  9.1983 +
  9.1984 +}	// tinyxml2
  9.1985 +
  9.1986 +#if defined(_MSC_VER)
  9.1987 +#   pragma warning(pop)
  9.1988 +#endif
  9.1989 +
  9.1990 +#endif // TINYXML2_INCLUDED
    10.1 --- a/src/goat3d.cc	Fri Sep 27 03:17:36 2013 +0300
    10.2 +++ b/src/goat3d.cc	Fri Sep 27 06:58:37 2013 +0300
    10.3 @@ -243,15 +243,7 @@
    10.4  	return (int)mesh->faces.size();
    10.5  }
    10.6  
    10.7 -#if __cplusplus >= 201103L
    10.8 -#define MOVE(x)	std::move(x)
    10.9 -#else
   10.10 -#define MOVE(x) x
   10.11 -#endif
   10.12 -
   10.13 -#define VECDATA(type, data, num) \
   10.14 -	MOVE(std::vector<type>((type*)(data), (type*)(data) + (num)))
   10.15 -
   10.16 +// VECDATA is in goat3d_impl.h
   10.17  void goat3d_set_mesh_attribs(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib, const void *data, int vnum)
   10.18  {
   10.19  	if(attrib == GOAT3D_MESH_ATTR_VERTEX) {
   10.20 @@ -472,6 +464,16 @@
   10.21  	g->scn->add_mesh(mesh);
   10.22  }
   10.23  
   10.24 +int goat3d_get_mesh_count(struct goat3d *g)
   10.25 +{
   10.26 +	return g->scn->get_mesh_count();
   10.27 +}
   10.28 +
   10.29 +struct goat3d_mesh *goat3d_get_mesh(struct goat3d *g, int idx)
   10.30 +{
   10.31 +	return (goat3d_mesh*)g->scn->get_mesh(idx);
   10.32 +}
   10.33 +
   10.34  
   10.35  }	// extern "C"
   10.36  
    11.1 --- a/src/goat3d.h	Fri Sep 27 03:17:36 2013 +0300
    11.2 +++ b/src/goat3d.h	Fri Sep 27 06:58:37 2013 +0300
    11.3 @@ -155,6 +155,9 @@
    11.4  
    11.5  void goat3d_add_mesh(struct goat3d *g, struct goat3d_mesh *mesh);
    11.6  
    11.7 +int goat3d_get_mesh_count(struct goat3d *g);
    11.8 +struct goat3d_mesh *goat3d_get_mesh(struct goat3d *g, int idx);
    11.9 +
   11.10  #ifdef __cplusplus
   11.11  }
   11.12  #endif
    12.1 --- a/src/goat3d_impl.h	Fri Sep 27 03:17:36 2013 +0300
    12.2 +++ b/src/goat3d_impl.h	Fri Sep 27 06:58:37 2013 +0300
    12.3 @@ -12,6 +12,16 @@
    12.4  
    12.5  extern int goat_log_level;
    12.6  
    12.7 +#if __cplusplus >= 201103L
    12.8 +#define MOVE(x)	std::move(x)
    12.9 +#else
   12.10 +#define MOVE(x) x
   12.11 +#endif
   12.12 +
   12.13 +#define VECDATA(type, data, num) \
   12.14 +	MOVE(std::vector<type>((type*)(data), (type*)(data) + (num)))
   12.15 +
   12.16 +
   12.17  class Scene {
   12.18  private:
   12.19  	std::string name;
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/goat3d_readxml.cc	Fri Sep 27 06:58:37 2013 +0300
    13.3 @@ -0,0 +1,175 @@
    13.4 +#include <stdio.h>
    13.5 +#include "goat3d.h"
    13.6 +#include "goat3d_impl.h"
    13.7 +#include "tinyxml2.h"
    13.8 +#include "log.h"
    13.9 +
   13.10 +using namespace tinyxml2;
   13.11 +
   13.12 +static Material *read_material(Scene *scn, XMLElement *xml_mtl);
   13.13 +static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr);
   13.14 +static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh);
   13.15 +static std::string get_name(XMLElement *node, int idx);
   13.16 +
   13.17 +bool Scene::loadxml(goat3d_io *io)
   13.18 +{
   13.19 +	long bytes = io->seek(0, SEEK_END, io->cls);
   13.20 +	io->seek(0, SEEK_SET, io->cls);
   13.21 +
   13.22 +	char *buf = new char[bytes];
   13.23 +	if(io->read(buf, bytes, io->cls) < bytes) {
   13.24 +		logmsg(LOG_ERROR, "failed to read XML scene file\n");
   13.25 +		return false;
   13.26 +	}
   13.27 +
   13.28 +	XMLDocument xml;
   13.29 +	XMLError err = xml.Parse(buf, bytes);
   13.30 +	if(err) {
   13.31 +		logmsg(LOG_ERROR, "failed to parse XML scene file: %s\n%s\n", xml.GetErrorStr1(),
   13.32 +				xml.GetErrorStr2());
   13.33 +		return false;
   13.34 +	}
   13.35 +
   13.36 +	XMLElement *root = xml.RootElement();
   13.37 +	if(strcmp(root->Name(), "scene") != 0) {
   13.38 +		logmsg(LOG_ERROR, "invalid XML file, root node is not <scene>\n");
   13.39 +		return false;
   13.40 +	}
   13.41 +
   13.42 +	XMLElement *elem;
   13.43 +
   13.44 +	// get all materials
   13.45 +	elem = root->FirstChildElement("mtl");
   13.46 +	while(elem) {
   13.47 +		Material *mtl = read_material(this, elem);
   13.48 +		if(mtl) {
   13.49 +			add_material(mtl);
   13.50 +		}
   13.51 +		elem = elem->NextSiblingElement("mtl");
   13.52 +	}
   13.53 +
   13.54 +	// get all meshes
   13.55 +	elem = root->FirstChildElement("mesh");
   13.56 +	while(elem) {
   13.57 +		Mesh *mesh = read_mesh(this, elem);
   13.58 +		if(mesh) {
   13.59 +			add_mesh(mesh);
   13.60 +		}
   13.61 +		elem = elem->NextSiblingElement("mesh");
   13.62 +	}
   13.63 +
   13.64 +	return false;
   13.65 +}
   13.66 +
   13.67 +
   13.68 +static Material *read_material(Scene *scn, XMLElement *xml_mtl)
   13.69 +{
   13.70 +	Material *mtl = new Material;
   13.71 +	mtl->name = get_name(xml_mtl, scn->get_material_count());
   13.72 +
   13.73 +	// get all the material attributes in turn
   13.74 +	XMLElement *elem = xml_mtl->FirstChildElement("attr");
   13.75 +	while(elem) {
   13.76 +		MaterialAttrib attr;
   13.77 +		const char *name = read_material_attrib(&attr, elem);
   13.78 +		if(name) {
   13.79 +			(*mtl)[name] = attr;
   13.80 +		}
   13.81 +
   13.82 +		elem = elem->NextSiblingElement("attr");
   13.83 +	}
   13.84 +
   13.85 +	return mtl;
   13.86 +}
   13.87 +
   13.88 +static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr)
   13.89 +{
   13.90 +	const char *name;
   13.91 +
   13.92 +	XMLElement *elem;
   13.93 +	if((elem = xml_attr->FirstChildElement("name"))) {
   13.94 +		if(!(name = elem->Attribute("string"))) {
   13.95 +			return 0;
   13.96 +		}
   13.97 +	}
   13.98 +
   13.99 +	if((elem = xml_attr->FirstChildElement("val"))) {
  13.100 +		if(elem->QueryFloatAttribute("float", &attr->value.x) != XML_NO_ERROR) {
  13.101 +			// try a float3
  13.102 +			const char *valstr = elem->Attribute("float3");
  13.103 +			if(!valstr || sscanf(valstr, "%f %f %f", &attr->value.x, &attr->value.y,
  13.104 +						&attr->value.z) != 3) {
  13.105 +				// try a float4
  13.106 +				valstr = elem->Attribute("float4");
  13.107 +				if(!valstr || sscanf(valstr, "%f %f %f %f", &attr->value.x, &attr->value.y,
  13.108 +							&attr->value.z, &attr->value.w) != 4) {
  13.109 +					// no valid val attribute found
  13.110 +					return 0;
  13.111 +				}
  13.112 +			}
  13.113 +		}
  13.114 +	}
  13.115 +
  13.116 +	if((elem = xml_attr->FirstChildElement("map"))) {
  13.117 +		const char *tex = elem->Attribute("string");
  13.118 +		if(tex) {
  13.119 +			attr->map = std::string(tex);
  13.120 +		}
  13.121 +	}
  13.122 +
  13.123 +	return name;
  13.124 +}
  13.125 +
  13.126 +static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh)
  13.127 +{
  13.128 +	Mesh *mesh = new Mesh;
  13.129 +	mesh->name = get_name(xml_mesh, scn->get_mesh_count());
  13.130 +
  13.131 +	XMLElement *elem;
  13.132 +	if((elem = xml_mesh->FirstChildElement("material"))) {
  13.133 +		int idx;
  13.134 +		if(elem->QueryIntAttribute("int", &idx) == XML_NO_ERROR) {
  13.135 +			mesh->material = scn->get_material(idx);
  13.136 +		} else {
  13.137 +			// try string
  13.138 +			const char *mtlstr = elem->Attribute("string");
  13.139 +			if(mtlstr) {
  13.140 +				mesh->material = scn->get_material(mtlstr);
  13.141 +			}
  13.142 +		}
  13.143 +	}
  13.144 +
  13.145 +	/* reading mesh data from XML is not supported, only MESH_FILE can be used to
  13.146 +	 * specify an external mesh file to be loaded
  13.147 +	 */
  13.148 +
  13.149 +	if((elem = xml_mesh->FirstChildElement("file"))) {
  13.150 +		const char *fname = elem->Attribute("string");
  13.151 +		if(fname) {
  13.152 +			if(!mesh->load(fname)) {
  13.153 +				delete mesh;
  13.154 +				return 0;
  13.155 +			}
  13.156 +		}
  13.157 +	}
  13.158 +
  13.159 +	return mesh;
  13.160 +}
  13.161 +
  13.162 +static std::string get_name(XMLElement *node, int idx)
  13.163 +{
  13.164 +	char buf[64];
  13.165 +	const char *name = 0;
  13.166 +
  13.167 +	XMLElement *elem;
  13.168 +	if((elem = node->FirstChildElement("name"))) {
  13.169 +		name = elem->Attribute("string");
  13.170 +	}
  13.171 +
  13.172 +	if(!name) {
  13.173 +		sprintf(buf, "mesh%04d", idx);
  13.174 +		name = buf;
  13.175 +	}
  13.176 +
  13.177 +	return std::string(name);
  13.178 +}
    14.1 --- a/src/goat3d_writexml.cc	Fri Sep 27 03:17:36 2013 +0300
    14.2 +++ b/src/goat3d_writexml.cc	Fri Sep 27 06:58:37 2013 +0300
    14.3 @@ -1,11 +1,9 @@
    14.4  #include <stdarg.h>
    14.5  #include "goat3d_impl.h"
    14.6  #include "log.h"
    14.7 -#include "openctm.h"
    14.8  
    14.9  static bool write_material(const Scene *scn, goat3d_io *io, const Material *mat, int level);
   14.10  static bool write_mesh(const Scene *scn, goat3d_io *io, const Mesh *mesh, int idx, int level);
   14.11 -static void write_ctm_mesh(const Mesh *mesh, const char *fname);
   14.12  static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level);
   14.13  static bool write_camera(const Scene *scn, goat3d_io *io, const Camera *cam, int level);
   14.14  static bool write_node(const Scene *scn, goat3d_io *io, const Node *node, int level);
   14.15 @@ -72,7 +70,9 @@
   14.16  	char *mesh_filename = (char*)alloca(strlen(prefix) + 32);
   14.17  	sprintf(mesh_filename, "%s-mesh%04d.ctm", prefix, idx);
   14.18  
   14.19 -	write_ctm_mesh(mesh, mesh_filename);
   14.20 +	if(!mesh->save(mesh_filename)) {
   14.21 +		return false;
   14.22 +	}
   14.23  
   14.24  	// then refer to that filename in the XML tags
   14.25  	xmlout(io, level, "<mesh>\n");
   14.26 @@ -85,75 +85,6 @@
   14.27  	return true;
   14.28  }
   14.29  
   14.30 -static void write_ctm_mesh(const Mesh *mesh, const char *fname)
   14.31 -{
   14.32 -	int vnum = (int)mesh->vertices.size();
   14.33 -
   14.34 -	CTMcontext ctm = ctmNewContext(CTM_EXPORT);
   14.35 -
   14.36 -	// vertices, normals, and face-vertex indices
   14.37 -	ctmDefineMesh(ctm, &mesh->vertices[0].x, vnum, (CTMuint*)mesh->faces[0].v,
   14.38 -			mesh->faces.size(), mesh->normals.empty() ? 0 : &mesh->normals[0].x);
   14.39 -
   14.40 -	// texture coordinates
   14.41 -	if(!mesh->texcoords.empty()) {
   14.42 -		ctmAddUVMap(ctm, &mesh->texcoords[0].x, "texcoord", 0);
   14.43 -	}
   14.44 -
   14.45 -	// vertex colors
   14.46 -	if(!mesh->colors.empty()) {
   14.47 -		ctmAddAttribMap(ctm, &mesh->colors[0].x, "color");
   14.48 -	}
   14.49 -
   14.50 -	// skin weights
   14.51 -	if(!mesh->skin_weights.empty()) {
   14.52 -		ctmAddAttribMap(ctm, &mesh->skin_weights[0].x, "skin_weight");
   14.53 -	}
   14.54 -
   14.55 -	// if either of the non-float4 attributes are present we need to make a tmp array
   14.56 -	CTMfloat *attr_array = 0;
   14.57 -	if(!mesh->tangents.empty() || !mesh->skin_matrices.empty()) {
   14.58 -		attr_array = new CTMfloat[vnum * 4 * sizeof *attr_array];
   14.59 -	}
   14.60 -
   14.61 -	// tangents
   14.62 -	if(!mesh->tangents.empty()) {
   14.63 -		CTMfloat *ptr = attr_array;
   14.64 -
   14.65 -		for(int i=0; i<vnum; i++) {
   14.66 -			*ptr++ = mesh->tangents[i].x;
   14.67 -			*ptr++ = mesh->tangents[i].y;
   14.68 -			*ptr++ = mesh->tangents[i].z;
   14.69 -			*ptr++ = 1.0;
   14.70 -		}
   14.71 -		ctmAddAttribMap(ctm, attr_array, "tangent");
   14.72 -	}
   14.73 -
   14.74 -	// skin matrix indices (4 per vertex)
   14.75 -	if(!mesh->skin_matrices.empty()) {
   14.76 -		CTMfloat *ptr = attr_array;
   14.77 -
   14.78 -		for(int i=0; i<vnum; i++) {
   14.79 -			*ptr++ = (float)mesh->skin_matrices[i].x;
   14.80 -			*ptr++ = (float)mesh->skin_matrices[i].y;
   14.81 -			*ptr++ = (float)mesh->skin_matrices[i].z;
   14.82 -			*ptr++ = (float)mesh->skin_matrices[i].w;
   14.83 -		}
   14.84 -		ctmAddAttribMap(ctm, attr_array, "skin_matrix");
   14.85 -	}
   14.86 -
   14.87 -	delete [] attr_array;
   14.88 -
   14.89 -	/* TODO find a way to specify the nodes participating in the skinning of this mesh
   14.90 -	 * probably in the comment field?
   14.91 -	 */
   14.92 -
   14.93 -	logmsg(LOG_INFO, "saving CTM mesh file: %s\n", fname);
   14.94 -	ctmSave(ctm, fname);
   14.95 -
   14.96 -	ctmFreeContext(ctm);
   14.97 -}
   14.98 -
   14.99  static bool write_light(const Scene *scn, goat3d_io *io, const Light *light, int level)
  14.100  {
  14.101  	return true;
    15.1 --- a/src/mesh.cc	Fri Sep 27 03:17:36 2013 +0300
    15.2 +++ b/src/mesh.cc	Fri Sep 27 06:58:37 2013 +0300
    15.3 @@ -1,10 +1,182 @@
    15.4 +#include "goat3d_impl.h"
    15.5  #include "mesh.h"
    15.6 +#include "openctm.h"
    15.7 +#include "log.h"
    15.8  
    15.9  Mesh::Mesh()
   15.10  {
   15.11  	material = 0;
   15.12  }
   15.13  
   15.14 +bool Mesh::load(const char *fname)
   15.15 +{
   15.16 +	CTMcontext ctm = ctmNewContext(CTM_IMPORT);
   15.17 +
   15.18 +	ctmLoad(ctm, fname);
   15.19 +	if(ctmGetError(ctm) != CTM_NONE) {
   15.20 +		logmsg(LOG_ERROR, "failed to load ctm mesh: %s\n", fname);
   15.21 +		ctmFreeContext(ctm);
   15.22 +		return false;
   15.23 +	}
   15.24 +
   15.25 +	int vnum = ctmGetInteger(ctm, CTM_VERTEX_COUNT);
   15.26 +	int fnum = ctmGetInteger(ctm, CTM_TRIANGLE_COUNT);
   15.27 +
   15.28 +	const CTMfloat *vertices = ctmGetFloatArray(ctm, CTM_VERTICES);
   15.29 +	if(!vertices) {
   15.30 +		logmsg(LOG_ERROR, "failed to load ctm mesh: %s: no vertices found!\n", fname);
   15.31 +		ctmFreeContext(ctm);
   15.32 +		return false;
   15.33 +	}
   15.34 +
   15.35 +	const CTMuint *indices = ctmGetIntegerArray(ctm, CTM_INDICES);
   15.36 +	if(!indices) {
   15.37 +		logmsg(LOG_ERROR, "failed to load ctm mesh: %s: no faces found!\n", fname);
   15.38 +		ctmFreeContext(ctm);
   15.39 +		return false;
   15.40 +	}
   15.41 +
   15.42 +	const CTMfloat *normals = ctmGetFloatArray(ctm, CTM_NORMALS);
   15.43 +	const CTMfloat *texcoords = ctmGetFloatArray(ctm, CTM_UV_MAP_1);
   15.44 +
   15.45 +	CTMenum tangent_id = ctmGetNamedAttribMap(ctm, "tangent");
   15.46 +	const CTMfloat *tangents = tangent_id ? ctmGetFloatArray(ctm, tangent_id) : 0;
   15.47 +
   15.48 +	CTMenum skinweight_id = ctmGetNamedAttribMap(ctm, "skin_weight");
   15.49 +	const CTMfloat *skinweights = skinweight_id ? ctmGetFloatArray(ctm, skinweight_id) : 0;
   15.50 +
   15.51 +	CTMenum skinmat_id = ctmGetNamedAttribMap(ctm, "skin_matrix");
   15.52 +	const CTMuint *skinmats = skinmat_id ? ctmGetIntegerArray(ctm, skinmat_id) : 0;
   15.53 +
   15.54 +	CTMenum color_id = ctmGetNamedAttribMap(ctm, "color");
   15.55 +	const CTMfloat *colors = color_id ? ctmGetFloatArray(ctm, color_id) : 0;
   15.56 +
   15.57 +	// now put everything we found into our vectors
   15.58 +	this->vertices = VECDATA(Vector3, vertices, vnum);
   15.59 +
   15.60 +	if(texcoords) {
   15.61 +		this->texcoords = VECDATA(Vector2, texcoords, vnum);
   15.62 +	}
   15.63 +	if(normals) {
   15.64 +		this->normals = VECDATA(Vector3, normals, vnum);
   15.65 +	}
   15.66 +	if(skinweights) {
   15.67 +		this->skin_weights = VECDATA(Vector4, skinweights, vnum);
   15.68 +	}
   15.69 +	if(colors) {
   15.70 +		this->colors = VECDATA(Vector4, colors, vnum);
   15.71 +	}
   15.72 +
   15.73 +	// the rest need converting
   15.74 +	if(tangents) {
   15.75 +		this->tangents.clear();
   15.76 +		this->tangents.resize(vnum);
   15.77 +
   15.78 +		for(int i=0; i<vnum; i++) {
   15.79 +			for(int j=0; j<3; j++) {
   15.80 +				this->tangents[i][j] = tangents[j];
   15.81 +			}
   15.82 +			tangents += 4;
   15.83 +		}
   15.84 +	}
   15.85 +	if(skinmats) {
   15.86 +		this->skin_matrices.clear();
   15.87 +		this->skin_matrices.resize(vnum);
   15.88 +
   15.89 +		for(int i=0; i<vnum; i++) {
   15.90 +			this->skin_matrices[i].x = skinmats[0];
   15.91 +			this->skin_matrices[i].y = skinmats[1];
   15.92 +			this->skin_matrices[i].z = skinmats[2];
   15.93 +			this->skin_matrices[i].w = skinmats[3];
   15.94 +		}
   15.95 +	}
   15.96 +
   15.97 +	// grab the face data
   15.98 +	this->faces.clear();
   15.99 +	this->faces.resize(fnum);
  15.100 +
  15.101 +	for(int i=0; i<fnum; i++) {
  15.102 +		for(int j=0; j<3; j++) {
  15.103 +			this->faces[i].v[j] = indices[j];
  15.104 +		}
  15.105 +		indices += 3;
  15.106 +	}
  15.107 +
  15.108 +
  15.109 +	ctmFreeContext(ctm);
  15.110 +	return true;
  15.111 +}
  15.112 +
  15.113 +bool Mesh::save(const char *fname) const
  15.114 +{
  15.115 +	int vnum = (int)vertices.size();
  15.116 +
  15.117 +	CTMcontext ctm = ctmNewContext(CTM_EXPORT);
  15.118 +
  15.119 +	// vertices, normals, and face-vertex indices
  15.120 +	ctmDefineMesh(ctm, &vertices[0].x, vnum, (CTMuint*)faces[0].v, faces.size(),
  15.121 +			normals.empty() ? 0 : &normals[0].x);
  15.122 +
  15.123 +	// texture coordinates
  15.124 +	if(!texcoords.empty()) {
  15.125 +		ctmAddUVMap(ctm, &texcoords[0].x, "texcoord", 0);
  15.126 +	}
  15.127 +
  15.128 +	// vertex colors
  15.129 +	if(!colors.empty()) {
  15.130 +		ctmAddAttribMap(ctm, &colors[0].x, "color");
  15.131 +	}
  15.132 +
  15.133 +	// skin weights
  15.134 +	if(!skin_weights.empty()) {
  15.135 +		ctmAddAttribMap(ctm, &skin_weights[0].x, "skin_weight");
  15.136 +	}
  15.137 +
  15.138 +	// if either of the non-float4 attributes are present we need to make a tmp array
  15.139 +	CTMfloat *attr_array = 0;
  15.140 +	if(!tangents.empty() || !skin_matrices.empty()) {
  15.141 +		attr_array = new CTMfloat[vnum * 4 * sizeof *attr_array];
  15.142 +	}
  15.143 +
  15.144 +	// tangents
  15.145 +	if(!tangents.empty()) {
  15.146 +		CTMfloat *ptr = attr_array;
  15.147 +
  15.148 +		for(int i=0; i<vnum; i++) {
  15.149 +			*ptr++ = tangents[i].x;
  15.150 +			*ptr++ = tangents[i].y;
  15.151 +			*ptr++ = tangents[i].z;
  15.152 +			*ptr++ = 1.0;
  15.153 +		}
  15.154 +		ctmAddAttribMap(ctm, attr_array, "tangent");
  15.155 +	}
  15.156 +
  15.157 +	// skin matrix indices (4 per vertex)
  15.158 +	if(!skin_matrices.empty()) {
  15.159 +		CTMfloat *ptr = attr_array;
  15.160 +
  15.161 +		for(int i=0; i<vnum; i++) {
  15.162 +			*ptr++ = (float)skin_matrices[i].x;
  15.163 +			*ptr++ = (float)skin_matrices[i].y;
  15.164 +			*ptr++ = (float)skin_matrices[i].z;
  15.165 +			*ptr++ = (float)skin_matrices[i].w;
  15.166 +		}
  15.167 +		ctmAddAttribMap(ctm, attr_array, "skin_matrix");
  15.168 +	}
  15.169 +
  15.170 +	delete [] attr_array;
  15.171 +
  15.172 +	/* TODO find a way to specify the nodes participating in the skinning of this mesh
  15.173 +	 * probably in the comment field?
  15.174 +	 */
  15.175 +
  15.176 +	logmsg(LOG_INFO, "saving CTM mesh file: %s\n", fname);
  15.177 +	ctmSave(ctm, fname);
  15.178 +
  15.179 +	ctmFreeContext(ctm);
  15.180 +	return true;
  15.181 +}
  15.182 +
  15.183  void Mesh::set_material(Material *mat)
  15.184  {
  15.185  	material = mat;
    16.1 --- a/src/mesh.h	Fri Sep 27 03:17:36 2013 +0300
    16.2 +++ b/src/mesh.h	Fri Sep 27 06:58:37 2013 +0300
    16.3 @@ -32,6 +32,9 @@
    16.4  
    16.5  	Mesh();
    16.6  
    16.7 +	bool load(const char *fname);
    16.8 +	bool save(const char *fname) const;
    16.9 +
   16.10  	void set_material(Material *mat);
   16.11  	Material *get_material();
   16.12  	const Material *get_material() const;
    17.1 --- a/src/scene.cc	Fri Sep 27 03:17:36 2013 +0300
    17.2 +++ b/src/scene.cc	Fri Sep 27 06:58:37 2013 +0300
    17.3 @@ -208,12 +208,9 @@
    17.4  	return false;
    17.5  }
    17.6  
    17.7 -bool Scene::loadxml(goat3d_io *io)
    17.8 -{
    17.9 -	return false;
   17.10 -}
   17.11 -
   17.12 +// Scene::loadxml is defined in goat3d_readxml.cc
   17.13  // Scene::save is defined in goat3d_write.cc
   17.14 +// Scene::savexml is defined in goat3d_writexml.cc
   17.15  
   17.16  
   17.17  void io_fprintf(goat3d_io *io, const char *fmt, ...)