blob: 2fd52a5c5951cb934f5774e6d3ac423ad0a8a081 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Jerome Martinez7fbefab2012-10-19 11:30:33 +020033using namespace std;
U-Lama\Lee560bd472011-12-28 19:42:49 -080034
Lee Thomasone4422302012-01-20 17:59:50 -080035static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080036static const char LF = LINE_FEED;
37static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
38static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080039static const char SINGLE_QUOTE = '\'';
40static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080041
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080042// Bunch of unicode info at:
43// http://www.unicode.org/faq/utf_bom.html
44// ef bb bf (Microsoft "lead bytes") - designates UTF-8
45
46static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
47static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
48static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080049
50
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080051#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070053 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070054 node->~XMLNode(); \
55 pool->Free( node ); \
56 } \
57 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080058#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070060 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070061 attrib->~XMLAttribute(); \
62 pool->Free( attrib ); \
63 } \
64 }
Lee Thomason43f59302012-02-06 18:18:11 -080065
Kevin Wojniak04c22d22012-11-08 11:02:22 -080066namespace tinyxml2
67{
68
Lee Thomason8ee79892012-01-25 17:44:30 -080069struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070070 const char* pattern;
71 int length;
72 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080073};
74
75static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070076static const Entity entities[NUM_ENTITIES] = {
77 { "quot", 4, DOUBLE_QUOTE },
78 { "amp", 3, '&' },
79 { "apos", 4, SINGLE_QUOTE },
80 { "lt", 2, '<' },
81 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080082};
83
Lee Thomasonfde6a752012-01-14 18:08:12 -080084
Lee Thomason1a1d4a72012-02-15 09:09:25 -080085StrPair::~StrPair()
86{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070087 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080088}
89
90
91void StrPair::Reset()
92{
Lee Thomason120b3a62012-10-12 10:06:59 -070093 if ( _flags & NEEDS_DELETE ) {
94 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070095 }
Lee Thomason120b3a62012-10-12 10:06:59 -070096 _flags = 0;
97 _start = 0;
98 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080099}
100
101
102void StrPair::SetStr( const char* str, int flags )
103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700104 Reset();
105 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700106 _start = new char[ len+1 ];
107 memcpy( _start, str, len+1 );
108 _end = _start + len;
109 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800110}
111
112
113char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700115 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800116
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700117 char* start = p; // fixme: hides a member
118 char endChar = *endTag;
119 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800120
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700121 // Inner loop of text parsing.
122 while ( *p ) {
123 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
124 Set( start, p, strFlags );
125 return p + length;
126 }
127 ++p;
128 }
129 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800130}
131
132
133char* StrPair::ParseName( char* p )
134{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800136
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700137 if ( !start || !(*start) ) {
138 return 0;
139 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800140
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 while( *p && (
142 XMLUtil::IsAlphaNum( (unsigned char) *p )
143 || *p == '_'
144 || *p == ':'
145 || (*p == '-' && p>start ) // can be in a name, but not lead it.
146 || (*p == '.' && p>start ) )) { // can be in a name, but not lead it.
147 ++p;
148 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800149
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 if ( p > start ) {
151 Set( start, p, 0 );
152 return p;
153 }
154 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700160 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700161 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700162
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 if ( _start && *_start ) {
164 char* p = _start; // the read pointer
165 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700166
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700167 while( *p ) {
168 if ( XMLUtil::IsWhiteSpace( *p )) {
169 p = XMLUtil::SkipWhiteSpace( p );
170 if ( *p == 0 ) {
171 break; // don't write to q; this trims the trailing space.
172 }
173 *q = ' ';
174 ++q;
175 }
176 *q = *p;
177 ++q;
178 ++p;
179 }
180 *q = 0;
181 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700182}
183
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800184
Lee Thomasone4422302012-01-20 17:59:50 -0800185const char* StrPair::GetStr()
186{
Lee Thomason120b3a62012-10-12 10:06:59 -0700187 if ( _flags & NEEDS_FLUSH ) {
188 *_end = 0;
189 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800190
Lee Thomason120b3a62012-10-12 10:06:59 -0700191 if ( _flags ) {
192 char* p = _start; // the read pointer
193 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800194
Lee Thomason120b3a62012-10-12 10:06:59 -0700195 while( p < _end ) {
196 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700197 // CR-LF pair becomes LF
198 // CR alone becomes LF
199 // LF-CR becomes LF
200 if ( *(p+1) == LF ) {
201 p += 2;
202 }
203 else {
204 ++p;
205 }
206 *q++ = LF;
207 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700208 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700209 if ( *(p+1) == CR ) {
210 p += 2;
211 }
212 else {
213 ++p;
214 }
215 *q++ = LF;
216 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700217 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700218 // Entities handled by tinyXML2:
219 // - special entities in the entity table [in/out]
220 // - numeric character reference [in]
221 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800222
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700223 if ( *(p+1) == '#' ) {
224 char buf[10] = { 0 };
225 int len;
226 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
227 for( int i=0; i<len; ++i ) {
228 *q++ = buf[i];
229 }
230 TIXMLASSERT( q <= p );
231 }
232 else {
233 int i=0;
234 for(; i<NUM_ENTITIES; ++i ) {
235 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
236 && *(p+entities[i].length+1) == ';' ) {
237 // Found an entity convert;
238 *q = entities[i].value;
239 ++q;
240 p += entities[i].length + 2;
241 break;
242 }
243 }
244 if ( i == NUM_ENTITIES ) {
245 // fixme: treat as error?
246 ++p;
247 ++q;
248 }
249 }
250 }
251 else {
252 *q = *p;
253 ++p;
254 ++q;
255 }
256 }
257 *q = 0;
258 }
259 // The loop below has plenty going on, and this
260 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700261 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700262 CollapseWhitespace();
263 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700264 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700265 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700266 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800267}
268
Lee Thomason2c85a712012-01-31 08:24:24 -0800269
Lee Thomasone4422302012-01-20 17:59:50 -0800270
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800271
Lee Thomason56bdd022012-02-09 18:16:58 -0800272// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800273
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800274const char* XMLUtil::ReadBOM( const char* p, bool* bom )
275{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700276 *bom = false;
277 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
278 // Check for BOM:
279 if ( *(pu+0) == TIXML_UTF_LEAD_0
280 && *(pu+1) == TIXML_UTF_LEAD_1
281 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
282 *bom = true;
283 p += 3;
284 }
285 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800286}
287
288
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800289void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
290{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700291 const unsigned long BYTE_MASK = 0xBF;
292 const unsigned long BYTE_MARK = 0x80;
293 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800294
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 if (input < 0x80) {
296 *length = 1;
297 }
298 else if ( input < 0x800 ) {
299 *length = 2;
300 }
301 else if ( input < 0x10000 ) {
302 *length = 3;
303 }
304 else if ( input < 0x200000 ) {
305 *length = 4;
306 }
307 else {
308 *length = 0; // This code won't covert this correctly anyway.
309 return;
310 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800311
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700312 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800313
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700314 // Scary scary fall throughs.
315 switch (*length) {
316 case 4:
317 --output;
318 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
319 input >>= 6;
320 case 3:
321 --output;
322 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
323 input >>= 6;
324 case 2:
325 --output;
326 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
327 input >>= 6;
328 case 1:
329 --output;
330 *output = (char)(input | FIRST_BYTE_MARK[*length]);
331 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800332}
333
334
335const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
336{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 // Presume an entity, and pull it out.
338 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 if ( *(p+1) == '#' && *(p+2) ) {
341 unsigned long ucs = 0;
342 ptrdiff_t delta = 0;
343 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800344
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700345 if ( *(p+2) == 'x' ) {
346 // Hexadecimal.
347 if ( !*(p+3) ) {
348 return 0;
349 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 const char* q = p+3;
352 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800353
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700354 if ( !q || !*q ) {
355 return 0;
356 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800357
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 delta = q-p;
359 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800360
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700361 while ( *q != 'x' ) {
362 if ( *q >= '0' && *q <= '9' ) {
363 ucs += mult * (*q - '0');
364 }
365 else if ( *q >= 'a' && *q <= 'f' ) {
366 ucs += mult * (*q - 'a' + 10);
367 }
368 else if ( *q >= 'A' && *q <= 'F' ) {
369 ucs += mult * (*q - 'A' + 10 );
370 }
371 else {
372 return 0;
373 }
374 mult *= 16;
375 --q;
376 }
377 }
378 else {
379 // Decimal.
380 if ( !*(p+2) ) {
381 return 0;
382 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800383
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 const char* q = p+2;
385 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800386
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700387 if ( !q || !*q ) {
388 return 0;
389 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800390
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 delta = q-p;
392 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800393
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700394 while ( *q != '#' ) {
395 if ( *q >= '0' && *q <= '9' ) {
396 ucs += mult * (*q - '0');
397 }
398 else {
399 return 0;
400 }
401 mult *= 10;
402 --q;
403 }
404 }
405 // convert the UCS to UTF-8
406 ConvertUTF32ToUTF8( ucs, value, length );
407 return p + delta + 1;
408 }
409 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800410}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800411
412
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700413void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700415 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700416}
417
418
419void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700422}
423
424
425void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
438{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700439 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700440}
441
442
443bool XMLUtil::ToInt( const char* str, int* value )
444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700445 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
446 return true;
447 }
448 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
452{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700453 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
454 return true;
455 }
456 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700457}
458
459bool XMLUtil::ToBool( const char* str, bool* value )
460{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700461 int ival = 0;
462 if ( ToInt( str, &ival )) {
463 *value = (ival==0) ? false : true;
464 return true;
465 }
466 if ( StringEqual( str, "true" ) ) {
467 *value = true;
468 return true;
469 }
470 else if ( StringEqual( str, "false" ) ) {
471 *value = false;
472 return true;
473 }
474 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700475}
476
477
478bool XMLUtil::ToFloat( const char* str, float* value )
479{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700480 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
481 return true;
482 }
483 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700484}
485
486bool XMLUtil::ToDouble( const char* str, double* value )
487{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700488 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
489 return true;
490 }
491 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700492}
493
494
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700495char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 XMLNode* returnNode = 0;
498 char* start = p;
499 p = XMLUtil::SkipWhiteSpace( p );
500 if( !p || !*p ) {
501 return p;
502 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800503
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 // What is this thing?
505 // - Elements start with a letter or underscore, but xml is reserved.
506 // - Comments: <!--
507 // - Decleration: <?
508 // - Everthing else is unknown to tinyxml.
509 //
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800510
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700511 static const char* xmlHeader = { "<?" };
512 static const char* commentHeader = { "<!--" };
513 static const char* dtdHeader = { "<!" };
514 static const char* cdataHeader = { "<![CDATA[" };
515 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800516
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700517 static const int xmlHeaderLen = 2;
518 static const int commentHeaderLen = 4;
519 static const int dtdHeaderLen = 2;
520 static const int cdataHeaderLen = 9;
521 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800522
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800523#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800524#pragma warning ( push )
525#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
528 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800530#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800531#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700532 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700533 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
534 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 p += xmlHeaderLen;
536 }
537 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 returnNode = new (_commentPool.Alloc()) XMLComment( this );
539 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 p += commentHeaderLen;
541 }
542 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700544 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700545 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 p += cdataHeaderLen;
547 text->SetCData( true );
548 }
549 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
551 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += dtdHeaderLen;
553 }
554 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700555 returnNode = new (_elementPool.Alloc()) XMLElement( this );
556 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 p += elementHeaderLen;
558 }
559 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700560 returnNode = new (_textPool.Alloc()) XMLText( this );
561 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 p = start; // Back it up, all the text counts.
563 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800564
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 *node = returnNode;
566 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800567}
568
569
Lee Thomason751da522012-02-10 08:50:51 -0800570bool XMLDocument::Accept( XMLVisitor* visitor ) const
571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 if ( visitor->VisitEnter( *this ) ) {
573 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
574 if ( !node->Accept( visitor ) ) {
575 break;
576 }
577 }
578 }
579 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800580}
Lee Thomason56bdd022012-02-09 18:16:58 -0800581
582
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800583// --------- XMLNode ----------- //
584
585XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700586 _document( doc ),
587 _parent( 0 ),
588 _firstChild( 0 ), _lastChild( 0 ),
589 _prev( 0 ), _next( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800590{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800591}
592
593
594XMLNode::~XMLNode()
595{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700596 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700597 if ( _parent ) {
598 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700599 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800600}
601
602
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800603void XMLNode::SetValue( const char* str, bool staticMem )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700606 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
608 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700609 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800611}
612
613
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800614void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800615{
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 while( _firstChild ) {
617 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700619
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 DELETE_NODE( node );
621 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700622 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800623}
624
625
626void XMLNode::Unlink( XMLNode* child )
627{
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 TIXMLASSERT( child->_parent == this );
629 if ( child == _firstChild ) {
630 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700632 if ( child == _lastChild ) {
633 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 }
Lee Thomasond923c672012-01-23 08:44:25 -0800635
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 if ( child->_prev ) {
637 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700639 if ( child->_next ) {
640 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700641 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700642 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800643}
644
645
U-Stream\Leeae25a442012-02-17 17:48:16 -0800646void XMLNode::DeleteChild( XMLNode* node )
647{
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700649 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800650}
651
652
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800653XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
654{
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( _lastChild ) {
656 TIXMLASSERT( _firstChild );
657 TIXMLASSERT( _lastChild->_next == 0 );
658 _lastChild->_next = addThis;
659 addThis->_prev = _lastChild;
660 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800661
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700663 }
664 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 TIXMLASSERT( _firstChild == 0 );
666 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 addThis->_prev = 0;
669 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700672 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800673}
674
675
Lee Thomason1ff38e02012-02-14 18:18:16 -0800676XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
677{
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 if ( _firstChild ) {
679 TIXMLASSERT( _lastChild );
680 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800681
Lee Thomason624d43f2012-10-12 10:58:48 -0700682 _firstChild->_prev = addThis;
683 addThis->_next = _firstChild;
684 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800685
Lee Thomason624d43f2012-10-12 10:58:48 -0700686 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700687 }
688 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700689 TIXMLASSERT( _lastChild == 0 );
690 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 addThis->_prev = 0;
693 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700694 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700696 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800697}
698
699
700XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
701{
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 TIXMLASSERT( afterThis->_parent == this );
703 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 return 0;
705 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 // The last node or the only node.
709 return InsertEndChild( addThis );
710 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700711 addThis->_prev = afterThis;
712 addThis->_next = afterThis->_next;
713 afterThis->_next->_prev = addThis;
714 afterThis->_next = addThis;
715 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700716 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800717}
718
719
720
721
Lee Thomason56bdd022012-02-09 18:16:58 -0800722const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800723{
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700725 XMLElement* element = node->ToElement();
726 if ( element ) {
727 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
728 return element;
729 }
730 }
731 }
732 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800733}
734
735
Lee Thomason56bdd022012-02-09 18:16:58 -0800736const XMLElement* XMLNode::LastChildElement( const char* value ) const
737{
Lee Thomason624d43f2012-10-12 10:58:48 -0700738 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 XMLElement* element = node->ToElement();
740 if ( element ) {
741 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
742 return element;
743 }
744 }
745 }
746 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800747}
748
749
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800750const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
751{
Lee Thomason624d43f2012-10-12 10:58:48 -0700752 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700753 if ( element->ToElement()
754 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
755 return element->ToElement();
756 }
757 }
758 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800759}
760
761
762const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
763{
Lee Thomason624d43f2012-10-12 10:58:48 -0700764 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700765 if ( element->ToElement()
766 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
767 return element->ToElement();
768 }
769 }
770 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800771}
772
773
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800774char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800775{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 // This is a recursive method, but thinking about it "at the current level"
777 // it is a pretty simple flat list:
778 // <foo/>
779 // <!-- comment -->
780 //
781 // With a special case:
782 // <foo>
783 // </foo>
784 // <!-- comment -->
785 //
786 // Where the closing element (/foo) *must* be the next thing after the opening
787 // element, and the names must match. BUT the tricky bit is that the closing
788 // element will be read by the child.
789 //
790 // 'endTag' is the end tag for this node, it is returned by a call to a child.
791 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800792
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 while( p && *p ) {
794 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800795
Lee Thomason624d43f2012-10-12 10:58:48 -0700796 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700797 if ( p == 0 || node == 0 ) {
798 break;
799 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800800
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700801 StrPair endTag;
802 p = node->ParseDeep( p, &endTag );
803 if ( !p ) {
804 DELETE_NODE( node );
805 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700806 if ( !_document->Error() ) {
807 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 }
809 break;
810 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800811
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700812 // We read the end tag. Return it to the parent.
813 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
814 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700815 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700816 }
817 DELETE_NODE( node );
818 return p;
819 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800820
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 // Handle an end tag returned to this level.
822 // And handle a bunch of annoying errors.
823 XMLElement* ele = node->ToElement();
824 if ( ele ) {
825 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700826 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700827 p = 0;
828 }
829 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700830 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 p = 0;
832 }
833 else if ( !endTag.Empty() ) {
834 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700835 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700836 p = 0;
837 }
838 }
839 }
840 if ( p == 0 ) {
841 DELETE_NODE( node );
842 node = 0;
843 }
844 if ( node ) {
845 this->InsertEndChild( node );
846 }
847 }
848 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800849}
850
Lee Thomason5492a1c2012-01-23 15:32:10 -0800851// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800852char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800853{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 const char* start = p;
855 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700856 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700857 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 }
860 return p;
861 }
862 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700863 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
864 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 flags |= StrPair::COLLAPSE_WHITESPACE;
866 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700867
Lee Thomason624d43f2012-10-12 10:58:48 -0700868 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700869 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700870 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700871 }
872 if ( p && *p ) {
873 return p-1;
874 }
875 }
876 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800877}
878
879
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800880XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
881{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700883 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700884 }
885 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
886 text->SetCData( this->CData() );
887 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800888}
889
890
891bool XMLText::ShallowEqual( const XMLNode* compare ) const
892{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800894}
895
896
Lee Thomason56bdd022012-02-09 18:16:58 -0800897bool XMLText::Accept( XMLVisitor* visitor ) const
898{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700899 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800900}
901
902
Lee Thomason3f57d272012-01-11 15:30:03 -0800903// --------- XMLComment ---------- //
904
Lee Thomasone4422302012-01-20 17:59:50 -0800905XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800906{
907}
908
909
Lee Thomasonce0763e2012-01-11 15:43:54 -0800910XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800911{
Lee Thomason3f57d272012-01-11 15:30:03 -0800912}
913
914
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800915char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800916{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 // Comment parses as text.
918 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700919 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700921 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 }
923 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800924}
925
926
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800927XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
928{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700929 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700930 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 }
932 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
933 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800934}
935
936
937bool XMLComment::ShallowEqual( const XMLNode* compare ) const
938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800940}
941
942
Lee Thomason751da522012-02-10 08:50:51 -0800943bool XMLComment::Accept( XMLVisitor* visitor ) const
944{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800946}
Lee Thomason56bdd022012-02-09 18:16:58 -0800947
948
Lee Thomason50f97b22012-02-11 16:33:40 -0800949// --------- XMLDeclaration ---------- //
950
951XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
952{
953}
954
955
956XMLDeclaration::~XMLDeclaration()
957{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700958 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800959}
960
961
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800962char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800963{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700964 // Declaration parses as text.
965 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700966 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700968 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 }
970 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800971}
972
973
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800974XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
975{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700976 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700977 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700978 }
979 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
980 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800981}
982
983
984bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800987}
988
989
990
Lee Thomason50f97b22012-02-11 16:33:40 -0800991bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
992{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -0800994}
995
996// --------- XMLUnknown ---------- //
997
998XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
999{
1000}
1001
1002
1003XMLUnknown::~XMLUnknown()
1004{
1005}
1006
1007
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001008char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 // Unknown parses as text.
1011 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001012
Lee Thomason624d43f2012-10-12 10:58:48 -07001013 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001014 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001015 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 }
1017 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001018}
1019
1020
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001021XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1022{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001023 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001024 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001025 }
1026 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1027 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001028}
1029
1030
1031bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001034}
1035
1036
Lee Thomason50f97b22012-02-11 16:33:40 -08001037bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1038{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001040}
1041
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001042// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001043char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001044{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001046 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 if ( !p || !*p ) {
1048 return 0;
1049 }
Lee Thomason22aead12012-01-23 13:29:35 -08001050
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001051 // Skip white space before =
1052 p = XMLUtil::SkipWhiteSpace( p );
1053 if ( !p || *p != '=' ) {
1054 return 0;
1055 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001056
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001057 ++p; // move up to opening quote
1058 p = XMLUtil::SkipWhiteSpace( p );
1059 if ( *p != '\"' && *p != '\'' ) {
1060 return 0;
1061 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001062
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 char endTag[2] = { *p, 0 };
1064 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001065
Lee Thomason624d43f2012-10-12 10:58:48 -07001066 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001068}
1069
1070
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001071void XMLAttribute::SetName( const char* n )
1072{
Lee Thomason624d43f2012-10-12 10:58:48 -07001073 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001074}
1075
1076
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001077int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 if ( XMLUtil::ToInt( Value(), value )) {
1080 return XML_NO_ERROR;
1081 }
1082 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001083}
1084
1085
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001086int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001087{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 if ( XMLUtil::ToUnsigned( Value(), value )) {
1089 return XML_NO_ERROR;
1090 }
1091 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001092}
1093
1094
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001095int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 if ( XMLUtil::ToBool( Value(), value )) {
1098 return XML_NO_ERROR;
1099 }
1100 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001101}
1102
1103
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001104int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001105{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001106 if ( XMLUtil::ToFloat( Value(), value )) {
1107 return XML_NO_ERROR;
1108 }
1109 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001110}
1111
1112
1113int XMLAttribute::QueryDoubleValue( double* value ) const
1114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001115 if ( XMLUtil::ToDouble( Value(), value )) {
1116 return XML_NO_ERROR;
1117 }
1118 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001119}
1120
1121
1122void XMLAttribute::SetAttribute( const char* v )
1123{
Lee Thomason624d43f2012-10-12 10:58:48 -07001124 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001125}
1126
1127
Lee Thomason1ff38e02012-02-14 18:18:16 -08001128void XMLAttribute::SetAttribute( int v )
1129{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 char buf[BUF_SIZE];
1131 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001132 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001133}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001134
1135
1136void XMLAttribute::SetAttribute( unsigned v )
1137{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001138 char buf[BUF_SIZE];
1139 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001140 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001141}
1142
1143
1144void XMLAttribute::SetAttribute( bool v )
1145{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001146 char buf[BUF_SIZE];
1147 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001148 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001149}
1150
1151void XMLAttribute::SetAttribute( double v )
1152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001153 char buf[BUF_SIZE];
1154 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001155 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001156}
1157
1158void XMLAttribute::SetAttribute( float v )
1159{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001160 char buf[BUF_SIZE];
1161 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001162 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001163}
1164
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001165
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001166// --------- XMLElement ---------- //
1167XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001168 _closingType( 0 ),
1169 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001170{
1171}
1172
1173
1174XMLElement::~XMLElement()
1175{
Lee Thomason624d43f2012-10-12 10:58:48 -07001176 while( _rootAttribute ) {
1177 XMLAttribute* next = _rootAttribute->_next;
1178 DELETE_ATTRIBUTE( _rootAttribute );
1179 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001181}
1182
1183
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001184XMLAttribute* XMLElement::FindAttribute( const char* name )
1185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001187 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1189 return a;
1190 }
1191 }
1192 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001193}
1194
1195
1196const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1197{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001198 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001199 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001200 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1201 return a;
1202 }
1203 }
1204 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001205}
1206
1207
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001208const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001209{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001210 const XMLAttribute* a = FindAttribute( name );
1211 if ( !a ) {
1212 return 0;
1213 }
1214 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1215 return a->Value();
1216 }
1217 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001218}
1219
1220
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001221const char* XMLElement::GetText() const
1222{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 if ( FirstChild() && FirstChild()->ToText() ) {
1224 return FirstChild()->ToText()->Value();
1225 }
1226 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001227}
1228
1229
Lee Thomason21be8822012-07-15 17:27:22 -07001230int XMLElement::QueryIntText( int* _value ) const
1231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 if ( FirstChild() && FirstChild()->ToText() ) {
1233 const char* t = FirstChild()->ToText()->Value();
1234 if ( XMLUtil::ToInt( t, _value ) ) {
1235 return XML_SUCCESS;
1236 }
1237 return XML_CAN_NOT_CONVERT_TEXT;
1238 }
1239 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001240}
1241
1242
1243int XMLElement::QueryUnsignedText( unsigned* _value ) const
1244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 if ( FirstChild() && FirstChild()->ToText() ) {
1246 const char* t = FirstChild()->ToText()->Value();
1247 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1248 return XML_SUCCESS;
1249 }
1250 return XML_CAN_NOT_CONVERT_TEXT;
1251 }
1252 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001253}
1254
1255
1256int XMLElement::QueryBoolText( bool* _value ) const
1257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 if ( FirstChild() && FirstChild()->ToText() ) {
1259 const char* t = FirstChild()->ToText()->Value();
1260 if ( XMLUtil::ToBool( t, _value ) ) {
1261 return XML_SUCCESS;
1262 }
1263 return XML_CAN_NOT_CONVERT_TEXT;
1264 }
1265 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001266}
1267
1268
1269int XMLElement::QueryDoubleText( double* _value ) const
1270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001271 if ( FirstChild() && FirstChild()->ToText() ) {
1272 const char* t = FirstChild()->ToText()->Value();
1273 if ( XMLUtil::ToDouble( t, _value ) ) {
1274 return XML_SUCCESS;
1275 }
1276 return XML_CAN_NOT_CONVERT_TEXT;
1277 }
1278 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001279}
1280
1281
1282int XMLElement::QueryFloatText( float* _value ) const
1283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001284 if ( FirstChild() && FirstChild()->ToText() ) {
1285 const char* t = FirstChild()->ToText()->Value();
1286 if ( XMLUtil::ToFloat( t, _value ) ) {
1287 return XML_SUCCESS;
1288 }
1289 return XML_CAN_NOT_CONVERT_TEXT;
1290 }
1291 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001292}
1293
1294
1295
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001296XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 XMLAttribute* last = 0;
1299 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001300 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001301 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001302 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001303 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1304 break;
1305 }
1306 }
1307 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001308 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1309 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001310 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001311 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001312 }
1313 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001314 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001315 }
1316 attrib->SetName( name );
1317 }
1318 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001319}
1320
1321
U-Stream\Leeae25a442012-02-17 17:48:16 -08001322void XMLElement::DeleteAttribute( const char* name )
1323{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001324 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001325 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001326 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1327 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001328 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001329 }
1330 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001331 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001332 }
1333 DELETE_ATTRIBUTE( a );
1334 break;
1335 }
1336 prev = a;
1337 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001338}
1339
1340
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001341char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001343 const char* start = p;
1344 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001345
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001346 // Read the attributes.
1347 while( p ) {
1348 p = XMLUtil::SkipWhiteSpace( p );
1349 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001350 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001351 return 0;
1352 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001353
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 // attribute.
1355 if ( XMLUtil::IsAlpha( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001356 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1357 attrib->_memPool = &_document->_attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001358
Lee Thomason624d43f2012-10-12 10:58:48 -07001359 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 if ( !p || Attribute( attrib->Name() ) ) {
1361 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001362 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 return 0;
1364 }
1365 // There is a minor bug here: if the attribute in the source xml
1366 // document is duplicated, it will not be detected and the
1367 // attribute will be doubly added. However, tracking the 'prevAttribute'
1368 // avoids re-scanning the attribute list. Preferring performance for
1369 // now, may reconsider in the future.
1370 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001371 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001372 }
1373 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001374 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001375 }
1376 prevAttribute = attrib;
1377 }
1378 // end of the tag
1379 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001380 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 return p+2; // done; sealed element.
1382 }
1383 // end of the tag
1384 else if ( *p == '>' ) {
1385 ++p;
1386 break;
1387 }
1388 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001389 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001390 return 0;
1391 }
1392 }
1393 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001394}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001395
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001396
Lee Thomason67d61312012-01-24 16:01:51 -08001397//
1398// <ele></ele>
1399// <ele>foo<b>bar</b></ele>
1400//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001401char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001402{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001403 // Read the element name.
1404 p = XMLUtil::SkipWhiteSpace( p );
1405 if ( !p ) {
1406 return 0;
1407 }
Lee Thomason67d61312012-01-24 16:01:51 -08001408
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 // The closing element is the </element> form. It is
1410 // parsed just like a regular element then deleted from
1411 // the DOM.
1412 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001413 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001414 ++p;
1415 }
Lee Thomason67d61312012-01-24 16:01:51 -08001416
Lee Thomason624d43f2012-10-12 10:58:48 -07001417 p = _value.ParseName( p );
1418 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 return 0;
1420 }
Lee Thomason67d61312012-01-24 16:01:51 -08001421
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001422 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001423 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 return p;
1425 }
Lee Thomason67d61312012-01-24 16:01:51 -08001426
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 p = XMLNode::ParseDeep( p, strPair );
1428 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001429}
1430
1431
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001432
1433XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1434{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 }
1438 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1439 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1440 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1441 }
1442 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001443}
1444
1445
1446bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1447{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 const XMLElement* other = compare->ToElement();
1449 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001450
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 const XMLAttribute* a=FirstAttribute();
1452 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001453
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 while ( a && b ) {
1455 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1456 return false;
1457 }
1458 a = a->Next();
1459 b = b->Next();
1460 }
1461 if ( a || b ) {
1462 // different count
1463 return false;
1464 }
1465 return true;
1466 }
1467 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001468}
1469
1470
Lee Thomason751da522012-02-10 08:50:51 -08001471bool XMLElement::Accept( XMLVisitor* visitor ) const
1472{
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1475 if ( !node->Accept( visitor ) ) {
1476 break;
1477 }
1478 }
1479 }
1480 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001481}
Lee Thomason56bdd022012-02-09 18:16:58 -08001482
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001483
Lee Thomason3f57d272012-01-11 15:30:03 -08001484// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001485XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001486 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001487 _writeBOM( false ),
1488 _processEntities( processEntities ),
1489 _errorID( 0 ),
1490 _whitespace( whitespace ),
1491 _errorStr1( 0 ),
1492 _errorStr2( 0 ),
1493 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001494{
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001496}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001497
1498
Lee Thomason3f57d272012-01-11 15:30:03 -08001499XMLDocument::~XMLDocument()
1500{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001501 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001503
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001504#if 0
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 textPool.Trace( "text" );
1506 elementPool.Trace( "element" );
1507 commentPool.Trace( "comment" );
1508 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001509#endif
1510
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 TIXMLASSERT( _textPool.CurrentAllocs() == 0 );
1512 TIXMLASSERT( _elementPool.CurrentAllocs() == 0 );
1513 TIXMLASSERT( _commentPool.CurrentAllocs() == 0 );
1514 TIXMLASSERT( _attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001515}
1516
1517
Lee Thomason18d68bd2012-01-26 18:17:26 -08001518void XMLDocument::InitDocument()
1519{
Lee Thomason624d43f2012-10-12 10:58:48 -07001520 _errorID = XML_NO_ERROR;
1521 _errorStr1 = 0;
1522 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001523
Lee Thomason624d43f2012-10-12 10:58:48 -07001524 delete [] _charBuffer;
1525 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001526}
1527
Lee Thomason3f57d272012-01-11 15:30:03 -08001528
Lee Thomason2c85a712012-01-31 08:24:24 -08001529XMLElement* XMLDocument::NewElement( const char* name )
1530{
Lee Thomason624d43f2012-10-12 10:58:48 -07001531 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1532 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 ele->SetName( name );
1534 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001535}
1536
1537
Lee Thomason1ff38e02012-02-14 18:18:16 -08001538XMLComment* XMLDocument::NewComment( const char* str )
1539{
Lee Thomason624d43f2012-10-12 10:58:48 -07001540 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1541 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 comment->SetValue( str );
1543 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001544}
1545
1546
1547XMLText* XMLDocument::NewText( const char* str )
1548{
Lee Thomason624d43f2012-10-12 10:58:48 -07001549 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1550 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 text->SetValue( str );
1552 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001553}
1554
1555
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001556XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1557{
Lee Thomason624d43f2012-10-12 10:58:48 -07001558 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1559 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1561 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001562}
1563
1564
1565XMLUnknown* XMLDocument::NewUnknown( const char* str )
1566{
Lee Thomason624d43f2012-10-12 10:58:48 -07001567 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1568 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001569 unk->SetValue( str );
1570 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001571}
1572
1573
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001574int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001575{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 DeleteChildren();
1577 InitDocument();
1578 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001579
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001580#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1581 errno_t err = fopen_s(&fp, filename, "rb" );
1582 if ( !fp || err) {
1583#else
1584 fp = fopen( filename, "rb" );
1585 if ( !fp) {
1586#endif
1587 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001588 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 }
1590 LoadFile( fp );
1591 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001592 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001593}
1594
1595
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001596int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001597{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 DeleteChildren();
1599 InitDocument();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001600
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001601 fseek( fp, 0, SEEK_END );
1602 size_t size = ftell( fp );
1603 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001604
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001605 if ( size == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001608
Lee Thomason624d43f2012-10-12 10:58:48 -07001609 _charBuffer = new char[size+1];
1610 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001611 if ( read != size ) {
1612 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001613 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001614 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001615
Lee Thomason624d43f2012-10-12 10:58:48 -07001616 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001617
Lee Thomason624d43f2012-10-12 10:58:48 -07001618 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001621 if ( !p || !*p ) {
1622 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001623 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001624 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001625
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1627 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001628}
1629
1630
Robert Reif312a20f2012-09-08 19:33:57 -04001631int XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001632{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001633 FILE* fp = 0;
1634#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1635 errno_t err = fopen_s(&fp, filename, "w" );
1636 if ( !fp || err) {
1637#else
1638 fp = fopen( filename, "w" );
1639 if ( !fp) {
1640#endif
1641 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001642 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001643 }
1644 SaveFile(fp, compact);
1645 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001646 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001647}
1648
1649
Robert Reif312a20f2012-09-08 19:33:57 -04001650int XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001652 XMLPrinter stream( fp, compact );
1653 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001655}
1656
Lee Thomason1ff38e02012-02-14 18:18:16 -08001657
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001658int XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001659{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001660 DeleteChildren();
1661 InitDocument();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001662
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 if ( !p || !*p ) {
1664 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001665 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001666 }
1667 if ( len == (size_t)(-1) ) {
1668 len = strlen( p );
1669 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 _charBuffer = new char[ len+1 ];
1671 memcpy( _charBuffer, p, len );
1672 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001673
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001674 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001675 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001676 if ( !p || !*p ) {
1677 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001678 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001680
Lee Thomason624d43f2012-10-12 10:58:48 -07001681 ParseDeep( _charBuffer, 0 );
1682 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001683}
1684
1685
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001686void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001687{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 XMLPrinter stdStreamer( stdout );
1689 if ( !streamer ) {
1690 streamer = &stdStreamer;
1691 }
1692 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001693}
1694
1695
Lee Thomason67d61312012-01-24 16:01:51 -08001696void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1697{
Lee Thomason624d43f2012-10-12 10:58:48 -07001698 _errorID = error;
1699 _errorStr1 = str1;
1700 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001701}
1702
Lee Thomason5cae8972012-01-24 18:03:07 -08001703
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001704void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001705{
Lee Thomason624d43f2012-10-12 10:58:48 -07001706 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 static const int LEN = 20;
1708 char buf1[LEN] = { 0 };
1709 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001710
Lee Thomason624d43f2012-10-12 10:58:48 -07001711 if ( _errorStr1 ) {
1712 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001713 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001714 if ( _errorStr2 ) {
1715 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001717
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001720 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001721}
1722
1723
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001724XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001725 _elementJustOpened( false ),
1726 _firstElement( true ),
1727 _fp( file ),
1728 _depth( 0 ),
1729 _textDepth( -1 ),
1730 _processEntities( true ),
1731 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001732{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001733 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001734 _entityFlag[i] = false;
1735 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 }
1737 for( int i=0; i<NUM_ENTITIES; ++i ) {
1738 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1739 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 }
1742 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001743 _restrictedEntityFlag[(int)'&'] = true;
1744 _restrictedEntityFlag[(int)'<'] = true;
1745 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1746 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001747}
1748
1749
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001750void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001751{
1752 va_list va;
1753 va_start( va, format );
1754
Lee Thomason624d43f2012-10-12 10:58:48 -07001755 if ( _fp ) {
1756 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 }
1758 else {
1759 // This seems brutally complex. Haven't figured out a better
1760 // way on windows.
1761#ifdef _MSC_VER
1762 int len = -1;
1763 int expand = 1000;
1764 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 if ( len < 0 ) {
1767 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001768 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 }
1770 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001771 char* p = _buffer.PushArr( len ) - 1;
1772 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001773#else
1774 int len = vsnprintf( 0, 0, format, va );
1775 // Close out and re-start the va-args
1776 va_end( va );
1777 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 vsnprintf( p, len+1, format, va );
1780#endif
1781 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001782 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001783}
1784
1785
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001786void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001787{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 for( int i=0; i<depth; ++i ) {
1789 Print( " " );
1790 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001791}
1792
1793
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001794void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001795{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001796 // Look for runs of bytes between entities to print.
1797 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001798 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001799
Lee Thomason624d43f2012-10-12 10:58:48 -07001800 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001801 while ( *q ) {
1802 // Remember, char is sometimes signed. (How many times has that bitten me?)
1803 if ( *q > 0 && *q < ENTITY_RANGE ) {
1804 // Check for entities. If one is found, flush
1805 // the stream up until the entity, write the
1806 // entity, and keep looking.
1807 if ( flag[(unsigned)(*q)] ) {
1808 while ( p < q ) {
1809 Print( "%c", *p );
1810 ++p;
1811 }
1812 for( int i=0; i<NUM_ENTITIES; ++i ) {
1813 if ( entities[i].value == *q ) {
1814 Print( "&%s;", entities[i].pattern );
1815 break;
1816 }
1817 }
1818 ++p;
1819 }
1820 }
1821 ++q;
1822 }
1823 }
1824 // Flush the remaining string. This will be the entire
1825 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001826 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001827 Print( "%s", p );
1828 }
Lee Thomason857b8682012-01-25 17:50:25 -08001829}
1830
U-Stream\Leeae25a442012-02-17 17:48:16 -08001831
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001832void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001833{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001834 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1835 if ( writeBOM ) {
1836 Print( "%s", bom );
1837 }
1838 if ( writeDec ) {
1839 PushDeclaration( "xml version=\"1.0\"" );
1840 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001841}
1842
1843
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001844void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001845{
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 SealElement();
1848 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001850
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001852 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001854 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001855
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 _elementJustOpened = true;
1858 _firstElement = false;
1859 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001860}
1861
1862
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001863void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001864{
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 Print( " %s=\"", name );
1867 PrintString( value, false );
1868 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001869}
1870
1871
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001872void XMLPrinter::PushAttribute( const char* name, int v )
1873{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001874 char buf[BUF_SIZE];
1875 XMLUtil::ToStr( v, buf, BUF_SIZE );
1876 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001877}
1878
1879
1880void XMLPrinter::PushAttribute( const char* name, unsigned v )
1881{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001882 char buf[BUF_SIZE];
1883 XMLUtil::ToStr( v, buf, BUF_SIZE );
1884 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001885}
1886
1887
1888void XMLPrinter::PushAttribute( const char* name, bool v )
1889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001890 char buf[BUF_SIZE];
1891 XMLUtil::ToStr( v, buf, BUF_SIZE );
1892 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001893}
1894
1895
1896void XMLPrinter::PushAttribute( const char* name, double v )
1897{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001898 char buf[BUF_SIZE];
1899 XMLUtil::ToStr( v, buf, BUF_SIZE );
1900 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001901}
1902
1903
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001904void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001905{
Lee Thomason624d43f2012-10-12 10:58:48 -07001906 --_depth;
1907 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001908
Lee Thomason624d43f2012-10-12 10:58:48 -07001909 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001910 Print( "/>" );
1911 }
1912 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001914 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07001915 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 }
1917 Print( "</%s>", name );
1918 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001919
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 if ( _textDepth == _depth ) {
1921 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924 Print( "\n" );
1925 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001926 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001927}
1928
1929
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001930void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001931{
Lee Thomason624d43f2012-10-12 10:58:48 -07001932 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001933 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001934}
1935
1936
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001937void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001938{
Lee Thomason624d43f2012-10-12 10:58:48 -07001939 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001940
Lee Thomason624d43f2012-10-12 10:58:48 -07001941 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001942 SealElement();
1943 }
1944 if ( cdata ) {
1945 Print( "<![CDATA[" );
1946 Print( "%s", text );
1947 Print( "]]>" );
1948 }
1949 else {
1950 PrintString( text, true );
1951 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001952}
1953
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001954void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001955{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001956 char buf[BUF_SIZE];
1957 XMLUtil::ToStr( value, buf, BUF_SIZE );
1958 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001959}
1960
1961
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001962void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001963{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001964 char buf[BUF_SIZE];
1965 XMLUtil::ToStr( value, buf, BUF_SIZE );
1966 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001967}
1968
1969
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001970void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001971{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001972 char buf[BUF_SIZE];
1973 XMLUtil::ToStr( value, buf, BUF_SIZE );
1974 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001975}
1976
1977
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001978void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07001979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980 char buf[BUF_SIZE];
1981 XMLUtil::ToStr( value, buf, BUF_SIZE );
1982 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001983}
1984
1985
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001986void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07001987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001988 char buf[BUF_SIZE];
1989 XMLUtil::ToStr( value, buf, BUF_SIZE );
1990 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001991}
1992
Lee Thomason5cae8972012-01-24 18:03:07 -08001993
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001994void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001995{
Lee Thomason624d43f2012-10-12 10:58:48 -07001996 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001997 SealElement();
1998 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001999 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002001 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002002 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002003 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002004 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002005}
Lee Thomason751da522012-02-10 08:50:51 -08002006
2007
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002008void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002009{
Lee Thomason624d43f2012-10-12 10:58:48 -07002010 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 SealElement();
2012 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002013 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002014 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002015 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002017 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002019}
2020
2021
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002022void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002023{
Lee Thomason624d43f2012-10-12 10:58:48 -07002024 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002025 SealElement();
2026 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002027 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002028 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002029 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002030 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002031 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002033}
2034
2035
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002036bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002037{
Lee Thomason624d43f2012-10-12 10:58:48 -07002038 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002039 if ( doc.HasBOM() ) {
2040 PushHeader( true, false );
2041 }
2042 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002043}
2044
2045
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002046bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002047{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002048 OpenElement( element.Name() );
2049 while ( attribute ) {
2050 PushAttribute( attribute->Name(), attribute->Value() );
2051 attribute = attribute->Next();
2052 }
2053 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002054}
2055
2056
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002057bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002058{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002059 CloseElement();
2060 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002061}
2062
2063
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002064bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002065{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 PushText( text.Value(), text.CData() );
2067 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002068}
2069
2070
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002071bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002072{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 PushComment( comment.Value() );
2074 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002075}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002076
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002077bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002079 PushDeclaration( declaration.Value() );
2080 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002081}
2082
2083
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002084bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 PushUnknown( unknown.Value() );
2087 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002088}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002089
2090}