blob: 58a0e4f6c7fe31f2da2781e2f278ab21baccf532 [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{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700153 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700154 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700155
Lee Thomason120b3a62012-10-12 10:06:59 -0700156 if ( _start && *_start ) {
157 char* p = _start; // the read pointer
158 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700159
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700160 while( *p ) {
161 if ( XMLUtil::IsWhiteSpace( *p )) {
162 p = XMLUtil::SkipWhiteSpace( p );
163 if ( *p == 0 ) {
164 break; // don't write to q; this trims the trailing space.
165 }
166 *q = ' ';
167 ++q;
168 }
169 *q = *p;
170 ++q;
171 ++p;
172 }
173 *q = 0;
174 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700175}
176
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800177
Lee Thomasone4422302012-01-20 17:59:50 -0800178const char* StrPair::GetStr()
179{
Lee Thomason120b3a62012-10-12 10:06:59 -0700180 if ( _flags & NEEDS_FLUSH ) {
181 *_end = 0;
182 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800183
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 if ( _flags ) {
185 char* p = _start; // the read pointer
186 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800187
Lee Thomason120b3a62012-10-12 10:06:59 -0700188 while( p < _end ) {
189 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700190 // CR-LF pair becomes LF
191 // CR alone becomes LF
192 // LF-CR becomes LF
193 if ( *(p+1) == LF ) {
194 p += 2;
195 }
196 else {
197 ++p;
198 }
199 *q++ = LF;
200 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700201 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == CR ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 // Entities handled by tinyXML2:
212 // - special entities in the entity table [in/out]
213 // - numeric character reference [in]
214 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800215
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 if ( *(p+1) == '#' ) {
217 char buf[10] = { 0 };
218 int len;
219 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
220 for( int i=0; i<len; ++i ) {
221 *q++ = buf[i];
222 }
223 TIXMLASSERT( q <= p );
224 }
225 else {
226 int i=0;
227 for(; i<NUM_ENTITIES; ++i ) {
228 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
229 && *(p+entities[i].length+1) == ';' ) {
230 // Found an entity convert;
231 *q = entities[i].value;
232 ++q;
233 p += entities[i].length + 2;
234 break;
235 }
236 }
237 if ( i == NUM_ENTITIES ) {
238 // fixme: treat as error?
239 ++p;
240 ++q;
241 }
242 }
243 }
244 else {
245 *q = *p;
246 ++p;
247 ++q;
248 }
249 }
250 *q = 0;
251 }
252 // The loop below has plenty going on, and this
253 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700254 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 CollapseWhitespace();
256 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700257 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700258 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800260}
261
Lee Thomason2c85a712012-01-31 08:24:24 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800264
Lee Thomason56bdd022012-02-09 18:16:58 -0800265// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800266
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800267const char* XMLUtil::ReadBOM( const char* p, bool* bom )
268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 *bom = false;
270 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
271 // Check for BOM:
272 if ( *(pu+0) == TIXML_UTF_LEAD_0
273 && *(pu+1) == TIXML_UTF_LEAD_1
274 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
275 *bom = true;
276 p += 3;
277 }
278 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800279}
280
281
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800282void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700284 const unsigned long BYTE_MASK = 0xBF;
285 const unsigned long BYTE_MARK = 0x80;
286 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800287
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 if (input < 0x80) {
289 *length = 1;
290 }
291 else if ( input < 0x800 ) {
292 *length = 2;
293 }
294 else if ( input < 0x10000 ) {
295 *length = 3;
296 }
297 else if ( input < 0x200000 ) {
298 *length = 4;
299 }
300 else {
301 *length = 0; // This code won't covert this correctly anyway.
302 return;
303 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800306
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700307 // Scary scary fall throughs.
308 switch (*length) {
309 case 4:
310 --output;
311 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
312 input >>= 6;
313 case 3:
314 --output;
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
316 input >>= 6;
317 case 2:
318 --output;
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
320 input >>= 6;
321 case 1:
322 --output;
323 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100324 default:
325 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800327}
328
329
330const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Presume an entity, and pull it out.
333 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800334
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 if ( *(p+1) == '#' && *(p+2) ) {
336 unsigned long ucs = 0;
337 ptrdiff_t delta = 0;
338 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 if ( *(p+2) == 'x' ) {
341 // Hexadecimal.
342 if ( !*(p+3) ) {
343 return 0;
344 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 const char* q = p+3;
347 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 if ( !q || !*q ) {
350 return 0;
351 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 delta = q-p;
354 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 while ( *q != 'x' ) {
357 if ( *q >= '0' && *q <= '9' ) {
358 ucs += mult * (*q - '0');
359 }
360 else if ( *q >= 'a' && *q <= 'f' ) {
361 ucs += mult * (*q - 'a' + 10);
362 }
363 else if ( *q >= 'A' && *q <= 'F' ) {
364 ucs += mult * (*q - 'A' + 10 );
365 }
366 else {
367 return 0;
368 }
369 mult *= 16;
370 --q;
371 }
372 }
373 else {
374 // Decimal.
375 if ( !*(p+2) ) {
376 return 0;
377 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800378
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 const char* q = p+2;
380 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 if ( !q || !*q ) {
383 return 0;
384 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 delta = q-p;
387 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 while ( *q != '#' ) {
390 if ( *q >= '0' && *q <= '9' ) {
391 ucs += mult * (*q - '0');
392 }
393 else {
394 return 0;
395 }
396 mult *= 10;
397 --q;
398 }
399 }
400 // convert the UCS to UTF-8
401 ConvertUTF32ToUTF8( ucs, value, length );
402 return p + delta + 1;
403 }
404 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800406
407
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700408void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700410 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700411}
412
413
414void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700416 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700417}
418
419
420void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700423}
424
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800425/*
426 ToStr() of a number is a very tricky topic.
427 https://github.com/leethomason/tinyxml2/issues/106
428*/
Lee Thomason21be8822012-07-15 17:27:22 -0700429void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
430{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800431 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700432}
433
434
435void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
436{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800437 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700438}
439
440
441bool XMLUtil::ToInt( const char* str, int* value )
442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
444 return true;
445 }
446 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700447}
448
Uli Kusterer664d0562014-01-21 12:24:47 +0100449
Lee Thomason21be8822012-07-15 17:27:22 -0700450bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
453 return true;
454 }
455 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700456}
457
458bool XMLUtil::ToBool( const char* str, bool* value )
459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 int ival = 0;
461 if ( ToInt( str, &ival )) {
462 *value = (ival==0) ? false : true;
463 return true;
464 }
465 if ( StringEqual( str, "true" ) ) {
466 *value = true;
467 return true;
468 }
469 else if ( StringEqual( str, "false" ) ) {
470 *value = false;
471 return true;
472 }
473 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700474}
475
476
477bool XMLUtil::ToFloat( const char* str, float* value )
478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700479 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
480 return true;
481 }
482 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700483}
484
485bool XMLUtil::ToDouble( const char* str, double* value )
486{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
488 return true;
489 }
490 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700491}
492
493
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700494char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800495{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 XMLNode* returnNode = 0;
497 char* start = p;
498 p = XMLUtil::SkipWhiteSpace( p );
499 if( !p || !*p ) {
500 return p;
501 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800502
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800504 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700505 static const char* xmlHeader = { "<?" };
506 static const char* commentHeader = { "<!--" };
507 static const char* dtdHeader = { "<!" };
508 static const char* cdataHeader = { "<![CDATA[" };
509 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800510
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700511 static const int xmlHeaderLen = 2;
512 static const int commentHeaderLen = 4;
513 static const int dtdHeaderLen = 2;
514 static const int cdataHeaderLen = 9;
515 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800516
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800517#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800518#pragma warning ( push )
519#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800520#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
522 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800523#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800524#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800525#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700527 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
528 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 p += xmlHeaderLen;
530 }
531 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700532 returnNode = new (_commentPool.Alloc()) XMLComment( this );
533 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 p += commentHeaderLen;
535 }
536 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700539 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 p += cdataHeaderLen;
541 text->SetCData( true );
542 }
543 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700544 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
545 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 p += dtdHeaderLen;
547 }
548 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 returnNode = new (_elementPool.Alloc()) XMLElement( this );
550 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 p += elementHeaderLen;
552 }
553 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode = new (_textPool.Alloc()) XMLText( this );
555 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p = start; // Back it up, all the text counts.
557 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800558
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 *node = returnNode;
560 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800561}
562
563
Lee Thomason751da522012-02-10 08:50:51 -0800564bool XMLDocument::Accept( XMLVisitor* visitor ) const
565{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 if ( visitor->VisitEnter( *this ) ) {
567 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
568 if ( !node->Accept( visitor ) ) {
569 break;
570 }
571 }
572 }
573 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800574}
Lee Thomason56bdd022012-02-09 18:16:58 -0800575
576
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800577// --------- XMLNode ----------- //
578
579XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700580 _document( doc ),
581 _parent( 0 ),
582 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200583 _prev( 0 ), _next( 0 ),
584 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800585{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800586}
587
588
589XMLNode::~XMLNode()
590{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700591 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700592 if ( _parent ) {
593 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700594 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800595}
596
Michael Daumling21626882013-10-22 17:03:37 +0200597const char* XMLNode::Value() const
598{
599 return _value.GetStr();
600}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800601
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800602void XMLNode::SetValue( const char* str, bool staticMem )
603{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700604 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700605 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700606 }
607 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700608 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700609 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800610}
611
612
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800613void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800614{
Lee Thomason624d43f2012-10-12 10:58:48 -0700615 while( _firstChild ) {
616 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700617 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700618
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700619 DELETE_NODE( node );
620 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800622}
623
624
625void XMLNode::Unlink( XMLNode* child )
626{
Lee Thomason624d43f2012-10-12 10:58:48 -0700627 if ( child == _firstChild ) {
628 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700629 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700630 if ( child == _lastChild ) {
631 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700632 }
Lee Thomasond923c672012-01-23 08:44:25 -0800633
Lee Thomason624d43f2012-10-12 10:58:48 -0700634 if ( child->_prev ) {
635 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700636 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700637 if ( child->_next ) {
638 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700639 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700640 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800641}
642
643
U-Stream\Leeae25a442012-02-17 17:48:16 -0800644void XMLNode::DeleteChild( XMLNode* node )
645{
Lee Thomason624d43f2012-10-12 10:58:48 -0700646 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800648}
649
650
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800651XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
652{
Michael Daumlinged523282013-10-23 07:47:29 +0200653 if (addThis->_document != _document)
654 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700655
Michael Daumlinged523282013-10-23 07:47:29 +0200656 if (addThis->_parent)
657 addThis->_parent->Unlink( addThis );
658 else
659 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700660
Lee Thomason624d43f2012-10-12 10:58:48 -0700661 if ( _lastChild ) {
662 TIXMLASSERT( _firstChild );
663 TIXMLASSERT( _lastChild->_next == 0 );
664 _lastChild->_next = addThis;
665 addThis->_prev = _lastChild;
666 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800667
Lee Thomason624d43f2012-10-12 10:58:48 -0700668 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700669 }
670 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700671 TIXMLASSERT( _firstChild == 0 );
672 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800673
Lee Thomason624d43f2012-10-12 10:58:48 -0700674 addThis->_prev = 0;
675 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700676 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700677 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700678 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800679}
680
681
Lee Thomason1ff38e02012-02-14 18:18:16 -0800682XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
683{
Michael Daumlinged523282013-10-23 07:47:29 +0200684 if (addThis->_document != _document)
685 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700686
Michael Daumlinged523282013-10-23 07:47:29 +0200687 if (addThis->_parent)
688 addThis->_parent->Unlink( addThis );
689 else
690 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700691
Lee Thomason624d43f2012-10-12 10:58:48 -0700692 if ( _firstChild ) {
693 TIXMLASSERT( _lastChild );
694 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800695
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 _firstChild->_prev = addThis;
697 addThis->_next = _firstChild;
698 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800699
Lee Thomason624d43f2012-10-12 10:58:48 -0700700 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700701 }
702 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700703 TIXMLASSERT( _lastChild == 0 );
704 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800705
Lee Thomason624d43f2012-10-12 10:58:48 -0700706 addThis->_prev = 0;
707 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700708 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700709 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200710 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800711}
712
713
714XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
715{
Michael Daumlinged523282013-10-23 07:47:29 +0200716 if (addThis->_document != _document)
717 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700718
Lee Thomason624d43f2012-10-12 10:58:48 -0700719 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700722 return 0;
723 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 // The last node or the only node.
727 return InsertEndChild( addThis );
728 }
Michael Daumlinged523282013-10-23 07:47:29 +0200729 if (addThis->_parent)
730 addThis->_parent->Unlink( addThis );
731 else
732 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700733 addThis->_prev = afterThis;
734 addThis->_next = afterThis->_next;
735 afterThis->_next->_prev = addThis;
736 afterThis->_next = addThis;
737 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700738 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800739}
740
741
742
743
Lee Thomason56bdd022012-02-09 18:16:58 -0800744const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800745{
Lee Thomason624d43f2012-10-12 10:58:48 -0700746 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700747 XMLElement* element = node->ToElement();
748 if ( element ) {
749 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
750 return element;
751 }
752 }
753 }
754 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800755}
756
757
Lee Thomason56bdd022012-02-09 18:16:58 -0800758const XMLElement* XMLNode::LastChildElement( const char* value ) const
759{
Lee Thomason624d43f2012-10-12 10:58:48 -0700760 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700761 XMLElement* element = node->ToElement();
762 if ( element ) {
763 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
764 return element;
765 }
766 }
767 }
768 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800769}
770
771
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800772const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
773{
Lee Thomason624d43f2012-10-12 10:58:48 -0700774 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700775 if ( element->ToElement()
776 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
777 return element->ToElement();
778 }
779 }
780 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800781}
782
783
784const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
785{
Lee Thomason624d43f2012-10-12 10:58:48 -0700786 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700787 if ( element->ToElement()
788 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
789 return element->ToElement();
790 }
791 }
792 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800793}
794
795
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800796char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800797{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700798 // This is a recursive method, but thinking about it "at the current level"
799 // it is a pretty simple flat list:
800 // <foo/>
801 // <!-- comment -->
802 //
803 // With a special case:
804 // <foo>
805 // </foo>
806 // <!-- comment -->
807 //
808 // Where the closing element (/foo) *must* be the next thing after the opening
809 // element, and the names must match. BUT the tricky bit is that the closing
810 // element will be read by the child.
811 //
812 // 'endTag' is the end tag for this node, it is returned by a call to a child.
813 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800814
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700815 while( p && *p ) {
816 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800817
Lee Thomason624d43f2012-10-12 10:58:48 -0700818 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700819 if ( p == 0 || node == 0 ) {
820 break;
821 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800822
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700823 StrPair endTag;
824 p = node->ParseDeep( p, &endTag );
825 if ( !p ) {
826 DELETE_NODE( node );
827 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700828 if ( !_document->Error() ) {
829 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700830 }
831 break;
832 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800833
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700834 // We read the end tag. Return it to the parent.
835 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
836 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700837 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700838 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800839 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700840 DELETE_NODE( node );
841 return p;
842 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800843
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700844 // Handle an end tag returned to this level.
845 // And handle a bunch of annoying errors.
846 XMLElement* ele = node->ToElement();
847 if ( ele ) {
848 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 p = 0;
851 }
852 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700853 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 p = 0;
855 }
856 else if ( !endTag.Empty() ) {
857 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700858 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700859 p = 0;
860 }
861 }
862 }
863 if ( p == 0 ) {
864 DELETE_NODE( node );
865 node = 0;
866 }
867 if ( node ) {
868 this->InsertEndChild( node );
869 }
870 }
871 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800872}
873
Lee Thomason5492a1c2012-01-23 15:32:10 -0800874// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800875char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800876{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700877 const char* start = p;
878 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700879 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700881 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 return p;
884 }
885 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700886 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
887 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700888 flags |= StrPair::COLLAPSE_WHITESPACE;
889 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700890
Lee Thomason624d43f2012-10-12 10:58:48 -0700891 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700892 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700893 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700894 }
895 if ( p && *p ) {
896 return p-1;
897 }
898 }
899 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800900}
901
902
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800903XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
904{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700905 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700906 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700907 }
908 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
909 text->SetCData( this->CData() );
910 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800911}
912
913
914bool XMLText::ShallowEqual( const XMLNode* compare ) const
915{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700916 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800917}
918
919
Lee Thomason56bdd022012-02-09 18:16:58 -0800920bool XMLText::Accept( XMLVisitor* visitor ) const
921{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700922 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800923}
924
925
Lee Thomason3f57d272012-01-11 15:30:03 -0800926// --------- XMLComment ---------- //
927
Lee Thomasone4422302012-01-20 17:59:50 -0800928XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800929{
930}
931
932
Lee Thomasonce0763e2012-01-11 15:43:54 -0800933XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800934{
Lee Thomason3f57d272012-01-11 15:30:03 -0800935}
936
937
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800938char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800939{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700940 // Comment parses as text.
941 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700942 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700943 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700944 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700945 }
946 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800947}
948
949
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800950XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
951{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700952 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700953 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700954 }
955 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
956 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800957}
958
959
960bool XMLComment::ShallowEqual( const XMLNode* compare ) const
961{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700962 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800963}
964
965
Lee Thomason751da522012-02-10 08:50:51 -0800966bool XMLComment::Accept( XMLVisitor* visitor ) const
967{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700968 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800969}
Lee Thomason56bdd022012-02-09 18:16:58 -0800970
971
Lee Thomason50f97b22012-02-11 16:33:40 -0800972// --------- XMLDeclaration ---------- //
973
974XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
975{
976}
977
978
979XMLDeclaration::~XMLDeclaration()
980{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700981 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800982}
983
984
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800985char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800986{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700987 // Declaration parses as text.
988 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700989 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700991 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700992 }
993 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800994}
995
996
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800997XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
998{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001000 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001001 }
1002 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1003 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001004}
1005
1006
1007bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1008{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001009 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010}
1011
1012
1013
Lee Thomason50f97b22012-02-11 16:33:40 -08001014bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001017}
1018
1019// --------- XMLUnknown ---------- //
1020
1021XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1022{
1023}
1024
1025
1026XMLUnknown::~XMLUnknown()
1027{
1028}
1029
1030
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001031char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001032{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001033 // Unknown parses as text.
1034 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001035
Lee Thomason624d43f2012-10-12 10:58:48 -07001036 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001037 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001038 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001039 }
1040 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001041}
1042
1043
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001044XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1045{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001046 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001047 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001048 }
1049 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1050 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001051}
1052
1053
1054bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1055{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001056 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001057}
1058
1059
Lee Thomason50f97b22012-02-11 16:33:40 -08001060bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1061{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001062 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001063}
1064
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001065// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001066
1067const char* XMLAttribute::Name() const
1068{
1069 return _name.GetStr();
1070}
1071
1072const char* XMLAttribute::Value() const
1073{
1074 return _value.GetStr();
1075}
1076
Lee Thomason6f381b72012-03-02 12:59:39 -08001077char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001078{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001079 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001080 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001081 if ( !p || !*p ) {
1082 return 0;
1083 }
Lee Thomason22aead12012-01-23 13:29:35 -08001084
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001085 // Skip white space before =
1086 p = XMLUtil::SkipWhiteSpace( p );
1087 if ( !p || *p != '=' ) {
1088 return 0;
1089 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001090
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001091 ++p; // move up to opening quote
1092 p = XMLUtil::SkipWhiteSpace( p );
1093 if ( *p != '\"' && *p != '\'' ) {
1094 return 0;
1095 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001096
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 char endTag[2] = { *p, 0 };
1098 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001099
Lee Thomason624d43f2012-10-12 10:58:48 -07001100 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001101 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001102}
1103
1104
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001105void XMLAttribute::SetName( const char* n )
1106{
Lee Thomason624d43f2012-10-12 10:58:48 -07001107 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001108}
1109
1110
Lee Thomason2fa81722012-11-09 12:37:46 -08001111XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001113 if ( XMLUtil::ToInt( Value(), value )) {
1114 return XML_NO_ERROR;
1115 }
1116 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001117}
1118
1119
Lee Thomason2fa81722012-11-09 12:37:46 -08001120XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001122 if ( XMLUtil::ToUnsigned( Value(), value )) {
1123 return XML_NO_ERROR;
1124 }
1125 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001126}
1127
1128
Lee Thomason2fa81722012-11-09 12:37:46 -08001129XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001130{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001131 if ( XMLUtil::ToBool( Value(), value )) {
1132 return XML_NO_ERROR;
1133 }
1134 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001135}
1136
1137
Lee Thomason2fa81722012-11-09 12:37:46 -08001138XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001139{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001140 if ( XMLUtil::ToFloat( Value(), value )) {
1141 return XML_NO_ERROR;
1142 }
1143 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001144}
1145
1146
Lee Thomason2fa81722012-11-09 12:37:46 -08001147XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001148{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001149 if ( XMLUtil::ToDouble( Value(), value )) {
1150 return XML_NO_ERROR;
1151 }
1152 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001153}
1154
1155
1156void XMLAttribute::SetAttribute( const char* v )
1157{
Lee Thomason624d43f2012-10-12 10:58:48 -07001158 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001159}
1160
1161
Lee Thomason1ff38e02012-02-14 18:18:16 -08001162void XMLAttribute::SetAttribute( int v )
1163{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001164 char buf[BUF_SIZE];
1165 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001166 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001167}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001168
1169
1170void XMLAttribute::SetAttribute( unsigned v )
1171{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001172 char buf[BUF_SIZE];
1173 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001174 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001175}
1176
1177
1178void XMLAttribute::SetAttribute( bool v )
1179{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001180 char buf[BUF_SIZE];
1181 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001182 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001183}
1184
1185void XMLAttribute::SetAttribute( double v )
1186{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001187 char buf[BUF_SIZE];
1188 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001189 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001190}
1191
1192void XMLAttribute::SetAttribute( float v )
1193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 char buf[BUF_SIZE];
1195 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001196 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001197}
1198
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001199
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001200// --------- XMLElement ---------- //
1201XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001202 _closingType( 0 ),
1203 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001204{
1205}
1206
1207
1208XMLElement::~XMLElement()
1209{
Lee Thomason624d43f2012-10-12 10:58:48 -07001210 while( _rootAttribute ) {
1211 XMLAttribute* next = _rootAttribute->_next;
1212 DELETE_ATTRIBUTE( _rootAttribute );
1213 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001214 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001215}
1216
1217
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001218XMLAttribute* XMLElement::FindAttribute( const char* name )
1219{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001220 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001221 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001222 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1223 return a;
1224 }
1225 }
1226 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001227}
1228
1229
1230const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001232 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001233 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1235 return a;
1236 }
1237 }
1238 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001239}
1240
1241
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001242const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001243{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001244 const XMLAttribute* a = FindAttribute( name );
1245 if ( !a ) {
1246 return 0;
1247 }
1248 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1249 return a->Value();
1250 }
1251 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001252}
1253
1254
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001255const char* XMLElement::GetText() const
1256{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001257 if ( FirstChild() && FirstChild()->ToText() ) {
1258 return FirstChild()->ToText()->Value();
1259 }
1260 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001261}
1262
1263
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001264void XMLElement::SetText( const char* inText )
1265{
Uli Kusterer869bb592014-01-21 01:36:16 +01001266 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001267 FirstChild()->SetValue( inText );
1268 else {
1269 XMLText* theText = GetDocument()->NewText( inText );
1270 InsertFirstChild( theText );
1271 }
1272}
1273
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001274
Lee Thomason5bb2d802014-01-24 10:42:57 -08001275void XMLElement::SetText( int v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001276{
1277 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001278 XMLUtil::ToStr( v, buf, BUF_SIZE );
1279 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001280}
1281
1282
Lee Thomason5bb2d802014-01-24 10:42:57 -08001283void XMLElement::SetText( unsigned v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001284{
1285 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001286 XMLUtil::ToStr( v, buf, BUF_SIZE );
1287 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001288}
1289
1290
Lee Thomason5bb2d802014-01-24 10:42:57 -08001291void XMLElement::SetText( bool v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001292{
1293 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001294 XMLUtil::ToStr( v, buf, BUF_SIZE );
1295 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001296}
1297
1298
Lee Thomason5bb2d802014-01-24 10:42:57 -08001299void XMLElement::SetText( float v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001300{
1301 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001302 XMLUtil::ToStr( v, buf, BUF_SIZE );
1303 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001304}
1305
Lee Thomason5bb2d802014-01-24 10:42:57 -08001306
Uli Kusterer35ce3092014-01-25 03:37:16 +01001307void XMLElement::SetText( double v )
1308{
1309 char buf[BUF_SIZE];
1310 XMLUtil::ToStr( v, buf, BUF_SIZE );
1311 SetText( buf );
1312}
1313
1314
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001315void XMLElement::SetBoolFirstChild( bool inBool )
1316{
1317 if( FirstChild() && FirstChild()->ToElement()
1318 && (strcmp(FirstChild()->Value(),"true") == 0 || strcmp(FirstChild()->Value(),"false") == 0) ) {
1319 FirstChild()->SetValue( inBool ? "true" : "false" );
1320 }
1321 else if( !FirstChild() ) {
1322 XMLElement* theText = GetDocument()->NewElement( inBool ? "true" : "false" );
1323 InsertFirstChild( theText );
1324 }
1325}
1326
1327
Uli Kustererff8e2042014-01-21 02:53:47 +01001328XMLError XMLElement::QueryBoolFirstChild( bool *outBool )
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001329{
Uli Kustererff8e2042014-01-21 02:53:47 +01001330 if ( FirstChild() )
1331 {
1332 if ( FirstChild()->ToElement() )
1333 {
1334 bool isTrue = strcmp( FirstChild()->Value(), "true" ) == 0;
1335 bool isFalse = strcmp( FirstChild()->Value(), "false" ) == 0;
1336 if( !isTrue && !isFalse )
1337 return XML_CAN_NOT_CONVERT_TEXT;
1338
1339 *outBool = isTrue;
1340 return XML_SUCCESS;
1341 }
1342 else
1343 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001344 }
Uli Kustererff8e2042014-01-21 02:53:47 +01001345 else
1346 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001347}
1348
1349
MortenMacFly4ee49f12013-01-14 20:03:14 +01001350XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001351{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001352 if ( FirstChild() && FirstChild()->ToText() ) {
1353 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001354 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001355 return XML_SUCCESS;
1356 }
1357 return XML_CAN_NOT_CONVERT_TEXT;
1358 }
1359 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001360}
1361
1362
MortenMacFly4ee49f12013-01-14 20:03:14 +01001363XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001364{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001365 if ( FirstChild() && FirstChild()->ToText() ) {
1366 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001367 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001368 return XML_SUCCESS;
1369 }
1370 return XML_CAN_NOT_CONVERT_TEXT;
1371 }
1372 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001373}
1374
1375
MortenMacFly4ee49f12013-01-14 20:03:14 +01001376XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001377{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001378 if ( FirstChild() && FirstChild()->ToText() ) {
1379 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001380 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001381 return XML_SUCCESS;
1382 }
1383 return XML_CAN_NOT_CONVERT_TEXT;
1384 }
1385 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001386}
1387
1388
MortenMacFly4ee49f12013-01-14 20:03:14 +01001389XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001390{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001391 if ( FirstChild() && FirstChild()->ToText() ) {
1392 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001393 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001394 return XML_SUCCESS;
1395 }
1396 return XML_CAN_NOT_CONVERT_TEXT;
1397 }
1398 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001399}
1400
1401
MortenMacFly4ee49f12013-01-14 20:03:14 +01001402XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001403{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001404 if ( FirstChild() && FirstChild()->ToText() ) {
1405 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001406 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001407 return XML_SUCCESS;
1408 }
1409 return XML_CAN_NOT_CONVERT_TEXT;
1410 }
1411 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001412}
1413
1414
1415
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001416XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1417{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 XMLAttribute* last = 0;
1419 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001420 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001421 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1424 break;
1425 }
1426 }
1427 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001428 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1429 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001430 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001431 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 }
1433 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001434 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001435 }
1436 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001437 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001438 }
1439 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001440}
1441
1442
U-Stream\Leeae25a442012-02-17 17:48:16 -08001443void XMLElement::DeleteAttribute( const char* name )
1444{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001446 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1448 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001449 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001450 }
1451 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001452 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001453 }
1454 DELETE_ATTRIBUTE( a );
1455 break;
1456 }
1457 prev = a;
1458 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001459}
1460
1461
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001462char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001463{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 const char* start = p;
1465 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001466
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001467 // Read the attributes.
1468 while( p ) {
1469 p = XMLUtil::SkipWhiteSpace( p );
1470 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001471 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001472 return 0;
1473 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001474
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001476 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001477 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1478 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001479 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001480
Lee Thomason624d43f2012-10-12 10:58:48 -07001481 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 if ( !p || Attribute( attrib->Name() ) ) {
1483 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001484 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001485 return 0;
1486 }
1487 // There is a minor bug here: if the attribute in the source xml
1488 // document is duplicated, it will not be detected and the
1489 // attribute will be doubly added. However, tracking the 'prevAttribute'
1490 // avoids re-scanning the attribute list. Preferring performance for
1491 // now, may reconsider in the future.
1492 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001493 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001494 }
1495 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001496 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001497 }
1498 prevAttribute = attrib;
1499 }
1500 // end of the tag
1501 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001502 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001503 return p+2; // done; sealed element.
1504 }
1505 // end of the tag
1506 else if ( *p == '>' ) {
1507 ++p;
1508 break;
1509 }
1510 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001511 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001512 return 0;
1513 }
1514 }
1515 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001516}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001517
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001518
Lee Thomason67d61312012-01-24 16:01:51 -08001519//
1520// <ele></ele>
1521// <ele>foo<b>bar</b></ele>
1522//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001523char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001524{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001525 // Read the element name.
1526 p = XMLUtil::SkipWhiteSpace( p );
1527 if ( !p ) {
1528 return 0;
1529 }
Lee Thomason67d61312012-01-24 16:01:51 -08001530
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001531 // The closing element is the </element> form. It is
1532 // parsed just like a regular element then deleted from
1533 // the DOM.
1534 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001535 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 ++p;
1537 }
Lee Thomason67d61312012-01-24 16:01:51 -08001538
Lee Thomason624d43f2012-10-12 10:58:48 -07001539 p = _value.ParseName( p );
1540 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001541 return 0;
1542 }
Lee Thomason67d61312012-01-24 16:01:51 -08001543
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001544 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001545 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 return p;
1547 }
Lee Thomason67d61312012-01-24 16:01:51 -08001548
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001549 p = XMLNode::ParseDeep( p, strPair );
1550 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001551}
1552
1553
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001554
1555XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1556{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001558 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 }
1560 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1561 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1562 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1563 }
1564 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001565}
1566
1567
1568bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1569{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 const XMLElement* other = compare->ToElement();
1571 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001572
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001573 const XMLAttribute* a=FirstAttribute();
1574 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001575
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 while ( a && b ) {
1577 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1578 return false;
1579 }
1580 a = a->Next();
1581 b = b->Next();
1582 }
1583 if ( a || b ) {
1584 // different count
1585 return false;
1586 }
1587 return true;
1588 }
1589 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001590}
1591
1592
Lee Thomason751da522012-02-10 08:50:51 -08001593bool XMLElement::Accept( XMLVisitor* visitor ) const
1594{
Lee Thomason624d43f2012-10-12 10:58:48 -07001595 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001596 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1597 if ( !node->Accept( visitor ) ) {
1598 break;
1599 }
1600 }
1601 }
1602 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001603}
Lee Thomason56bdd022012-02-09 18:16:58 -08001604
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001605
Lee Thomason3f57d272012-01-11 15:30:03 -08001606// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001607XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001608 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001609 _writeBOM( false ),
1610 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001611 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001612 _whitespace( whitespace ),
1613 _errorStr1( 0 ),
1614 _errorStr2( 0 ),
1615 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001616{
Lee Thomason624d43f2012-10-12 10:58:48 -07001617 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001618}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001619
1620
Lee Thomason3f57d272012-01-11 15:30:03 -08001621XMLDocument::~XMLDocument()
1622{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001623 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001624 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001625
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001626#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001627 _textPool.Trace( "text" );
1628 _elementPool.Trace( "element" );
1629 _commentPool.Trace( "comment" );
1630 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001631#endif
1632
Lee Thomason5b0a6772012-11-19 13:54:42 -08001633#ifdef DEBUG
1634 if ( Error() == false ) {
1635 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1636 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1637 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1638 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1639 }
1640#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001641}
1642
1643
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001644void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001645{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001646 DeleteChildren();
1647
Lee Thomason624d43f2012-10-12 10:58:48 -07001648 _errorID = XML_NO_ERROR;
1649 _errorStr1 = 0;
1650 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001651
Lee Thomason624d43f2012-10-12 10:58:48 -07001652 delete [] _charBuffer;
1653 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001654}
1655
Lee Thomason3f57d272012-01-11 15:30:03 -08001656
Lee Thomason2c85a712012-01-31 08:24:24 -08001657XMLElement* XMLDocument::NewElement( const char* name )
1658{
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1660 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001661 ele->SetName( name );
1662 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001663}
1664
1665
Lee Thomason1ff38e02012-02-14 18:18:16 -08001666XMLComment* XMLDocument::NewComment( const char* str )
1667{
Lee Thomason624d43f2012-10-12 10:58:48 -07001668 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1669 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001670 comment->SetValue( str );
1671 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001672}
1673
1674
1675XMLText* XMLDocument::NewText( const char* str )
1676{
Lee Thomason624d43f2012-10-12 10:58:48 -07001677 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1678 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001679 text->SetValue( str );
1680 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001681}
1682
1683
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001684XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1685{
Lee Thomason624d43f2012-10-12 10:58:48 -07001686 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1687 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001688 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1689 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001690}
1691
1692
1693XMLUnknown* XMLDocument::NewUnknown( const char* str )
1694{
Lee Thomason624d43f2012-10-12 10:58:48 -07001695 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1696 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001697 unk->SetValue( str );
1698 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001699}
1700
1701
Lee Thomason2fa81722012-11-09 12:37:46 -08001702XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001703{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001704 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001705 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001706
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1708 errno_t err = fopen_s(&fp, filename, "rb" );
1709 if ( !fp || err) {
1710#else
1711 fp = fopen( filename, "rb" );
1712 if ( !fp) {
1713#endif
1714 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001715 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 }
1717 LoadFile( fp );
1718 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001719 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001720}
1721
1722
Lee Thomason2fa81722012-11-09 12:37:46 -08001723XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001724{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001725 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001726
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001727 fseek( fp, 0, SEEK_SET );
1728 fgetc( fp );
1729 if ( ferror( fp ) != 0 ) {
1730 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1731 return _errorID;
1732 }
1733
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001734 fseek( fp, 0, SEEK_END );
1735 size_t size = ftell( fp );
1736 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001737
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001738 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001739 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001740 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001741 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001742
Lee Thomason624d43f2012-10-12 10:58:48 -07001743 _charBuffer = new char[size+1];
1744 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 if ( read != size ) {
1746 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001748 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001749
Lee Thomason624d43f2012-10-12 10:58:48 -07001750 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001751
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001753 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 if ( !p || !*p ) {
1756 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001757 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001758 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001759
Lee Thomason624d43f2012-10-12 10:58:48 -07001760 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1761 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001762}
1763
1764
Lee Thomason2fa81722012-11-09 12:37:46 -08001765XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001766{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001767 FILE* fp = 0;
1768#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1769 errno_t err = fopen_s(&fp, filename, "w" );
1770 if ( !fp || err) {
1771#else
1772 fp = fopen( filename, "w" );
1773 if ( !fp) {
1774#endif
1775 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001776 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001777 }
1778 SaveFile(fp, compact);
1779 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001780 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001781}
1782
1783
Lee Thomason2fa81722012-11-09 12:37:46 -08001784XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001785{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001786 XMLPrinter stream( fp, compact );
1787 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001788 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001789}
1790
Lee Thomason1ff38e02012-02-14 18:18:16 -08001791
Lee Thomason2fa81722012-11-09 12:37:46 -08001792XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001793{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001794 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001795 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001796
psi690ba072013-11-03 10:54:33 +09001797 if ( len == 0 ) {
1798 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1799 return _errorID;
1800 }
1801
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 if ( !p || !*p ) {
1803 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001804 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 }
1806 if ( len == (size_t)(-1) ) {
1807 len = strlen( p );
1808 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001809 _charBuffer = new char[ len+1 ];
1810 memcpy( _charBuffer, p, len );
1811 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001812
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 if ( !p || !*p ) {
1816 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001817 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001818 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001819
Thomas Roß1470edc2013-05-10 15:44:12 +02001820 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001821 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001822 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001823}
1824
1825
PKEuS1c5f99e2013-07-06 11:28:39 +02001826void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001827{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001828 XMLPrinter stdStreamer( stdout );
1829 if ( !streamer ) {
1830 streamer = &stdStreamer;
1831 }
1832 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001833}
1834
1835
Lee Thomason2fa81722012-11-09 12:37:46 -08001836void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001837{
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 _errorID = error;
1839 _errorStr1 = str1;
1840 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001841}
1842
Lee Thomason5cae8972012-01-24 18:03:07 -08001843
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001844void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001845{
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001847 static const int LEN = 20;
1848 char buf1[LEN] = { 0 };
1849 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001850
Lee Thomason624d43f2012-10-12 10:58:48 -07001851 if ( _errorStr1 ) {
1852 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001853 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001854 if ( _errorStr2 ) {
1855 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001857
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001859 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001861}
1862
1863
PKEuS1bfb9542013-08-04 13:51:17 +02001864XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 _elementJustOpened( false ),
1866 _firstElement( true ),
1867 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001868 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001869 _textDepth( -1 ),
1870 _processEntities( true ),
1871 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001872{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001873 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001874 _entityFlag[i] = false;
1875 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001876 }
1877 for( int i=0; i<NUM_ENTITIES; ++i ) {
1878 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1879 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001881 }
1882 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001883 _restrictedEntityFlag[(int)'&'] = true;
1884 _restrictedEntityFlag[(int)'<'] = true;
1885 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1886 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001887}
1888
1889
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001890void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001891{
1892 va_list va;
1893 va_start( va, format );
1894
Lee Thomason624d43f2012-10-12 10:58:48 -07001895 if ( _fp ) {
1896 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001897 }
1898 else {
1899 // This seems brutally complex. Haven't figured out a better
1900 // way on windows.
1901#ifdef _MSC_VER
1902 int len = -1;
1903 int expand = 1000;
1904 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001905 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001906 if ( len < 0 ) {
1907 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001908 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001909 }
1910 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001911 char* p = _buffer.PushArr( len ) - 1;
1912 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001913#else
1914 int len = vsnprintf( 0, 0, format, va );
1915 // Close out and re-start the va-args
1916 va_end( va );
1917 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001918 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001919 vsnprintf( p, len+1, format, va );
1920#endif
1921 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001922 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001923}
1924
1925
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001926void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001927{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001928 for( int i=0; i<depth; ++i ) {
1929 Print( " " );
1930 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001931}
1932
1933
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001934void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001935{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001936 // Look for runs of bytes between entities to print.
1937 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001939
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001941 while ( *q ) {
1942 // Remember, char is sometimes signed. (How many times has that bitten me?)
1943 if ( *q > 0 && *q < ENTITY_RANGE ) {
1944 // Check for entities. If one is found, flush
1945 // the stream up until the entity, write the
1946 // entity, and keep looking.
1947 if ( flag[(unsigned)(*q)] ) {
1948 while ( p < q ) {
1949 Print( "%c", *p );
1950 ++p;
1951 }
1952 for( int i=0; i<NUM_ENTITIES; ++i ) {
1953 if ( entities[i].value == *q ) {
1954 Print( "&%s;", entities[i].pattern );
1955 break;
1956 }
1957 }
1958 ++p;
1959 }
1960 }
1961 ++q;
1962 }
1963 }
1964 // Flush the remaining string. This will be the entire
1965 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001966 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001967 Print( "%s", p );
1968 }
Lee Thomason857b8682012-01-25 17:50:25 -08001969}
1970
U-Stream\Leeae25a442012-02-17 17:48:16 -08001971
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001972void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001973{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001974 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001975 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 -07001976 Print( "%s", bom );
1977 }
1978 if ( writeDec ) {
1979 PushDeclaration( "xml version=\"1.0\"" );
1980 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001981}
1982
1983
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001984void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001985{
Lee Thomason624d43f2012-10-12 10:58:48 -07001986 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001987 SealElement();
1988 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001989 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001990
Lee Thomason624d43f2012-10-12 10:58:48 -07001991 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001992 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001993 }
1994 if ( !_compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001995 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001997
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07001999 _elementJustOpened = true;
2000 _firstElement = false;
2001 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002002}
2003
2004
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002005void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002006{
Lee Thomason624d43f2012-10-12 10:58:48 -07002007 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002008 Print( " %s=\"", name );
2009 PrintString( value, false );
2010 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002011}
2012
2013
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002014void XMLPrinter::PushAttribute( const char* name, int v )
2015{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 char buf[BUF_SIZE];
2017 XMLUtil::ToStr( v, buf, BUF_SIZE );
2018 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002019}
2020
2021
2022void XMLPrinter::PushAttribute( const char* name, unsigned v )
2023{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002024 char buf[BUF_SIZE];
2025 XMLUtil::ToStr( v, buf, BUF_SIZE );
2026 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002027}
2028
2029
2030void XMLPrinter::PushAttribute( const char* name, bool v )
2031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002032 char buf[BUF_SIZE];
2033 XMLUtil::ToStr( v, buf, BUF_SIZE );
2034 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002035}
2036
2037
2038void XMLPrinter::PushAttribute( const char* name, double v )
2039{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002040 char buf[BUF_SIZE];
2041 XMLUtil::ToStr( v, buf, BUF_SIZE );
2042 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002043}
2044
2045
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002046void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002047{
Lee Thomason624d43f2012-10-12 10:58:48 -07002048 --_depth;
2049 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002050
Lee Thomason624d43f2012-10-12 10:58:48 -07002051 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002052 Print( "/>" );
2053 }
2054 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07002055 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002056 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002057 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 }
2059 Print( "</%s>", name );
2060 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002061
Lee Thomason624d43f2012-10-12 10:58:48 -07002062 if ( _textDepth == _depth ) {
2063 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002064 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002065 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 Print( "\n" );
2067 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002068 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002069}
2070
2071
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002072void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002073{
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002076}
2077
2078
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002079void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002080{
Lee Thomason624d43f2012-10-12 10:58:48 -07002081 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002082
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002084 SealElement();
2085 }
2086 if ( cdata ) {
2087 Print( "<![CDATA[" );
2088 Print( "%s", text );
2089 Print( "]]>" );
2090 }
2091 else {
2092 PrintString( text, true );
2093 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002094}
2095
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002096void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002097{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002098 char buf[BUF_SIZE];
2099 XMLUtil::ToStr( value, buf, BUF_SIZE );
2100 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002101}
2102
2103
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002104void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002105{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002106 char buf[BUF_SIZE];
2107 XMLUtil::ToStr( value, buf, BUF_SIZE );
2108 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002109}
2110
2111
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002112void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002114 char buf[BUF_SIZE];
2115 XMLUtil::ToStr( value, buf, BUF_SIZE );
2116 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002117}
2118
2119
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002120void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002121{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002122 char buf[BUF_SIZE];
2123 XMLUtil::ToStr( value, buf, BUF_SIZE );
2124 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002125}
2126
2127
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002128void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002129{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002130 char buf[BUF_SIZE];
2131 XMLUtil::ToStr( value, buf, BUF_SIZE );
2132 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002133}
2134
Lee Thomason5cae8972012-01-24 18:03:07 -08002135
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002136void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002137{
Lee Thomason624d43f2012-10-12 10:58:48 -07002138 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 SealElement();
2140 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002141 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002142 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002147}
Lee Thomason751da522012-02-10 08:50:51 -08002148
2149
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002150void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002151{
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 SealElement();
2154 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002155 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002156 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002159 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002161}
2162
2163
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002164void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002165{
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 SealElement();
2168 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002169 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002170 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002173 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002174 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002175}
2176
2177
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002178bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002179{
Lee Thomason624d43f2012-10-12 10:58:48 -07002180 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 if ( doc.HasBOM() ) {
2182 PushHeader( true, false );
2183 }
2184 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002185}
2186
2187
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002188bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002189{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002190 OpenElement( element.Name() );
2191 while ( attribute ) {
2192 PushAttribute( attribute->Name(), attribute->Value() );
2193 attribute = attribute->Next();
2194 }
2195 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002196}
2197
2198
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002199bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 CloseElement();
2202 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002203}
2204
2205
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002206bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002207{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002208 PushText( text.Value(), text.CData() );
2209 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002210}
2211
2212
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002213bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002214{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002215 PushComment( comment.Value() );
2216 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002217}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002218
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002219bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 PushDeclaration( declaration.Value() );
2222 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002223}
2224
2225
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002226bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 PushUnknown( unknown.Value() );
2229 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002230}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002231
Lee Thomason685b8952012-11-12 13:00:06 -08002232} // namespace tinyxml2
2233