blob: c00f0e3e9739e1aad7cd543b35451372b3683a40 [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
449bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
450{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700451 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
452 return true;
453 }
454 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700455}
456
457bool XMLUtil::ToBool( const char* str, bool* value )
458{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700459 int ival = 0;
460 if ( ToInt( str, &ival )) {
461 *value = (ival==0) ? false : true;
462 return true;
463 }
464 if ( StringEqual( str, "true" ) ) {
465 *value = true;
466 return true;
467 }
468 else if ( StringEqual( str, "false" ) ) {
469 *value = false;
470 return true;
471 }
472 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700473}
474
475
476bool XMLUtil::ToFloat( const char* str, float* value )
477{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700478 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
479 return true;
480 }
481 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700482}
483
484bool XMLUtil::ToDouble( const char* str, double* value )
485{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700486 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
487 return true;
488 }
489 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700490}
491
492
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700493char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800494{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700495 XMLNode* returnNode = 0;
496 char* start = p;
497 p = XMLUtil::SkipWhiteSpace( p );
498 if( !p || !*p ) {
499 return p;
500 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800501
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700502 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800503 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700504 static const char* xmlHeader = { "<?" };
505 static const char* commentHeader = { "<!--" };
506 static const char* dtdHeader = { "<!" };
507 static const char* cdataHeader = { "<![CDATA[" };
508 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800509
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700510 static const int xmlHeaderLen = 2;
511 static const int commentHeaderLen = 4;
512 static const int dtdHeaderLen = 2;
513 static const int cdataHeaderLen = 9;
514 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800515
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800516#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800517#pragma warning ( push )
518#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800519#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
521 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800522#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800523#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800524#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700525 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700526 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
527 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700528 p += xmlHeaderLen;
529 }
530 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700531 returnNode = new (_commentPool.Alloc()) XMLComment( this );
532 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700533 p += commentHeaderLen;
534 }
535 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700536 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700537 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700539 p += cdataHeaderLen;
540 text->SetCData( true );
541 }
542 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700543 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
544 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700545 p += dtdHeaderLen;
546 }
547 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700548 returnNode = new (_elementPool.Alloc()) XMLElement( this );
549 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700550 p += elementHeaderLen;
551 }
552 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700553 returnNode = new (_textPool.Alloc()) XMLText( this );
554 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700555 p = start; // Back it up, all the text counts.
556 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800557
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700558 *node = returnNode;
559 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800560}
561
562
Lee Thomason751da522012-02-10 08:50:51 -0800563bool XMLDocument::Accept( XMLVisitor* visitor ) const
564{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700565 if ( visitor->VisitEnter( *this ) ) {
566 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
567 if ( !node->Accept( visitor ) ) {
568 break;
569 }
570 }
571 }
572 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800573}
Lee Thomason56bdd022012-02-09 18:16:58 -0800574
575
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800576// --------- XMLNode ----------- //
577
578XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700579 _document( doc ),
580 _parent( 0 ),
581 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200582 _prev( 0 ), _next( 0 ),
583 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800584{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800585}
586
587
588XMLNode::~XMLNode()
589{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700590 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700591 if ( _parent ) {
592 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700593 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800594}
595
Michael Daumling21626882013-10-22 17:03:37 +0200596const char* XMLNode::Value() const
597{
598 return _value.GetStr();
599}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800600
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800601void XMLNode::SetValue( const char* str, bool staticMem )
602{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700603 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700604 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 }
606 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700607 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700608 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800609}
610
611
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800612void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800613{
Lee Thomason624d43f2012-10-12 10:58:48 -0700614 while( _firstChild ) {
615 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700616 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700617
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 DELETE_NODE( node );
619 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700620 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800621}
622
623
624void XMLNode::Unlink( XMLNode* child )
625{
Lee Thomason624d43f2012-10-12 10:58:48 -0700626 if ( child == _firstChild ) {
627 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700628 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700629 if ( child == _lastChild ) {
630 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700631 }
Lee Thomasond923c672012-01-23 08:44:25 -0800632
Lee Thomason624d43f2012-10-12 10:58:48 -0700633 if ( child->_prev ) {
634 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700635 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700636 if ( child->_next ) {
637 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700638 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700639 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800640}
641
642
U-Stream\Leeae25a442012-02-17 17:48:16 -0800643void XMLNode::DeleteChild( XMLNode* node )
644{
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700646 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800647}
648
649
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800650XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
651{
Michael Daumlinged523282013-10-23 07:47:29 +0200652 if (addThis->_document != _document)
653 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700654
Michael Daumlinged523282013-10-23 07:47:29 +0200655 if (addThis->_parent)
656 addThis->_parent->Unlink( addThis );
657 else
658 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700659
Lee Thomason624d43f2012-10-12 10:58:48 -0700660 if ( _lastChild ) {
661 TIXMLASSERT( _firstChild );
662 TIXMLASSERT( _lastChild->_next == 0 );
663 _lastChild->_next = addThis;
664 addThis->_prev = _lastChild;
665 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800666
Lee Thomason624d43f2012-10-12 10:58:48 -0700667 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700668 }
669 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700670 TIXMLASSERT( _firstChild == 0 );
671 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800672
Lee Thomason624d43f2012-10-12 10:58:48 -0700673 addThis->_prev = 0;
674 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700675 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700676 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800678}
679
680
Lee Thomason1ff38e02012-02-14 18:18:16 -0800681XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
682{
Michael Daumlinged523282013-10-23 07:47:29 +0200683 if (addThis->_document != _document)
684 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700685
Michael Daumlinged523282013-10-23 07:47:29 +0200686 if (addThis->_parent)
687 addThis->_parent->Unlink( addThis );
688 else
689 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700690
Lee Thomason624d43f2012-10-12 10:58:48 -0700691 if ( _firstChild ) {
692 TIXMLASSERT( _lastChild );
693 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800694
Lee Thomason624d43f2012-10-12 10:58:48 -0700695 _firstChild->_prev = addThis;
696 addThis->_next = _firstChild;
697 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800698
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 }
701 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700702 TIXMLASSERT( _lastChild == 0 );
703 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800704
Lee Thomason624d43f2012-10-12 10:58:48 -0700705 addThis->_prev = 0;
706 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700707 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700708 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200709 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800710}
711
712
713XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
714{
Michael Daumlinged523282013-10-23 07:47:29 +0200715 if (addThis->_document != _document)
716 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700717
Lee Thomason624d43f2012-10-12 10:58:48 -0700718 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700719
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700721 return 0;
722 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800723
Lee Thomason624d43f2012-10-12 10:58:48 -0700724 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700725 // The last node or the only node.
726 return InsertEndChild( addThis );
727 }
Michael Daumlinged523282013-10-23 07:47:29 +0200728 if (addThis->_parent)
729 addThis->_parent->Unlink( addThis );
730 else
731 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700732 addThis->_prev = afterThis;
733 addThis->_next = afterThis->_next;
734 afterThis->_next->_prev = addThis;
735 afterThis->_next = addThis;
736 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700737 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800738}
739
740
741
742
Lee Thomason56bdd022012-02-09 18:16:58 -0800743const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800744{
Lee Thomason624d43f2012-10-12 10:58:48 -0700745 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700746 XMLElement* element = node->ToElement();
747 if ( element ) {
748 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
749 return element;
750 }
751 }
752 }
753 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800754}
755
756
Lee Thomason56bdd022012-02-09 18:16:58 -0800757const XMLElement* XMLNode::LastChildElement( const char* value ) const
758{
Lee Thomason624d43f2012-10-12 10:58:48 -0700759 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700760 XMLElement* element = node->ToElement();
761 if ( element ) {
762 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
763 return element;
764 }
765 }
766 }
767 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800768}
769
770
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800771const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
772{
Lee Thomason624d43f2012-10-12 10:58:48 -0700773 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700774 if ( element->ToElement()
775 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
776 return element->ToElement();
777 }
778 }
779 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800780}
781
782
783const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
784{
Lee Thomason624d43f2012-10-12 10:58:48 -0700785 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700786 if ( element->ToElement()
787 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
788 return element->ToElement();
789 }
790 }
791 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800792}
793
794
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800795char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800796{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700797 // This is a recursive method, but thinking about it "at the current level"
798 // it is a pretty simple flat list:
799 // <foo/>
800 // <!-- comment -->
801 //
802 // With a special case:
803 // <foo>
804 // </foo>
805 // <!-- comment -->
806 //
807 // Where the closing element (/foo) *must* be the next thing after the opening
808 // element, and the names must match. BUT the tricky bit is that the closing
809 // element will be read by the child.
810 //
811 // 'endTag' is the end tag for this node, it is returned by a call to a child.
812 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800813
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700814 while( p && *p ) {
815 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800816
Lee Thomason624d43f2012-10-12 10:58:48 -0700817 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700818 if ( p == 0 || node == 0 ) {
819 break;
820 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800821
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700822 StrPair endTag;
823 p = node->ParseDeep( p, &endTag );
824 if ( !p ) {
825 DELETE_NODE( node );
826 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700827 if ( !_document->Error() ) {
828 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 }
830 break;
831 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800832
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700833 // We read the end tag. Return it to the parent.
834 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
835 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700836 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700837 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800838 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 DELETE_NODE( node );
840 return p;
841 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800842
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700843 // Handle an end tag returned to this level.
844 // And handle a bunch of annoying errors.
845 XMLElement* ele = node->ToElement();
846 if ( ele ) {
847 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700848 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700849 p = 0;
850 }
851 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700852 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700853 p = 0;
854 }
855 else if ( !endTag.Empty() ) {
856 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700857 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 p = 0;
859 }
860 }
861 }
862 if ( p == 0 ) {
863 DELETE_NODE( node );
864 node = 0;
865 }
866 if ( node ) {
867 this->InsertEndChild( node );
868 }
869 }
870 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800871}
872
Lee Thomason5492a1c2012-01-23 15:32:10 -0800873// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800874char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800875{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 const char* start = p;
877 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700878 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700879 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 }
882 return p;
883 }
884 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700885 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
886 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700887 flags |= StrPair::COLLAPSE_WHITESPACE;
888 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700889
Lee Thomason624d43f2012-10-12 10:58:48 -0700890 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700891 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 }
894 if ( p && *p ) {
895 return p-1;
896 }
897 }
898 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800899}
900
901
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800902XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
903{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700904 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700905 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 }
907 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
908 text->SetCData( this->CData() );
909 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800910}
911
912
913bool XMLText::ShallowEqual( const XMLNode* compare ) const
914{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700915 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800916}
917
918
Lee Thomason56bdd022012-02-09 18:16:58 -0800919bool XMLText::Accept( XMLVisitor* visitor ) const
920{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700921 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800922}
923
924
Lee Thomason3f57d272012-01-11 15:30:03 -0800925// --------- XMLComment ---------- //
926
Lee Thomasone4422302012-01-20 17:59:50 -0800927XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800928{
929}
930
931
Lee Thomasonce0763e2012-01-11 15:43:54 -0800932XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800933{
Lee Thomason3f57d272012-01-11 15:30:03 -0800934}
935
936
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800937char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700939 // Comment parses as text.
940 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700941 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700942 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 }
945 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800946}
947
948
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800949XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
950{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700951 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700952 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 }
954 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
955 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800956}
957
958
959bool XMLComment::ShallowEqual( const XMLNode* compare ) const
960{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700961 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800962}
963
964
Lee Thomason751da522012-02-10 08:50:51 -0800965bool XMLComment::Accept( XMLVisitor* visitor ) const
966{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800968}
Lee Thomason56bdd022012-02-09 18:16:58 -0800969
970
Lee Thomason50f97b22012-02-11 16:33:40 -0800971// --------- XMLDeclaration ---------- //
972
973XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
974{
975}
976
977
978XMLDeclaration::~XMLDeclaration()
979{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700980 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800981}
982
983
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800984char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800985{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700986 // Declaration parses as text.
987 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700988 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700989 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 }
992 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800993}
994
995
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800996XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
997{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700998 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700999 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 }
1001 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1002 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001003}
1004
1005
1006bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1007{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001008 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001009}
1010
1011
1012
Lee Thomason50f97b22012-02-11 16:33:40 -08001013bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1014{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001015 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001016}
1017
1018// --------- XMLUnknown ---------- //
1019
1020XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1021{
1022}
1023
1024
1025XMLUnknown::~XMLUnknown()
1026{
1027}
1028
1029
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001030char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001031{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001032 // Unknown parses as text.
1033 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001034
Lee Thomason624d43f2012-10-12 10:58:48 -07001035 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001036 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 }
1039 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001040}
1041
1042
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001043XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1044{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001045 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001046 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 }
1048 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1049 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001050}
1051
1052
1053bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1054{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001055 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001056}
1057
1058
Lee Thomason50f97b22012-02-11 16:33:40 -08001059bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1060{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001061 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001062}
1063
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001064// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001065
1066const char* XMLAttribute::Name() const
1067{
1068 return _name.GetStr();
1069}
1070
1071const char* XMLAttribute::Value() const
1072{
1073 return _value.GetStr();
1074}
1075
Lee Thomason6f381b72012-03-02 12:59:39 -08001076char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001077{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001078 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001079 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 if ( !p || !*p ) {
1081 return 0;
1082 }
Lee Thomason22aead12012-01-23 13:29:35 -08001083
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 // Skip white space before =
1085 p = XMLUtil::SkipWhiteSpace( p );
1086 if ( !p || *p != '=' ) {
1087 return 0;
1088 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001089
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 ++p; // move up to opening quote
1091 p = XMLUtil::SkipWhiteSpace( p );
1092 if ( *p != '\"' && *p != '\'' ) {
1093 return 0;
1094 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001095
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001096 char endTag[2] = { *p, 0 };
1097 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001098
Lee Thomason624d43f2012-10-12 10:58:48 -07001099 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001100 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001101}
1102
1103
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001104void XMLAttribute::SetName( const char* n )
1105{
Lee Thomason624d43f2012-10-12 10:58:48 -07001106 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001107}
1108
1109
Lee Thomason2fa81722012-11-09 12:37:46 -08001110XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001111{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001112 if ( XMLUtil::ToInt( Value(), value )) {
1113 return XML_NO_ERROR;
1114 }
1115 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001116}
1117
1118
Lee Thomason2fa81722012-11-09 12:37:46 -08001119XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001120{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001121 if ( XMLUtil::ToUnsigned( Value(), value )) {
1122 return XML_NO_ERROR;
1123 }
1124 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001125}
1126
1127
Lee Thomason2fa81722012-11-09 12:37:46 -08001128XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001129{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001130 if ( XMLUtil::ToBool( Value(), value )) {
1131 return XML_NO_ERROR;
1132 }
1133 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001134}
1135
1136
Lee Thomason2fa81722012-11-09 12:37:46 -08001137XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001138{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 if ( XMLUtil::ToFloat( Value(), value )) {
1140 return XML_NO_ERROR;
1141 }
1142 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001143}
1144
1145
Lee Thomason2fa81722012-11-09 12:37:46 -08001146XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001147{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001148 if ( XMLUtil::ToDouble( Value(), value )) {
1149 return XML_NO_ERROR;
1150 }
1151 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001152}
1153
1154
1155void XMLAttribute::SetAttribute( const char* v )
1156{
Lee Thomason624d43f2012-10-12 10:58:48 -07001157 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001158}
1159
1160
Lee Thomason1ff38e02012-02-14 18:18:16 -08001161void XMLAttribute::SetAttribute( int v )
1162{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001163 char buf[BUF_SIZE];
1164 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001165 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001167
1168
1169void XMLAttribute::SetAttribute( unsigned v )
1170{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001171 char buf[BUF_SIZE];
1172 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001173 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001174}
1175
1176
1177void XMLAttribute::SetAttribute( bool v )
1178{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001179 char buf[BUF_SIZE];
1180 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001181 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001182}
1183
1184void XMLAttribute::SetAttribute( double v )
1185{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001186 char buf[BUF_SIZE];
1187 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001188 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001189}
1190
1191void XMLAttribute::SetAttribute( float v )
1192{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001193 char buf[BUF_SIZE];
1194 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001195 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001196}
1197
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001198
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001199// --------- XMLElement ---------- //
1200XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001201 _closingType( 0 ),
1202 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001203{
1204}
1205
1206
1207XMLElement::~XMLElement()
1208{
Lee Thomason624d43f2012-10-12 10:58:48 -07001209 while( _rootAttribute ) {
1210 XMLAttribute* next = _rootAttribute->_next;
1211 DELETE_ATTRIBUTE( _rootAttribute );
1212 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001213 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001214}
1215
1216
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001217XMLAttribute* XMLElement::FindAttribute( const char* name )
1218{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001219 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001220 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1222 return a;
1223 }
1224 }
1225 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001226}
1227
1228
1229const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1230{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001231 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001232 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1234 return a;
1235 }
1236 }
1237 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001238}
1239
1240
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001241const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001242{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001243 const XMLAttribute* a = FindAttribute( name );
1244 if ( !a ) {
1245 return 0;
1246 }
1247 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1248 return a->Value();
1249 }
1250 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001251}
1252
1253
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001254const char* XMLElement::GetText() const
1255{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001256 if ( FirstChild() && FirstChild()->ToText() ) {
1257 return FirstChild()->ToText()->Value();
1258 }
1259 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001260}
1261
1262
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001263void XMLElement::SetText( const char* inText )
1264{
Uli Kusterer869bb592014-01-21 01:36:16 +01001265 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001266 FirstChild()->SetValue( inText );
1267 else {
1268 XMLText* theText = GetDocument()->NewText( inText );
1269 InsertFirstChild( theText );
1270 }
1271}
1272
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001273
1274void XMLElement::SetText( int inNum )
1275{
1276 char buf[BUF_SIZE];
1277 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1278 if ( FirstChild() && FirstChild()->ToText() )
1279 FirstChild()->SetValue( buf );
1280 else {
1281 XMLText* theText = GetDocument()->NewText( buf );
1282 InsertFirstChild( theText );
1283 }
1284}
1285
1286
1287void XMLElement::SetText( unsigned inNum )
1288{
1289 char buf[BUF_SIZE];
1290 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1291 if ( FirstChild() && FirstChild()->ToText() )
1292 FirstChild()->SetValue( buf );
1293 else {
1294 XMLText* theText = GetDocument()->NewText( buf );
1295 InsertFirstChild( theText );
1296 }
1297}
1298
1299
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001300void XMLElement::SetText( double inNum )
1301{
1302 char buf[BUF_SIZE];
1303 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1304 if ( FirstChild() && FirstChild()->ToText() )
1305 FirstChild()->SetValue( buf );
1306 else {
1307 XMLText* theText = GetDocument()->NewText( buf );
1308 InsertFirstChild( theText );
1309 }
1310}
1311
1312
1313void XMLElement::SetText( float inNum )
1314{
1315 char buf[BUF_SIZE];
1316 XMLUtil::ToStr( inNum, buf, BUF_SIZE );
1317 if ( FirstChild() && FirstChild()->ToText() )
1318 FirstChild()->SetValue( buf );
1319 else {
1320 XMLText* theText = GetDocument()->NewText( buf );
1321 InsertFirstChild( theText );
1322 }
1323}
1324
1325
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001326void XMLElement::SetBoolFirstChild( bool inBool )
1327{
1328 if( FirstChild() && FirstChild()->ToElement()
1329 && (strcmp(FirstChild()->Value(),"true") == 0 || strcmp(FirstChild()->Value(),"false") == 0) ) {
1330 FirstChild()->SetValue( inBool ? "true" : "false" );
1331 }
1332 else if( !FirstChild() ) {
1333 XMLElement* theText = GetDocument()->NewElement( inBool ? "true" : "false" );
1334 InsertFirstChild( theText );
1335 }
1336}
1337
1338
Uli Kustererff8e2042014-01-21 02:53:47 +01001339XMLError XMLElement::QueryBoolFirstChild( bool *outBool )
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001340{
Uli Kustererff8e2042014-01-21 02:53:47 +01001341 if ( FirstChild() )
1342 {
1343 if ( FirstChild()->ToElement() )
1344 {
1345 bool isTrue = strcmp( FirstChild()->Value(), "true" ) == 0;
1346 bool isFalse = strcmp( FirstChild()->Value(), "false" ) == 0;
1347 if( !isTrue && !isFalse )
1348 return XML_CAN_NOT_CONVERT_TEXT;
1349
1350 *outBool = isTrue;
1351 return XML_SUCCESS;
1352 }
1353 else
1354 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001355 }
Uli Kustererff8e2042014-01-21 02:53:47 +01001356 else
1357 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001358}
1359
1360
MortenMacFly4ee49f12013-01-14 20:03:14 +01001361XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001362{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001363 if ( FirstChild() && FirstChild()->ToText() ) {
1364 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001365 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001366 return XML_SUCCESS;
1367 }
1368 return XML_CAN_NOT_CONVERT_TEXT;
1369 }
1370 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001371}
1372
1373
MortenMacFly4ee49f12013-01-14 20:03:14 +01001374XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001375{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001376 if ( FirstChild() && FirstChild()->ToText() ) {
1377 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001379 return XML_SUCCESS;
1380 }
1381 return XML_CAN_NOT_CONVERT_TEXT;
1382 }
1383 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001384}
1385
1386
MortenMacFly4ee49f12013-01-14 20:03:14 +01001387XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001388{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001389 if ( FirstChild() && FirstChild()->ToText() ) {
1390 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001392 return XML_SUCCESS;
1393 }
1394 return XML_CAN_NOT_CONVERT_TEXT;
1395 }
1396 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001397}
1398
1399
MortenMacFly4ee49f12013-01-14 20:03:14 +01001400XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001401{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001402 if ( FirstChild() && FirstChild()->ToText() ) {
1403 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001405 return XML_SUCCESS;
1406 }
1407 return XML_CAN_NOT_CONVERT_TEXT;
1408 }
1409 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001410}
1411
1412
MortenMacFly4ee49f12013-01-14 20:03:14 +01001413XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001414{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001415 if ( FirstChild() && FirstChild()->ToText() ) {
1416 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001417 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001418 return XML_SUCCESS;
1419 }
1420 return XML_CAN_NOT_CONVERT_TEXT;
1421 }
1422 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001423}
1424
1425
1426
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001427XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1428{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 XMLAttribute* last = 0;
1430 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001431 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1435 break;
1436 }
1437 }
1438 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001439 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1440 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001441 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001442 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001443 }
1444 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001445 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001446 }
1447 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001448 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 }
1450 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001451}
1452
1453
U-Stream\Leeae25a442012-02-17 17:48:16 -08001454void XMLElement::DeleteAttribute( const char* name )
1455{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001456 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001457 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001458 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1459 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001460 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001461 }
1462 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001463 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001464 }
1465 DELETE_ATTRIBUTE( a );
1466 break;
1467 }
1468 prev = a;
1469 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001470}
1471
1472
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001473char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001474{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001475 const char* start = p;
1476 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001477
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001478 // Read the attributes.
1479 while( p ) {
1480 p = XMLUtil::SkipWhiteSpace( p );
1481 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001482 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001483 return 0;
1484 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001485
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001486 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001487 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001488 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1489 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001490 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001491
Lee Thomason624d43f2012-10-12 10:58:48 -07001492 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 if ( !p || Attribute( attrib->Name() ) ) {
1494 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 return 0;
1497 }
1498 // There is a minor bug here: if the attribute in the source xml
1499 // document is duplicated, it will not be detected and the
1500 // attribute will be doubly added. However, tracking the 'prevAttribute'
1501 // avoids re-scanning the attribute list. Preferring performance for
1502 // now, may reconsider in the future.
1503 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 }
1506 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001507 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001508 }
1509 prevAttribute = attrib;
1510 }
1511 // end of the tag
1512 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001513 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return p+2; // done; sealed element.
1515 }
1516 // end of the tag
1517 else if ( *p == '>' ) {
1518 ++p;
1519 break;
1520 }
1521 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001522 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001523 return 0;
1524 }
1525 }
1526 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001527}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001528
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001529
Lee Thomason67d61312012-01-24 16:01:51 -08001530//
1531// <ele></ele>
1532// <ele>foo<b>bar</b></ele>
1533//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001534char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001535{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001536 // Read the element name.
1537 p = XMLUtil::SkipWhiteSpace( p );
1538 if ( !p ) {
1539 return 0;
1540 }
Lee Thomason67d61312012-01-24 16:01:51 -08001541
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 // The closing element is the </element> form. It is
1543 // parsed just like a regular element then deleted from
1544 // the DOM.
1545 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001546 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001547 ++p;
1548 }
Lee Thomason67d61312012-01-24 16:01:51 -08001549
Lee Thomason624d43f2012-10-12 10:58:48 -07001550 p = _value.ParseName( p );
1551 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001552 return 0;
1553 }
Lee Thomason67d61312012-01-24 16:01:51 -08001554
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001555 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001557 return p;
1558 }
Lee Thomason67d61312012-01-24 16:01:51 -08001559
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001560 p = XMLNode::ParseDeep( p, strPair );
1561 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001562}
1563
1564
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001565
1566XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1567{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001568 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001569 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001570 }
1571 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1572 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1573 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1574 }
1575 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001576}
1577
1578
1579bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1580{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001581 const XMLElement* other = compare->ToElement();
1582 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001583
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001584 const XMLAttribute* a=FirstAttribute();
1585 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001586
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001587 while ( a && b ) {
1588 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1589 return false;
1590 }
1591 a = a->Next();
1592 b = b->Next();
1593 }
1594 if ( a || b ) {
1595 // different count
1596 return false;
1597 }
1598 return true;
1599 }
1600 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001601}
1602
1603
Lee Thomason751da522012-02-10 08:50:51 -08001604bool XMLElement::Accept( XMLVisitor* visitor ) const
1605{
Lee Thomason624d43f2012-10-12 10:58:48 -07001606 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001607 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1608 if ( !node->Accept( visitor ) ) {
1609 break;
1610 }
1611 }
1612 }
1613 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001614}
Lee Thomason56bdd022012-02-09 18:16:58 -08001615
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001616
Lee Thomason3f57d272012-01-11 15:30:03 -08001617// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001618XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001619 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001620 _writeBOM( false ),
1621 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001622 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001623 _whitespace( whitespace ),
1624 _errorStr1( 0 ),
1625 _errorStr2( 0 ),
1626 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001627{
Lee Thomason624d43f2012-10-12 10:58:48 -07001628 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001629}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001630
1631
Lee Thomason3f57d272012-01-11 15:30:03 -08001632XMLDocument::~XMLDocument()
1633{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001634 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001635 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001636
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001637#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001638 _textPool.Trace( "text" );
1639 _elementPool.Trace( "element" );
1640 _commentPool.Trace( "comment" );
1641 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001642#endif
1643
Lee Thomason5b0a6772012-11-19 13:54:42 -08001644#ifdef DEBUG
1645 if ( Error() == false ) {
1646 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1647 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1648 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1649 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1650 }
1651#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001652}
1653
1654
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001655void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001656{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001657 DeleteChildren();
1658
Lee Thomason624d43f2012-10-12 10:58:48 -07001659 _errorID = XML_NO_ERROR;
1660 _errorStr1 = 0;
1661 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001662
Lee Thomason624d43f2012-10-12 10:58:48 -07001663 delete [] _charBuffer;
1664 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001665}
1666
Lee Thomason3f57d272012-01-11 15:30:03 -08001667
Lee Thomason2c85a712012-01-31 08:24:24 -08001668XMLElement* XMLDocument::NewElement( const char* name )
1669{
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1671 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 ele->SetName( name );
1673 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001674}
1675
1676
Lee Thomason1ff38e02012-02-14 18:18:16 -08001677XMLComment* XMLDocument::NewComment( const char* str )
1678{
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1680 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 comment->SetValue( str );
1682 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001683}
1684
1685
1686XMLText* XMLDocument::NewText( const char* str )
1687{
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1689 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001690 text->SetValue( str );
1691 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001692}
1693
1694
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001695XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1696{
Lee Thomason624d43f2012-10-12 10:58:48 -07001697 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1698 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1700 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001701}
1702
1703
1704XMLUnknown* XMLDocument::NewUnknown( const char* str )
1705{
Lee Thomason624d43f2012-10-12 10:58:48 -07001706 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1707 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001708 unk->SetValue( str );
1709 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001710}
1711
1712
Lee Thomason2fa81722012-11-09 12:37:46 -08001713XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001714{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001715 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001716 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001717
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1719 errno_t err = fopen_s(&fp, filename, "rb" );
1720 if ( !fp || err) {
1721#else
1722 fp = fopen( filename, "rb" );
1723 if ( !fp) {
1724#endif
1725 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001726 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001727 }
1728 LoadFile( fp );
1729 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001730 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001731}
1732
1733
Lee Thomason2fa81722012-11-09 12:37:46 -08001734XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001735{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001736 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001737
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001738 fseek( fp, 0, SEEK_SET );
1739 fgetc( fp );
1740 if ( ferror( fp ) != 0 ) {
1741 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1742 return _errorID;
1743 }
1744
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001745 fseek( fp, 0, SEEK_END );
1746 size_t size = ftell( fp );
1747 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001748
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001750 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001751 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001752 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001753
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 _charBuffer = new char[size+1];
1755 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001756 if ( read != size ) {
1757 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001758 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001759 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001760
Lee Thomason624d43f2012-10-12 10:58:48 -07001761 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001762
Lee Thomason624d43f2012-10-12 10:58:48 -07001763 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001764 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001765 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001766 if ( !p || !*p ) {
1767 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001768 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001770
Lee Thomason624d43f2012-10-12 10:58:48 -07001771 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1772 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001773}
1774
1775
Lee Thomason2fa81722012-11-09 12:37:46 -08001776XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001777{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001778 FILE* fp = 0;
1779#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1780 errno_t err = fopen_s(&fp, filename, "w" );
1781 if ( !fp || err) {
1782#else
1783 fp = fopen( filename, "w" );
1784 if ( !fp) {
1785#endif
1786 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001787 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 }
1789 SaveFile(fp, compact);
1790 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001791 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001792}
1793
1794
Lee Thomason2fa81722012-11-09 12:37:46 -08001795XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001796{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001797 XMLPrinter stream( fp, compact );
1798 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001799 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001800}
1801
Lee Thomason1ff38e02012-02-14 18:18:16 -08001802
Lee Thomason2fa81722012-11-09 12:37:46 -08001803XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001804{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001805 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001806 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001807
psi690ba072013-11-03 10:54:33 +09001808 if ( len == 0 ) {
1809 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1810 return _errorID;
1811 }
1812
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001813 if ( !p || !*p ) {
1814 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001815 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001816 }
1817 if ( len == (size_t)(-1) ) {
1818 len = strlen( p );
1819 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001820 _charBuffer = new char[ len+1 ];
1821 memcpy( _charBuffer, p, len );
1822 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001823
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001824 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001825 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001826 if ( !p || !*p ) {
1827 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001828 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001829 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001830
Thomas Roß1470edc2013-05-10 15:44:12 +02001831 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001832 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001833 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001834}
1835
1836
PKEuS1c5f99e2013-07-06 11:28:39 +02001837void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001838{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001839 XMLPrinter stdStreamer( stdout );
1840 if ( !streamer ) {
1841 streamer = &stdStreamer;
1842 }
1843 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001844}
1845
1846
Lee Thomason2fa81722012-11-09 12:37:46 -08001847void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001848{
Lee Thomason624d43f2012-10-12 10:58:48 -07001849 _errorID = error;
1850 _errorStr1 = str1;
1851 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001852}
1853
Lee Thomason5cae8972012-01-24 18:03:07 -08001854
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001855void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001856{
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 static const int LEN = 20;
1859 char buf1[LEN] = { 0 };
1860 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001861
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 if ( _errorStr1 ) {
1863 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001864 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001865 if ( _errorStr2 ) {
1866 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001867 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001868
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001869 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001872}
1873
1874
PKEuS1bfb9542013-08-04 13:51:17 +02001875XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 _elementJustOpened( false ),
1877 _firstElement( true ),
1878 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001879 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001880 _textDepth( -1 ),
1881 _processEntities( true ),
1882 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001883{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001884 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 _entityFlag[i] = false;
1886 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001887 }
1888 for( int i=0; i<NUM_ENTITIES; ++i ) {
1889 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1890 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001891 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001892 }
1893 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001894 _restrictedEntityFlag[(int)'&'] = true;
1895 _restrictedEntityFlag[(int)'<'] = true;
1896 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1897 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001898}
1899
1900
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001901void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001902{
1903 va_list va;
1904 va_start( va, format );
1905
Lee Thomason624d43f2012-10-12 10:58:48 -07001906 if ( _fp ) {
1907 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 }
1909 else {
1910 // This seems brutally complex. Haven't figured out a better
1911 // way on windows.
1912#ifdef _MSC_VER
1913 int len = -1;
1914 int expand = 1000;
1915 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001916 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001917 if ( len < 0 ) {
1918 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001919 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001920 }
1921 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001922 char* p = _buffer.PushArr( len ) - 1;
1923 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001924#else
1925 int len = vsnprintf( 0, 0, format, va );
1926 // Close out and re-start the va-args
1927 va_end( va );
1928 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001929 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 vsnprintf( p, len+1, format, va );
1931#endif
1932 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001933 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001934}
1935
1936
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001937void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001938{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001939 for( int i=0; i<depth; ++i ) {
1940 Print( " " );
1941 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001942}
1943
1944
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001945void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001946{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001947 // Look for runs of bytes between entities to print.
1948 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001950
Lee Thomason624d43f2012-10-12 10:58:48 -07001951 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001952 while ( *q ) {
1953 // Remember, char is sometimes signed. (How many times has that bitten me?)
1954 if ( *q > 0 && *q < ENTITY_RANGE ) {
1955 // Check for entities. If one is found, flush
1956 // the stream up until the entity, write the
1957 // entity, and keep looking.
1958 if ( flag[(unsigned)(*q)] ) {
1959 while ( p < q ) {
1960 Print( "%c", *p );
1961 ++p;
1962 }
1963 for( int i=0; i<NUM_ENTITIES; ++i ) {
1964 if ( entities[i].value == *q ) {
1965 Print( "&%s;", entities[i].pattern );
1966 break;
1967 }
1968 }
1969 ++p;
1970 }
1971 }
1972 ++q;
1973 }
1974 }
1975 // Flush the remaining string. This will be the entire
1976 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001977 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001978 Print( "%s", p );
1979 }
Lee Thomason857b8682012-01-25 17:50:25 -08001980}
1981
U-Stream\Leeae25a442012-02-17 17:48:16 -08001982
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001983void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001984{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001985 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001986 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 -07001987 Print( "%s", bom );
1988 }
1989 if ( writeDec ) {
1990 PushDeclaration( "xml version=\"1.0\"" );
1991 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001992}
1993
1994
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001995void XMLPrinter::OpenElement( const char* name )
Lee Thomason5cae8972012-01-24 18:03:07 -08001996{
Lee Thomason624d43f2012-10-12 10:58:48 -07001997 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 SealElement();
1999 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002000 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002001
Lee Thomason624d43f2012-10-12 10:58:48 -07002002 if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002004 }
2005 if ( !_compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002006 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002007 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002008
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002009 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002010 _elementJustOpened = true;
2011 _firstElement = false;
2012 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002013}
2014
2015
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002016void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002017{
Lee Thomason624d43f2012-10-12 10:58:48 -07002018 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002019 Print( " %s=\"", name );
2020 PrintString( value, false );
2021 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002022}
2023
2024
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002025void XMLPrinter::PushAttribute( const char* name, int v )
2026{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002027 char buf[BUF_SIZE];
2028 XMLUtil::ToStr( v, buf, BUF_SIZE );
2029 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002030}
2031
2032
2033void XMLPrinter::PushAttribute( const char* name, unsigned v )
2034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002035 char buf[BUF_SIZE];
2036 XMLUtil::ToStr( v, buf, BUF_SIZE );
2037 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002038}
2039
2040
2041void XMLPrinter::PushAttribute( const char* name, bool v )
2042{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002043 char buf[BUF_SIZE];
2044 XMLUtil::ToStr( v, buf, BUF_SIZE );
2045 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002046}
2047
2048
2049void XMLPrinter::PushAttribute( const char* name, double v )
2050{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002051 char buf[BUF_SIZE];
2052 XMLUtil::ToStr( v, buf, BUF_SIZE );
2053 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002054}
2055
2056
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002057void XMLPrinter::CloseElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002058{
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 --_depth;
2060 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002061
Lee Thomason624d43f2012-10-12 10:58:48 -07002062 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002063 Print( "/>" );
2064 }
2065 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07002066 if ( _textDepth < 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002068 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002069 }
2070 Print( "</%s>", name );
2071 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002072
Lee Thomason624d43f2012-10-12 10:58:48 -07002073 if ( _textDepth == _depth ) {
2074 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002075 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 if ( _depth == 0 && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 Print( "\n" );
2078 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002079 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002080}
2081
2082
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002083void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002084{
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002087}
2088
2089
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002090void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002091{
Lee Thomason624d43f2012-10-12 10:58:48 -07002092 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002093
Lee Thomason624d43f2012-10-12 10:58:48 -07002094 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002095 SealElement();
2096 }
2097 if ( cdata ) {
2098 Print( "<![CDATA[" );
2099 Print( "%s", text );
2100 Print( "]]>" );
2101 }
2102 else {
2103 PrintString( text, true );
2104 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002105}
2106
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002107void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002109 char buf[BUF_SIZE];
2110 XMLUtil::ToStr( value, buf, BUF_SIZE );
2111 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002112}
2113
2114
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002115void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002116{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002117 char buf[BUF_SIZE];
2118 XMLUtil::ToStr( value, buf, BUF_SIZE );
2119 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002120}
2121
2122
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002123void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002124{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002125 char buf[BUF_SIZE];
2126 XMLUtil::ToStr( value, buf, BUF_SIZE );
2127 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002128}
2129
2130
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002131void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 char buf[BUF_SIZE];
2134 XMLUtil::ToStr( value, buf, BUF_SIZE );
2135 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002136}
2137
2138
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002139void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 char buf[BUF_SIZE];
2142 XMLUtil::ToStr( value, buf, BUF_SIZE );
2143 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002144}
2145
Lee Thomason5cae8972012-01-24 18:03:07 -08002146
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002147void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002148{
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 SealElement();
2151 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002152 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002153 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002157 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002158}
Lee Thomason751da522012-02-10 08:50:51 -08002159
2160
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002161void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002162{
Lee Thomason624d43f2012-10-12 10:58:48 -07002163 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002164 SealElement();
2165 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002166 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002167 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002170 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002171 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002172}
2173
2174
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002175void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002176{
Lee Thomason624d43f2012-10-12 10:58:48 -07002177 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002178 SealElement();
2179 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002180 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002184 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002185 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002186}
2187
2188
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002189bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002190{
Lee Thomason624d43f2012-10-12 10:58:48 -07002191 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002192 if ( doc.HasBOM() ) {
2193 PushHeader( true, false );
2194 }
2195 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002196}
2197
2198
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002199bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002200{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002201 OpenElement( element.Name() );
2202 while ( attribute ) {
2203 PushAttribute( attribute->Name(), attribute->Value() );
2204 attribute = attribute->Next();
2205 }
2206 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002207}
2208
2209
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -08002210bool XMLPrinter::VisitExit( const XMLElement& )
Lee Thomason751da522012-02-10 08:50:51 -08002211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 CloseElement();
2213 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002214}
2215
2216
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002217bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002218{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 PushText( text.Value(), text.CData() );
2220 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002221}
2222
2223
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002224bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002226 PushComment( comment.Value() );
2227 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002228}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002229
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002230bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 PushDeclaration( declaration.Value() );
2233 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234}
2235
2236
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002237bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002238{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002239 PushUnknown( unknown.Value() );
2240 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002241}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002242
Lee Thomason685b8952012-11-12 13:00:06 -08002243} // namespace tinyxml2
2244