blob: beaeeb87a37e181200ad9138861c8da9e1bf43a8 [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
U-Lama\Lee560bd472011-12-28 19:42:49 -080024#include "tinyxml2.h"
25
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070026#include <new> // yes, this one new style header, is in the Android SDK.
Lee Thomasona9cf3f92012-10-11 16:56:51 -070027# ifdef ANDROID_NDK
28# include <stddef.h>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070029#else
Lee Thomasona9cf3f92012-10-11 16:56:51 -070030# include <cstddef>
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070031#endif
U-Lama\Lee560bd472011-12-28 19:42:49 -080032
Lee Thomasone4422302012-01-20 17:59:50 -080033static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
Lee Thomasonfde6a752012-01-14 18:08:12 -080034static const char LF = LINE_FEED;
35static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
36static const char CR = CARRIAGE_RETURN;
Lee Thomasone4422302012-01-20 17:59:50 -080037static const char SINGLE_QUOTE = '\'';
38static const char DOUBLE_QUOTE = '\"';
Lee Thomasonfde6a752012-01-14 18:08:12 -080039
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080040// Bunch of unicode info at:
41// http://www.unicode.org/faq/utf_bom.html
42// ef bb bf (Microsoft "lead bytes") - designates UTF-8
43
44static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
45static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
46static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -080047
48
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080049#define DELETE_NODE( node ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070050 if ( node ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070051 MemPool* pool = node->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 node->~XMLNode(); \
53 pool->Free( node ); \
54 } \
55 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -080056#define DELETE_ATTRIBUTE( attrib ) { \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070057 if ( attrib ) { \
Lee Thomason624d43f2012-10-12 10:58:48 -070058 MemPool* pool = attrib->_memPool; \
Lee Thomasona9cf3f92012-10-11 16:56:51 -070059 attrib->~XMLAttribute(); \
60 pool->Free( attrib ); \
61 } \
62 }
Lee Thomason43f59302012-02-06 18:18:11 -080063
Kevin Wojniak04c22d22012-11-08 11:02:22 -080064namespace tinyxml2
65{
66
Lee Thomason8ee79892012-01-25 17:44:30 -080067struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070068 const char* pattern;
69 int length;
70 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080071};
72
73static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070074static const Entity entities[NUM_ENTITIES] = {
75 { "quot", 4, DOUBLE_QUOTE },
76 { "amp", 3, '&' },
77 { "apos", 4, SINGLE_QUOTE },
78 { "lt", 2, '<' },
79 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080080};
81
Lee Thomasonfde6a752012-01-14 18:08:12 -080082
Lee Thomason1a1d4a72012-02-15 09:09:25 -080083StrPair::~StrPair()
84{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070085 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080086}
87
88
89void StrPair::Reset()
90{
Lee Thomason120b3a62012-10-12 10:06:59 -070091 if ( _flags & NEEDS_DELETE ) {
92 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070093 }
Lee Thomason120b3a62012-10-12 10:06:59 -070094 _flags = 0;
95 _start = 0;
96 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -080097}
98
99
100void StrPair::SetStr( const char* str, int flags )
101{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700102 Reset();
103 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700104 _start = new char[ len+1 ];
105 memcpy( _start, str, len+1 );
106 _end = _start + len;
107 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800108}
109
110
111char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
112{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700113 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800114
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700115 char* start = p; // fixme: hides a member
116 char endChar = *endTag;
117 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800118
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700119 // Inner loop of text parsing.
120 while ( *p ) {
121 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
122 Set( start, p, strFlags );
123 return p + length;
124 }
125 ++p;
126 }
127 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800128}
129
130
131char* StrPair::ParseName( char* p )
132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700133 char* start = p;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800134
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700135 if ( !start || !(*start) ) {
136 return 0;
137 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800138
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200139 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700140 ++p;
141 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800142
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700143 if ( p > start ) {
144 Set( start, p, 0 );
145 return p;
146 }
147 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800148}
149
150
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700151void StrPair::CollapseWhitespace()
152{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700153 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700154 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700155
Lee Thomason120b3a62012-10-12 10:06:59 -0700156 if ( _start && *_start ) {
157 char* p = _start; // the read pointer
158 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700159
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700160 while( *p ) {
161 if ( XMLUtil::IsWhiteSpace( *p )) {
162 p = XMLUtil::SkipWhiteSpace( p );
163 if ( *p == 0 ) {
164 break; // don't write to q; this trims the trailing space.
165 }
166 *q = ' ';
167 ++q;
168 }
169 *q = *p;
170 ++q;
171 ++p;
172 }
173 *q = 0;
174 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700175}
176
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800177
Lee Thomasone4422302012-01-20 17:59:50 -0800178const char* StrPair::GetStr()
179{
Lee Thomason120b3a62012-10-12 10:06:59 -0700180 if ( _flags & NEEDS_FLUSH ) {
181 *_end = 0;
182 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800183
Lee Thomason120b3a62012-10-12 10:06:59 -0700184 if ( _flags ) {
185 char* p = _start; // the read pointer
186 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800187
Lee Thomason120b3a62012-10-12 10:06:59 -0700188 while( p < _end ) {
189 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700190 // CR-LF pair becomes LF
191 // CR alone becomes LF
192 // LF-CR becomes LF
193 if ( *(p+1) == LF ) {
194 p += 2;
195 }
196 else {
197 ++p;
198 }
199 *q++ = LF;
200 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700201 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700202 if ( *(p+1) == CR ) {
203 p += 2;
204 }
205 else {
206 ++p;
207 }
208 *q++ = LF;
209 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700210 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 // Entities handled by tinyXML2:
212 // - special entities in the entity table [in/out]
213 // - numeric character reference [in]
214 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800215
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700216 if ( *(p+1) == '#' ) {
217 char buf[10] = { 0 };
218 int len;
219 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
220 for( int i=0; i<len; ++i ) {
221 *q++ = buf[i];
222 }
223 TIXMLASSERT( q <= p );
224 }
225 else {
226 int i=0;
227 for(; i<NUM_ENTITIES; ++i ) {
228 if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
229 && *(p+entities[i].length+1) == ';' ) {
230 // Found an entity convert;
231 *q = entities[i].value;
232 ++q;
233 p += entities[i].length + 2;
234 break;
235 }
236 }
237 if ( i == NUM_ENTITIES ) {
238 // fixme: treat as error?
239 ++p;
240 ++q;
241 }
242 }
243 }
244 else {
245 *q = *p;
246 ++p;
247 ++q;
248 }
249 }
250 *q = 0;
251 }
252 // The loop below has plenty going on, and this
253 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700254 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700255 CollapseWhitespace();
256 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700257 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700258 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700259 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800260}
261
Lee Thomason2c85a712012-01-31 08:24:24 -0800262
Lee Thomasone4422302012-01-20 17:59:50 -0800263
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800264
Lee Thomason56bdd022012-02-09 18:16:58 -0800265// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800266
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800267const char* XMLUtil::ReadBOM( const char* p, bool* bom )
268{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 *bom = false;
270 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
271 // Check for BOM:
272 if ( *(pu+0) == TIXML_UTF_LEAD_0
273 && *(pu+1) == TIXML_UTF_LEAD_1
274 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
275 *bom = true;
276 p += 3;
277 }
278 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800279}
280
281
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800282void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
283{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700284 const unsigned long BYTE_MASK = 0xBF;
285 const unsigned long BYTE_MARK = 0x80;
286 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800287
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700288 if (input < 0x80) {
289 *length = 1;
290 }
291 else if ( input < 0x800 ) {
292 *length = 2;
293 }
294 else if ( input < 0x10000 ) {
295 *length = 3;
296 }
297 else if ( input < 0x200000 ) {
298 *length = 4;
299 }
300 else {
301 *length = 0; // This code won't covert this correctly anyway.
302 return;
303 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800304
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700305 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800306
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700307 // Scary scary fall throughs.
308 switch (*length) {
309 case 4:
310 --output;
311 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
312 input >>= 6;
313 case 3:
314 --output;
315 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
316 input >>= 6;
317 case 2:
318 --output;
319 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
320 input >>= 6;
321 case 1:
322 --output;
323 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100324 default:
325 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700326 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800327}
328
329
330const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
331{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700332 // Presume an entity, and pull it out.
333 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800334
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700335 if ( *(p+1) == '#' && *(p+2) ) {
336 unsigned long ucs = 0;
337 ptrdiff_t delta = 0;
338 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800339
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700340 if ( *(p+2) == 'x' ) {
341 // Hexadecimal.
342 if ( !*(p+3) ) {
343 return 0;
344 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 const char* q = p+3;
347 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800348
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700349 if ( !q || !*q ) {
350 return 0;
351 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800352
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700353 delta = q-p;
354 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800355
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700356 while ( *q != 'x' ) {
357 if ( *q >= '0' && *q <= '9' ) {
358 ucs += mult * (*q - '0');
359 }
360 else if ( *q >= 'a' && *q <= 'f' ) {
361 ucs += mult * (*q - 'a' + 10);
362 }
363 else if ( *q >= 'A' && *q <= 'F' ) {
364 ucs += mult * (*q - 'A' + 10 );
365 }
366 else {
367 return 0;
368 }
369 mult *= 16;
370 --q;
371 }
372 }
373 else {
374 // Decimal.
375 if ( !*(p+2) ) {
376 return 0;
377 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800378
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700379 const char* q = p+2;
380 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800381
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700382 if ( !q || !*q ) {
383 return 0;
384 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800385
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700386 delta = q-p;
387 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800388
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700389 while ( *q != '#' ) {
390 if ( *q >= '0' && *q <= '9' ) {
391 ucs += mult * (*q - '0');
392 }
393 else {
394 return 0;
395 }
396 mult *= 10;
397 --q;
398 }
399 }
400 // convert the UCS to UTF-8
401 ConvertUTF32ToUTF8( ucs, value, length );
402 return p + delta + 1;
403 }
404 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800405}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800406
407
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700408void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700410 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700411}
412
413
414void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
415{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700416 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700417}
418
419
420void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
421{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700422 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700423}
424
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800425/*
426 ToStr() of a number is a very tricky topic.
427 https://github.com/leethomason/tinyxml2/issues/106
428*/
Lee Thomason21be8822012-07-15 17:27:22 -0700429void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
430{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800431 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700432}
433
434
435void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
436{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800437 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700438}
439
440
441bool XMLUtil::ToInt( const char* str, int* value )
442{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700443 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
444 return true;
445 }
446 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700447}
448
Uli Kusterer664d0562014-01-21 12:24:47 +0100449
Lee Thomason21be8822012-07-15 17:27:22 -0700450bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700452 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
453 return true;
454 }
455 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700456}
457
458bool XMLUtil::ToBool( const char* str, bool* value )
459{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700460 int ival = 0;
461 if ( ToInt( str, &ival )) {
462 *value = (ival==0) ? false : true;
463 return true;
464 }
465 if ( StringEqual( str, "true" ) ) {
466 *value = true;
467 return true;
468 }
469 else if ( StringEqual( str, "false" ) ) {
470 *value = false;
471 return true;
472 }
473 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700474}
475
476
477bool XMLUtil::ToFloat( const char* str, float* value )
478{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700479 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
480 return true;
481 }
482 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700483}
484
485bool XMLUtil::ToDouble( const char* str, double* value )
486{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700487 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
488 return true;
489 }
490 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700491}
492
493
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700494char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800495{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700496 XMLNode* returnNode = 0;
497 char* start = p;
498 p = XMLUtil::SkipWhiteSpace( p );
499 if( !p || !*p ) {
500 return p;
501 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800502
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700503 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800504 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700505 static const char* xmlHeader = { "<?" };
506 static const char* commentHeader = { "<!--" };
507 static const char* dtdHeader = { "<!" };
508 static const char* cdataHeader = { "<![CDATA[" };
509 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800510
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700511 static const int xmlHeaderLen = 2;
512 static const int commentHeaderLen = 4;
513 static const int dtdHeaderLen = 2;
514 static const int cdataHeaderLen = 9;
515 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800516
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800517#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800518#pragma warning ( push )
519#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800520#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700521 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
522 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800523#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800524#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800525#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700526 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700527 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
528 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700529 p += xmlHeaderLen;
530 }
531 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700532 returnNode = new (_commentPool.Alloc()) XMLComment( this );
533 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700534 p += commentHeaderLen;
535 }
536 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700537 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700538 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700539 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 p += cdataHeaderLen;
541 text->SetCData( true );
542 }
543 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700544 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
545 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 p += dtdHeaderLen;
547 }
548 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700549 returnNode = new (_elementPool.Alloc()) XMLElement( this );
550 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 p += elementHeaderLen;
552 }
553 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700554 returnNode = new (_textPool.Alloc()) XMLText( this );
555 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700556 p = start; // Back it up, all the text counts.
557 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800558
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700559 *node = returnNode;
560 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800561}
562
563
Lee Thomason751da522012-02-10 08:50:51 -0800564bool XMLDocument::Accept( XMLVisitor* visitor ) const
565{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 if ( visitor->VisitEnter( *this ) ) {
567 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
568 if ( !node->Accept( visitor ) ) {
569 break;
570 }
571 }
572 }
573 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800574}
Lee Thomason56bdd022012-02-09 18:16:58 -0800575
576
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800577// --------- XMLNode ----------- //
578
579XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700580 _document( doc ),
581 _parent( 0 ),
582 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200583 _prev( 0 ), _next( 0 ),
Uli Kusterer593a33d2014-02-01 12:48:51 +0100584 _memPool( 0 ),
585 _forceCompactMode( false )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800586{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800587}
588
589
590XMLNode::~XMLNode()
591{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700592 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700593 if ( _parent ) {
594 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700595 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800596}
597
Michael Daumling21626882013-10-22 17:03:37 +0200598const char* XMLNode::Value() const
599{
600 return _value.GetStr();
601}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800602
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800603void XMLNode::SetValue( const char* str, bool staticMem )
604{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700605 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700606 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 }
608 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700609 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800611}
612
613
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800614void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800615{
Lee Thomason624d43f2012-10-12 10:58:48 -0700616 while( _firstChild ) {
617 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700618 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700619
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 DELETE_NODE( node );
621 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700622 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800623}
624
625
626void XMLNode::Unlink( XMLNode* child )
627{
Lee Thomason624d43f2012-10-12 10:58:48 -0700628 if ( child == _firstChild ) {
629 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700630 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 if ( child == _lastChild ) {
632 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700633 }
Lee Thomasond923c672012-01-23 08:44:25 -0800634
Lee Thomason624d43f2012-10-12 10:58:48 -0700635 if ( child->_prev ) {
636 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700638 if ( child->_next ) {
639 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700640 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700641 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800642}
643
644
U-Stream\Leeae25a442012-02-17 17:48:16 -0800645void XMLNode::DeleteChild( XMLNode* node )
646{
Lee Thomason624d43f2012-10-12 10:58:48 -0700647 TIXMLASSERT( node->_parent == this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700648 DELETE_NODE( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800649}
650
651
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800652XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
653{
Michael Daumlinged523282013-10-23 07:47:29 +0200654 if (addThis->_document != _document)
655 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700656
Michael Daumlinged523282013-10-23 07:47:29 +0200657 if (addThis->_parent)
658 addThis->_parent->Unlink( addThis );
659 else
660 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700661
Lee Thomason624d43f2012-10-12 10:58:48 -0700662 if ( _lastChild ) {
663 TIXMLASSERT( _firstChild );
664 TIXMLASSERT( _lastChild->_next == 0 );
665 _lastChild->_next = addThis;
666 addThis->_prev = _lastChild;
667 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800668
Lee Thomason624d43f2012-10-12 10:58:48 -0700669 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700670 }
671 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700672 TIXMLASSERT( _firstChild == 0 );
673 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800674
Lee Thomason624d43f2012-10-12 10:58:48 -0700675 addThis->_prev = 0;
676 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700677 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700678 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700679 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680}
681
682
Lee Thomason1ff38e02012-02-14 18:18:16 -0800683XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
684{
Michael Daumlinged523282013-10-23 07:47:29 +0200685 if (addThis->_document != _document)
686 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700687
Michael Daumlinged523282013-10-23 07:47:29 +0200688 if (addThis->_parent)
689 addThis->_parent->Unlink( addThis );
690 else
691 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700692
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 if ( _firstChild ) {
694 TIXMLASSERT( _lastChild );
695 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800696
Lee Thomason624d43f2012-10-12 10:58:48 -0700697 _firstChild->_prev = addThis;
698 addThis->_next = _firstChild;
699 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800700
Lee Thomason624d43f2012-10-12 10:58:48 -0700701 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700702 }
703 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700704 TIXMLASSERT( _lastChild == 0 );
705 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800706
Lee Thomason624d43f2012-10-12 10:58:48 -0700707 addThis->_prev = 0;
708 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700709 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700710 addThis->_parent = this;
Michael Daumlinged523282013-10-23 07:47:29 +0200711 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800712}
713
714
715XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
716{
Michael Daumlinged523282013-10-23 07:47:29 +0200717 if (addThis->_document != _document)
718 return 0;
Lee Thomason3b7927e2013-10-26 21:50:46 -0700719
Lee Thomason624d43f2012-10-12 10:58:48 -0700720 TIXMLASSERT( afterThis->_parent == this );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700721
Lee Thomason624d43f2012-10-12 10:58:48 -0700722 if ( afterThis->_parent != this ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700723 return 0;
724 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800725
Lee Thomason624d43f2012-10-12 10:58:48 -0700726 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700727 // The last node or the only node.
728 return InsertEndChild( addThis );
729 }
Michael Daumlinged523282013-10-23 07:47:29 +0200730 if (addThis->_parent)
731 addThis->_parent->Unlink( addThis );
732 else
733 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 addThis->_prev = afterThis;
735 addThis->_next = afterThis->_next;
736 afterThis->_next->_prev = addThis;
737 afterThis->_next = addThis;
738 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700739 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800740}
741
742
743
744
Lee Thomason56bdd022012-02-09 18:16:58 -0800745const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800746{
Lee Thomason624d43f2012-10-12 10:58:48 -0700747 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700748 XMLElement* element = node->ToElement();
749 if ( element ) {
750 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
751 return element;
752 }
753 }
754 }
755 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800756}
757
758
Lee Thomason56bdd022012-02-09 18:16:58 -0800759const XMLElement* XMLNode::LastChildElement( const char* value ) const
760{
Lee Thomason624d43f2012-10-12 10:58:48 -0700761 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700762 XMLElement* element = node->ToElement();
763 if ( element ) {
764 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
765 return element;
766 }
767 }
768 }
769 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800770}
771
772
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800773const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
774{
Lee Thomason624d43f2012-10-12 10:58:48 -0700775 for( XMLNode* element=this->_next; element; element = element->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 if ( element->ToElement()
777 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
778 return element->ToElement();
779 }
780 }
781 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800782}
783
784
785const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
786{
Lee Thomason624d43f2012-10-12 10:58:48 -0700787 for( XMLNode* element=_prev; element; element = element->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700788 if ( element->ToElement()
789 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
790 return element->ToElement();
791 }
792 }
793 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800794}
795
796
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800797char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800798{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700799 // This is a recursive method, but thinking about it "at the current level"
800 // it is a pretty simple flat list:
801 // <foo/>
802 // <!-- comment -->
803 //
804 // With a special case:
805 // <foo>
806 // </foo>
807 // <!-- comment -->
808 //
809 // Where the closing element (/foo) *must* be the next thing after the opening
810 // element, and the names must match. BUT the tricky bit is that the closing
811 // element will be read by the child.
812 //
813 // 'endTag' is the end tag for this node, it is returned by a call to a child.
814 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800815
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700816 while( p && *p ) {
817 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800818
Lee Thomason624d43f2012-10-12 10:58:48 -0700819 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700820 if ( p == 0 || node == 0 ) {
821 break;
822 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800823
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700824 StrPair endTag;
825 p = node->ParseDeep( p, &endTag );
826 if ( !p ) {
827 DELETE_NODE( node );
828 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700829 if ( !_document->Error() ) {
830 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700831 }
832 break;
833 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800834
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700835 // We read the end tag. Return it to the parent.
836 if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
837 if ( parentEnd ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700838 *parentEnd = static_cast<XMLElement*>(node)->_value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700839 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800840 node->_memPool->SetTracked(); // created and then immediately deleted.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700841 DELETE_NODE( node );
842 return p;
843 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800844
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700845 // Handle an end tag returned to this level.
846 // And handle a bunch of annoying errors.
847 XMLElement* ele = node->ToElement();
848 if ( ele ) {
849 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700850 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700851 p = 0;
852 }
853 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700854 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700855 p = 0;
856 }
857 else if ( !endTag.Empty() ) {
858 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700860 p = 0;
861 }
862 }
863 }
864 if ( p == 0 ) {
865 DELETE_NODE( node );
866 node = 0;
867 }
868 if ( node ) {
869 this->InsertEndChild( node );
870 }
871 }
872 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800873}
874
Lee Thomason5492a1c2012-01-23 15:32:10 -0800875// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800876char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800877{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 const char* start = p;
879 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700880 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700881 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700882 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700883 }
884 return p;
885 }
886 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700887 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
888 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 flags |= StrPair::COLLAPSE_WHITESPACE;
890 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700891
Lee Thomason624d43f2012-10-12 10:58:48 -0700892 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700893 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700894 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 if ( p && *p ) {
897 return p-1;
898 }
899 }
900 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800901}
902
903
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800904XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
905{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700906 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700907 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700908 }
909 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
910 text->SetCData( this->CData() );
911 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800912}
913
914
915bool XMLText::ShallowEqual( const XMLNode* compare ) const
916{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700917 return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800918}
919
920
Lee Thomason56bdd022012-02-09 18:16:58 -0800921bool XMLText::Accept( XMLVisitor* visitor ) const
922{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800924}
925
926
Lee Thomason3f57d272012-01-11 15:30:03 -0800927// --------- XMLComment ---------- //
928
Lee Thomasone4422302012-01-20 17:59:50 -0800929XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800930{
931}
932
933
Lee Thomasonce0763e2012-01-11 15:43:54 -0800934XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800935{
Lee Thomason3f57d272012-01-11 15:30:03 -0800936}
937
938
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800939char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800940{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700941 // Comment parses as text.
942 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700943 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700944 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700945 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700946 }
947 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800948}
949
950
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800951XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
952{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700953 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700954 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700955 }
956 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
957 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800958}
959
960
961bool XMLComment::ShallowEqual( const XMLNode* compare ) const
962{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700963 return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800964}
965
966
Lee Thomason751da522012-02-10 08:50:51 -0800967bool XMLComment::Accept( XMLVisitor* visitor ) const
968{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700969 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800970}
Lee Thomason56bdd022012-02-09 18:16:58 -0800971
972
Lee Thomason50f97b22012-02-11 16:33:40 -0800973// --------- XMLDeclaration ---------- //
974
975XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
976{
977}
978
979
980XMLDeclaration::~XMLDeclaration()
981{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700982 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -0800983}
984
985
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800986char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -0800987{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 // Declaration parses as text.
989 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700990 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700991 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700992 _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700993 }
994 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -0800995}
996
997
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800998XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
999{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001000 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001001 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001002 }
1003 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1004 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001005}
1006
1007
1008bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1009{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001010 return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001011}
1012
1013
1014
Lee Thomason50f97b22012-02-11 16:33:40 -08001015bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1016{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001017 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001018}
1019
1020// --------- XMLUnknown ---------- //
1021
1022XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1023{
1024}
1025
1026
1027XMLUnknown::~XMLUnknown()
1028{
1029}
1030
1031
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001032char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001033{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001034 // Unknown parses as text.
1035 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001036
Lee Thomason624d43f2012-10-12 10:58:48 -07001037 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001038 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001039 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001040 }
1041 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001042}
1043
1044
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001045XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1046{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001047 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001048 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001049 }
1050 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1051 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001052}
1053
1054
1055bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1056{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001057 return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001058}
1059
1060
Lee Thomason50f97b22012-02-11 16:33:40 -08001061bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1062{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001063 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001064}
1065
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001066// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001067
1068const char* XMLAttribute::Name() const
1069{
1070 return _name.GetStr();
1071}
1072
1073const char* XMLAttribute::Value() const
1074{
1075 return _value.GetStr();
1076}
1077
Lee Thomason6f381b72012-03-02 12:59:39 -08001078char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001079{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001080 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001081 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001082 if ( !p || !*p ) {
1083 return 0;
1084 }
Lee Thomason22aead12012-01-23 13:29:35 -08001085
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001086 // Skip white space before =
1087 p = XMLUtil::SkipWhiteSpace( p );
1088 if ( !p || *p != '=' ) {
1089 return 0;
1090 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001091
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001092 ++p; // move up to opening quote
1093 p = XMLUtil::SkipWhiteSpace( p );
1094 if ( *p != '\"' && *p != '\'' ) {
1095 return 0;
1096 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001097
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001098 char endTag[2] = { *p, 0 };
1099 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001100
Lee Thomason624d43f2012-10-12 10:58:48 -07001101 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001102 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001103}
1104
1105
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001106void XMLAttribute::SetName( const char* n )
1107{
Lee Thomason624d43f2012-10-12 10:58:48 -07001108 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001109}
1110
1111
Lee Thomason2fa81722012-11-09 12:37:46 -08001112XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001113{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001114 if ( XMLUtil::ToInt( Value(), value )) {
1115 return XML_NO_ERROR;
1116 }
1117 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001118}
1119
1120
Lee Thomason2fa81722012-11-09 12:37:46 -08001121XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001122{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001123 if ( XMLUtil::ToUnsigned( Value(), value )) {
1124 return XML_NO_ERROR;
1125 }
1126 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001127}
1128
1129
Lee Thomason2fa81722012-11-09 12:37:46 -08001130XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001132 if ( XMLUtil::ToBool( Value(), value )) {
1133 return XML_NO_ERROR;
1134 }
1135 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001136}
1137
1138
Lee Thomason2fa81722012-11-09 12:37:46 -08001139XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001140{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001141 if ( XMLUtil::ToFloat( Value(), value )) {
1142 return XML_NO_ERROR;
1143 }
1144 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001145}
1146
1147
Lee Thomason2fa81722012-11-09 12:37:46 -08001148XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001149{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001150 if ( XMLUtil::ToDouble( Value(), value )) {
1151 return XML_NO_ERROR;
1152 }
1153 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001154}
1155
1156
1157void XMLAttribute::SetAttribute( const char* v )
1158{
Lee Thomason624d43f2012-10-12 10:58:48 -07001159 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160}
1161
1162
Lee Thomason1ff38e02012-02-14 18:18:16 -08001163void XMLAttribute::SetAttribute( int v )
1164{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001165 char buf[BUF_SIZE];
1166 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001167 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001168}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001169
1170
1171void XMLAttribute::SetAttribute( unsigned v )
1172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001173 char buf[BUF_SIZE];
1174 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001175 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001176}
1177
1178
1179void XMLAttribute::SetAttribute( bool v )
1180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001181 char buf[BUF_SIZE];
1182 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001183 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001184}
1185
1186void XMLAttribute::SetAttribute( double v )
1187{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001188 char buf[BUF_SIZE];
1189 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001190 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001191}
1192
1193void XMLAttribute::SetAttribute( float v )
1194{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001195 char buf[BUF_SIZE];
1196 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001197 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001198}
1199
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001200
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001201// --------- XMLElement ---------- //
1202XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001203 _closingType( 0 ),
1204 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001205{
1206}
1207
1208
1209XMLElement::~XMLElement()
1210{
Lee Thomason624d43f2012-10-12 10:58:48 -07001211 while( _rootAttribute ) {
1212 XMLAttribute* next = _rootAttribute->_next;
1213 DELETE_ATTRIBUTE( _rootAttribute );
1214 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001215 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001216}
1217
1218
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001219XMLAttribute* XMLElement::FindAttribute( const char* name )
1220{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001221 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001222 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001223 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1224 return a;
1225 }
1226 }
1227 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001228}
1229
1230
1231const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1232{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001233 XMLAttribute* a = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001234 for( a=_rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001235 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1236 return a;
1237 }
1238 }
1239 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001240}
1241
1242
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001243const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001244{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001245 const XMLAttribute* a = FindAttribute( name );
1246 if ( !a ) {
1247 return 0;
1248 }
1249 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1250 return a->Value();
1251 }
1252 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001253}
1254
1255
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001256const char* XMLElement::GetText() const
1257{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001258 if ( FirstChild() && FirstChild()->ToText() ) {
1259 return FirstChild()->ToText()->Value();
1260 }
1261 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001262}
1263
1264
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001265void XMLElement::SetText( const char* inText )
1266{
Uli Kusterer869bb592014-01-21 01:36:16 +01001267 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001268 FirstChild()->SetValue( inText );
1269 else {
1270 XMLText* theText = GetDocument()->NewText( inText );
1271 InsertFirstChild( theText );
1272 }
1273}
1274
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001275
Lee Thomason5bb2d802014-01-24 10:42:57 -08001276void XMLElement::SetText( int v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001277{
1278 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001279 XMLUtil::ToStr( v, buf, BUF_SIZE );
1280 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001281}
1282
1283
Lee Thomason5bb2d802014-01-24 10:42:57 -08001284void XMLElement::SetText( unsigned v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001285{
1286 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001287 XMLUtil::ToStr( v, buf, BUF_SIZE );
1288 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001289}
1290
1291
Lee Thomason5bb2d802014-01-24 10:42:57 -08001292void XMLElement::SetText( bool v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001293{
1294 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001295 XMLUtil::ToStr( v, buf, BUF_SIZE );
1296 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001297}
1298
1299
Lee Thomason5bb2d802014-01-24 10:42:57 -08001300void XMLElement::SetText( float v )
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001301{
1302 char buf[BUF_SIZE];
Lee Thomason5bb2d802014-01-24 10:42:57 -08001303 XMLUtil::ToStr( v, buf, BUF_SIZE );
1304 SetText( buf );
Uli Kustererdcefa0e2014-01-21 01:36:41 +01001305}
1306
Lee Thomason5bb2d802014-01-24 10:42:57 -08001307
Uli Kusterer35ce3092014-01-25 03:37:16 +01001308void XMLElement::SetText( double v )
1309{
1310 char buf[BUF_SIZE];
1311 XMLUtil::ToStr( v, buf, BUF_SIZE );
1312 SetText( buf );
1313}
1314
1315
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001316void XMLElement::SetBoolFirstChild( bool inBool )
1317{
Uli Kusterer07ac7622014-02-01 15:06:50 +01001318 XMLElement * theBoolElem = FirstChild() ? FirstChild()->ToElement() : NULL;
1319 if( theBoolElem
1320 && (strcmp(theBoolElem->Value(),"true") == 0 || strcmp(theBoolElem->Value(),"false") == 0) ) {
1321 theBoolElem->SetValue( inBool ? "true" : "false" );
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001322 }
1323 else if( !FirstChild() ) {
Uli Kusterer07ac7622014-02-01 15:06:50 +01001324 theBoolElem = GetDocument()->NewElement( inBool ? "true" : "false" );
1325 InsertFirstChild( theBoolElem );
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001326 }
1327}
1328
1329
Uli Kustererff8e2042014-01-21 02:53:47 +01001330XMLError XMLElement::QueryBoolFirstChild( bool *outBool )
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001331{
Uli Kustererff8e2042014-01-21 02:53:47 +01001332 if ( FirstChild() )
1333 {
1334 if ( FirstChild()->ToElement() )
1335 {
1336 bool isTrue = strcmp( FirstChild()->Value(), "true" ) == 0;
1337 bool isFalse = strcmp( FirstChild()->Value(), "false" ) == 0;
1338 if( !isTrue && !isFalse )
1339 return XML_CAN_NOT_CONVERT_TEXT;
1340
1341 *outBool = isTrue;
1342 return XML_SUCCESS;
1343 }
1344 else
1345 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001346 }
Uli Kustererff8e2042014-01-21 02:53:47 +01001347 else
1348 return XML_NO_ELEMENT_NODE;
Uli Kustererc1c20bb2014-01-21 02:23:20 +01001349}
1350
1351
MortenMacFly4ee49f12013-01-14 20:03:14 +01001352XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001353{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001354 if ( FirstChild() && FirstChild()->ToText() ) {
1355 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001356 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001357 return XML_SUCCESS;
1358 }
1359 return XML_CAN_NOT_CONVERT_TEXT;
1360 }
1361 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001362}
1363
1364
MortenMacFly4ee49f12013-01-14 20:03:14 +01001365XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001366{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001367 if ( FirstChild() && FirstChild()->ToText() ) {
1368 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001369 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001370 return XML_SUCCESS;
1371 }
1372 return XML_CAN_NOT_CONVERT_TEXT;
1373 }
1374 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001375}
1376
1377
MortenMacFly4ee49f12013-01-14 20:03:14 +01001378XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001379{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001380 if ( FirstChild() && FirstChild()->ToText() ) {
1381 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001382 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001383 return XML_SUCCESS;
1384 }
1385 return XML_CAN_NOT_CONVERT_TEXT;
1386 }
1387 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001388}
1389
1390
MortenMacFly4ee49f12013-01-14 20:03:14 +01001391XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001392{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001393 if ( FirstChild() && FirstChild()->ToText() ) {
1394 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001395 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001396 return XML_SUCCESS;
1397 }
1398 return XML_CAN_NOT_CONVERT_TEXT;
1399 }
1400 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001401}
1402
1403
MortenMacFly4ee49f12013-01-14 20:03:14 +01001404XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001405{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001406 if ( FirstChild() && FirstChild()->ToText() ) {
1407 const char* t = FirstChild()->ToText()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001408 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001409 return XML_SUCCESS;
1410 }
1411 return XML_CAN_NOT_CONVERT_TEXT;
1412 }
1413 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001414}
1415
1416
1417
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001418XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1419{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001420 XMLAttribute* last = 0;
1421 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001422 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001423 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001424 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001425 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1426 break;
1427 }
1428 }
1429 if ( !attrib ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001430 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1431 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001432 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001433 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001434 }
1435 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001436 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 }
1438 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001439 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001440 }
1441 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001442}
1443
1444
U-Stream\Leeae25a442012-02-17 17:48:16 -08001445void XMLElement::DeleteAttribute( const char* name )
1446{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001447 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001448 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001449 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1450 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001451 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 }
1453 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001454 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001455 }
1456 DELETE_ATTRIBUTE( a );
1457 break;
1458 }
1459 prev = a;
1460 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001461}
1462
1463
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001464char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001465{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001466 const char* start = p;
1467 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001468
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001469 // Read the attributes.
1470 while( p ) {
1471 p = XMLUtil::SkipWhiteSpace( p );
1472 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001473 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 return 0;
1475 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001476
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001477 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001478 if (XMLUtil::IsNameStartChar( *p ) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001479 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1480 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001481 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001482
Lee Thomason624d43f2012-10-12 10:58:48 -07001483 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001484 if ( !p || Attribute( attrib->Name() ) ) {
1485 DELETE_ATTRIBUTE( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001486 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001487 return 0;
1488 }
1489 // There is a minor bug here: if the attribute in the source xml
1490 // document is duplicated, it will not be detected and the
1491 // attribute will be doubly added. However, tracking the 'prevAttribute'
1492 // avoids re-scanning the attribute list. Preferring performance for
1493 // now, may reconsider in the future.
1494 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001495 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001496 }
1497 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001498 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001499 }
1500 prevAttribute = attrib;
1501 }
1502 // end of the tag
1503 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 return p+2; // done; sealed element.
1506 }
1507 // end of the tag
1508 else if ( *p == '>' ) {
1509 ++p;
1510 break;
1511 }
1512 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001513 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001514 return 0;
1515 }
1516 }
1517 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001518}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001519
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001520
Lee Thomason67d61312012-01-24 16:01:51 -08001521//
1522// <ele></ele>
1523// <ele>foo<b>bar</b></ele>
1524//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001525char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001526{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001527 // Read the element name.
1528 p = XMLUtil::SkipWhiteSpace( p );
1529 if ( !p ) {
1530 return 0;
1531 }
Lee Thomason67d61312012-01-24 16:01:51 -08001532
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001533 // The closing element is the </element> form. It is
1534 // parsed just like a regular element then deleted from
1535 // the DOM.
1536 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001537 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001538 ++p;
1539 }
Lee Thomason67d61312012-01-24 16:01:51 -08001540
Lee Thomason624d43f2012-10-12 10:58:48 -07001541 p = _value.ParseName( p );
1542 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001543 return 0;
1544 }
Lee Thomason67d61312012-01-24 16:01:51 -08001545
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001546 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001547 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 return p;
1549 }
Lee Thomason67d61312012-01-24 16:01:51 -08001550
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001551 p = XMLNode::ParseDeep( p, strPair );
1552 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001553}
1554
1555
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001556
1557XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1558{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001559 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001560 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 }
1562 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1563 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1564 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1565 }
1566 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001567}
1568
1569
1570bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1571{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001572 const XMLElement* other = compare->ToElement();
1573 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001574
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001575 const XMLAttribute* a=FirstAttribute();
1576 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001577
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001578 while ( a && b ) {
1579 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1580 return false;
1581 }
1582 a = a->Next();
1583 b = b->Next();
1584 }
1585 if ( a || b ) {
1586 // different count
1587 return false;
1588 }
1589 return true;
1590 }
1591 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001592}
1593
1594
Lee Thomason751da522012-02-10 08:50:51 -08001595bool XMLElement::Accept( XMLVisitor* visitor ) const
1596{
Lee Thomason624d43f2012-10-12 10:58:48 -07001597 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001598 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1599 if ( !node->Accept( visitor ) ) {
1600 break;
1601 }
1602 }
1603 }
1604 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001605}
Lee Thomason56bdd022012-02-09 18:16:58 -08001606
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001607
Lee Thomason3f57d272012-01-11 15:30:03 -08001608// --------- XMLDocument ----------- //
Lee Thomason624d43f2012-10-12 10:58:48 -07001609XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001610 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001611 _writeBOM( false ),
1612 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001613 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 _whitespace( whitespace ),
1615 _errorStr1( 0 ),
1616 _errorStr2( 0 ),
1617 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001618{
Lee Thomason624d43f2012-10-12 10:58:48 -07001619 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001620}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001621
1622
Lee Thomason3f57d272012-01-11 15:30:03 -08001623XMLDocument::~XMLDocument()
1624{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001625 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -07001626 delete [] _charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001627
Lee Thomason (grinliz)61cea672013-02-01 19:13:13 -08001628#if 0
Lee Thomason (grinliz)ac83b4e2013-02-01 09:02:34 -08001629 _textPool.Trace( "text" );
1630 _elementPool.Trace( "element" );
1631 _commentPool.Trace( "comment" );
1632 _attributePool.Trace( "attribute" );
Lee Thomasone9ecdab2012-02-13 18:11:20 -08001633#endif
1634
Lee Thomason5b0a6772012-11-19 13:54:42 -08001635#ifdef DEBUG
1636 if ( Error() == false ) {
1637 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1638 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1639 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1640 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1641 }
1642#endif
Lee Thomason3f57d272012-01-11 15:30:03 -08001643}
1644
1645
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001646void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001647{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001648 DeleteChildren();
1649
Lee Thomason624d43f2012-10-12 10:58:48 -07001650 _errorID = XML_NO_ERROR;
1651 _errorStr1 = 0;
1652 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001653
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 delete [] _charBuffer;
1655 _charBuffer = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001656}
1657
Lee Thomason3f57d272012-01-11 15:30:03 -08001658
Lee Thomason2c85a712012-01-31 08:24:24 -08001659XMLElement* XMLDocument::NewElement( const char* name )
1660{
Lee Thomason624d43f2012-10-12 10:58:48 -07001661 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1662 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001663 ele->SetName( name );
1664 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001665}
1666
1667
Lee Thomason1ff38e02012-02-14 18:18:16 -08001668XMLComment* XMLDocument::NewComment( const char* str )
1669{
Lee Thomason624d43f2012-10-12 10:58:48 -07001670 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1671 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001672 comment->SetValue( str );
1673 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001674}
1675
1676
1677XMLText* XMLDocument::NewText( const char* str )
1678{
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1680 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001681 text->SetValue( str );
1682 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001683}
1684
1685
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001686XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1687{
Lee Thomason624d43f2012-10-12 10:58:48 -07001688 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1689 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001690 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1691 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001692}
1693
1694
1695XMLUnknown* XMLDocument::NewUnknown( const char* str )
1696{
Lee Thomason624d43f2012-10-12 10:58:48 -07001697 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1698 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001699 unk->SetValue( str );
1700 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001701}
1702
1703
Lee Thomason2fa81722012-11-09 12:37:46 -08001704XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001705{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001706 Clear();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001707 FILE* fp = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001708
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1710 errno_t err = fopen_s(&fp, filename, "rb" );
1711 if ( !fp || err) {
1712#else
1713 fp = fopen( filename, "rb" );
1714 if ( !fp) {
1715#endif
1716 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001717 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001718 }
1719 LoadFile( fp );
1720 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001721 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001722}
1723
1724
Lee Thomason2fa81722012-11-09 12:37:46 -08001725XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001726{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001727 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001728
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001729 fseek( fp, 0, SEEK_SET );
1730 fgetc( fp );
1731 if ( ferror( fp ) != 0 ) {
1732 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1733 return _errorID;
1734 }
1735
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001736 fseek( fp, 0, SEEK_END );
1737 size_t size = ftell( fp );
1738 fseek( fp, 0, SEEK_SET );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001739
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001740 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001741 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001742 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001743 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001744
Lee Thomason624d43f2012-10-12 10:58:48 -07001745 _charBuffer = new char[size+1];
1746 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001747 if ( read != size ) {
1748 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001749 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001750 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001751
Lee Thomason624d43f2012-10-12 10:58:48 -07001752 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001753
Lee Thomason624d43f2012-10-12 10:58:48 -07001754 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001755 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001756 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001757 if ( !p || !*p ) {
1758 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001759 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001760 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001761
Lee Thomason624d43f2012-10-12 10:58:48 -07001762 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1763 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001764}
1765
1766
Lee Thomason2fa81722012-11-09 12:37:46 -08001767XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001768{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001769 FILE* fp = 0;
1770#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1771 errno_t err = fopen_s(&fp, filename, "w" );
1772 if ( !fp || err) {
1773#else
1774 fp = fopen( filename, "w" );
1775 if ( !fp) {
1776#endif
1777 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001778 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001779 }
1780 SaveFile(fp, compact);
1781 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001782 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001783}
1784
1785
Lee Thomason2fa81722012-11-09 12:37:46 -08001786XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001787{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001788 XMLPrinter stream( fp, compact );
1789 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001790 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001791}
1792
Lee Thomason1ff38e02012-02-14 18:18:16 -08001793
Lee Thomason2fa81722012-11-09 12:37:46 -08001794XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001795{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001796 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001797 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001798
psi690ba072013-11-03 10:54:33 +09001799 if ( len == 0 ) {
1800 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
1801 return _errorID;
1802 }
1803
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001804 if ( !p || !*p ) {
1805 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001806 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001807 }
1808 if ( len == (size_t)(-1) ) {
1809 len = strlen( p );
1810 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 _charBuffer = new char[ len+1 ];
1812 memcpy( _charBuffer, p, len );
1813 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001814
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001815 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 if ( !p || !*p ) {
1818 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001819 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001820 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001821
Thomas Roß1470edc2013-05-10 15:44:12 +02001822 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001823 ParseDeep( _charBuffer+delta, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001825}
1826
1827
PKEuS1c5f99e2013-07-06 11:28:39 +02001828void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001829{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001830 XMLPrinter stdStreamer( stdout );
1831 if ( !streamer ) {
1832 streamer = &stdStreamer;
1833 }
1834 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001835}
1836
1837
Lee Thomason2fa81722012-11-09 12:37:46 -08001838void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001839{
Lee Thomason624d43f2012-10-12 10:58:48 -07001840 _errorID = error;
1841 _errorStr1 = str1;
1842 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001843}
1844
Lee Thomason5cae8972012-01-24 18:03:07 -08001845
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001846void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001847{
Lee Thomason624d43f2012-10-12 10:58:48 -07001848 if ( _errorID ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001849 static const int LEN = 20;
1850 char buf1[LEN] = { 0 };
1851 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001852
Lee Thomason624d43f2012-10-12 10:58:48 -07001853 if ( _errorStr1 ) {
1854 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001855 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001856 if ( _errorStr2 ) {
1857 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001859
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001860 printf( "XMLDocument error id=%d str1=%s str2=%s\n",
Lee Thomason624d43f2012-10-12 10:58:48 -07001861 _errorID, buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001862 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001863}
1864
1865
PKEuS1bfb9542013-08-04 13:51:17 +02001866XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 _elementJustOpened( false ),
1868 _firstElement( true ),
1869 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001870 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001871 _textDepth( -1 ),
1872 _processEntities( true ),
1873 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001874{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001875 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001876 _entityFlag[i] = false;
1877 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001878 }
1879 for( int i=0; i<NUM_ENTITIES; ++i ) {
1880 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1881 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001882 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001883 }
1884 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 _restrictedEntityFlag[(int)'&'] = true;
1886 _restrictedEntityFlag[(int)'<'] = true;
1887 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1888 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001889}
1890
1891
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001892void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001893{
1894 va_list va;
1895 va_start( va, format );
1896
Lee Thomason624d43f2012-10-12 10:58:48 -07001897 if ( _fp ) {
1898 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001899 }
1900 else {
1901 // This seems brutally complex. Haven't figured out a better
1902 // way on windows.
1903#ifdef _MSC_VER
1904 int len = -1;
1905 int expand = 1000;
1906 while ( len < 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001907 len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001908 if ( len < 0 ) {
1909 expand *= 3/2;
Lee Thomason1aa8fc42012-10-13 20:01:30 -07001910 _accumulator.PushArr( expand );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001911 }
1912 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001913 char* p = _buffer.PushArr( len ) - 1;
1914 memcpy( p, _accumulator.Mem(), len+1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001915#else
1916 int len = vsnprintf( 0, 0, format, va );
1917 // Close out and re-start the va-args
1918 va_end( va );
1919 va_start( va, format );
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 char* p = _buffer.PushArr( len ) - 1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001921 vsnprintf( p, len+1, format, va );
1922#endif
1923 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001924 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001925}
1926
1927
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001928void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08001929{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001930 for( int i=0; i<depth; ++i ) {
1931 Print( " " );
1932 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001933}
1934
1935
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001936void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08001937{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001938 // Look for runs of bytes between entities to print.
1939 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07001940 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08001941
Lee Thomason624d43f2012-10-12 10:58:48 -07001942 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001943 while ( *q ) {
1944 // Remember, char is sometimes signed. (How many times has that bitten me?)
1945 if ( *q > 0 && *q < ENTITY_RANGE ) {
1946 // Check for entities. If one is found, flush
1947 // the stream up until the entity, write the
1948 // entity, and keep looking.
1949 if ( flag[(unsigned)(*q)] ) {
1950 while ( p < q ) {
1951 Print( "%c", *p );
1952 ++p;
1953 }
1954 for( int i=0; i<NUM_ENTITIES; ++i ) {
1955 if ( entities[i].value == *q ) {
1956 Print( "&%s;", entities[i].pattern );
1957 break;
1958 }
1959 }
1960 ++p;
1961 }
1962 }
1963 ++q;
1964 }
1965 }
1966 // Flush the remaining string. This will be the entire
1967 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07001968 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001969 Print( "%s", p );
1970 }
Lee Thomason857b8682012-01-25 17:50:25 -08001971}
1972
U-Stream\Leeae25a442012-02-17 17:48:16 -08001973
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001974void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001975{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001976 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02001977 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 -07001978 Print( "%s", bom );
1979 }
1980 if ( writeDec ) {
1981 PushDeclaration( "xml version=\"1.0\"" );
1982 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001983}
1984
1985
Uli Kusterer593a33d2014-02-01 12:48:51 +01001986void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08001987{
Lee Thomason624d43f2012-10-12 10:58:48 -07001988 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001989 SealElement();
1990 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001991 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08001992
Uli Kusterer593a33d2014-02-01 12:48:51 +01001993 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001994 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02001995 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01001996 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001997 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001998 }
Lee Thomason5cae8972012-01-24 18:03:07 -08001999
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002000 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002001 _elementJustOpened = true;
2002 _firstElement = false;
2003 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002004}
2005
2006
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002007void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002008{
Lee Thomason624d43f2012-10-12 10:58:48 -07002009 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002010 Print( " %s=\"", name );
2011 PrintString( value, false );
2012 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002013}
2014
2015
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002016void XMLPrinter::PushAttribute( const char* name, int v )
2017{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002018 char buf[BUF_SIZE];
2019 XMLUtil::ToStr( v, buf, BUF_SIZE );
2020 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002021}
2022
2023
2024void XMLPrinter::PushAttribute( const char* name, unsigned v )
2025{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002026 char buf[BUF_SIZE];
2027 XMLUtil::ToStr( v, buf, BUF_SIZE );
2028 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002029}
2030
2031
2032void XMLPrinter::PushAttribute( const char* name, bool v )
2033{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002034 char buf[BUF_SIZE];
2035 XMLUtil::ToStr( v, buf, BUF_SIZE );
2036 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002037}
2038
2039
2040void XMLPrinter::PushAttribute( const char* name, double v )
2041{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002042 char buf[BUF_SIZE];
2043 XMLUtil::ToStr( v, buf, BUF_SIZE );
2044 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002045}
2046
2047
Uli Kustererca412e82014-02-01 13:35:05 +01002048void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002049{
Lee Thomason624d43f2012-10-12 10:58:48 -07002050 --_depth;
2051 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002052
Lee Thomason624d43f2012-10-12 10:58:48 -07002053 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002054 Print( "/>" );
2055 }
2056 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002057 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002058 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002059 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002060 }
2061 Print( "</%s>", name );
2062 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002063
Lee Thomason624d43f2012-10-12 10:58:48 -07002064 if ( _textDepth == _depth ) {
2065 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002066 }
Uli Kustererca412e82014-02-01 13:35:05 +01002067 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002068 Print( "\n" );
2069 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002070 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002071}
2072
2073
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002074void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002075{
Lee Thomason624d43f2012-10-12 10:58:48 -07002076 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002077 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002078}
2079
2080
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002081void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002082{
Lee Thomason624d43f2012-10-12 10:58:48 -07002083 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002084
Lee Thomason624d43f2012-10-12 10:58:48 -07002085 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002086 SealElement();
2087 }
2088 if ( cdata ) {
2089 Print( "<![CDATA[" );
2090 Print( "%s", text );
2091 Print( "]]>" );
2092 }
2093 else {
2094 PrintString( text, true );
2095 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002096}
2097
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002098void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002099{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002100 char buf[BUF_SIZE];
2101 XMLUtil::ToStr( value, buf, BUF_SIZE );
2102 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002103}
2104
2105
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002106void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002107{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002108 char buf[BUF_SIZE];
2109 XMLUtil::ToStr( value, buf, BUF_SIZE );
2110 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002111}
2112
2113
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002114void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002115{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002116 char buf[BUF_SIZE];
2117 XMLUtil::ToStr( value, buf, BUF_SIZE );
2118 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002119}
2120
2121
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002122void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002123{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002124 char buf[BUF_SIZE];
2125 XMLUtil::ToStr( value, buf, BUF_SIZE );
2126 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002127}
2128
2129
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002130void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002131{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002132 char buf[BUF_SIZE];
2133 XMLUtil::ToStr( value, buf, BUF_SIZE );
2134 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002135}
2136
Lee Thomason5cae8972012-01-24 18:03:07 -08002137
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002138void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002139{
Lee Thomason624d43f2012-10-12 10:58:48 -07002140 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 SealElement();
2142 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002144 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002145 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002146 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002147 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002148 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002149}
Lee Thomason751da522012-02-10 08:50:51 -08002150
2151
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002152void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002153{
Lee Thomason624d43f2012-10-12 10:58:48 -07002154 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002155 SealElement();
2156 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002157 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002158 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002159 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002160 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002161 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002162 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002163}
2164
2165
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002166void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002167{
Lee Thomason624d43f2012-10-12 10:58:48 -07002168 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002169 SealElement();
2170 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002171 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002172 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002173 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002174 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002175 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002176 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002177}
2178
2179
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002180bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002181{
Lee Thomason624d43f2012-10-12 10:58:48 -07002182 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002183 if ( doc.HasBOM() ) {
2184 PushHeader( true, false );
2185 }
2186 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002187}
2188
2189
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002190bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002191{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002192 const XMLElement* parentElem = element.Parent()->ToElement();
2193 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2194 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002195 while ( attribute ) {
2196 PushAttribute( attribute->Name(), attribute->Value() );
2197 attribute = attribute->Next();
2198 }
2199 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002200}
2201
2202
Uli Kustererca412e82014-02-01 13:35:05 +01002203bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002204{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002205 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002206 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002207}
2208
2209
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002210bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002211{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002212 PushText( text.Value(), text.CData() );
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 XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002218{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 PushComment( comment.Value() );
2220 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002221}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002222
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002223bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002224{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002225 PushDeclaration( declaration.Value() );
2226 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002227}
2228
2229
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002230bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002231{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002232 PushUnknown( unknown.Value() );
2233 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002234}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002235
Lee Thomason685b8952012-11-12 13:00:06 -08002236} // namespace tinyxml2
2237