blob: 82637967516a024e31c9a951bac2cc5f9d8d1589 [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
33using namespace tinyxml2;
34
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 ) { \
53 MemPool* pool = node->memPool; \
54 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 ) { \
60 MemPool* pool = attrib->memPool; \
61 attrib->~XMLAttribute(); \
62 pool->Free( attrib ); \
63 } \
64 }
Lee Thomason43f59302012-02-06 18:18:11 -080065
Lee Thomason8ee79892012-01-25 17:44:30 -080066struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070067 const char* pattern;
68 int length;
69 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080070};
71
72static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070073static const Entity entities[NUM_ENTITIES] = {
74 { "quot", 4, DOUBLE_QUOTE },
75 { "amp", 3, '&' },
76 { "apos", 4, SINGLE_QUOTE },
77 { "lt", 2, '<' },
78 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080079};
80
Lee Thomasonfde6a752012-01-14 18:08:12 -080081
Lee Thomason1a1d4a72012-02-15 09:09:25 -080082StrPair::~StrPair()
83{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070084 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080085}
86
87
88void StrPair::Reset()
89{
Lee Thomason120b3a62012-10-12 10:06:59 -070090 if ( _flags & NEEDS_DELETE ) {
91 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070092 }
Lee Thomason120b3a62012-10-12 10:06:59 -070093 _flags = 0;
94 _start = 0;
95 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096}
97
98
99void StrPair::SetStr( const char* str, int flags )
100{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700101 Reset();
102 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700103 _start = new char[ len+1 ];
104 memcpy( _start, str, len+1 );
105 _end = _start + len;
106 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800107}
108
109
110char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700112 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800113
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700114 char* start = p; // fixme: hides a member
115 char endChar = *endTag;
116 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800117
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700118 // Inner loop of text parsing.
119 while ( *p ) {
120 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
121 Set( start, p, strFlags );
122 return p + length;
123 }
124 ++p;
125 }
126 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800127}
128
129
130char* StrPair::ParseName( char* p )
131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700132 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800133
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700134 if ( !start || !(*start) ) {
135 return 0;
136 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800137
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700138 while( *p && (
139 XMLUtil::IsAlphaNum( (unsigned char) *p )
140 || *p == '_'
141 || *p == ':'
142 || (*p == '-' && p>start ) // can be in a name, but not lead it.
143 || (*p == '.' && p>start ) )) { // can be in a name, but not lead it.
144 ++p;
145 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700147 if ( p > start ) {
148 Set( start, p, 0 );
149 return p;
150 }
151 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800152}
153
154
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700155void StrPair::CollapseWhitespace()
156{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700157 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700158 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700159
Lee Thomason120b3a62012-10-12 10:06:59 -0700160 if ( _start && *_start ) {
161 char* p = _start; // the read pointer
162 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700163
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700164 while( *p ) {
165 if ( XMLUtil::IsWhiteSpace( *p )) {
166 p = XMLUtil::SkipWhiteSpace( p );
167 if ( *p == 0 ) {
168 break; // don't write to q; this trims the trailing space.
169 }
170 *q = ' ';
171 ++q;
172 }
173 *q = *p;
174 ++q;
175 ++p;
176 }
177 *q = 0;
178 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700179}
180
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800181
Lee Thomasone4422302012-01-20 17:59:50 -0800182const char* StrPair::GetStr()
183{
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 if ( _flags & NEEDS_FLUSH ) {
185 *_end = 0;
186 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800187
Lee Thomason120b3a62012-10-12 10:06:59 -0700188 if ( _flags ) {
189 char* p = _start; // the read pointer
190 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800191
Lee Thomason120b3a62012-10-12 10:06:59 -0700192 while( p < _end ) {
193 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700194 // CR-LF pair becomes LF
195 // CR alone becomes LF
196 // LF-CR becomes LF
197 if ( *(p+1) == LF ) {
198 p += 2;
199 }
200 else {
201 ++p;
202 }
203 *q++ = LF;
204 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700205 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700206 if ( *(p+1) == CR ) {
207 p += 2;
208 }
209 else {
210 ++p;
211 }
212 *q++ = LF;
213 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700214 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700215 // Entities handled by tinyXML2:
216 // - special entities in the entity table [in/out]
217 // - numeric character reference [in]
218 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800219
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 if ( *(p+1) == '#' ) {
221 char buf[10] = { 0 };
222 int len;
223 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
224 for( int i=0; i<len; ++i ) {
225 *q++ = buf[i];
226 }
227 TIXMLASSERT( q <= p );
228 }
229 else {
230 int i=0;
231 for(; i<NUM_ENTITIES; ++i ) {
232 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
233 && *(p+entities[i].length+1) == ';' ) {
234 // Found an entity convert;
235 *q = entities[i].value;
236 ++q;
237 p += entities[i].length + 2;
238 break;
239 }
240 }
241 if ( i == NUM_ENTITIES ) {
242 // fixme: treat as error?
243 ++p;
244 ++q;
245 }
246 }
247 }
248 else {
249 *q = *p;
250 ++p;
251 ++q;
252 }
253 }
254 *q = 0;
255 }
256 // The loop below has plenty going on, and this
257 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700258 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700259 CollapseWhitespace();
260 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700261 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700262 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700263 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800264}
265
Lee Thomason2c85a712012-01-31 08:24:24 -0800266
Lee Thomasone4422302012-01-20 17:59:50 -0800267
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800268
Lee Thomason56bdd022012-02-09 18:16:58 -0800269// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800270
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800271const char* XMLUtil::ReadBOM( const char* p, bool* bom )
272{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700273 *bom = false;
274 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
275 // Check for BOM:
276 if ( *(pu+0) == TIXML_UTF_LEAD_0
277 && *(pu+1) == TIXML_UTF_LEAD_1
278 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
279 *bom = true;
280 p += 3;
281 }
282 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800283}
284
285
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800286void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
287{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 const unsigned long BYTE_MASK = 0xBF;
289 const unsigned long BYTE_MARK = 0x80;
290 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800291
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700292 if (input < 0x80) {
293 *length = 1;
294 }
295 else if ( input < 0x800 ) {
296 *length = 2;
297 }
298 else if ( input < 0x10000 ) {
299 *length = 3;
300 }
301 else if ( input < 0x200000 ) {
302 *length = 4;
303 }
304 else {
305 *length = 0; // This code won't covert this correctly anyway.
306 return;
307 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800308
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800310
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700311 // Scary scary fall throughs.
312 switch (*length) {
313 case 4:
314 --output;
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
316 input >>= 6;
317 case 3:
318 --output;
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
320 input >>= 6;
321 case 2:
322 --output;
323 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
324 input >>= 6;
325 case 1:
326 --output;
327 *output = (char)(input | FIRST_BYTE_MARK[*length]);
328 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800329}
330
331
332const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
333{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700334 // Presume an entity, and pull it out.
335 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800336
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 if ( *(p+1) == '#' && *(p+2) ) {
338 unsigned long ucs = 0;
339 ptrdiff_t delta = 0;
340 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800341
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700342 if ( *(p+2) == 'x' ) {
343 // Hexadecimal.
344 if ( !*(p+3) ) {
345 return 0;
346 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800347
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700348 const char* q = p+3;
349 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 if ( !q || !*q ) {
352 return 0;
353 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800354
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700355 delta = q-p;
356 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800357
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700358 while ( *q != 'x' ) {
359 if ( *q >= '0' && *q <= '9' ) {
360 ucs += mult * (*q - '0');
361 }
362 else if ( *q >= 'a' && *q <= 'f' ) {
363 ucs += mult * (*q - 'a' + 10);
364 }
365 else if ( *q >= 'A' && *q <= 'F' ) {
366 ucs += mult * (*q - 'A' + 10 );
367 }
368 else {
369 return 0;
370 }
371 mult *= 16;
372 --q;
373 }
374 }
375 else {
376 // Decimal.
377 if ( !*(p+2) ) {
378 return 0;
379 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800380
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700381 const char* q = p+2;
382 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800383
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700384 if ( !q || !*q ) {
385 return 0;
386 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800387
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700388 delta = q-p;
389 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800390
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700391 while ( *q != '#' ) {
392 if ( *q >= '0' && *q <= '9' ) {
393 ucs += mult * (*q - '0');
394 }
395 else {
396 return 0;
397 }
398 mult *= 10;
399 --q;
400 }
401 }
402 // convert the UCS to UTF-8
403 ConvertUTF32ToUTF8( ucs, value, length );
404 return p + delta + 1;
405 }
406 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800407}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800408
409
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700410void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700411{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700412 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700413}
414
415
416void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700418 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700419}
420
421
422void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700424 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700425}
426
427
428void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700430 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700431}
432
433
434void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
435{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700436 TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700437}
438
439
440bool XMLUtil::ToInt( const char* str, int* value )
441{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700442 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
443 return true;
444 }
445 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700446}
447
448bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
449{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700450 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
451 return true;
452 }
453 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700454}
455
456bool XMLUtil::ToBool( const char* str, bool* value )
457{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700458 int ival = 0;
459 if ( ToInt( str, &ival )) {
460 *value = (ival==0) ? false : true;
461 return true;
462 }
463 if ( StringEqual( str, "true" ) ) {
464 *value = true;
465 return true;
466 }
467 else if ( StringEqual( str, "false" ) ) {
468 *value = false;
469 return true;
470 }
471 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700472}
473
474
475bool XMLUtil::ToFloat( const char* str, float* value )
476{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700477 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
478 return true;
479 }
480 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700481}
482
483bool XMLUtil::ToDouble( const char* str, double* value )
484{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700485 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
486 return true;
487 }
488 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700489}
490
491
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700492char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800493{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700494 XMLNode* returnNode = 0;
495 char* start = p;
496 p = XMLUtil::SkipWhiteSpace( p );
497 if( !p || !*p ) {
498 return p;
499 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800500
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700501 // What is this thing?
502 // - Elements start with a letter or underscore, but xml is reserved.
503 // - Comments: <!--
504 // - Decleration: <?
505 // - Everthing else is unknown to tinyxml.
506 //
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800507
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700508 static const char* xmlHeader = { "<?" };
509 static const char* commentHeader = { "<!--" };
510 static const char* dtdHeader = { "<!" };
511 static const char* cdataHeader = { "<![CDATA[" };
512 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800513
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 static const int xmlHeaderLen = 2;
515 static const int commentHeaderLen = 4;
516 static const int dtdHeaderLen = 2;
517 static const int cdataHeaderLen = 9;
518 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800520#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800521#pragma warning ( push )
522#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800523#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700524 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
525 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800527#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800528#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
530 returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
531 returnNode->memPool = &commentPool;
532 p += xmlHeaderLen;
533 }
534 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
535 returnNode = new (commentPool.Alloc()) XMLComment( this );
536 returnNode->memPool = &commentPool;
537 p += commentHeaderLen;
538 }
539 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
540 XMLText* text = new (textPool.Alloc()) XMLText( this );
541 returnNode = text;
542 returnNode->memPool = &textPool;
543 p += cdataHeaderLen;
544 text->SetCData( true );
545 }
546 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
547 returnNode = new (commentPool.Alloc()) XMLUnknown( this );
548 returnNode->memPool = &commentPool;
549 p += dtdHeaderLen;
550 }
551 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
552 returnNode = new (elementPool.Alloc()) XMLElement( this );
553 returnNode->memPool = &elementPool;
554 p += elementHeaderLen;
555 }
556 else {
557 returnNode = new (textPool.Alloc()) XMLText( this );
558 returnNode->memPool = &textPool;
559 p = start; // Back it up, all the text counts.
560 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800561
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700562 *node = returnNode;
563 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800564}
565
566
Lee Thomason751da522012-02-10 08:50:51 -0800567bool XMLDocument::Accept( XMLVisitor* visitor ) const
568{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700569 if ( visitor->VisitEnter( *this ) ) {
570 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
571 if ( !node->Accept( visitor ) ) {
572 break;
573 }
574 }
575 }
576 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800577}
Lee Thomason56bdd022012-02-09 18:16:58 -0800578
579
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800580// --------- XMLNode ----------- //
581
582XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700583 document( doc ),
584 parent( 0 ),
585 firstChild( 0 ), lastChild( 0 ),
586 prev( 0 ), next( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800588}
589
590
591XMLNode::~XMLNode()
592{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 DeleteChildren();
594 if ( parent ) {
595 parent->Unlink( this );
596 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800597}
598
599
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800600void XMLNode::SetValue( const char* str, bool staticMem )
601{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700602 if ( staticMem ) {
603 value.SetInternedStr( str );
604 }
605 else {
606 value.SetStr( str );
607 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800608}
609
610
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800611void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800612{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700613 while( firstChild ) {
614 XMLNode* node = firstChild;
615 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700616
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 DELETE_NODE( node );
618 }
619 firstChild = lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800620}
621
622
623void XMLNode::Unlink( XMLNode* child )
624{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 TIXMLASSERT( child->parent == this );
626 if ( child == firstChild ) {
627 firstChild = firstChild->next;
628 }
629 if ( child == lastChild ) {
630 lastChild = lastChild->prev;
631 }
Lee Thomasond923c672012-01-23 08:44:25 -0800632
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 if ( child->prev ) {
634 child->prev->next = child->next;
635 }
636 if ( child->next ) {
637 child->next->prev = child->prev;
638 }
639 child->parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800640}
641
642
U-Stream\Leeae25a442012-02-17 17:48:16 -0800643void XMLNode::DeleteChild( XMLNode* node )
644{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700645 TIXMLASSERT( node->parent == this );
646 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800647}
648
649
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800650XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
651{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700652 if ( lastChild ) {
653 TIXMLASSERT( firstChild );
654 TIXMLASSERT( lastChild->next == 0 );
655 lastChild->next = addThis;
656 addThis->prev = lastChild;
657 lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800658
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700659 addThis->next = 0;
660 }
661 else {
662 TIXMLASSERT( firstChild == 0 );
663 firstChild = lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800664
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700665 addThis->prev = 0;
666 addThis->next = 0;
667 }
668 addThis->parent = this;
669 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670}
671
672
Lee Thomason1ff38e02012-02-14 18:18:16 -0800673XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
674{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 if ( firstChild ) {
676 TIXMLASSERT( lastChild );
677 TIXMLASSERT( firstChild->prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800678
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 firstChild->prev = addThis;
680 addThis->next = firstChild;
681 firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800682
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700683 addThis->prev = 0;
684 }
685 else {
686 TIXMLASSERT( lastChild == 0 );
687 firstChild = lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800688
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700689 addThis->prev = 0;
690 addThis->next = 0;
691 }
692 addThis->parent = this;
693 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800694}
695
696
697XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
698{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700699 TIXMLASSERT( afterThis->parent == this );
700 if ( afterThis->parent != this ) {
701 return 0;
702 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800703
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700704 if ( afterThis->next == 0 ) {
705 // The last node or the only node.
706 return InsertEndChild( addThis );
707 }
708 addThis->prev = afterThis;
709 addThis->next = afterThis->next;
710 afterThis->next->prev = addThis;
711 afterThis->next = addThis;
712 addThis->parent = this;
713 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800714}
715
716
717
718
Lee Thomason56bdd022012-02-09 18:16:58 -0800719const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800720{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 for( XMLNode* node=firstChild; node; node=node->next ) {
722 XMLElement* element = node->ToElement();
723 if ( element ) {
724 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
725 return element;
726 }
727 }
728 }
729 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800730}
731
732
Lee Thomason56bdd022012-02-09 18:16:58 -0800733const XMLElement* XMLNode::LastChildElement( const char* value ) const
734{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700735 for( XMLNode* node=lastChild; node; node=node->prev ) {
736 XMLElement* element = node->ToElement();
737 if ( element ) {
738 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
739 return element;
740 }
741 }
742 }
743 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800744}
745
746
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800747const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
748{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700749 for( XMLNode* element=this->next; element; element = element->next ) {
750 if ( element->ToElement()
751 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
752 return element->ToElement();
753 }
754 }
755 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800756}
757
758
759const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
760{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 for( XMLNode* element=this->prev; element; element = element->prev ) {
762 if ( element->ToElement()
763 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
764 return element->ToElement();
765 }
766 }
767 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800768}
769
770
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800771char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800772{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700773 // This is a recursive method, but thinking about it "at the current level"
774 // it is a pretty simple flat list:
775 // <foo/>
776 // <!-- comment -->
777 //
778 // With a special case:
779 // <foo>
780 // </foo>
781 // <!-- comment -->
782 //
783 // Where the closing element (/foo) *must* be the next thing after the opening
784 // element, and the names must match. BUT the tricky bit is that the closing
785 // element will be read by the child.
786 //
787 // 'endTag' is the end tag for this node, it is returned by a call to a child.
788 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800789
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 while( p && *p ) {
791 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800792
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700793 p = document->Identify( p, &node );
794 if ( p == 0 || node == 0 ) {
795 break;
796 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800797
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 StrPair endTag;
799 p = node->ParseDeep( p, &endTag );
800 if ( !p ) {
801 DELETE_NODE( node );
802 node = 0;
803 if ( !document->Error() ) {
804 document->SetError( XML_ERROR_PARSING, 0, 0 );
805 }
806 break;
807 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800808
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700809 // We read the end tag. Return it to the parent.
810 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
811 if ( parentEnd ) {
812 *parentEnd = static_cast<XMLElement*>(node)->value;
813 }
814 DELETE_NODE( node );
815 return p;
816 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800817
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 // Handle an end tag returned to this level.
819 // And handle a bunch of annoying errors.
820 XMLElement* ele = node->ToElement();
821 if ( ele ) {
822 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
823 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
824 p = 0;
825 }
826 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
827 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
828 p = 0;
829 }
830 else if ( !endTag.Empty() ) {
831 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
832 document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
833 p = 0;
834 }
835 }
836 }
837 if ( p == 0 ) {
838 DELETE_NODE( node );
839 node = 0;
840 }
841 if ( node ) {
842 this->InsertEndChild( node );
843 }
844 }
845 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800846}
847
Lee Thomason5492a1c2012-01-23 15:32:10 -0800848// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800849char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800850{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 const char* start = p;
852 if ( this->CData() ) {
853 p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
854 if ( !p ) {
855 document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
856 }
857 return p;
858 }
859 else {
860 int flags = document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
861 if ( document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
862 flags |= StrPair::COLLAPSE_WHITESPACE;
863 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700864
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700865 p = value.ParseText( p, "<", flags );
866 if ( !p ) {
867 document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
868 }
869 if ( p && *p ) {
870 return p-1;
871 }
872 }
873 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874}
875
876
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800877XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
878{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 if ( !doc ) {
880 doc = document;
881 }
882 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
883 text->SetCData( this->CData() );
884 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800885}
886
887
888bool XMLText::ShallowEqual( const XMLNode* compare ) const
889{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700890 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800891}
892
893
Lee Thomason56bdd022012-02-09 18:16:58 -0800894bool XMLText::Accept( XMLVisitor* visitor ) const
895{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700896 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800897}
898
899
Lee Thomason3f57d272012-01-11 15:30:03 -0800900// --------- XMLComment ---------- //
901
Lee Thomasone4422302012-01-20 17:59:50 -0800902XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800903{
904}
905
906
Lee Thomasonce0763e2012-01-11 15:43:54 -0800907XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800908{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700909 //printf( "~XMLComment\n" );
Lee Thomason3f57d272012-01-11 15:30:03 -0800910}
911
912
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800913char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 // Comment parses as text.
916 const char* start = p;
917 p = value.ParseText( p, "-->", StrPair::COMMENT );
918 if ( p == 0 ) {
919 document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
920 }
921 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800922}
923
924
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800925XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
926{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700927 if ( !doc ) {
928 doc = document;
929 }
930 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
931 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800932}
933
934
935bool XMLComment::ShallowEqual( const XMLNode* compare ) const
936{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800938}
939
940
Lee Thomason751da522012-02-10 08:50:51 -0800941bool XMLComment::Accept( XMLVisitor* visitor ) const
942{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800944}
Lee Thomason56bdd022012-02-09 18:16:58 -0800945
946
Lee Thomason50f97b22012-02-11 16:33:40 -0800947// --------- XMLDeclaration ---------- //
948
949XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
950{
951}
952
953
954XMLDeclaration::~XMLDeclaration()
955{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700956 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800957}
958
959
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800960char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800961{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 // Declaration parses as text.
963 const char* start = p;
964 p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
965 if ( p == 0 ) {
966 document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
967 }
968 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800969}
970
971
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800972XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
973{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700974 if ( !doc ) {
975 doc = document;
976 }
977 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
978 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800979}
980
981
982bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
983{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700984 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800985}
986
987
988
Lee Thomason50f97b22012-02-11 16:33:40 -0800989bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
990{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -0800992}
993
994// --------- XMLUnknown ---------- //
995
996XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
997{
998}
999
1000
1001XMLUnknown::~XMLUnknown()
1002{
1003}
1004
1005
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001006char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001007{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 // Unknown parses as text.
1009 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001010
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001011 p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
1012 if ( !p ) {
1013 document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
1014 }
1015 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001016}
1017
1018
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001019XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1020{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001021 if ( !doc ) {
1022 doc = document;
1023 }
1024 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1025 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001026}
1027
1028
1029bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1030{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001031 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001032}
1033
1034
Lee Thomason50f97b22012-02-11 16:33:40 -08001035bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1036{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001038}
1039
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001040// --------- XMLAttribute ---------- //
Lee Thomason6f381b72012-03-02 12:59:39 -08001041char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001043 // Parse using the name rules: bug fix, was using ParseText before
1044 p = name.ParseName( p );
1045 if ( !p || !*p ) {
1046 return 0;
1047 }
Lee Thomason22aead12012-01-23 13:29:35 -08001048
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 // Skip white space before =
1050 p = XMLUtil::SkipWhiteSpace( p );
1051 if ( !p || *p != '=' ) {
1052 return 0;
1053 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001054
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001055 ++p; // move up to opening quote
1056 p = XMLUtil::SkipWhiteSpace( p );
1057 if ( *p != '\"' && *p != '\'' ) {
1058 return 0;
1059 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001060
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 char endTag[2] = { *p, 0 };
1062 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001063
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001064 p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
1065 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001066}
1067
1068
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001069void XMLAttribute::SetName( const char* n )
1070{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001071 name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001072}
1073
1074
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001075int XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001076{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001077 if ( XMLUtil::ToInt( Value(), value )) {
1078 return XML_NO_ERROR;
1079 }
1080 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001081}
1082
1083
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001084int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001085{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 if ( XMLUtil::ToUnsigned( Value(), value )) {
1087 return XML_NO_ERROR;
1088 }
1089 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001090}
1091
1092
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001093int XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001094{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001095 if ( XMLUtil::ToBool( Value(), value )) {
1096 return XML_NO_ERROR;
1097 }
1098 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001099}
1100
1101
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001102int XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001103{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001104 if ( XMLUtil::ToFloat( Value(), value )) {
1105 return XML_NO_ERROR;
1106 }
1107 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001108}
1109
1110
1111int XMLAttribute::QueryDoubleValue( double* value ) const
1112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 if ( XMLUtil::ToDouble( Value(), value )) {
1114 return XML_NO_ERROR;
1115 }
1116 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001117}
1118
1119
1120void XMLAttribute::SetAttribute( const char* v )
1121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001123}
1124
1125
Lee Thomason1ff38e02012-02-14 18:18:16 -08001126void XMLAttribute::SetAttribute( int v )
1127{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001128 char buf[BUF_SIZE];
1129 XMLUtil::ToStr( v, buf, BUF_SIZE );
1130 value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001132
1133
1134void XMLAttribute::SetAttribute( unsigned v )
1135{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001136 char buf[BUF_SIZE];
1137 XMLUtil::ToStr( v, buf, BUF_SIZE );
1138 value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001139}
1140
1141
1142void XMLAttribute::SetAttribute( bool v )
1143{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001144 char buf[BUF_SIZE];
1145 XMLUtil::ToStr( v, buf, BUF_SIZE );
1146 value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001147}
1148
1149void XMLAttribute::SetAttribute( double v )
1150{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 char buf[BUF_SIZE];
1152 XMLUtil::ToStr( v, buf, BUF_SIZE );
1153 value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001154}
1155
1156void XMLAttribute::SetAttribute( float v )
1157{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001158 char buf[BUF_SIZE];
1159 XMLUtil::ToStr( v, buf, BUF_SIZE );
1160 value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001161}
1162
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001163
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001164// --------- XMLElement ---------- //
1165XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001166 closingType( 0 ),
1167 rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001168{
1169}
1170
1171
1172XMLElement::~XMLElement()
1173{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001174 while( rootAttribute ) {
1175 XMLAttribute* next = rootAttribute->next;
1176 DELETE_ATTRIBUTE( rootAttribute );
1177 rootAttribute = next;
1178 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001179}
1180
1181
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001182XMLAttribute* XMLElement::FindAttribute( const char* name )
1183{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001184 XMLAttribute* a = 0;
1185 for( a=rootAttribute; a; a = a->next ) {
1186 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1187 return a;
1188 }
1189 }
1190 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191}
1192
1193
1194const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1195{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001196 XMLAttribute* a = 0;
1197 for( a=rootAttribute; a; a = a->next ) {
1198 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1199 return a;
1200 }
1201 }
1202 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001203}
1204
1205
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001206const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001208 const XMLAttribute* a = FindAttribute( name );
1209 if ( !a ) {
1210 return 0;
1211 }
1212 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1213 return a->Value();
1214 }
1215 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001216}
1217
1218
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001219const char* XMLElement::GetText() const
1220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 if ( FirstChild() && FirstChild()->ToText() ) {
1222 return FirstChild()->ToText()->Value();
1223 }
1224 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001225}
1226
1227
Lee Thomason21be8822012-07-15 17:27:22 -07001228int XMLElement::QueryIntText( int* _value ) const
1229{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001230 if ( FirstChild() && FirstChild()->ToText() ) {
1231 const char* t = FirstChild()->ToText()->Value();
1232 if ( XMLUtil::ToInt( t, _value ) ) {
1233 return XML_SUCCESS;
1234 }
1235 return XML_CAN_NOT_CONVERT_TEXT;
1236 }
1237 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001238}
1239
1240
1241int XMLElement::QueryUnsignedText( unsigned* _value ) const
1242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 if ( FirstChild() && FirstChild()->ToText() ) {
1244 const char* t = FirstChild()->ToText()->Value();
1245 if ( XMLUtil::ToUnsigned( t, _value ) ) {
1246 return XML_SUCCESS;
1247 }
1248 return XML_CAN_NOT_CONVERT_TEXT;
1249 }
1250 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001251}
1252
1253
1254int XMLElement::QueryBoolText( bool* _value ) const
1255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 if ( FirstChild() && FirstChild()->ToText() ) {
1257 const char* t = FirstChild()->ToText()->Value();
1258 if ( XMLUtil::ToBool( t, _value ) ) {
1259 return XML_SUCCESS;
1260 }
1261 return XML_CAN_NOT_CONVERT_TEXT;
1262 }
1263 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001264}
1265
1266
1267int XMLElement::QueryDoubleText( double* _value ) const
1268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001269 if ( FirstChild() && FirstChild()->ToText() ) {
1270 const char* t = FirstChild()->ToText()->Value();
1271 if ( XMLUtil::ToDouble( t, _value ) ) {
1272 return XML_SUCCESS;
1273 }
1274 return XML_CAN_NOT_CONVERT_TEXT;
1275 }
1276 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001277}
1278
1279
1280int XMLElement::QueryFloatText( float* _value ) const
1281{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001282 if ( FirstChild() && FirstChild()->ToText() ) {
1283 const char* t = FirstChild()->ToText()->Value();
1284 if ( XMLUtil::ToFloat( t, _value ) ) {
1285 return XML_SUCCESS;
1286 }
1287 return XML_CAN_NOT_CONVERT_TEXT;
1288 }
1289 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001290}
1291
1292
1293
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001294XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1295{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001296 XMLAttribute* last = 0;
1297 XMLAttribute* attrib = 0;
1298 for( attrib = rootAttribute;
1299 attrib;
1300 last = attrib, attrib = attrib->next ) {
1301 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1302 break;
1303 }
1304 }
1305 if ( !attrib ) {
1306 attrib = new (document->attributePool.Alloc() ) XMLAttribute();
1307 attrib->memPool = &document->attributePool;
1308 if ( last ) {
1309 last->next = attrib;
1310 }
1311 else {
1312 rootAttribute = attrib;
1313 }
1314 attrib->SetName( name );
1315 }
1316 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001317}
1318
1319
U-Stream\Leeae25a442012-02-17 17:48:16 -08001320void XMLElement::DeleteAttribute( const char* name )
1321{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001322 XMLAttribute* prev = 0;
1323 for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1324 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1325 if ( prev ) {
1326 prev->next = a->next;
1327 }
1328 else {
1329 rootAttribute = a->next;
1330 }
1331 DELETE_ATTRIBUTE( a );
1332 break;
1333 }
1334 prev = a;
1335 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001336}
1337
1338
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001339char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001340{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001341 const char* start = p;
1342 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001343
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 // Read the attributes.
1345 while( p ) {
1346 p = XMLUtil::SkipWhiteSpace( p );
1347 if ( !p || !(*p) ) {
1348 document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
1349 return 0;
1350 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001351
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 // attribute.
1353 if ( XMLUtil::IsAlpha( *p ) ) {
1354 XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
1355 attrib->memPool = &document->attributePool;
Lee Thomasond1983222012-02-06 08:41:24 -08001356
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 p = attrib->ParseDeep( p, document->ProcessEntities() );
1358 if ( !p || Attribute( attrib->Name() ) ) {
1359 DELETE_ATTRIBUTE( attrib );
1360 document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
1361 return 0;
1362 }
1363 // There is a minor bug here: if the attribute in the source xml
1364 // document is duplicated, it will not be detected and the
1365 // attribute will be doubly added. However, tracking the 'prevAttribute'
1366 // avoids re-scanning the attribute list. Preferring performance for
1367 // now, may reconsider in the future.
1368 if ( prevAttribute ) {
1369 prevAttribute->next = attrib;
1370 }
1371 else {
1372 rootAttribute = attrib;
1373 }
1374 prevAttribute = attrib;
1375 }
1376 // end of the tag
1377 else if ( *p == '/' && *(p+1) == '>' ) {
1378 closingType = CLOSED;
1379 return p+2; // done; sealed element.
1380 }
1381 // end of the tag
1382 else if ( *p == '>' ) {
1383 ++p;
1384 break;
1385 }
1386 else {
1387 document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
1388 return 0;
1389 }
1390 }
1391 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001392}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001393
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001394
Lee Thomason67d61312012-01-24 16:01:51 -08001395//
1396// <ele></ele>
1397// <ele>foo<b>bar</b></ele>
1398//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001399char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001400{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 // Read the element name.
1402 p = XMLUtil::SkipWhiteSpace( p );
1403 if ( !p ) {
1404 return 0;
1405 }
Lee Thomason67d61312012-01-24 16:01:51 -08001406
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 // The closing element is the </element> form. It is
1408 // parsed just like a regular element then deleted from
1409 // the DOM.
1410 if ( *p == '/' ) {
1411 closingType = CLOSING;
1412 ++p;
1413 }
Lee Thomason67d61312012-01-24 16:01:51 -08001414
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 p = value.ParseName( p );
1416 if ( value.Empty() ) {
1417 return 0;
1418 }
Lee Thomason67d61312012-01-24 16:01:51 -08001419
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 p = ParseAttributes( p );
1421 if ( !p || !*p || closingType ) {
1422 return p;
1423 }
Lee Thomason67d61312012-01-24 16:01:51 -08001424
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 p = XMLNode::ParseDeep( p, strPair );
1426 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001427}
1428
1429
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001430
1431XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 if ( !doc ) {
1434 doc = document;
1435 }
1436 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1437 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1438 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1439 }
1440 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001441}
1442
1443
1444bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1445{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 const XMLElement* other = compare->ToElement();
1447 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001448
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 const XMLAttribute* a=FirstAttribute();
1450 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001451
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 while ( a && b ) {
1453 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1454 return false;
1455 }
1456 a = a->Next();
1457 b = b->Next();
1458 }
1459 if ( a || b ) {
1460 // different count
1461 return false;
1462 }
1463 return true;
1464 }
1465 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001466}
1467
1468
Lee Thomason751da522012-02-10 08:50:51 -08001469bool XMLElement::Accept( XMLVisitor* visitor ) const
1470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 if ( visitor->VisitEnter( *this, rootAttribute ) ) {
1472 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1473 if ( !node->Accept( visitor ) ) {
1474 break;
1475 }
1476 }
1477 }
1478 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001479}
Lee Thomason56bdd022012-02-09 18:16:58 -08001480
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001481
Lee Thomason3f57d272012-01-11 15:30:03 -08001482// --------- XMLDocument ----------- //
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001483XMLDocument::XMLDocument( bool _processEntities, Whitespace _whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 XMLNode( 0 ),
1485 writeBOM( false ),
1486 processEntities( _processEntities ),
1487 errorID( 0 ),
1488 whitespace( _whitespace ),
1489 errorStr1( 0 ),
1490 errorStr2( 0 ),
1491 charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001492{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001494}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001495
1496
Lee Thomason3f57d272012-01-11 15:30:03 -08001497XMLDocument::~XMLDocument()
1498{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 DeleteChildren();
1500 delete [] charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001501
Lee Thomasonec5a7b42012-02-13 18:16:52 -08001502#if 0
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 textPool.Trace( "text" );
1504 elementPool.Trace( "element" );
1505 commentPool.Trace( "comment" );
1506 attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001507#endif
1508
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001509 TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1510 TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1511 TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1512 TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
Lee Thomason3f57d272012-01-11 15:30:03 -08001513}
1514
1515
Lee Thomason18d68bd2012-01-26 18:17:26 -08001516void XMLDocument::InitDocument()
1517{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001518 errorID = XML_NO_ERROR;
1519 errorStr1 = 0;
1520 errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001521
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001522 delete [] charBuffer;
1523 charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001524
1525}
1526
Lee Thomason3f57d272012-01-11 15:30:03 -08001527
Lee Thomason2c85a712012-01-31 08:24:24 -08001528XMLElement* XMLDocument::NewElement( const char* name )
1529{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001530 XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1531 ele->memPool = &elementPool;
1532 ele->SetName( name );
1533 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001534}
1535
1536
Lee Thomason1ff38e02012-02-14 18:18:16 -08001537XMLComment* XMLDocument::NewComment( const char* str )
1538{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1540 comment->memPool = &commentPool;
1541 comment->SetValue( str );
1542 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001543}
1544
1545
1546XMLText* XMLDocument::NewText( const char* str )
1547{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 XMLText* text = new (textPool.Alloc()) XMLText( this );
1549 text->memPool = &textPool;
1550 text->SetValue( str );
1551 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001552}
1553
1554
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001555XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1556{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
1558 dec->memPool = &commentPool;
1559 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1560 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001561}
1562
1563
1564XMLUnknown* XMLDocument::NewUnknown( const char* str )
1565{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
1567 unk->memPool = &commentPool;
1568 unk->SetValue( str );
1569 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001570}
1571
1572
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001573int XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001574{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 DeleteChildren();
1576 InitDocument();
1577 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001578
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001579#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1580 errno_t err = fopen_s(&fp, filename, "rb" );
1581 if ( !fp || err) {
1582#else
1583 fp = fopen( filename, "rb" );
1584 if ( !fp) {
1585#endif
1586 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
1587 return errorID;
1588 }
1589 LoadFile( fp );
1590 fclose( fp );
1591 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001592}
1593
1594
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001595int XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001596{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001597 DeleteChildren();
1598 InitDocument();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001599
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001600 fseek( fp, 0, SEEK_END );
1601 size_t size = ftell( fp );
1602 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001603
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001604 if ( size == 0 ) {
1605 return errorID;
1606 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001607
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 charBuffer = new char[size+1];
1609 size_t read = fread( charBuffer, 1, size, fp );
1610 if ( read != size ) {
1611 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1612 return errorID;
1613 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001614
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001616
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001617 const char* p = charBuffer;
1618 p = XMLUtil::SkipWhiteSpace( p );
1619 p = XMLUtil::ReadBOM( p, &writeBOM );
1620 if ( !p || !*p ) {
1621 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1622 return errorID;
1623 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001624
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 ParseDeep( charBuffer + (p-charBuffer), 0 );
1626 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001627}
1628
1629
Robert Reif312a20f2012-09-08 19:33:57 -04001630int XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001631{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001632 FILE* fp = 0;
1633#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1634 errno_t err = fopen_s(&fp, filename, "w" );
1635 if ( !fp || err) {
1636#else
1637 fp = fopen( filename, "w" );
1638 if ( !fp) {
1639#endif
1640 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
1641 return errorID;
1642 }
1643 SaveFile(fp, compact);
1644 fclose( fp );
1645 return errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001646}
1647
1648
Robert Reif312a20f2012-09-08 19:33:57 -04001649int XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001650{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001651 XMLPrinter stream( fp, compact );
1652 Print( &stream );
1653 return errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001654}
1655
Lee Thomason1ff38e02012-02-14 18:18:16 -08001656
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001657int XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001658{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001659 DeleteChildren();
1660 InitDocument();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001661
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001662 if ( !p || !*p ) {
1663 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1664 return errorID;
1665 }
1666 if ( len == (size_t)(-1) ) {
1667 len = strlen( p );
1668 }
1669 charBuffer = new char[ len+1 ];
1670 memcpy( charBuffer, p, len );
1671 charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001672
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001673 p = XMLUtil::SkipWhiteSpace( p );
1674 p = XMLUtil::ReadBOM( p, &writeBOM );
1675 if ( !p || !*p ) {
1676 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1677 return errorID;
1678 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001679
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001680 ParseDeep( charBuffer, 0 );
1681 return errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001682}
1683
1684
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001685void XMLDocument::Print( XMLPrinter* streamer )
Lee Thomason3f57d272012-01-11 15:30:03 -08001686{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001687 XMLPrinter stdStreamer( stdout );
1688 if ( !streamer ) {
1689 streamer = &stdStreamer;
1690 }
1691 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001692}
1693
1694
Lee Thomason67d61312012-01-24 16:01:51 -08001695void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1696{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 errorID = error;
1698 errorStr1 = str1;
1699 errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001700}
1701
Lee Thomason5cae8972012-01-24 18:03:07 -08001702
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001703void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001704{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 if ( errorID ) {
1706 static const int LEN = 20;
1707 char buf1[LEN] = { 0 };
1708 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001709
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001710 if ( errorStr1 ) {
1711 TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
1712 }
1713 if ( errorStr2 ) {
1714 TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
1715 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001716
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001717 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1718 errorID, buf1, buf2 );
1719 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001720}
1721
1722
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001723XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 elementJustOpened( false ),
1725 firstElement( true ),
1726 fp( file ),
1727 depth( 0 ),
1728 textDepth( -1 ),
1729 processEntities( true ),
1730 compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001731{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001732 for( int i=0; i<ENTITY_RANGE; ++i ) {
1733 entityFlag[i] = false;
1734 restrictedEntityFlag[i] = false;
1735 }
1736 for( int i=0; i<NUM_ENTITIES; ++i ) {
1737 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1738 if ( entities[i].value < ENTITY_RANGE ) {
1739 entityFlag[ (int)entities[i].value ] = true;
1740 }
1741 }
1742 restrictedEntityFlag[(int)'&'] = true;
1743 restrictedEntityFlag[(int)'<'] = true;
1744 restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1745 buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001746}
1747
1748
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001749void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001750{
1751 va_list va;
1752 va_start( va, format );
1753
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001754 if ( fp ) {
1755 vfprintf( fp, format, va );
1756 }
1757 else {
1758 // This seems brutally complex. Haven't figured out a better
1759 // way on windows.
1760#ifdef _MSC_VER
1761 int len = -1;
1762 int expand = 1000;
1763 while ( len < 0 ) {
1764 len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
1765 if ( len < 0 ) {
1766 expand *= 3/2;
1767 accumulator.PushArr( expand );
1768 }
1769 }
1770 char* p = buffer.PushArr( len ) - 1;
1771 memcpy( p, accumulator.Mem(), len+1 );
1772#else
1773 int len = vsnprintf( 0, 0, format, va );
1774 // Close out and re-start the va-args
1775 va_end( va );
1776 va_start( va, format );
1777 char* p = buffer.PushArr( len ) - 1;
1778 vsnprintf( p, len+1, format, va );
1779#endif
1780 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001781 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001782}
1783
1784
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001785void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001786{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001787 for( int i=0; i<depth; ++i ) {
1788 Print( " " );
1789 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001790}
1791
1792
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001793void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001794{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 // Look for runs of bytes between entities to print.
1796 const char* q = p;
1797 const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001798
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001799 if ( processEntities ) {
1800 while ( *q ) {
1801 // Remember, char is sometimes signed. (How many times has that bitten me?)
1802 if ( *q > 0 && *q < ENTITY_RANGE ) {
1803 // Check for entities. If one is found, flush
1804 // the stream up until the entity, write the
1805 // entity, and keep looking.
1806 if ( flag[(unsigned)(*q)] ) {
1807 while ( p < q ) {
1808 Print( "%c", *p );
1809 ++p;
1810 }
1811 for( int i=0; i<NUM_ENTITIES; ++i ) {
1812 if ( entities[i].value == *q ) {
1813 Print( "&%s;", entities[i].pattern );
1814 break;
1815 }
1816 }
1817 ++p;
1818 }
1819 }
1820 ++q;
1821 }
1822 }
1823 // Flush the remaining string. This will be the entire
1824 // string if an entity wasn't found.
1825 if ( !processEntities || (q-p > 0) ) {
1826 Print( "%s", p );
1827 }
Lee Thomason857b8682012-01-25 17:50:25 -08001828}
1829
U-Stream\Leeae25a442012-02-17 17:48:16 -08001830
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001831void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001832{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1834 if ( writeBOM ) {
1835 Print( "%s", bom );
1836 }
1837 if ( writeDec ) {
1838 PushDeclaration( "xml version=\"1.0\"" );
1839 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001840}
1841
1842
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001843void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001844{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001845 if ( elementJustOpened ) {
1846 SealElement();
1847 }
1848 stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001849
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001850 if ( textDepth < 0 && !firstElement && !compactMode ) {
1851 Print( "\n" );
1852 PrintSpace( depth );
1853 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001854
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 Print( "<%s", name );
1856 elementJustOpened = true;
1857 firstElement = false;
1858 ++depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001859}
1860
1861
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001862void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001863{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 TIXMLASSERT( elementJustOpened );
1865 Print( " %s=\"", name );
1866 PrintString( value, false );
1867 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001868}
1869
1870
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001871void XMLPrinter::PushAttribute( const char* name, int v )
1872{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 char buf[BUF_SIZE];
1874 XMLUtil::ToStr( v, buf, BUF_SIZE );
1875 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001876}
1877
1878
1879void XMLPrinter::PushAttribute( const char* name, unsigned v )
1880{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 char buf[BUF_SIZE];
1882 XMLUtil::ToStr( v, buf, BUF_SIZE );
1883 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001884}
1885
1886
1887void XMLPrinter::PushAttribute( const char* name, bool v )
1888{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001889 char buf[BUF_SIZE];
1890 XMLUtil::ToStr( v, buf, BUF_SIZE );
1891 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001892}
1893
1894
1895void XMLPrinter::PushAttribute( const char* name, double v )
1896{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 char buf[BUF_SIZE];
1898 XMLUtil::ToStr( v, buf, BUF_SIZE );
1899 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001900}
1901
1902
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001903void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001905 --depth;
1906 const char* name = stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08001907
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 if ( elementJustOpened ) {
1909 Print( "/>" );
1910 }
1911 else {
1912 if ( textDepth < 0 && !compactMode) {
1913 Print( "\n" );
1914 PrintSpace( depth );
1915 }
1916 Print( "</%s>", name );
1917 }
Lee Thomason56bdd022012-02-09 18:16:58 -08001918
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 if ( textDepth == depth ) {
1920 textDepth = -1;
1921 }
1922 if ( depth == 0 && !compactMode) {
1923 Print( "\n" );
1924 }
1925 elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08001926}
1927
1928
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001929void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08001930{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001931 elementJustOpened = false;
1932 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001933}
1934
1935
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001936void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08001937{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 textDepth = depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08001939
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001940 if ( elementJustOpened ) {
1941 SealElement();
1942 }
1943 if ( cdata ) {
1944 Print( "<![CDATA[" );
1945 Print( "%s", text );
1946 Print( "]]>" );
1947 }
1948 else {
1949 PrintString( text, true );
1950 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001951}
1952
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001953void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07001954{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001955 char buf[BUF_SIZE];
1956 XMLUtil::ToStr( value, buf, BUF_SIZE );
1957 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001958}
1959
1960
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001961void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07001962{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 char buf[BUF_SIZE];
1964 XMLUtil::ToStr( value, buf, BUF_SIZE );
1965 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001966}
1967
1968
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001969void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07001970{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001971 char buf[BUF_SIZE];
1972 XMLUtil::ToStr( value, buf, BUF_SIZE );
1973 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001974}
1975
1976
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001977void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07001978{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 char buf[BUF_SIZE];
1980 XMLUtil::ToStr( value, buf, BUF_SIZE );
1981 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001982}
1983
1984
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001985void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07001986{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 char buf[BUF_SIZE];
1988 XMLUtil::ToStr( value, buf, BUF_SIZE );
1989 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07001990}
1991
Lee Thomason5cae8972012-01-24 18:03:07 -08001992
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001993void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08001994{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001995 if ( elementJustOpened ) {
1996 SealElement();
1997 }
1998 if ( textDepth < 0 && !firstElement && !compactMode) {
1999 Print( "\n" );
2000 PrintSpace( depth );
2001 }
2002 firstElement = false;
2003 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002004}
Lee Thomason751da522012-02-10 08:50:51 -08002005
2006
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002007void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 if ( elementJustOpened ) {
2010 SealElement();
2011 }
2012 if ( textDepth < 0 && !firstElement && !compactMode) {
2013 Print( "\n" );
2014 PrintSpace( depth );
2015 }
2016 firstElement = false;
2017 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002018}
2019
2020
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002021void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002022{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 if ( elementJustOpened ) {
2024 SealElement();
2025 }
2026 if ( textDepth < 0 && !firstElement && !compactMode) {
2027 Print( "\n" );
2028 PrintSpace( depth );
2029 }
2030 firstElement = false;
2031 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002032}
2033
2034
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002035bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002036{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 processEntities = doc.ProcessEntities();
2038 if ( doc.HasBOM() ) {
2039 PushHeader( true, false );
2040 }
2041 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002042}
2043
2044
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002045bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002046{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002047 OpenElement( element.Name() );
2048 while ( attribute ) {
2049 PushAttribute( attribute->Name(), attribute->Value() );
2050 attribute = attribute->Next();
2051 }
2052 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002053}
2054
2055
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002056bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002057{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 CloseElement();
2059 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002060}
2061
2062
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002063bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002064{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002065 PushText( text.Value(), text.CData() );
2066 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002067}
2068
2069
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002070bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002071{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002072 PushComment( comment.Value() );
2073 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002074}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002075
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002076bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002078 PushDeclaration( declaration.Value() );
2079 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002080}
2081
2082
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002083bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 PushUnknown( unknown.Value() );
2086 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002087}