blob: 4efc76862c5f8914306971119828a12151d0355e [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
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
48
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080049#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070050 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070051 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 node->~XMLNode(); \
53 pool->Free( node ); \
54 } \
55 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080056#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070057 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070058 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059 attrib->~XMLAttribute(); \
60 pool->Free( attrib ); \
61 } \
62 }
Lee Thomason43f59302012-02-06 18:18:11 -080063
Kevin Wojniak04c22d22012-11-08 11:02:22 -080064namespace tinyxml2
65{
66
Lee Thomason8ee79892012-01-25 17:44:30 -080067struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070068 const char* pattern;
69 int length;
70 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080071};
72
73static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070074static const Entity entities[NUM_ENTITIES] = {
75 { "quot", 4, DOUBLE_QUOTE },
76 { "amp", 3, '&' },
77 { "apos", 4, SINGLE_QUOTE },
78 { "lt", 2, '<' },
79 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080080};
81
Lee Thomasonfde6a752012-01-14 18:08:12 -080082
Lee Thomason1a1d4a72012-02-15 09:09:25 -080083StrPair::~StrPair()
84{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070085 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080086}
87
88
89void StrPair::Reset()
90{
Lee Thomason120b3a62012-10-12 10:06:59 -070091 if ( _flags & NEEDS_DELETE ) {
92 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070093 }
Lee Thomason120b3a62012-10-12 10:06:59 -070094 _flags = 0;
95 _start = 0;
96 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080097}
98
99
100void StrPair::SetStr( const char* str, int flags )
101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700102 Reset();
103 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700104 _start = new char[ len+1 ];
105 memcpy( _start, str, len+1 );
106 _end = _start + len;
107 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800108}
109
110
111char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700113 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800114
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700115 char* start = p; // fixme: hides a member
116 char endChar = *endTag;
117 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 // Inner loop of text parsing.
120 while ( *p ) {
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
122 Set( start, p, strFlags );
123 return p + length;
124 }
125 ++p;
126 }
127 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128}
129
130
131char* StrPair::ParseName( char* p )
132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700133 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800134
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 if ( !start || !(*start) ) {
136 return 0;
137 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200139 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 ++p;
141 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800142
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700143 if ( p > start ) {
144 Set( start, p, 0 );
145 return p;
146 }
147 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800148}
149
150
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700151void StrPair::CollapseWhitespace()
152{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400153 // Adjusting _start would cause undefined behavior on delete[]
154 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700155 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700156 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700157
Lee Thomason120b3a62012-10-12 10:06:59 -0700158 if ( _start && *_start ) {
159 char* p = _start; // the read pointer
160 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700161
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 while( *p ) {
163 if ( XMLUtil::IsWhiteSpace( *p )) {
164 p = XMLUtil::SkipWhiteSpace( p );
165 if ( *p == 0 ) {
166 break; // don't write to q; this trims the trailing space.
167 }
168 *q = ' ';
169 ++q;
170 }
171 *q = *p;
172 ++q;
173 ++p;
174 }
175 *q = 0;
176 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700177}
178
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800179
Lee Thomasone4422302012-01-20 17:59:50 -0800180const char* StrPair::GetStr()
181{
Lee Thomason120b3a62012-10-12 10:06:59 -0700182 if ( _flags & NEEDS_FLUSH ) {
183 *_end = 0;
184 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800185
Lee Thomason120b3a62012-10-12 10:06:59 -0700186 if ( _flags ) {
187 char* p = _start; // the read pointer
188 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800189
Lee Thomason120b3a62012-10-12 10:06:59 -0700190 while( p < _end ) {
191 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700192 // CR-LF pair becomes LF
193 // CR alone becomes LF
194 // LF-CR becomes LF
195 if ( *(p+1) == LF ) {
196 p += 2;
197 }
198 else {
199 ++p;
200 }
201 *q++ = LF;
202 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700203 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700204 if ( *(p+1) == CR ) {
205 p += 2;
206 }
207 else {
208 ++p;
209 }
210 *q++ = LF;
211 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700212 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700213 // Entities handled by tinyXML2:
214 // - special entities in the entity table [in/out]
215 // - numeric character reference [in]
216 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800217
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700218 if ( *(p+1) == '#' ) {
219 char buf[10] = { 0 };
220 int len;
221 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
222 for( int i=0; i<len; ++i ) {
223 *q++ = buf[i];
224 }
225 TIXMLASSERT( q <= p );
226 }
227 else {
228 int i=0;
229 for(; i<NUM_ENTITIES; ++i ) {
230 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
231 && *(p+entities[i].length+1) == ';' ) {
232 // Found an entity convert;
233 *q = entities[i].value;
234 ++q;
235 p += entities[i].length + 2;
236 break;
237 }
238 }
239 if ( i == NUM_ENTITIES ) {
240 // fixme: treat as error?
241 ++p;
242 ++q;
243 }
244 }
245 }
246 else {
247 *q = *p;
248 ++p;
249 ++q;
250 }
251 }
252 *q = 0;
253 }
254 // The loop below has plenty going on, and this
255 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700256 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700257 CollapseWhitespace();
258 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700260 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700261 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800262}
263
Lee Thomason2c85a712012-01-31 08:24:24 -0800264
Lee Thomasone4422302012-01-20 17:59:50 -0800265
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800266
Lee Thomason56bdd022012-02-09 18:16:58 -0800267// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800268
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800269const char* XMLUtil::ReadBOM( const char* p, bool* bom )
270{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700271 *bom = false;
272 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
273 // Check for BOM:
274 if ( *(pu+0) == TIXML_UTF_LEAD_0
275 && *(pu+1) == TIXML_UTF_LEAD_1
276 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
277 *bom = true;
278 p += 3;
279 }
280 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800281}
282
283
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800284void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
285{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700286 const unsigned long BYTE_MASK = 0xBF;
287 const unsigned long BYTE_MARK = 0x80;
288 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800289
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700290 if (input < 0x80) {
291 *length = 1;
292 }
293 else if ( input < 0x800 ) {
294 *length = 2;
295 }
296 else if ( input < 0x10000 ) {
297 *length = 3;
298 }
299 else if ( input < 0x200000 ) {
300 *length = 4;
301 }
302 else {
303 *length = 0; // This code won't covert this correctly anyway.
304 return;
305 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800306
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700307 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800308
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700309 // Scary scary fall throughs.
310 switch (*length) {
311 case 4:
312 --output;
313 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
314 input >>= 6;
315 case 3:
316 --output;
317 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
318 input >>= 6;
319 case 2:
320 --output;
321 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
322 input >>= 6;
323 case 1:
324 --output;
325 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100326 default:
327 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700328 }
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
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800427/*
428 ToStr() of a number is a very tricky topic.
429 https://github.com/leethomason/tinyxml2/issues/106
430*/
Lee Thomason21be8822012-07-15 17:27:22 -0700431void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
432{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800433 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
436
437void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
438{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800439 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", 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?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800505 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700506 static const char* xmlHeader = { "<?" };
507 static const char* commentHeader = { "<!--" };
508 static const char* dtdHeader = { "<!" };
509 static const char* cdataHeader = { "<![CDATA[" };
510 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 static const int xmlHeaderLen = 2;
513 static const int commentHeaderLen = 4;
514 static const int dtdHeaderLen = 2;
515 static const int cdataHeaderLen = 9;
516 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800517
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800518#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800519#pragma warning ( push )
520#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800521#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700522 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
523 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800524#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800525#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700527 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700528 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
529 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 p += xmlHeaderLen;
531 }
532 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700533 returnNode = new (_commentPool.Alloc()) XMLComment( this );
534 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700535 p += commentHeaderLen;
536 }
537 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700540 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700541 p += cdataHeaderLen;
542 text->SetCData( true );
543 }
544 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700545 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
546 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700547 p += dtdHeaderLen;
548 }
549 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 returnNode = new (_elementPool.Alloc()) XMLElement( this );
551 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700552 p += elementHeaderLen;
553 }
554 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700555 returnNode = new (_textPool.Alloc()) XMLText( this );
556 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700557 p = start; // Back it up, all the text counts.
558 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800559
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 *node = returnNode;
561 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800562}
563
564
Lee Thomason751da522012-02-10 08:50:51 -0800565bool XMLDocument::Accept( XMLVisitor* visitor ) const
566{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700567 if ( visitor->VisitEnter( *this ) ) {
568 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
569 if ( !node->Accept( visitor ) ) {
570 break;
571 }
572 }
573 }
574 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800575}
Lee Thomason56bdd022012-02-09 18:16:58 -0800576
577
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800578// --------- XMLNode ----------- //
579
580XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700581 _document( doc ),
582 _parent( 0 ),
583 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200584 _prev( 0 ), _next( 0 ),
585 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800586{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587}
588
589
590XMLNode::~XMLNode()
591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700593 if ( _parent ) {
594 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800596}
597
Michael Daumling21626882013-10-22 17:03:37 +0200598const char* XMLNode::Value() const
599{
600 return _value.GetStr();
601}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800602
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 if ( child == _firstChild ) {
629 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 if ( child == _lastChild ) {
632 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 }
Lee Thomasond923c672012-01-23 08:44:25 -0800634
Lee Thomason624d43f2012-10-12 10:58:48 -0700635 if ( child->_prev ) {
636 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700638 if ( child->_next ) {
639 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700641 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800642}
643
644
U-Stream\Leeae25a442012-02-17 17:48:16 -0800645void XMLNode::DeleteChild( XMLNode* node )
646{
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800649}
650
651
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800652XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
653{
Michael Daumlinged523282013-10-23 07:47:29 +0200654 if (addThis->_document != _document)
655 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700656
Michael Daumlinged523282013-10-23 07:47:29 +0200657 if (addThis->_parent)
658 addThis->_parent->Unlink( addThis );
659 else
660 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700661
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 if ( _lastChild ) {
663 TIXMLASSERT( _firstChild );
664 TIXMLASSERT( _lastChild->_next == 0 );
665 _lastChild->_next = addThis;
666 addThis->_prev = _lastChild;
667 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800668
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 }
671 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700672 TIXMLASSERT( _firstChild == 0 );
673 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800674
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 addThis->_prev = 0;
676 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680}
681
682
Lee Thomason1ff38e02012-02-14 18:18:16 -0800683XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
684{
Michael Daumlinged523282013-10-23 07:47:29 +0200685 if (addThis->_document != _document)
686 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700687
Michael Daumlinged523282013-10-23 07:47:29 +0200688 if (addThis->_parent)
689 addThis->_parent->Unlink( addThis );
690 else
691 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700692
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 if ( _firstChild ) {
694 TIXMLASSERT( _lastChild );
695 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800696
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 _firstChild->_prev = addThis;
698 addThis->_next = _firstChild;
699 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800700
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 }
703 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 TIXMLASSERT( _lastChild == 0 );
705 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 addThis->_prev = 0;
708 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200711 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800712}
713
714
715XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
716{
Michael Daumlinged523282013-10-23 07:47:29 +0200717 if (addThis->_document != _document)
718 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700719
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700721
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700723 return 0;
724 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 // The last node or the only node.
728 return InsertEndChild( addThis );
729 }
Michael Daumlinged523282013-10-23 07:47:29 +0200730 if (addThis->_parent)
731 addThis->_parent->Unlink( addThis );
732 else
733 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 addThis->_prev = afterThis;
735 addThis->_next = afterThis->_next;
736 afterThis->_next->_prev = addThis;
737 afterThis->_next = addThis;
738 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800740}
741
742
743
744
Lee Thomason56bdd022012-02-09 18:16:58 -0800745const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800746{
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 XMLElement* element = node->ToElement();
749 if ( element ) {
750 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
751 return element;
752 }
753 }
754 }
755 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800756}
757
758
Lee Thomason56bdd022012-02-09 18:16:58 -0800759const XMLElement* XMLNode::LastChildElement( const char* value ) const
760{
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 XMLElement* element = node->ToElement();
763 if ( element ) {
764 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
765 return element;
766 }
767 }
768 }
769 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800770}
771
772
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800773const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
774{
Lee Thomason624d43f2012-10-12 10:58:48 -0700775 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 if ( element->ToElement()
777 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
778 return element->ToElement();
779 }
780 }
781 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800782}
783
784
785const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
786{
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 if ( element->ToElement()
789 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
790 return element->ToElement();
791 }
792 }
793 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800794}
795
796
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800797char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800798{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 // This is a recursive method, but thinking about it "at the current level"
800 // it is a pretty simple flat list:
801 // <foo/>
802 // <!-- comment -->
803 //
804 // With a special case:
805 // <foo>
806 // </foo>
807 // <!-- comment -->
808 //
809 // Where the closing element (/foo) *must* be the next thing after the opening
810 // element, and the names must match. BUT the tricky bit is that the closing
811 // element will be read by the child.
812 //
813 // 'endTag' is the end tag for this node, it is returned by a call to a child.
814 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800815
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700816 while( p && *p ) {
817 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800818
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 if ( p == 0 || node == 0 ) {
821 break;
822 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800823
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 StrPair endTag;
825 p = node->ParseDeep( p, &endTag );
826 if ( !p ) {
827 DELETE_NODE( node );
828 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700829 if ( !_document->Error() ) {
830 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 }
832 break;
833 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800834
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 // We read the end tag. Return it to the parent.
836 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
837 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700838 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800840 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700841 DELETE_NODE( node );
842 return p;
843 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800844
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700845 // Handle an end tag returned to this level.
846 // And handle a bunch of annoying errors.
847 XMLElement* ele = node->ToElement();
848 if ( ele ) {
849 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 p = 0;
852 }
853 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 p = 0;
856 }
857 else if ( !endTag.Empty() ) {
858 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 p = 0;
861 }
862 }
863 }
864 if ( p == 0 ) {
865 DELETE_NODE( node );
866 node = 0;
867 }
868 if ( node ) {
869 this->InsertEndChild( node );
870 }
871 }
872 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800873}
874
Lee Thomason5492a1c2012-01-23 15:32:10 -0800875// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800876char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800877{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 const char* start = p;
879 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 return p;
885 }
886 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
888 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 flags |= StrPair::COLLAPSE_WHITESPACE;
890 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700891
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 if ( p && *p ) {
897 return p-1;
898 }
899 }
900 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800901}
902
903
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800904XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
905{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700907 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700908 }
909 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
910 text->SetCData( this->CData() );
911 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800912}
913
914
915bool XMLText::ShallowEqual( const XMLNode* compare ) const
916{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800918}
919
920
Lee Thomason56bdd022012-02-09 18:16:58 -0800921bool XMLText::Accept( XMLVisitor* visitor ) const
922{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800924}
925
926
Lee Thomason3f57d272012-01-11 15:30:03 -0800927// --------- XMLComment ---------- //
928
Lee Thomasone4422302012-01-20 17:59:50 -0800929XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800930{
931}
932
933
Lee Thomasonce0763e2012-01-11 15:43:54 -0800934XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800935{
Lee Thomason3f57d272012-01-11 15:30:03 -0800936}
937
938
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800939char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800940{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 // Comment parses as text.
942 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700945 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 }
947 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800948}
949
950
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800951XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700954 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 }
956 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
957 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800958}
959
960
961bool XMLComment::ShallowEqual( const XMLNode* compare ) const
962{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700963 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964}
965
966
Lee Thomason751da522012-02-10 08:50:51 -0800967bool XMLComment::Accept( XMLVisitor* visitor ) const
968{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800970}
Lee Thomason56bdd022012-02-09 18:16:58 -0800971
972
Lee Thomason50f97b22012-02-11 16:33:40 -0800973// --------- XMLDeclaration ---------- //
974
975XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
976{
977}
978
979
980XMLDeclaration::~XMLDeclaration()
981{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800983}
984
985
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800986char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 // Declaration parses as text.
989 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 }
994 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800995}
996
997
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800998XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
999{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001001 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 }
1003 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1004 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001005}
1006
1007
1008bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001011}
1012
1013
1014
Lee Thomason50f97b22012-02-11 16:33:40 -08001015bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1016{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001017 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001018}
1019
1020// --------- XMLUnknown ---------- //
1021
1022XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1023{
1024}
1025
1026
1027XMLUnknown::~XMLUnknown()
1028{
1029}
1030
1031
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001032char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001033{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 // Unknown parses as text.
1035 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001036
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001039 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 }
1041 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001042}
1043
1044
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001045XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1046{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 }
1050 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1051 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001052}
1053
1054
1055bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1056{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001057 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001058}
1059
1060
Lee Thomason50f97b22012-02-11 16:33:40 -08001061bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001064}
1065
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001066// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001067
1068const char* XMLAttribute::Name() const
1069{
1070 return _name.GetStr();
1071}
1072
1073const char* XMLAttribute::Value() const
1074{
1075 return _value.GetStr();
1076}
1077
Lee Thomason6f381b72012-03-02 12:59:39 -08001078char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !p || !*p ) {
1083 return 0;
1084 }
Lee Thomason22aead12012-01-23 13:29:35 -08001085
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 // Skip white space before =
1087 p = XMLUtil::SkipWhiteSpace( p );
1088 if ( !p || *p != '=' ) {
1089 return 0;
1090 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001091
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 ++p; // move up to opening quote
1093 p = XMLUtil::SkipWhiteSpace( p );
1094 if ( *p != '\"' && *p != '\'' ) {
1095 return 0;
1096 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001097
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 char endTag[2] = { *p, 0 };
1099 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001100
Lee Thomason624d43f2012-10-12 10:58:48 -07001101 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001103}
1104
1105
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001106void XMLAttribute::SetName( const char* n )
1107{
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001109}
1110
1111
Lee Thomason2fa81722012-11-09 12:37:46 -08001112XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 if ( XMLUtil::ToInt( Value(), value )) {
1115 return XML_NO_ERROR;
1116 }
1117 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001118}
1119
1120
Lee Thomason2fa81722012-11-09 12:37:46 -08001121XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 if ( XMLUtil::ToUnsigned( Value(), value )) {
1124 return XML_NO_ERROR;
1125 }
1126 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001127}
1128
1129
Lee Thomason2fa81722012-11-09 12:37:46 -08001130XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 if ( XMLUtil::ToBool( Value(), value )) {
1133 return XML_NO_ERROR;
1134 }
1135 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001136}
1137
1138
Lee Thomason2fa81722012-11-09 12:37:46 -08001139XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( XMLUtil::ToFloat( Value(), value )) {
1142 return XML_NO_ERROR;
1143 }
1144 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001145}
1146
1147
Lee Thomason2fa81722012-11-09 12:37:46 -08001148XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( XMLUtil::ToDouble( Value(), value )) {
1151 return XML_NO_ERROR;
1152 }
1153 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001154}
1155
1156
1157void XMLAttribute::SetAttribute( const char* v )
1158{
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160}
1161
1162
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163void XMLAttribute::SetAttribute( int v )
1164{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 char buf[BUF_SIZE];
1166 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001168}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001169
1170
1171void XMLAttribute::SetAttribute( unsigned v )
1172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 char buf[BUF_SIZE];
1174 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001176}
1177
1178
1179void XMLAttribute::SetAttribute( bool v )
1180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 char buf[BUF_SIZE];
1182 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001183 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001184}
1185
1186void XMLAttribute::SetAttribute( double v )
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 char buf[BUF_SIZE];
1189 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191}
1192
1193void XMLAttribute::SetAttribute( float v )
1194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 char buf[BUF_SIZE];
1196 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001197 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001198}
1199
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001200
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001201// --------- XMLElement ---------- //
1202XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 _closingType( 0 ),
1204 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001205{
1206}
1207
1208
1209XMLElement::~XMLElement()
1210{
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 while( _rootAttribute ) {
1212 XMLAttribute* next = _rootAttribute->_next;
1213 DELETE_ATTRIBUTE( _rootAttribute );
1214 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001216}
1217
1218
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001219XMLAttribute* XMLElement::FindAttribute( const char* name )
1220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001222 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1224 return a;
1225 }
1226 }
1227 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001228}
1229
1230
1231const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1232{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001234 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1236 return a;
1237 }
1238 }
1239 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001240}
1241
1242
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001243const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 const XMLAttribute* a = FindAttribute( name );
1246 if ( !a ) {
1247 return 0;
1248 }
1249 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1250 return a->Value();
1251 }
1252 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001253}
1254
1255
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001256const char* XMLElement::GetText() const
1257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 if ( FirstChild() && FirstChild()->ToText() ) {
1259 return FirstChild()->ToText()->Value();
1260 }
1261 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001262}
1263
1264
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001265void XMLElement::SetText( const char* inText )
1266{
Uli Kusterer869bb592014-01-21 01:36:16 +01001267 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001268 FirstChild()->SetValue( inText );
1269 else {
1270 XMLText* theText = GetDocument()->NewText( inText );
1271 InsertFirstChild( theText );
1272 }
1273}
1274
Lee Thomason5bb2d802014-01-24 10:42:57 -08001275
1276void XMLElement::SetText( int v )
1277{
1278 char buf[BUF_SIZE];
1279 XMLUtil::ToStr( v, buf, BUF_SIZE );
1280 SetText( buf );
1281}
1282
1283
1284void XMLElement::SetText( unsigned v )
1285{
1286 char buf[BUF_SIZE];
1287 XMLUtil::ToStr( v, buf, BUF_SIZE );
1288 SetText( buf );
1289}
1290
1291
1292void XMLElement::SetText( bool v )
1293{
1294 char buf[BUF_SIZE];
1295 XMLUtil::ToStr( v, buf, BUF_SIZE );
1296 SetText( buf );
1297}
1298
1299
1300void XMLElement::SetText( float v )
1301{
1302 char buf[BUF_SIZE];
1303 XMLUtil::ToStr( v, buf, BUF_SIZE );
1304 SetText( buf );
1305}
1306
1307
1308void XMLElement::SetText( double v )
1309{
1310 char buf[BUF_SIZE];
1311 XMLUtil::ToStr( v, buf, BUF_SIZE );
1312 SetText( buf );
1313}
1314
1315
MortenMacFly4ee49f12013-01-14 20:03:14 +01001316XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001317{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001318 if ( FirstChild() && FirstChild()->ToText() ) {
1319 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001320 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001321 return XML_SUCCESS;
1322 }
1323 return XML_CAN_NOT_CONVERT_TEXT;
1324 }
1325 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001326}
1327
1328
MortenMacFly4ee49f12013-01-14 20:03:14 +01001329XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001330{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001331 if ( FirstChild() && FirstChild()->ToText() ) {
1332 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001333 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001334 return XML_SUCCESS;
1335 }
1336 return XML_CAN_NOT_CONVERT_TEXT;
1337 }
1338 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001339}
1340
1341
MortenMacFly4ee49f12013-01-14 20:03:14 +01001342XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001343{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001344 if ( FirstChild() && FirstChild()->ToText() ) {
1345 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001346 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001347 return XML_SUCCESS;
1348 }
1349 return XML_CAN_NOT_CONVERT_TEXT;
1350 }
1351 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001352}
1353
1354
MortenMacFly4ee49f12013-01-14 20:03:14 +01001355XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001356{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 if ( FirstChild() && FirstChild()->ToText() ) {
1358 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001359 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001360 return XML_SUCCESS;
1361 }
1362 return XML_CAN_NOT_CONVERT_TEXT;
1363 }
1364 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001365}
1366
1367
MortenMacFly4ee49f12013-01-14 20:03:14 +01001368XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001369{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 if ( FirstChild() && FirstChild()->ToText() ) {
1371 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001372 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001373 return XML_SUCCESS;
1374 }
1375 return XML_CAN_NOT_CONVERT_TEXT;
1376 }
1377 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001378}
1379
1380
1381
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001382XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 XMLAttribute* last = 0;
1385 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001386 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001388 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1390 break;
1391 }
1392 }
1393 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001394 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1395 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001397 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001398 }
1399 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001400 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001401 }
1402 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001403 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 }
1405 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001406}
1407
1408
U-Stream\Leeae25a442012-02-17 17:48:16 -08001409void XMLElement::DeleteAttribute( const char* name )
1410{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001411 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001412 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1414 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001415 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001416 }
1417 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001418 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001419 }
1420 DELETE_ATTRIBUTE( a );
1421 break;
1422 }
1423 prev = a;
1424 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001425}
1426
1427
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001428char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001429{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 const char* start = p;
1431 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001432
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001433 // Read the attributes.
1434 while( p ) {
1435 p = XMLUtil::SkipWhiteSpace( p );
1436 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001437 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 return 0;
1439 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001440
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001442 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001443 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1444 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001445 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001446
Lee Thomason624d43f2012-10-12 10:58:48 -07001447 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001448 if ( !p || Attribute( attrib->Name() ) ) {
1449 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001450 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001451 return 0;
1452 }
1453 // There is a minor bug here: if the attribute in the source xml
1454 // document is duplicated, it will not be detected and the
1455 // attribute will be doubly added. However, tracking the 'prevAttribute'
1456 // avoids re-scanning the attribute list. Preferring performance for
1457 // now, may reconsider in the future.
1458 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
1461 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001462 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001463 }
1464 prevAttribute = attrib;
1465 }
1466 // end of the tag
1467 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001468 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 return p+2; // done; sealed element.
1470 }
1471 // end of the tag
1472 else if ( *p == '>' ) {
1473 ++p;
1474 break;
1475 }
1476 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 return 0;
1479 }
1480 }
1481 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001482}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001483
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001484
Lee Thomason67d61312012-01-24 16:01:51 -08001485//
1486// <ele></ele>
1487// <ele>foo<b>bar</b></ele>
1488//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001489char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001490{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001491 // Read the element name.
1492 p = XMLUtil::SkipWhiteSpace( p );
1493 if ( !p ) {
1494 return 0;
1495 }
Lee Thomason67d61312012-01-24 16:01:51 -08001496
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 // The closing element is the </element> form. It is
1498 // parsed just like a regular element then deleted from
1499 // the DOM.
1500 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 ++p;
1503 }
Lee Thomason67d61312012-01-24 16:01:51 -08001504
Lee Thomason624d43f2012-10-12 10:58:48 -07001505 p = _value.ParseName( p );
1506 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001507 return 0;
1508 }
Lee Thomason67d61312012-01-24 16:01:51 -08001509
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001510 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 return p;
1513 }
Lee Thomason67d61312012-01-24 16:01:51 -08001514
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001515 p = XMLNode::ParseDeep( p, strPair );
1516 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001517}
1518
1519
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001520
1521XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1522{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001524 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 }
1526 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1527 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1528 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1529 }
1530 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001531}
1532
1533
1534bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 const XMLElement* other = compare->ToElement();
1537 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001538
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001539 const XMLAttribute* a=FirstAttribute();
1540 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001541
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 while ( a && b ) {
1543 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1544 return false;
1545 }
1546 a = a->Next();
1547 b = b->Next();
1548 }
1549 if ( a || b ) {
1550 // different count
1551 return false;
1552 }
1553 return true;
1554 }
1555 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001556}
1557
1558
Lee Thomason751da522012-02-10 08:50:51 -08001559bool XMLElement::Accept( XMLVisitor* visitor ) const
1560{
Lee Thomason624d43f2012-10-12 10:58:48 -07001561 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001562 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1563 if ( !node->Accept( visitor ) ) {
1564 break;
1565 }
1566 }
1567 }
1568 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001569}
Lee Thomason56bdd022012-02-09 18:16:58 -08001570
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001571
Lee Thomason3f57d272012-01-11 15:30:03 -08001572// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001573XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001575 _writeBOM( false ),
1576 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001577 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001578 _whitespace( whitespace ),
1579 _errorStr1( 0 ),
1580 _errorStr2( 0 ),
1581 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001582{
Lee Thomason624d43f2012-10-12 10:58:48 -07001583 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001584}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001585
1586
Lee Thomason3f57d272012-01-11 15:30:03 -08001587XMLDocument::~XMLDocument()
1588{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001589 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001590 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001591
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001592#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001593 _textPool.Trace( "text" );
1594 _elementPool.Trace( "element" );
1595 _commentPool.Trace( "comment" );
1596 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001597#endif
1598
Lee Thomason5b0a6772012-11-19 13:54:42 -08001599#ifdef DEBUG
1600 if ( Error() == false ) {
1601 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1602 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1603 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1604 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1605 }
1606#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001607}
1608
1609
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001610void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001611{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001612 DeleteChildren();
1613
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 _errorID = XML_NO_ERROR;
1615 _errorStr1 = 0;
1616 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001617
Lee Thomason624d43f2012-10-12 10:58:48 -07001618 delete [] _charBuffer;
1619 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001620}
1621
Lee Thomason3f57d272012-01-11 15:30:03 -08001622
Lee Thomason2c85a712012-01-31 08:24:24 -08001623XMLElement* XMLDocument::NewElement( const char* name )
1624{
Lee Thomason624d43f2012-10-12 10:58:48 -07001625 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1626 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001627 ele->SetName( name );
1628 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001629}
1630
1631
Lee Thomason1ff38e02012-02-14 18:18:16 -08001632XMLComment* XMLDocument::NewComment( const char* str )
1633{
Lee Thomason624d43f2012-10-12 10:58:48 -07001634 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1635 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001636 comment->SetValue( str );
1637 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001638}
1639
1640
1641XMLText* XMLDocument::NewText( const char* str )
1642{
Lee Thomason624d43f2012-10-12 10:58:48 -07001643 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1644 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001645 text->SetValue( str );
1646 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001647}
1648
1649
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001650XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1651{
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1653 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001654 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1655 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001656}
1657
1658
1659XMLUnknown* XMLDocument::NewUnknown( const char* str )
1660{
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1662 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 unk->SetValue( str );
1664 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001665}
1666
Dmitry-Me01578db2014-08-19 10:18:48 +04001667static FILE* callfopen( const char* filepath, const char* mode )
1668{
1669#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1670 FILE* fp = 0;
1671 errno_t err = fopen_s( &fp, filepath, mode );
1672 if ( err ) {
1673 return 0;
1674 }
1675#else
1676 FILE* fp = fopen( filepath, mode );
1677#endif
1678 return fp;
1679}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001680
Lee Thomason2fa81722012-11-09 12:37:46 -08001681XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001682{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001683 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001684 FILE* fp = callfopen( filename, "rb" );
1685 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001686 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001687 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 }
1689 LoadFile( fp );
1690 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001691 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001692}
1693
1694
Lee Thomason2fa81722012-11-09 12:37:46 -08001695XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001696{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001697 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001698
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001699 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001700 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001701 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1702 return _errorID;
1703 }
1704
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001706 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001708 if ( filelength == -1L ) {
1709 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1710 return _errorID;
1711 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001712
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001713 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001714 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001715 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001716 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001717 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001718
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 _charBuffer = new char[size+1];
1720 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001721 if ( read != size ) {
1722 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001723 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001724 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001725
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001727
Lee Thomason624d43f2012-10-12 10:58:48 -07001728 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001731 if ( !p || !*p ) {
1732 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001733 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001735
Lee Thomason624d43f2012-10-12 10:58:48 -07001736 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1737 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001738}
1739
1740
Lee Thomason2fa81722012-11-09 12:37:46 -08001741XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001742{
Dmitry-Me01578db2014-08-19 10:18:48 +04001743 FILE* fp = callfopen( filename, "w" );
1744 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001746 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 }
1748 SaveFile(fp, compact);
1749 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001751}
1752
1753
Lee Thomason2fa81722012-11-09 12:37:46 -08001754XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001755{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 XMLPrinter stream( fp, compact );
1757 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001758 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001759}
1760
Lee Thomason1ff38e02012-02-14 18:18:16 -08001761
Lee Thomason2fa81722012-11-09 12:37:46 -08001762XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001763{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001764 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001765 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001766
Lee Thomason82d32002014-02-21 22:47:18 -08001767 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001768 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001769 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001770 }
1771 if ( len == (size_t)(-1) ) {
1772 len = strlen( p );
1773 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001774 _charBuffer = new char[ len+1 ];
1775 memcpy( _charBuffer, p, len );
1776 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001777
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001780 if ( !p || !*p ) {
1781 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001783 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001784
Thomas Roß1470edc2013-05-10 15:44:12 +02001785 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001786 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001788}
1789
1790
PKEuS1c5f99e2013-07-06 11:28:39 +02001791void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001792{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 XMLPrinter stdStreamer( stdout );
1794 if ( !streamer ) {
1795 streamer = &stdStreamer;
1796 }
1797 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001798}
1799
1800
Lee Thomason2fa81722012-11-09 12:37:46 -08001801void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001802{
Lee Thomason624d43f2012-10-12 10:58:48 -07001803 _errorID = error;
1804 _errorStr1 = str1;
1805 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001806}
1807
Lee Thomason5cae8972012-01-24 18:03:07 -08001808
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001809void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001810{
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 static const int LEN = 20;
1813 char buf1[LEN] = { 0 };
1814 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001815
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 if ( _errorStr1 ) {
1817 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 if ( _errorStr2 ) {
1820 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001821 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001822
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001823 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001825 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001826}
1827
1828
PKEuS1bfb9542013-08-04 13:51:17 +02001829XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001830 _elementJustOpened( false ),
1831 _firstElement( true ),
1832 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001833 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 _textDepth( -1 ),
1835 _processEntities( true ),
1836 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001837{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001838 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001839 _entityFlag[i] = false;
1840 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001841 }
1842 for( int i=0; i<NUM_ENTITIES; ++i ) {
1843 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1844 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001845 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001846 }
1847 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 _restrictedEntityFlag[(int)'&'] = true;
1849 _restrictedEntityFlag[(int)'<'] = true;
1850 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1851 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001852}
1853
1854
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001855void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001856{
1857 va_list va;
1858 va_start( va, format );
1859
Lee Thomason624d43f2012-10-12 10:58:48 -07001860 if ( _fp ) {
1861 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 }
1863 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001864#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001865 #if defined(WINCE)
1866 int len = 512;
1867 do {
1868 len = len*2;
1869 char* str = new char[len]();
1870 len = _vsnprintf(str, len, format, va);
1871 delete[] str;
1872 }while (len < 0);
1873 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001874 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001875 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876#else
1877 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001878#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001879 // Close out and re-start the va-args
1880 va_end( va );
1881 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001882 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1883#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001884 #if defined(WINCE)
1885 _vsnprintf( p, len+1, format, va );
1886 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001887 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001888 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001889#else
1890 vsnprintf( p, len+1, format, va );
1891#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001893 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001894}
1895
1896
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001897void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001898{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 for( int i=0; i<depth; ++i ) {
1900 Print( " " );
1901 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001902}
1903
1904
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001905void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001906{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001907 // Look for runs of bytes between entities to print.
1908 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001909 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001910
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001912 while ( *q ) {
1913 // Remember, char is sometimes signed. (How many times has that bitten me?)
1914 if ( *q > 0 && *q < ENTITY_RANGE ) {
1915 // Check for entities. If one is found, flush
1916 // the stream up until the entity, write the
1917 // entity, and keep looking.
1918 if ( flag[(unsigned)(*q)] ) {
1919 while ( p < q ) {
1920 Print( "%c", *p );
1921 ++p;
1922 }
1923 for( int i=0; i<NUM_ENTITIES; ++i ) {
1924 if ( entities[i].value == *q ) {
1925 Print( "&%s;", entities[i].pattern );
1926 break;
1927 }
1928 }
1929 ++p;
1930 }
1931 }
1932 ++q;
1933 }
1934 }
1935 // Flush the remaining string. This will be the entire
1936 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001937 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 Print( "%s", p );
1939 }
Lee Thomason857b8682012-01-25 17:50:25 -08001940}
1941
U-Stream\Leeae25a442012-02-17 17:48:16 -08001942
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001943void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001944{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001945 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001946 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 Print( "%s", bom );
1948 }
1949 if ( writeDec ) {
1950 PushDeclaration( "xml version=\"1.0\"" );
1951 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001952}
1953
1954
Uli Kusterer593a33d2014-02-01 12:48:51 +01001955void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001956{
Lee Thomason624d43f2012-10-12 10:58:48 -07001957 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001958 SealElement();
1959 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001960 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001961
Uli Kusterer593a33d2014-02-01 12:48:51 +01001962 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001963 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001964 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01001965 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001968
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001970 _elementJustOpened = true;
1971 _firstElement = false;
1972 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08001973}
1974
1975
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001976void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08001977{
Lee Thomason624d43f2012-10-12 10:58:48 -07001978 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001979 Print( " %s=\"", name );
1980 PrintString( value, false );
1981 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08001982}
1983
1984
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001985void XMLPrinter::PushAttribute( const char* name, int v )
1986{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 char buf[BUF_SIZE];
1988 XMLUtil::ToStr( v, buf, BUF_SIZE );
1989 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001990}
1991
1992
1993void XMLPrinter::PushAttribute( const char* name, unsigned v )
1994{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001995 char buf[BUF_SIZE];
1996 XMLUtil::ToStr( v, buf, BUF_SIZE );
1997 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001998}
1999
2000
2001void XMLPrinter::PushAttribute( const char* name, bool v )
2002{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 char buf[BUF_SIZE];
2004 XMLUtil::ToStr( v, buf, BUF_SIZE );
2005 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002006}
2007
2008
2009void XMLPrinter::PushAttribute( const char* name, double v )
2010{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 char buf[BUF_SIZE];
2012 XMLUtil::ToStr( v, buf, BUF_SIZE );
2013 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002014}
2015
2016
Uli Kustererca412e82014-02-01 13:35:05 +01002017void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002018{
Lee Thomason624d43f2012-10-12 10:58:48 -07002019 --_depth;
2020 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002021
Lee Thomason624d43f2012-10-12 10:58:48 -07002022 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002023 Print( "/>" );
2024 }
2025 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002026 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002028 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002029 }
2030 Print( "</%s>", name );
2031 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002032
Lee Thomason624d43f2012-10-12 10:58:48 -07002033 if ( _textDepth == _depth ) {
2034 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 }
Uli Kustererca412e82014-02-01 13:35:05 +01002036 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002037 Print( "\n" );
2038 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002039 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002040}
2041
2042
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002043void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002044{
Lee Thomason624d43f2012-10-12 10:58:48 -07002045 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002046 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002047}
2048
2049
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002050void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002051{
Lee Thomason624d43f2012-10-12 10:58:48 -07002052 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002053
Lee Thomason624d43f2012-10-12 10:58:48 -07002054 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002055 SealElement();
2056 }
2057 if ( cdata ) {
2058 Print( "<![CDATA[" );
2059 Print( "%s", text );
2060 Print( "]]>" );
2061 }
2062 else {
2063 PrintString( text, true );
2064 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002065}
2066
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002067void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002068{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 char buf[BUF_SIZE];
2070 XMLUtil::ToStr( value, buf, BUF_SIZE );
2071 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002072}
2073
2074
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002075void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002076{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 char buf[BUF_SIZE];
2078 XMLUtil::ToStr( value, buf, BUF_SIZE );
2079 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002080}
2081
2082
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002083void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002084{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002085 char buf[BUF_SIZE];
2086 XMLUtil::ToStr( value, buf, BUF_SIZE );
2087 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002088}
2089
2090
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002091void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002092{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002093 char buf[BUF_SIZE];
2094 XMLUtil::ToStr( value, buf, BUF_SIZE );
2095 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002096}
2097
2098
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002099void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002100{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002101 char buf[BUF_SIZE];
2102 XMLUtil::ToStr( value, buf, BUF_SIZE );
2103 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002104}
2105
Lee Thomason5cae8972012-01-24 18:03:07 -08002106
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002107void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002108{
Lee Thomason624d43f2012-10-12 10:58:48 -07002109 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002110 SealElement();
2111 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002112 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002113 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002114 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002116 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002118}
Lee Thomason751da522012-02-10 08:50:51 -08002119
2120
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002121void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002122{
Lee Thomason624d43f2012-10-12 10:58:48 -07002123 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 SealElement();
2125 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002127 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002128 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002129 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002130 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002132}
2133
2134
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002135void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002136{
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002138 SealElement();
2139 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002142 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002143 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002144 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002145 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002146}
2147
2148
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002149bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002150{
Lee Thomason624d43f2012-10-12 10:58:48 -07002151 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002152 if ( doc.HasBOM() ) {
2153 PushHeader( true, false );
2154 }
2155 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002156}
2157
2158
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002159bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002160{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002161 const XMLElement* parentElem = element.Parent()->ToElement();
2162 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2163 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 while ( attribute ) {
2165 PushAttribute( attribute->Name(), attribute->Value() );
2166 attribute = attribute->Next();
2167 }
2168 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002169}
2170
2171
Uli Kustererca412e82014-02-01 13:35:05 +01002172bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002173{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002174 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002175 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002176}
2177
2178
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002179bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 PushText( text.Value(), text.CData() );
2182 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002183}
2184
2185
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002186bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002188 PushComment( comment.Value() );
2189 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002190}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002191
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002192bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002194 PushDeclaration( declaration.Value() );
2195 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002196}
2197
2198
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002199bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 PushUnknown( unknown.Value() );
2202 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002203}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002204
Lee Thomason685b8952012-11-12 13:00:06 -08002205} // namespace tinyxml2
2206