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 + // 中 or 中 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, ...)