blob: 77c1a8ab74ba684c35bf4c81bdcf390602d757d3 [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.
Anton Indrawanf59e2d62014-11-18 20:50:42 +010027#if defined(ANDROID_NDK) || defined(__QNXNTO__)
Lee Thomasona9cf3f92012-10-11 16:56:51 -070028# 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
Kevin Wojniak04c22d22012-11-08 11:02:22 -080048namespace tinyxml2
49{
50
Lee Thomason8ee79892012-01-25 17:44:30 -080051struct Entity {
Lee Thomasona9cf3f92012-10-11 16:56:51 -070052 const char* pattern;
53 int length;
54 char value;
Lee Thomason8ee79892012-01-25 17:44:30 -080055};
56
57static const int NUM_ENTITIES = 5;
Lee Thomasona9cf3f92012-10-11 16:56:51 -070058static const Entity entities[NUM_ENTITIES] = {
59 { "quot", 4, DOUBLE_QUOTE },
60 { "amp", 3, '&' },
61 { "apos", 4, SINGLE_QUOTE },
62 { "lt", 2, '<' },
63 { "gt", 2, '>' }
Lee Thomason8ee79892012-01-25 17:44:30 -080064};
65
Lee Thomasonfde6a752012-01-14 18:08:12 -080066
Lee Thomason1a1d4a72012-02-15 09:09:25 -080067StrPair::~StrPair()
68{
Lee Thomasona9cf3f92012-10-11 16:56:51 -070069 Reset();
Lee Thomason1a1d4a72012-02-15 09:09:25 -080070}
71
72
Lee Thomason29658802014-11-27 22:31:11 -080073void StrPair::TransferTo( StrPair* other )
Dmitry-Me08b40dd2014-11-10 11:17:21 +030074{
Lee Thomason29658802014-11-27 22:31:11 -080075 if ( this == other ) {
Dmitry-Me08b40dd2014-11-10 11:17:21 +030076 return;
77 }
78 // This in effect implements the assignment operator by "moving"
79 // ownership (as in auto_ptr).
80
Lee Thomason29658802014-11-27 22:31:11 -080081 TIXMLASSERT( other->_flags == 0 );
82 TIXMLASSERT( other->_start == 0 );
83 TIXMLASSERT( other->_end == 0 );
Dmitry-Me08b40dd2014-11-10 11:17:21 +030084
Lee Thomason29658802014-11-27 22:31:11 -080085 other->Reset();
Dmitry-Me08b40dd2014-11-10 11:17:21 +030086
Lee Thomason29658802014-11-27 22:31:11 -080087 other->_flags = _flags;
88 other->_start = _start;
89 other->_end = _end;
Dmitry-Me08b40dd2014-11-10 11:17:21 +030090
91 _flags = 0;
92 _start = 0;
93 _end = 0;
94}
95
Lee Thomason1a1d4a72012-02-15 09:09:25 -080096void StrPair::Reset()
97{
Lee Thomason120b3a62012-10-12 10:06:59 -070098 if ( _flags & NEEDS_DELETE ) {
99 delete [] _start;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700100 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700101 _flags = 0;
102 _start = 0;
103 _end = 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800104}
105
106
107void StrPair::SetStr( const char* str, int flags )
108{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700109 Reset();
110 size_t len = strlen( str );
Lee Thomason120b3a62012-10-12 10:06:59 -0700111 _start = new char[ len+1 ];
112 memcpy( _start, str, len+1 );
113 _end = _start + len;
114 _flags = flags | NEEDS_DELETE;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800115}
116
117
118char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
119{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700120 TIXMLASSERT( endTag && *endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800121
Dmitry-Meec19a0e2014-08-25 11:05:55 +0400122 char* start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700123 char endChar = *endTag;
124 size_t length = strlen( endTag );
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800125
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700126 // Inner loop of text parsing.
127 while ( *p ) {
128 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
129 Set( start, p, strFlags );
130 return p + length;
131 }
132 ++p;
133 }
134 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800135}
136
137
138char* StrPair::ParseName( char* p )
139{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400140 if ( !p || !(*p) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700141 return 0;
142 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800143
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400144 char* const start = p;
145
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +0200146 while( *p && ( p == start ? XMLUtil::IsNameStartChar( *p ) : XMLUtil::IsNameChar( *p ) )) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700147 ++p;
148 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800149
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700150 if ( p > start ) {
151 Set( start, p, 0 );
152 return p;
153 }
154 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155}
156
157
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700158void StrPair::CollapseWhitespace()
159{
Dmitry-Me67a5bb02014-08-20 10:01:53 +0400160 // Adjusting _start would cause undefined behavior on delete[]
161 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700162 // Trim leading space.
Lee Thomason120b3a62012-10-12 10:06:59 -0700163 _start = XMLUtil::SkipWhiteSpace( _start );
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700164
Lee Thomason120b3a62012-10-12 10:06:59 -0700165 if ( _start && *_start ) {
166 char* p = _start; // the read pointer
167 char* q = _start; // the write pointer
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700168
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700169 while( *p ) {
170 if ( XMLUtil::IsWhiteSpace( *p )) {
171 p = XMLUtil::SkipWhiteSpace( p );
172 if ( *p == 0 ) {
173 break; // don't write to q; this trims the trailing space.
174 }
175 *q = ' ';
176 ++q;
177 }
178 *q = *p;
179 ++q;
180 ++p;
181 }
182 *q = 0;
183 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700184}
185
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800186
Lee Thomasone4422302012-01-20 17:59:50 -0800187const char* StrPair::GetStr()
188{
Lee Thomason120b3a62012-10-12 10:06:59 -0700189 if ( _flags & NEEDS_FLUSH ) {
190 *_end = 0;
191 _flags ^= NEEDS_FLUSH;
Lee Thomasone4422302012-01-20 17:59:50 -0800192
Lee Thomason120b3a62012-10-12 10:06:59 -0700193 if ( _flags ) {
194 char* p = _start; // the read pointer
195 char* q = _start; // the write pointer
Lee Thomasone4422302012-01-20 17:59:50 -0800196
Lee Thomason120b3a62012-10-12 10:06:59 -0700197 while( p < _end ) {
198 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700199 // CR-LF pair becomes LF
200 // CR alone becomes LF
201 // LF-CR becomes LF
202 if ( *(p+1) == LF ) {
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_NEWLINE_NORMALIZATION) && *p == LF ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700211 if ( *(p+1) == CR ) {
212 p += 2;
213 }
214 else {
215 ++p;
216 }
217 *q++ = LF;
218 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700219 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700220 // Entities handled by tinyXML2:
221 // - special entities in the entity table [in/out]
222 // - numeric character reference [in]
223 // &#20013; or &#x4e2d;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800224
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700225 if ( *(p+1) == '#' ) {
Dmitry-Me63f3de12014-08-21 12:33:19 +0400226 const int buflen = 10;
227 char buf[buflen] = { 0 };
228 int len = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700229 p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
Dmitry-Me63f3de12014-08-21 12:33:19 +0400230 TIXMLASSERT( 0 <= len && len <= buflen );
231 TIXMLASSERT( q + len <= p );
232 memcpy( q, buf, len );
233 q += len;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700234 }
235 else {
236 int i=0;
237 for(; i<NUM_ENTITIES; ++i ) {
Dmitry-Med048f1e2014-10-01 10:30:16 +0400238 const Entity& entity = entities[i];
239 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
240 && *( p + entity.length + 1 ) == ';' ) {
241 // Found an entity - convert.
242 *q = entity.value;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700243 ++q;
Dmitry-Med048f1e2014-10-01 10:30:16 +0400244 p += entity.length + 2;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700245 break;
246 }
247 }
248 if ( i == NUM_ENTITIES ) {
249 // fixme: treat as error?
250 ++p;
251 ++q;
252 }
253 }
254 }
255 else {
256 *q = *p;
257 ++p;
258 ++q;
259 }
260 }
261 *q = 0;
262 }
263 // The loop below has plenty going on, and this
264 // is a less useful mode. Break it out.
Lee Thomason120b3a62012-10-12 10:06:59 -0700265 if ( _flags & COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700266 CollapseWhitespace();
267 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700268 _flags = (_flags & NEEDS_DELETE);
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700269 }
Lee Thomason120b3a62012-10-12 10:06:59 -0700270 return _start;
Lee Thomasone4422302012-01-20 17:59:50 -0800271}
272
Lee Thomason2c85a712012-01-31 08:24:24 -0800273
Lee Thomasone4422302012-01-20 17:59:50 -0800274
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800275
Lee Thomason56bdd022012-02-09 18:16:58 -0800276// --------- XMLUtil ----------- //
Lee Thomasond1983222012-02-06 08:41:24 -0800277
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800278const char* XMLUtil::ReadBOM( const char* p, bool* bom )
279{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700280 *bom = false;
281 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
282 // Check for BOM:
283 if ( *(pu+0) == TIXML_UTF_LEAD_0
284 && *(pu+1) == TIXML_UTF_LEAD_1
285 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
286 *bom = true;
287 p += 3;
288 }
289 return p;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800290}
291
292
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800293void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
294{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700295 const unsigned long BYTE_MASK = 0xBF;
296 const unsigned long BYTE_MARK = 0x80;
297 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800298
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700299 if (input < 0x80) {
300 *length = 1;
301 }
302 else if ( input < 0x800 ) {
303 *length = 2;
304 }
305 else if ( input < 0x10000 ) {
306 *length = 3;
307 }
308 else if ( input < 0x200000 ) {
309 *length = 4;
310 }
311 else {
312 *length = 0; // This code won't covert this correctly anyway.
313 return;
314 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800315
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700316 output += *length;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800317
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700318 // Scary scary fall throughs.
319 switch (*length) {
320 case 4:
321 --output;
322 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
323 input >>= 6;
324 case 3:
325 --output;
326 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
327 input >>= 6;
328 case 2:
329 --output;
330 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
331 input >>= 6;
332 case 1:
333 --output;
334 *output = (char)(input | FIRST_BYTE_MARK[*length]);
MortenMacFly4ee49f12013-01-14 20:03:14 +0100335 default:
336 break;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700337 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800338}
339
340
341const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
342{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700343 // Presume an entity, and pull it out.
344 *length = 0;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800345
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700346 if ( *(p+1) == '#' && *(p+2) ) {
347 unsigned long ucs = 0;
348 ptrdiff_t delta = 0;
349 unsigned mult = 1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800350
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700351 if ( *(p+2) == 'x' ) {
352 // Hexadecimal.
353 if ( !*(p+3) ) {
354 return 0;
355 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800356
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700357 const char* q = p+3;
358 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800359
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700360 if ( !q || !*q ) {
361 return 0;
362 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800363
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700364 delta = q-p;
365 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800366
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700367 while ( *q != 'x' ) {
368 if ( *q >= '0' && *q <= '9' ) {
369 ucs += mult * (*q - '0');
370 }
371 else if ( *q >= 'a' && *q <= 'f' ) {
372 ucs += mult * (*q - 'a' + 10);
373 }
374 else if ( *q >= 'A' && *q <= 'F' ) {
375 ucs += mult * (*q - 'A' + 10 );
376 }
377 else {
378 return 0;
379 }
380 mult *= 16;
381 --q;
382 }
383 }
384 else {
385 // Decimal.
386 if ( !*(p+2) ) {
387 return 0;
388 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800389
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700390 const char* q = p+2;
391 q = strchr( q, ';' );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800392
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700393 if ( !q || !*q ) {
394 return 0;
395 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800396
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700397 delta = q-p;
398 --q;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800399
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700400 while ( *q != '#' ) {
401 if ( *q >= '0' && *q <= '9' ) {
402 ucs += mult * (*q - '0');
403 }
404 else {
405 return 0;
406 }
407 mult *= 10;
408 --q;
409 }
410 }
411 // convert the UCS to UTF-8
412 ConvertUTF32ToUTF8( ucs, value, length );
413 return p + delta + 1;
414 }
415 return p+1;
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800416}
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800417
418
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700419void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
Lee Thomason21be8822012-07-15 17:27:22 -0700420{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700421 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700422}
423
424
425void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
426{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700427 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700428}
429
430
431void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
432{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700433 TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
Lee Thomason21be8822012-07-15 17:27:22 -0700434}
435
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800436/*
437 ToStr() of a number is a very tricky topic.
438 https://github.com/leethomason/tinyxml2/issues/106
439*/
Lee Thomason21be8822012-07-15 17:27:22 -0700440void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
441{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800442 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700443}
444
445
446void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
447{
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800448 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
Lee Thomason21be8822012-07-15 17:27:22 -0700449}
450
451
452bool XMLUtil::ToInt( const char* str, int* value )
453{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700454 if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
455 return true;
456 }
457 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700458}
459
460bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
461{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700462 if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
463 return true;
464 }
465 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700466}
467
468bool XMLUtil::ToBool( const char* str, bool* value )
469{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700470 int ival = 0;
471 if ( ToInt( str, &ival )) {
472 *value = (ival==0) ? false : true;
473 return true;
474 }
475 if ( StringEqual( str, "true" ) ) {
476 *value = true;
477 return true;
478 }
479 else if ( StringEqual( str, "false" ) ) {
480 *value = false;
481 return true;
482 }
483 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700484}
485
486
487bool XMLUtil::ToFloat( const char* str, float* value )
488{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700489 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
490 return true;
491 }
492 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700493}
494
495bool XMLUtil::ToDouble( const char* str, double* value )
496{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700497 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
498 return true;
499 }
500 return false;
Lee Thomason21be8822012-07-15 17:27:22 -0700501}
502
503
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700504char* XMLDocument::Identify( char* p, XMLNode** node )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800505{
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400506 char* const start = p;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700507 p = XMLUtil::SkipWhiteSpace( p );
508 if( !p || !*p ) {
509 return p;
510 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800511
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700512 // What is this thing?
Lee Thomasonc3708cc2014-01-14 12:30:03 -0800513 // These strings define the matching patters:
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700514 static const char* xmlHeader = { "<?" };
515 static const char* commentHeader = { "<!--" };
516 static const char* dtdHeader = { "<!" };
517 static const char* cdataHeader = { "<![CDATA[" };
518 static const char* elementHeader = { "<" }; // and a header for everything else; check last.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800519
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700520 static const int xmlHeaderLen = 2;
521 static const int commentHeaderLen = 4;
522 static const int dtdHeaderLen = 2;
523 static const int cdataHeaderLen = 9;
524 static const int elementHeaderLen = 1;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800525
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800526#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800527#pragma warning ( push )
528#pragma warning ( disable : 4127 )
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800529#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700530 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
531 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800532#if defined(_MSC_VER)
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800533#pragma warning (pop)
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800534#endif
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400535 XMLNode* returnNode = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700536 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300537 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700538 returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
539 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700540 p += xmlHeaderLen;
541 }
542 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300543 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700544 returnNode = new (_commentPool.Alloc()) XMLComment( this );
545 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700546 p += commentHeaderLen;
547 }
548 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300549 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700550 XMLText* text = new (_textPool.Alloc()) XMLText( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700551 returnNode = text;
Lee Thomason624d43f2012-10-12 10:58:48 -0700552 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700553 p += cdataHeaderLen;
554 text->SetCData( true );
555 }
556 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300557 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700558 returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
559 returnNode->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700560 p += dtdHeaderLen;
561 }
562 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300563 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700564 returnNode = new (_elementPool.Alloc()) XMLElement( this );
565 returnNode->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700566 p += elementHeaderLen;
567 }
568 else {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +0300569 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -0700570 returnNode = new (_textPool.Alloc()) XMLText( this );
571 returnNode->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700572 p = start; // Back it up, all the text counts.
573 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800574
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700575 *node = returnNode;
576 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800577}
578
579
Lee Thomason751da522012-02-10 08:50:51 -0800580bool XMLDocument::Accept( XMLVisitor* visitor ) const
581{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700582 if ( visitor->VisitEnter( *this ) ) {
583 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
584 if ( !node->Accept( visitor ) ) {
585 break;
586 }
587 }
588 }
589 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -0800590}
Lee Thomason56bdd022012-02-09 18:16:58 -0800591
592
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800593// --------- XMLNode ----------- //
594
595XMLNode::XMLNode( XMLDocument* doc ) :
Lee Thomason624d43f2012-10-12 10:58:48 -0700596 _document( doc ),
597 _parent( 0 ),
598 _firstChild( 0 ), _lastChild( 0 ),
Thomas Roß61892312013-05-12 14:07:38 +0200599 _prev( 0 ), _next( 0 ),
600 _memPool( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800601{
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800602}
603
604
605XMLNode::~XMLNode()
606{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700607 DeleteChildren();
Lee Thomason624d43f2012-10-12 10:58:48 -0700608 if ( _parent ) {
609 _parent->Unlink( this );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700610 }
Lee Thomason18d68bd2012-01-26 18:17:26 -0800611}
612
Michael Daumling21626882013-10-22 17:03:37 +0200613const char* XMLNode::Value() const
614{
615 return _value.GetStr();
616}
Lee Thomason18d68bd2012-01-26 18:17:26 -0800617
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800618void XMLNode::SetValue( const char* str, bool staticMem )
619{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700620 if ( staticMem ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700621 _value.SetInternedStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700622 }
623 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700624 _value.SetStr( str );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700625 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800626}
627
628
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800629void XMLNode::DeleteChildren()
Lee Thomason18d68bd2012-01-26 18:17:26 -0800630{
Lee Thomason624d43f2012-10-12 10:58:48 -0700631 while( _firstChild ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300632 TIXMLASSERT( _firstChild->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700633 XMLNode* node = _firstChild;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700634 Unlink( node );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700635
Dmitry-Mee3225b12014-09-03 11:03:11 +0400636 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700637 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700638 _firstChild = _lastChild = 0;
Lee Thomasond923c672012-01-23 08:44:25 -0800639}
640
641
642void XMLNode::Unlink( XMLNode* child )
643{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300644 TIXMLASSERT( child->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700645 if ( child == _firstChild ) {
646 _firstChild = _firstChild->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700647 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700648 if ( child == _lastChild ) {
649 _lastChild = _lastChild->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700650 }
Lee Thomasond923c672012-01-23 08:44:25 -0800651
Lee Thomason624d43f2012-10-12 10:58:48 -0700652 if ( child->_prev ) {
653 child->_prev->_next = child->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700654 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700655 if ( child->_next ) {
656 child->_next->_prev = child->_prev;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700657 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700658 child->_parent = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800659}
660
661
U-Stream\Leeae25a442012-02-17 17:48:16 -0800662void XMLNode::DeleteChild( XMLNode* node )
663{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300664 TIXMLASSERT( node->_document == _document );
Lee Thomason624d43f2012-10-12 10:58:48 -0700665 TIXMLASSERT( node->_parent == this );
Dmitry-Mee3225b12014-09-03 11:03:11 +0400666 DeleteNode( node );
U-Stream\Leeae25a442012-02-17 17:48:16 -0800667}
668
669
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800670XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
671{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300672 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300673 if ( addThis->_document != _document ) {
674 TIXMLASSERT( false );
675 return 0;
676 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700677
Michael Daumlinged523282013-10-23 07:47:29 +0200678 if (addThis->_parent)
679 addThis->_parent->Unlink( addThis );
680 else
681 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700682
Lee Thomason624d43f2012-10-12 10:58:48 -0700683 if ( _lastChild ) {
684 TIXMLASSERT( _firstChild );
685 TIXMLASSERT( _lastChild->_next == 0 );
686 _lastChild->_next = addThis;
687 addThis->_prev = _lastChild;
688 _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800689
Lee Thomason624d43f2012-10-12 10:58:48 -0700690 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700691 }
692 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700693 TIXMLASSERT( _firstChild == 0 );
694 _firstChild = _lastChild = addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800695
Lee Thomason624d43f2012-10-12 10:58:48 -0700696 addThis->_prev = 0;
697 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700698 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700699 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700700 return addThis;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800701}
702
703
Lee Thomason1ff38e02012-02-14 18:18:16 -0800704XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
705{
Dmitry-Meed2a4072014-12-12 10:38:48 +0300706 TIXMLASSERT( addThis );
Dmitry-Meabb2d042014-12-09 12:59:31 +0300707 if ( addThis->_document != _document ) {
708 TIXMLASSERT( false );
709 return 0;
710 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700711
Michael Daumlinged523282013-10-23 07:47:29 +0200712 if (addThis->_parent)
713 addThis->_parent->Unlink( addThis );
714 else
715 addThis->_memPool->SetTracked();
Lee Thomason3b7927e2013-10-26 21:50:46 -0700716
Lee Thomason624d43f2012-10-12 10:58:48 -0700717 if ( _firstChild ) {
718 TIXMLASSERT( _lastChild );
719 TIXMLASSERT( _firstChild->_prev == 0 );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800720
Lee Thomason624d43f2012-10-12 10:58:48 -0700721 _firstChild->_prev = addThis;
722 addThis->_next = _firstChild;
723 _firstChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800724
Lee Thomason624d43f2012-10-12 10:58:48 -0700725 addThis->_prev = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700726 }
727 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700728 TIXMLASSERT( _lastChild == 0 );
729 _firstChild = _lastChild = addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800730
Lee Thomason624d43f2012-10-12 10:58:48 -0700731 addThis->_prev = 0;
732 addThis->_next = 0;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700733 }
Lee Thomason624d43f2012-10-12 10:58:48 -0700734 addThis->_parent = this;
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400735 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800736}
737
738
739XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
740{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300741 TIXMLASSERT( addThis );
742 if ( addThis->_document != _document ) {
743 TIXMLASSERT( false );
744 return 0;
745 }
Lee Thomason3b7927e2013-10-26 21:50:46 -0700746
Dmitry-Meabb2d042014-12-09 12:59:31 +0300747 TIXMLASSERT( afterThis );
Lee Thomason3b7927e2013-10-26 21:50:46 -0700748
Lee Thomason624d43f2012-10-12 10:58:48 -0700749 if ( afterThis->_parent != this ) {
Dmitry-Meabb2d042014-12-09 12:59:31 +0300750 TIXMLASSERT( false );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700751 return 0;
752 }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800753
Lee Thomason624d43f2012-10-12 10:58:48 -0700754 if ( afterThis->_next == 0 ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700755 // The last node or the only node.
756 return InsertEndChild( addThis );
757 }
Michael Daumlinged523282013-10-23 07:47:29 +0200758 if (addThis->_parent)
759 addThis->_parent->Unlink( addThis );
760 else
761 addThis->_memPool->SetTracked();
Lee Thomason624d43f2012-10-12 10:58:48 -0700762 addThis->_prev = afterThis;
763 addThis->_next = afterThis->_next;
764 afterThis->_next->_prev = addThis;
765 afterThis->_next = addThis;
766 addThis->_parent = this;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700767 return addThis;
Lee Thomason1ff38e02012-02-14 18:18:16 -0800768}
769
770
771
772
Lee Thomason56bdd022012-02-09 18:16:58 -0800773const XMLElement* XMLNode::FirstChildElement( const char* value ) const
Lee Thomason2c85a712012-01-31 08:24:24 -0800774{
Lee Thomason624d43f2012-10-12 10:58:48 -0700775 for( XMLNode* node=_firstChild; node; node=node->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700776 XMLElement* element = node->ToElement();
777 if ( element ) {
778 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
779 return element;
780 }
781 }
782 }
783 return 0;
Lee Thomason2c85a712012-01-31 08:24:24 -0800784}
785
786
Lee Thomason56bdd022012-02-09 18:16:58 -0800787const XMLElement* XMLNode::LastChildElement( const char* value ) const
788{
Lee Thomason624d43f2012-10-12 10:58:48 -0700789 for( XMLNode* node=_lastChild; node; node=node->_prev ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700790 XMLElement* element = node->ToElement();
791 if ( element ) {
792 if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
793 return element;
794 }
795 }
796 }
797 return 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800798}
799
800
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800801const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
802{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400803 for( XMLNode* node=this->_next; node; node = node->_next ) {
804 const XMLElement* element = node->ToElement();
805 if ( element
806 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
807 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700808 }
809 }
810 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800811}
812
813
814const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
815{
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400816 for( XMLNode* node=_prev; node; node = node->_prev ) {
817 const XMLElement* element = node->ToElement();
818 if ( element
819 && (!value || XMLUtil::StringEqual( value, node->Value() ))) {
820 return element;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700821 }
822 }
823 return 0;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800824}
825
826
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800827char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
Lee Thomason67d61312012-01-24 16:01:51 -0800828{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700829 // This is a recursive method, but thinking about it "at the current level"
830 // it is a pretty simple flat list:
831 // <foo/>
832 // <!-- comment -->
833 //
834 // With a special case:
835 // <foo>
836 // </foo>
837 // <!-- comment -->
838 //
839 // Where the closing element (/foo) *must* be the next thing after the opening
840 // element, and the names must match. BUT the tricky bit is that the closing
841 // element will be read by the child.
842 //
843 // 'endTag' is the end tag for this node, it is returned by a call to a child.
844 // 'parentEnd' is the end tag for the parent, which is filled in and returned.
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800845
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700846 while( p && *p ) {
847 XMLNode* node = 0;
Lee Thomasond6277762012-02-22 16:00:12 -0800848
Lee Thomason624d43f2012-10-12 10:58:48 -0700849 p = _document->Identify( p, &node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700850 if ( p == 0 || node == 0 ) {
851 break;
852 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800853
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700854 StrPair endTag;
855 p = node->ParseDeep( p, &endTag );
856 if ( !p ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400857 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700858 node = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -0700859 if ( !_document->Error() ) {
860 _document->SetError( XML_ERROR_PARSING, 0, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700861 }
862 break;
863 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800864
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400865 XMLElement* ele = node->ToElement();
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700866 // We read the end tag. Return it to the parent.
Dmitry-Meb6b4e822014-08-27 17:17:47 +0400867 if ( ele && ele->ClosingType() == XMLElement::CLOSING ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700868 if ( parentEnd ) {
Lee Thomason29658802014-11-27 22:31:11 -0800869 ele->_value.TransferTo( parentEnd );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700870 }
Lee Thomason5b0a6772012-11-19 13:54:42 -0800871 node->_memPool->SetTracked(); // created and then immediately deleted.
Dmitry-Mee3225b12014-09-03 11:03:11 +0400872 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700873 return p;
874 }
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -0800875
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700876 // Handle an end tag returned to this level.
877 // And handle a bunch of annoying errors.
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700878 if ( ele ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400879 bool mismatch = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700880 if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400881 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700882 }
883 else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400884 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700885 }
886 else if ( !endTag.Empty() ) {
887 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400888 mismatch = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700889 }
890 }
Dmitry-Me9fb2b0f2014-09-23 17:27:39 +0400891 if ( mismatch ) {
892 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
893 p = 0;
894 }
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700895 }
896 if ( p == 0 ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +0400897 DeleteNode( node );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700898 node = 0;
899 }
900 if ( node ) {
901 this->InsertEndChild( node );
902 }
903 }
904 return 0;
Lee Thomason67d61312012-01-24 16:01:51 -0800905}
906
Dmitry-Mee3225b12014-09-03 11:03:11 +0400907void XMLNode::DeleteNode( XMLNode* node )
908{
909 if ( node == 0 ) {
910 return;
911 }
912 MemPool* pool = node->_memPool;
913 node->~XMLNode();
914 pool->Free( node );
915}
916
Lee Thomason5492a1c2012-01-23 15:32:10 -0800917// --------- XMLText ---------- //
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800918char* XMLText::ParseDeep( char* p, StrPair* )
Lee Thomason5492a1c2012-01-23 15:32:10 -0800919{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700920 const char* start = p;
921 if ( this->CData() ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700922 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700923 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700924 _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700925 }
926 return p;
927 }
928 else {
Lee Thomason624d43f2012-10-12 10:58:48 -0700929 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
930 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700931 flags |= StrPair::COLLAPSE_WHITESPACE;
932 }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700933
Lee Thomason624d43f2012-10-12 10:58:48 -0700934 p = _value.ParseText( p, "<", flags );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700935 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700936 _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700937 }
938 if ( p && *p ) {
939 return p-1;
940 }
941 }
942 return 0;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800943}
944
945
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800946XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
947{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700948 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700949 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700950 }
951 XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
952 text->SetCData( this->CData() );
953 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800954}
955
956
957bool XMLText::ShallowEqual( const XMLNode* compare ) const
958{
Dmitry-Me6d202ff2014-09-26 14:21:00 +0400959 const XMLText* text = compare->ToText();
960 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800961}
962
963
Lee Thomason56bdd022012-02-09 18:16:58 -0800964bool XMLText::Accept( XMLVisitor* visitor ) const
965{
Dmitry-Meabb2d042014-12-09 12:59:31 +0300966 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700967 return visitor->Visit( *this );
Lee Thomason56bdd022012-02-09 18:16:58 -0800968}
969
970
Lee Thomason3f57d272012-01-11 15:30:03 -0800971// --------- XMLComment ---------- //
972
Lee Thomasone4422302012-01-20 17:59:50 -0800973XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
Lee Thomason3f57d272012-01-11 15:30:03 -0800974{
975}
976
977
Lee Thomasonce0763e2012-01-11 15:43:54 -0800978XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800979{
Lee Thomason3f57d272012-01-11 15:30:03 -0800980}
981
982
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800983char* XMLComment::ParseDeep( char* p, StrPair* )
Lee Thomason3f57d272012-01-11 15:30:03 -0800984{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700985 // Comment parses as text.
986 const char* start = p;
Lee Thomason624d43f2012-10-12 10:58:48 -0700987 p = _value.ParseText( p, "-->", StrPair::COMMENT );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700988 if ( p == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700989 _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700990 }
991 return p;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800992}
993
994
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800995XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
996{
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700997 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -0700998 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -0700999 }
1000 XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1001 return comment;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001002}
1003
1004
1005bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1006{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001007 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001008 const XMLComment* comment = compare->ToComment();
1009 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001010}
1011
1012
Lee Thomason751da522012-02-10 08:50:51 -08001013bool XMLComment::Accept( XMLVisitor* visitor ) const
1014{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001015 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001016 return visitor->Visit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001017}
Lee Thomason56bdd022012-02-09 18:16:58 -08001018
1019
Lee Thomason50f97b22012-02-11 16:33:40 -08001020// --------- XMLDeclaration ---------- //
1021
1022XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1023{
1024}
1025
1026
1027XMLDeclaration::~XMLDeclaration()
1028{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001029 //printf( "~XMLDeclaration\n" );
Lee Thomason50f97b22012-02-11 16:33:40 -08001030}
1031
1032
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001033char* XMLDeclaration::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001034{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001035 // Declaration parses as text.
1036 const char* start = p;
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 == 0 ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001039 _document->SetError( XML_ERROR_PARSING_DECLARATION, 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* XMLDeclaration::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 XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1051 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001052}
1053
1054
1055bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1056{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001057 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001058 const XMLDeclaration* declaration = compare->ToDeclaration();
1059 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001060}
1061
1062
1063
Lee Thomason50f97b22012-02-11 16:33:40 -08001064bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1065{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001066 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001067 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001068}
1069
1070// --------- XMLUnknown ---------- //
1071
1072XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1073{
1074}
1075
1076
1077XMLUnknown::~XMLUnknown()
1078{
1079}
1080
1081
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001082char* XMLUnknown::ParseDeep( char* p, StrPair* )
Lee Thomason50f97b22012-02-11 16:33:40 -08001083{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001084 // Unknown parses as text.
1085 const char* start = p;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001086
Lee Thomason624d43f2012-10-12 10:58:48 -07001087 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001088 if ( !p ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001089 _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001090 }
1091 return p;
Lee Thomason50f97b22012-02-11 16:33:40 -08001092}
1093
1094
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001095XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1096{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001097 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001098 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001099 }
1100 XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1101 return text;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001102}
1103
1104
1105bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1106{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001107 TIXMLASSERT( compare );
Dmitry-Meb6b4e822014-08-27 17:17:47 +04001108 const XMLUnknown* unknown = compare->ToUnknown();
1109 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001110}
1111
1112
Lee Thomason50f97b22012-02-11 16:33:40 -08001113bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1114{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001115 TIXMLASSERT( visitor );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001116 return visitor->Visit( *this );
Lee Thomason50f97b22012-02-11 16:33:40 -08001117}
1118
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001119// --------- XMLAttribute ---------- //
Michael Daumling21626882013-10-22 17:03:37 +02001120
1121const char* XMLAttribute::Name() const
1122{
1123 return _name.GetStr();
1124}
1125
1126const char* XMLAttribute::Value() const
1127{
1128 return _value.GetStr();
1129}
1130
Lee Thomason6f381b72012-03-02 12:59:39 -08001131char* XMLAttribute::ParseDeep( char* p, bool processEntities )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001132{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001133 // Parse using the name rules: bug fix, was using ParseText before
Lee Thomason624d43f2012-10-12 10:58:48 -07001134 p = _name.ParseName( p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001135 if ( !p || !*p ) {
1136 return 0;
1137 }
Lee Thomason22aead12012-01-23 13:29:35 -08001138
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001139 // Skip white space before =
1140 p = XMLUtil::SkipWhiteSpace( p );
1141 if ( !p || *p != '=' ) {
1142 return 0;
1143 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001144
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001145 ++p; // move up to opening quote
1146 p = XMLUtil::SkipWhiteSpace( p );
1147 if ( *p != '\"' && *p != '\'' ) {
1148 return 0;
1149 }
Lee Thomason78a773d2012-07-02 10:10:19 -07001150
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001151 char endTag[2] = { *p, 0 };
1152 ++p; // move past opening quote
Lee Thomason78a773d2012-07-02 10:10:19 -07001153
Lee Thomason624d43f2012-10-12 10:58:48 -07001154 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001155 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001156}
1157
1158
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001159void XMLAttribute::SetName( const char* n )
1160{
Lee Thomason624d43f2012-10-12 10:58:48 -07001161 _name.SetStr( n );
U-Stream\Lee09a11c52012-02-17 08:31:16 -08001162}
1163
1164
Lee Thomason2fa81722012-11-09 12:37:46 -08001165XMLError XMLAttribute::QueryIntValue( int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001166{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001167 if ( XMLUtil::ToInt( Value(), value )) {
1168 return XML_NO_ERROR;
1169 }
1170 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001171}
1172
1173
Lee Thomason2fa81722012-11-09 12:37:46 -08001174XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001175{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001176 if ( XMLUtil::ToUnsigned( Value(), value )) {
1177 return XML_NO_ERROR;
1178 }
1179 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001180}
1181
1182
Lee Thomason2fa81722012-11-09 12:37:46 -08001183XMLError XMLAttribute::QueryBoolValue( bool* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001184{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001185 if ( XMLUtil::ToBool( Value(), value )) {
1186 return XML_NO_ERROR;
1187 }
1188 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001189}
1190
1191
Lee Thomason2fa81722012-11-09 12:37:46 -08001192XMLError XMLAttribute::QueryFloatValue( float* value ) const
Lee Thomason1ff38e02012-02-14 18:18:16 -08001193{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001194 if ( XMLUtil::ToFloat( Value(), value )) {
1195 return XML_NO_ERROR;
1196 }
1197 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason21be8822012-07-15 17:27:22 -07001198}
1199
1200
Lee Thomason2fa81722012-11-09 12:37:46 -08001201XMLError XMLAttribute::QueryDoubleValue( double* value ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001202{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001203 if ( XMLUtil::ToDouble( Value(), value )) {
1204 return XML_NO_ERROR;
1205 }
1206 return XML_WRONG_ATTRIBUTE_TYPE;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001207}
1208
1209
1210void XMLAttribute::SetAttribute( const char* v )
1211{
Lee Thomason624d43f2012-10-12 10:58:48 -07001212 _value.SetStr( v );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001213}
1214
1215
Lee Thomason1ff38e02012-02-14 18:18:16 -08001216void XMLAttribute::SetAttribute( int v )
1217{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001218 char buf[BUF_SIZE];
1219 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001220 _value.SetStr( buf );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001221}
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001222
1223
1224void XMLAttribute::SetAttribute( unsigned v )
1225{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001226 char buf[BUF_SIZE];
1227 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001228 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001229}
1230
1231
1232void XMLAttribute::SetAttribute( bool v )
1233{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001234 char buf[BUF_SIZE];
1235 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001236 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001237}
1238
1239void XMLAttribute::SetAttribute( double v )
1240{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001241 char buf[BUF_SIZE];
1242 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001243 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001244}
1245
1246void XMLAttribute::SetAttribute( float v )
1247{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001248 char buf[BUF_SIZE];
1249 XMLUtil::ToStr( v, buf, BUF_SIZE );
Lee Thomason624d43f2012-10-12 10:58:48 -07001250 _value.SetStr( buf );
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001251}
1252
Lee Thomasondadcdfa2012-01-18 17:55:48 -08001253
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001254// --------- XMLElement ---------- //
1255XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001256 _closingType( 0 ),
1257 _rootAttribute( 0 )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001258{
1259}
1260
1261
1262XMLElement::~XMLElement()
1263{
Lee Thomason624d43f2012-10-12 10:58:48 -07001264 while( _rootAttribute ) {
1265 XMLAttribute* next = _rootAttribute->_next;
Dmitry-Mee3225b12014-09-03 11:03:11 +04001266 DeleteAttribute( _rootAttribute );
Lee Thomason624d43f2012-10-12 10:58:48 -07001267 _rootAttribute = next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001268 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001269}
1270
1271
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001272const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1273{
Dmitry-Me3659fe12014-09-04 11:33:49 +04001274 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001275 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1276 return a;
1277 }
1278 }
1279 return 0;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001280}
1281
1282
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001283const char* XMLElement::Attribute( const char* name, const char* value ) const
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001285 const XMLAttribute* a = FindAttribute( name );
1286 if ( !a ) {
1287 return 0;
1288 }
1289 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1290 return a->Value();
1291 }
1292 return 0;
Lee Thomason8ba7f7d2012-03-24 13:04:04 -07001293}
1294
1295
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001296const char* XMLElement::GetText() const
1297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001298 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001299 return FirstChild()->Value();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001300 }
1301 return 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001302}
1303
1304
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001305void XMLElement::SetText( const char* inText )
1306{
Uli Kusterer869bb592014-01-21 01:36:16 +01001307 if ( FirstChild() && FirstChild()->ToText() )
Uli Kusterer8fe342a2014-01-21 01:12:47 +01001308 FirstChild()->SetValue( inText );
1309 else {
1310 XMLText* theText = GetDocument()->NewText( inText );
1311 InsertFirstChild( theText );
1312 }
1313}
1314
Lee Thomason5bb2d802014-01-24 10:42:57 -08001315
1316void XMLElement::SetText( int v )
1317{
1318 char buf[BUF_SIZE];
1319 XMLUtil::ToStr( v, buf, BUF_SIZE );
1320 SetText( buf );
1321}
1322
1323
1324void XMLElement::SetText( unsigned v )
1325{
1326 char buf[BUF_SIZE];
1327 XMLUtil::ToStr( v, buf, BUF_SIZE );
1328 SetText( buf );
1329}
1330
1331
1332void XMLElement::SetText( bool v )
1333{
1334 char buf[BUF_SIZE];
1335 XMLUtil::ToStr( v, buf, BUF_SIZE );
1336 SetText( buf );
1337}
1338
1339
1340void XMLElement::SetText( float v )
1341{
1342 char buf[BUF_SIZE];
1343 XMLUtil::ToStr( v, buf, BUF_SIZE );
1344 SetText( buf );
1345}
1346
1347
1348void XMLElement::SetText( double v )
1349{
1350 char buf[BUF_SIZE];
1351 XMLUtil::ToStr( v, buf, BUF_SIZE );
1352 SetText( buf );
1353}
1354
1355
MortenMacFly4ee49f12013-01-14 20:03:14 +01001356XMLError XMLElement::QueryIntText( int* ival ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001357{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001358 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001359 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001360 if ( XMLUtil::ToInt( t, ival ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001361 return XML_SUCCESS;
1362 }
1363 return XML_CAN_NOT_CONVERT_TEXT;
1364 }
1365 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001366}
1367
1368
MortenMacFly4ee49f12013-01-14 20:03:14 +01001369XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001370{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001371 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001372 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001373 if ( XMLUtil::ToUnsigned( t, uval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001374 return XML_SUCCESS;
1375 }
1376 return XML_CAN_NOT_CONVERT_TEXT;
1377 }
1378 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001379}
1380
1381
MortenMacFly4ee49f12013-01-14 20:03:14 +01001382XMLError XMLElement::QueryBoolText( bool* bval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001383{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001384 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001385 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001386 if ( XMLUtil::ToBool( t, bval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001387 return XML_SUCCESS;
1388 }
1389 return XML_CAN_NOT_CONVERT_TEXT;
1390 }
1391 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001392}
1393
1394
MortenMacFly4ee49f12013-01-14 20:03:14 +01001395XMLError XMLElement::QueryDoubleText( double* dval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001396{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001397 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001398 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001399 if ( XMLUtil::ToDouble( t, dval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001400 return XML_SUCCESS;
1401 }
1402 return XML_CAN_NOT_CONVERT_TEXT;
1403 }
1404 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001405}
1406
1407
MortenMacFly4ee49f12013-01-14 20:03:14 +01001408XMLError XMLElement::QueryFloatText( float* fval ) const
Lee Thomason21be8822012-07-15 17:27:22 -07001409{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001410 if ( FirstChild() && FirstChild()->ToText() ) {
Dmitry-Me097339a2014-09-29 13:20:29 +04001411 const char* t = FirstChild()->Value();
MortenMacFly4ee49f12013-01-14 20:03:14 +01001412 if ( XMLUtil::ToFloat( t, fval ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001413 return XML_SUCCESS;
1414 }
1415 return XML_CAN_NOT_CONVERT_TEXT;
1416 }
1417 return XML_NO_TEXT_NODE;
Lee Thomason21be8822012-07-15 17:27:22 -07001418}
1419
1420
1421
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001422XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1423{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001424 XMLAttribute* last = 0;
1425 XMLAttribute* attrib = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001426 for( attrib = _rootAttribute;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001427 attrib;
Lee Thomason624d43f2012-10-12 10:58:48 -07001428 last = attrib, attrib = attrib->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001429 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1430 break;
1431 }
1432 }
1433 if ( !attrib ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001434 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001435 attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1436 attrib->_memPool = &_document->_attributePool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001437 if ( last ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001438 last->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001439 }
1440 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001441 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001442 }
1443 attrib->SetName( name );
Lee Thomason5b0a6772012-11-19 13:54:42 -08001444 attrib->_memPool->SetTracked(); // always created and linked.
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001445 }
1446 return attrib;
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001447}
1448
1449
U-Stream\Leeae25a442012-02-17 17:48:16 -08001450void XMLElement::DeleteAttribute( const char* name )
1451{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001452 XMLAttribute* prev = 0;
Lee Thomason624d43f2012-10-12 10:58:48 -07001453 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001454 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1455 if ( prev ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001456 prev->_next = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001457 }
1458 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001459 _rootAttribute = a->_next;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001460 }
Dmitry-Mee3225b12014-09-03 11:03:11 +04001461 DeleteAttribute( a );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001462 break;
1463 }
1464 prev = a;
1465 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001466}
1467
1468
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001469char* XMLElement::ParseAttributes( char* p )
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001470{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001471 const char* start = p;
1472 XMLAttribute* prevAttribute = 0;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001473
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001474 // Read the attributes.
1475 while( p ) {
1476 p = XMLUtil::SkipWhiteSpace( p );
1477 if ( !p || !(*p) ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001478 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001479 return 0;
1480 }
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001481
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001482 // attribute.
Martinsh Shaitersc6d02f42013-01-26 21:22:57 +02001483 if (XMLUtil::IsNameStartChar( *p ) ) {
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001484 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001485 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1486 attrib->_memPool = &_document->_attributePool;
Lee Thomason5b0a6772012-11-19 13:54:42 -08001487 attrib->_memPool->SetTracked();
Lee Thomasond1983222012-02-06 08:41:24 -08001488
Lee Thomason624d43f2012-10-12 10:58:48 -07001489 p = attrib->ParseDeep( p, _document->ProcessEntities() );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001490 if ( !p || Attribute( attrib->Name() ) ) {
Dmitry-Mee3225b12014-09-03 11:03:11 +04001491 DeleteAttribute( attrib );
Lee Thomason624d43f2012-10-12 10:58:48 -07001492 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001493 return 0;
1494 }
1495 // There is a minor bug here: if the attribute in the source xml
1496 // document is duplicated, it will not be detected and the
1497 // attribute will be doubly added. However, tracking the 'prevAttribute'
1498 // avoids re-scanning the attribute list. Preferring performance for
1499 // now, may reconsider in the future.
1500 if ( prevAttribute ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001501 prevAttribute->_next = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001502 }
1503 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001504 _rootAttribute = attrib;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001505 }
1506 prevAttribute = attrib;
1507 }
1508 // end of the tag
1509 else if ( *p == '/' && *(p+1) == '>' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001510 _closingType = CLOSED;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001511 return p+2; // done; sealed element.
1512 }
1513 // end of the tag
1514 else if ( *p == '>' ) {
1515 ++p;
1516 break;
1517 }
1518 else {
Lee Thomason624d43f2012-10-12 10:58:48 -07001519 _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001520 return 0;
1521 }
1522 }
1523 return p;
Lee Thomason67d61312012-01-24 16:01:51 -08001524}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001525
Dmitry-Mee3225b12014-09-03 11:03:11 +04001526void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1527{
1528 if ( attribute == 0 ) {
1529 return;
1530 }
1531 MemPool* pool = attribute->_memPool;
1532 attribute->~XMLAttribute();
1533 pool->Free( attribute );
1534}
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001535
Lee Thomason67d61312012-01-24 16:01:51 -08001536//
1537// <ele></ele>
1538// <ele>foo<b>bar</b></ele>
1539//
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001540char* XMLElement::ParseDeep( char* p, StrPair* strPair )
Lee Thomason67d61312012-01-24 16:01:51 -08001541{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001542 // Read the element name.
1543 p = XMLUtil::SkipWhiteSpace( p );
1544 if ( !p ) {
1545 return 0;
1546 }
Lee Thomason67d61312012-01-24 16:01:51 -08001547
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001548 // The closing element is the </element> form. It is
1549 // parsed just like a regular element then deleted from
1550 // the DOM.
1551 if ( *p == '/' ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001552 _closingType = CLOSING;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001553 ++p;
1554 }
Lee Thomason67d61312012-01-24 16:01:51 -08001555
Lee Thomason624d43f2012-10-12 10:58:48 -07001556 p = _value.ParseName( p );
1557 if ( _value.Empty() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001558 return 0;
1559 }
Lee Thomason67d61312012-01-24 16:01:51 -08001560
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001561 p = ParseAttributes( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001562 if ( !p || !*p || _closingType ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001563 return p;
1564 }
Lee Thomason67d61312012-01-24 16:01:51 -08001565
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001566 p = XMLNode::ParseDeep( p, strPair );
1567 return p;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001568}
1569
1570
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001571
1572XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
1573{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001574 if ( !doc ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001575 doc = _document;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001576 }
1577 XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1578 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1579 element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1580 }
1581 return element;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001582}
1583
1584
1585bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1586{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001587 TIXMLASSERT( compare );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001588 const XMLElement* other = compare->ToElement();
1589 if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001590
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001591 const XMLAttribute* a=FirstAttribute();
1592 const XMLAttribute* b=other->FirstAttribute();
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001593
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001594 while ( a && b ) {
1595 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1596 return false;
1597 }
1598 a = a->Next();
1599 b = b->Next();
1600 }
1601 if ( a || b ) {
1602 // different count
1603 return false;
1604 }
1605 return true;
1606 }
1607 return false;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001608}
1609
1610
Lee Thomason751da522012-02-10 08:50:51 -08001611bool XMLElement::Accept( XMLVisitor* visitor ) const
1612{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001613 TIXMLASSERT( visitor );
Lee Thomason624d43f2012-10-12 10:58:48 -07001614 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001615 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1616 if ( !node->Accept( visitor ) ) {
1617 break;
1618 }
1619 }
1620 }
1621 return visitor->VisitExit( *this );
Lee Thomason751da522012-02-10 08:50:51 -08001622}
Lee Thomason56bdd022012-02-09 18:16:58 -08001623
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001624
Lee Thomason3f57d272012-01-11 15:30:03 -08001625// --------- XMLDocument ----------- //
Lee Thomason331596e2014-09-11 14:56:43 -07001626
1627// Warning: List must match 'enum XMLError'
1628const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1629 "XML_SUCCESS",
1630 "XML_NO_ATTRIBUTE",
1631 "XML_WRONG_ATTRIBUTE_TYPE",
1632 "XML_ERROR_FILE_NOT_FOUND",
1633 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1634 "XML_ERROR_FILE_READ_ERROR",
1635 "XML_ERROR_ELEMENT_MISMATCH",
1636 "XML_ERROR_PARSING_ELEMENT",
1637 "XML_ERROR_PARSING_ATTRIBUTE",
1638 "XML_ERROR_IDENTIFYING_TAG",
1639 "XML_ERROR_PARSING_TEXT",
1640 "XML_ERROR_PARSING_CDATA",
1641 "XML_ERROR_PARSING_COMMENT",
1642 "XML_ERROR_PARSING_DECLARATION",
1643 "XML_ERROR_PARSING_UNKNOWN",
1644 "XML_ERROR_EMPTY_DOCUMENT",
1645 "XML_ERROR_MISMATCHED_ELEMENT",
1646 "XML_ERROR_PARSING",
1647 "XML_CAN_NOT_CONVERT_TEXT",
1648 "XML_NO_TEXT_NODE"
1649};
1650
1651
Lee Thomason624d43f2012-10-12 10:58:48 -07001652XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001653 XMLNode( 0 ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001654 _writeBOM( false ),
1655 _processEntities( processEntities ),
Lee Thomason2fa81722012-11-09 12:37:46 -08001656 _errorID( XML_NO_ERROR ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001657 _whitespace( whitespace ),
1658 _errorStr1( 0 ),
1659 _errorStr2( 0 ),
1660 _charBuffer( 0 )
U-Lama\Lee560bd472011-12-28 19:42:49 -08001661{
Lee Thomason624d43f2012-10-12 10:58:48 -07001662 _document = this; // avoid warning about 'this' in initializer list
U-Lama\Lee560bd472011-12-28 19:42:49 -08001663}
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001664
1665
Lee Thomason3f57d272012-01-11 15:30:03 -08001666XMLDocument::~XMLDocument()
1667{
Lee Thomasonf07b9522014-10-30 13:25:12 -07001668 Clear();
Lee Thomason3f57d272012-01-11 15:30:03 -08001669}
1670
1671
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001672void XMLDocument::Clear()
Lee Thomason18d68bd2012-01-26 18:17:26 -08001673{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001674 DeleteChildren();
1675
Dmitry-Meab37df82014-11-28 12:08:36 +03001676#ifdef DEBUG
1677 const bool hadError = Error();
1678#endif
Lee Thomason624d43f2012-10-12 10:58:48 -07001679 _errorID = XML_NO_ERROR;
1680 _errorStr1 = 0;
1681 _errorStr2 = 0;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001682
Lee Thomason624d43f2012-10-12 10:58:48 -07001683 delete [] _charBuffer;
1684 _charBuffer = 0;
Lee Thomasonf07b9522014-10-30 13:25:12 -07001685
1686#if 0
1687 _textPool.Trace( "text" );
1688 _elementPool.Trace( "element" );
1689 _commentPool.Trace( "comment" );
1690 _attributePool.Trace( "attribute" );
1691#endif
1692
1693#ifdef DEBUG
Dmitry-Meab37df82014-11-28 12:08:36 +03001694 if ( !hadError ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001695 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1696 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1697 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1698 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1699 }
1700#endif
Lee Thomason18d68bd2012-01-26 18:17:26 -08001701}
1702
Lee Thomason3f57d272012-01-11 15:30:03 -08001703
Lee Thomason2c85a712012-01-31 08:24:24 -08001704XMLElement* XMLDocument::NewElement( const char* name )
1705{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001706 TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001707 XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1708 ele->_memPool = &_elementPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001709 ele->SetName( name );
1710 return ele;
Lee Thomason2c85a712012-01-31 08:24:24 -08001711}
1712
1713
Lee Thomason1ff38e02012-02-14 18:18:16 -08001714XMLComment* XMLDocument::NewComment( const char* str )
1715{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001716 TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001717 XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1718 comment->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001719 comment->SetValue( str );
1720 return comment;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001721}
1722
1723
1724XMLText* XMLDocument::NewText( const char* str )
1725{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001726 TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001727 XMLText* text = new (_textPool.Alloc()) XMLText( this );
1728 text->_memPool = &_textPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001729 text->SetValue( str );
1730 return text;
Lee Thomason1ff38e02012-02-14 18:18:16 -08001731}
1732
1733
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001734XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
1735{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001736 TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001737 XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1738 dec->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001739 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1740 return dec;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001741}
1742
1743
1744XMLUnknown* XMLDocument::NewUnknown( const char* str )
1745{
Dmitry-Mee6a95ce2014-12-10 09:10:27 +03001746 TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
Lee Thomason624d43f2012-10-12 10:58:48 -07001747 XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1748 unk->_memPool = &_commentPool;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001749 unk->SetValue( str );
1750 return unk;
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001751}
1752
Dmitry-Me01578db2014-08-19 10:18:48 +04001753static FILE* callfopen( const char* filepath, const char* mode )
1754{
Dmitry-Meabb2d042014-12-09 12:59:31 +03001755 TIXMLASSERT( filepath );
1756 TIXMLASSERT( mode );
Dmitry-Me01578db2014-08-19 10:18:48 +04001757#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1758 FILE* fp = 0;
1759 errno_t err = fopen_s( &fp, filepath, mode );
1760 if ( err ) {
1761 return 0;
1762 }
1763#else
1764 FILE* fp = fopen( filepath, mode );
1765#endif
1766 return fp;
1767}
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001768
Lee Thomason2fa81722012-11-09 12:37:46 -08001769XMLError XMLDocument::LoadFile( const char* filename )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001770{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001771 Clear();
Dmitry-Me01578db2014-08-19 10:18:48 +04001772 FILE* fp = callfopen( filename, "rb" );
1773 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001774 SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001775 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001776 }
1777 LoadFile( fp );
1778 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001779 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001780}
1781
1782
Lee Thomason2fa81722012-11-09 12:37:46 -08001783XMLError XMLDocument::LoadFile( FILE* fp )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001784{
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001785 Clear();
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001786
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001787 fseek( fp, 0, SEEK_SET );
Dmitry-Me08e7f7b2014-07-31 15:19:14 +04001788 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
Daniel Marjamäkiba4b3282014-01-10 21:37:27 +01001789 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1790 return _errorID;
1791 }
1792
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001793 fseek( fp, 0, SEEK_END );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001794 const long filelength = ftell( fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001795 fseek( fp, 0, SEEK_SET );
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001796 if ( filelength == -1L ) {
1797 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
1798 return _errorID;
1799 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001800
Dmitry-Meacb9c9c2014-08-04 09:49:25 +04001801 const size_t size = filelength;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001802 if ( size == 0 ) {
Vasily Biryukov1cfafd02013-04-20 14:12:33 +06001803 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001804 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001805 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001806
Lee Thomason624d43f2012-10-12 10:58:48 -07001807 _charBuffer = new char[size+1];
1808 size_t read = fread( _charBuffer, 1, size, fp );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001809 if ( read != size ) {
1810 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001811 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001812 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001813
Lee Thomason624d43f2012-10-12 10:58:48 -07001814 _charBuffer[size] = 0;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001815
Lee Thomason624d43f2012-10-12 10:58:48 -07001816 const char* p = _charBuffer;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001817 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001818 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001819 if ( !p || !*p ) {
1820 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001821 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001822 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001823
Lee Thomason624d43f2012-10-12 10:58:48 -07001824 ParseDeep( _charBuffer + (p-_charBuffer), 0 );
1825 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001826}
1827
1828
Lee Thomason2fa81722012-11-09 12:37:46 -08001829XMLError XMLDocument::SaveFile( const char* filename, bool compact )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001830{
Dmitry-Me01578db2014-08-19 10:18:48 +04001831 FILE* fp = callfopen( filename, "w" );
1832 if ( !fp ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001833 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001834 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001835 }
1836 SaveFile(fp, compact);
1837 fclose( fp );
Lee Thomason624d43f2012-10-12 10:58:48 -07001838 return _errorID;
Ken Miller81da1fb2012-04-09 23:32:26 -05001839}
1840
1841
Lee Thomason2fa81722012-11-09 12:37:46 -08001842XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
Ken Miller81da1fb2012-04-09 23:32:26 -05001843{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001844 XMLPrinter stream( fp, compact );
1845 Print( &stream );
Lee Thomason624d43f2012-10-12 10:58:48 -07001846 return _errorID;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001847}
1848
Lee Thomason1ff38e02012-02-14 18:18:16 -08001849
Lee Thomason2fa81722012-11-09 12:37:46 -08001850XMLError XMLDocument::Parse( const char* p, size_t len )
Lee Thomason3f57d272012-01-11 15:30:03 -08001851{
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001852 const char* start = p;
Martinsh Shaitersa9d42b02013-01-30 11:14:27 +02001853 Clear();
Lee Thomason18d68bd2012-01-26 18:17:26 -08001854
Lee Thomason82d32002014-02-21 22:47:18 -08001855 if ( len == 0 || !p || !*p ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001856 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001857 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001858 }
1859 if ( len == (size_t)(-1) ) {
1860 len = strlen( p );
1861 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001862 _charBuffer = new char[ len+1 ];
1863 memcpy( _charBuffer, p, len );
1864 _charBuffer[len] = 0;
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001865
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001866 p = XMLUtil::SkipWhiteSpace( p );
Lee Thomason624d43f2012-10-12 10:58:48 -07001867 p = XMLUtil::ReadBOM( p, &_writeBOM );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001868 if ( !p || !*p ) {
1869 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
Lee Thomason624d43f2012-10-12 10:58:48 -07001870 return _errorID;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001871 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001872
Thomas Roß1470edc2013-05-10 15:44:12 +02001873 ptrdiff_t delta = p - start; // skip initial whitespace, BOM, etc.
Lee Thomason (grinliz)d0a38c32013-04-29 09:15:37 -07001874 ParseDeep( _charBuffer+delta, 0 );
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001875 if ( Error() ) {
Lee Thomasonf07b9522014-10-30 13:25:12 -07001876 // clean up now essentially dangling memory.
1877 // and the parse fail can put objects in the
1878 // pools that are dead and inaccessible.
1879 DeleteChildren();
1880 _elementPool.Clear();
1881 _attributePool.Clear();
1882 _textPool.Clear();
1883 _commentPool.Clear();
1884 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001885 return _errorID;
Lee Thomason3f57d272012-01-11 15:30:03 -08001886}
1887
1888
PKEuS1c5f99e2013-07-06 11:28:39 +02001889void XMLDocument::Print( XMLPrinter* streamer ) const
Lee Thomason3f57d272012-01-11 15:30:03 -08001890{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001891 XMLPrinter stdStreamer( stdout );
1892 if ( !streamer ) {
1893 streamer = &stdStreamer;
1894 }
1895 Accept( streamer );
Lee Thomason3f57d272012-01-11 15:30:03 -08001896}
1897
1898
Lee Thomason2fa81722012-11-09 12:37:46 -08001899void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
Lee Thomason67d61312012-01-24 16:01:51 -08001900{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001901 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
Lee Thomason624d43f2012-10-12 10:58:48 -07001902 _errorID = error;
1903 _errorStr1 = str1;
1904 _errorStr2 = str2;
Lee Thomason67d61312012-01-24 16:01:51 -08001905}
1906
Lee Thomason331596e2014-09-11 14:56:43 -07001907const char* XMLDocument::ErrorName() const
1908{
Dmitry-Me66d2a842014-11-08 15:24:52 +03001909 TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
Lee Thomason331596e2014-09-11 14:56:43 -07001910 return _errorNames[_errorID];
1911}
Lee Thomason5cae8972012-01-24 18:03:07 -08001912
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001913void XMLDocument::PrintError() const
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001914{
Dmitry-Me9bcd9c72014-12-09 10:58:14 +03001915 if ( Error() ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001916 static const int LEN = 20;
1917 char buf1[LEN] = { 0 };
1918 char buf2[LEN] = { 0 };
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001919
Lee Thomason624d43f2012-10-12 10:58:48 -07001920 if ( _errorStr1 ) {
1921 TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001922 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001923 if ( _errorStr2 ) {
1924 TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001925 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001926
Lee Thomason331596e2014-09-11 14:56:43 -07001927 printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
1928 _errorID, ErrorName(), buf1, buf2 );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001929 }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001930}
1931
1932
PKEuS1bfb9542013-08-04 13:51:17 +02001933XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
Lee Thomason624d43f2012-10-12 10:58:48 -07001934 _elementJustOpened( false ),
1935 _firstElement( true ),
1936 _fp( file ),
PKEuS1bfb9542013-08-04 13:51:17 +02001937 _depth( depth ),
Lee Thomason624d43f2012-10-12 10:58:48 -07001938 _textDepth( -1 ),
1939 _processEntities( true ),
1940 _compactMode( compact )
Lee Thomason5cae8972012-01-24 18:03:07 -08001941{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001942 for( int i=0; i<ENTITY_RANGE; ++i ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001943 _entityFlag[i] = false;
1944 _restrictedEntityFlag[i] = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001945 }
1946 for( int i=0; i<NUM_ENTITIES; ++i ) {
1947 TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1948 if ( entities[i].value < ENTITY_RANGE ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07001949 _entityFlag[ (int)entities[i].value ] = true;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001950 }
1951 }
Lee Thomason624d43f2012-10-12 10:58:48 -07001952 _restrictedEntityFlag[(int)'&'] = true;
1953 _restrictedEntityFlag[(int)'<'] = true;
1954 _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1955 _buffer.Push( 0 );
U-Stream\Leeae25a442012-02-17 17:48:16 -08001956}
1957
1958
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001959void XMLPrinter::Print( const char* format, ... )
U-Stream\Leeae25a442012-02-17 17:48:16 -08001960{
1961 va_list va;
1962 va_start( va, format );
1963
Lee Thomason624d43f2012-10-12 10:58:48 -07001964 if ( _fp ) {
1965 vfprintf( _fp, format, va );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001966 }
1967 else {
Lee Thomasona0744c82014-03-16 10:32:27 -07001968#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001969 #if defined(WINCE)
1970 int len = 512;
1971 do {
1972 len = len*2;
1973 char* str = new char[len]();
1974 len = _vsnprintf(str, len, format, va);
1975 delete[] str;
1976 }while (len < 0);
1977 #else
Thomas Roß268c6832014-03-13 23:35:16 +01001978 int len = _vscprintf( format, va );
pffang91d34a02014-07-10 10:02:35 +08001979 #endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001980#else
1981 int len = vsnprintf( 0, 0, format, va );
Thomas Roß268c6832014-03-13 23:35:16 +01001982#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001983 // Close out and re-start the va-args
1984 va_end( va );
1985 va_start( va, format );
Lee Thomasona0744c82014-03-16 10:32:27 -07001986 char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
1987#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
pffang91d34a02014-07-10 10:02:35 +08001988 #if defined(WINCE)
1989 _vsnprintf( p, len+1, format, va );
1990 #else
Lee Thomasona0744c82014-03-16 10:32:27 -07001991 vsnprintf_s( p, len+1, _TRUNCATE, format, va );
pffang91d34a02014-07-10 10:02:35 +08001992 #endif
Lee Thomasona0744c82014-03-16 10:32:27 -07001993#else
1994 vsnprintf( p, len+1, format, va );
1995#endif
Lee Thomasona9cf3f92012-10-11 16:56:51 -07001996 }
U-Stream\Leeae25a442012-02-17 17:48:16 -08001997 va_end( va );
Lee Thomason5cae8972012-01-24 18:03:07 -08001998}
1999
2000
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002001void XMLPrinter::PrintSpace( int depth )
Lee Thomason5cae8972012-01-24 18:03:07 -08002002{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002003 for( int i=0; i<depth; ++i ) {
2004 Print( " " );
2005 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002006}
2007
2008
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002009void XMLPrinter::PrintString( const char* p, bool restricted )
Lee Thomason857b8682012-01-25 17:50:25 -08002010{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002011 // Look for runs of bytes between entities to print.
2012 const char* q = p;
Lee Thomason624d43f2012-10-12 10:58:48 -07002013 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
Lee Thomason857b8682012-01-25 17:50:25 -08002014
Lee Thomason624d43f2012-10-12 10:58:48 -07002015 if ( _processEntities ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002016 while ( *q ) {
2017 // Remember, char is sometimes signed. (How many times has that bitten me?)
2018 if ( *q > 0 && *q < ENTITY_RANGE ) {
2019 // Check for entities. If one is found, flush
2020 // the stream up until the entity, write the
2021 // entity, and keep looking.
2022 if ( flag[(unsigned)(*q)] ) {
2023 while ( p < q ) {
2024 Print( "%c", *p );
2025 ++p;
2026 }
2027 for( int i=0; i<NUM_ENTITIES; ++i ) {
2028 if ( entities[i].value == *q ) {
2029 Print( "&%s;", entities[i].pattern );
2030 break;
2031 }
2032 }
2033 ++p;
2034 }
2035 }
2036 ++q;
2037 }
2038 }
2039 // Flush the remaining string. This will be the entire
2040 // string if an entity wasn't found.
Lee Thomason624d43f2012-10-12 10:58:48 -07002041 if ( !_processEntities || (q-p > 0) ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002042 Print( "%s", p );
2043 }
Lee Thomason857b8682012-01-25 17:50:25 -08002044}
2045
U-Stream\Leeae25a442012-02-17 17:48:16 -08002046
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002047void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002048{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002049 if ( writeBOM ) {
PKEuS1bfb9542013-08-04 13:51:17 +02002050 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 -07002051 Print( "%s", bom );
2052 }
2053 if ( writeDec ) {
2054 PushDeclaration( "xml version=\"1.0\"" );
2055 }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002056}
2057
2058
Uli Kusterer593a33d2014-02-01 12:48:51 +01002059void XMLPrinter::OpenElement( const char* name, bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002060{
Lee Thomason624d43f2012-10-12 10:58:48 -07002061 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002062 SealElement();
2063 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002064 _stack.Push( name );
Lee Thomason56bdd022012-02-09 18:16:58 -08002065
Uli Kusterer593a33d2014-02-01 12:48:51 +01002066 if ( _textDepth < 0 && !_firstElement && !compactMode ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002067 Print( "\n" );
PKEuS1bfb9542013-08-04 13:51:17 +02002068 }
Uli Kusterer593a33d2014-02-01 12:48:51 +01002069 if ( !compactMode ) {
Lee Thomason624d43f2012-10-12 10:58:48 -07002070 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002071 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002072
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002073 Print( "<%s", name );
Lee Thomason624d43f2012-10-12 10:58:48 -07002074 _elementJustOpened = true;
2075 _firstElement = false;
2076 ++_depth;
Lee Thomason5cae8972012-01-24 18:03:07 -08002077}
2078
2079
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002080void XMLPrinter::PushAttribute( const char* name, const char* value )
Lee Thomason5cae8972012-01-24 18:03:07 -08002081{
Lee Thomason624d43f2012-10-12 10:58:48 -07002082 TIXMLASSERT( _elementJustOpened );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002083 Print( " %s=\"", name );
2084 PrintString( value, false );
2085 Print( "\"" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002086}
2087
2088
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002089void XMLPrinter::PushAttribute( const char* name, int v )
2090{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002091 char buf[BUF_SIZE];
2092 XMLUtil::ToStr( v, buf, BUF_SIZE );
2093 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002094}
2095
2096
2097void XMLPrinter::PushAttribute( const char* name, unsigned v )
2098{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002099 char buf[BUF_SIZE];
2100 XMLUtil::ToStr( v, buf, BUF_SIZE );
2101 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002102}
2103
2104
2105void XMLPrinter::PushAttribute( const char* name, bool v )
2106{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002107 char buf[BUF_SIZE];
2108 XMLUtil::ToStr( v, buf, BUF_SIZE );
2109 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002110}
2111
2112
2113void XMLPrinter::PushAttribute( const char* name, double v )
2114{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002115 char buf[BUF_SIZE];
2116 XMLUtil::ToStr( v, buf, BUF_SIZE );
2117 PushAttribute( name, buf );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08002118}
2119
2120
Uli Kustererca412e82014-02-01 13:35:05 +01002121void XMLPrinter::CloseElement( bool compactMode )
Lee Thomason5cae8972012-01-24 18:03:07 -08002122{
Lee Thomason624d43f2012-10-12 10:58:48 -07002123 --_depth;
2124 const char* name = _stack.Pop();
Lee Thomason5cae8972012-01-24 18:03:07 -08002125
Lee Thomason624d43f2012-10-12 10:58:48 -07002126 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002127 Print( "/>" );
2128 }
2129 else {
Uli Kustererca412e82014-02-01 13:35:05 +01002130 if ( _textDepth < 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002131 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002132 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002133 }
2134 Print( "</%s>", name );
2135 }
Lee Thomason56bdd022012-02-09 18:16:58 -08002136
Lee Thomason624d43f2012-10-12 10:58:48 -07002137 if ( _textDepth == _depth ) {
2138 _textDepth = -1;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002139 }
Uli Kustererca412e82014-02-01 13:35:05 +01002140 if ( _depth == 0 && !compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002141 Print( "\n" );
2142 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002143 _elementJustOpened = false;
Lee Thomason5cae8972012-01-24 18:03:07 -08002144}
2145
2146
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002147void XMLPrinter::SealElement()
Lee Thomason5cae8972012-01-24 18:03:07 -08002148{
Lee Thomason624d43f2012-10-12 10:58:48 -07002149 _elementJustOpened = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002150 Print( ">" );
Lee Thomason5cae8972012-01-24 18:03:07 -08002151}
2152
2153
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002154void XMLPrinter::PushText( const char* text, bool cdata )
Lee Thomason5cae8972012-01-24 18:03:07 -08002155{
Lee Thomason624d43f2012-10-12 10:58:48 -07002156 _textDepth = _depth-1;
Lee Thomason56bdd022012-02-09 18:16:58 -08002157
Lee Thomason624d43f2012-10-12 10:58:48 -07002158 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002159 SealElement();
2160 }
2161 if ( cdata ) {
2162 Print( "<![CDATA[" );
2163 Print( "%s", text );
2164 Print( "]]>" );
2165 }
2166 else {
2167 PrintString( text, true );
2168 }
Lee Thomason5cae8972012-01-24 18:03:07 -08002169}
2170
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002171void XMLPrinter::PushText( int value )
Lee Thomason21be8822012-07-15 17:27:22 -07002172{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002173 char buf[BUF_SIZE];
2174 XMLUtil::ToStr( value, buf, BUF_SIZE );
2175 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002176}
2177
2178
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002179void XMLPrinter::PushText( unsigned value )
Lee Thomason21be8822012-07-15 17:27:22 -07002180{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002181 char buf[BUF_SIZE];
2182 XMLUtil::ToStr( value, buf, BUF_SIZE );
2183 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002184}
2185
2186
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002187void XMLPrinter::PushText( bool value )
Lee Thomason21be8822012-07-15 17:27:22 -07002188{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002189 char buf[BUF_SIZE];
2190 XMLUtil::ToStr( value, buf, BUF_SIZE );
2191 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002192}
2193
2194
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002195void XMLPrinter::PushText( float value )
Lee Thomason21be8822012-07-15 17:27:22 -07002196{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002197 char buf[BUF_SIZE];
2198 XMLUtil::ToStr( value, buf, BUF_SIZE );
2199 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002200}
2201
2202
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07002203void XMLPrinter::PushText( double value )
Lee Thomason21be8822012-07-15 17:27:22 -07002204{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002205 char buf[BUF_SIZE];
2206 XMLUtil::ToStr( value, buf, BUF_SIZE );
2207 PushText( buf, false );
Lee Thomason21be8822012-07-15 17:27:22 -07002208}
2209
Lee Thomason5cae8972012-01-24 18:03:07 -08002210
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002211void XMLPrinter::PushComment( const char* comment )
Lee Thomason5cae8972012-01-24 18:03:07 -08002212{
Lee Thomason624d43f2012-10-12 10:58:48 -07002213 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002214 SealElement();
2215 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002216 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002217 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002218 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002219 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002220 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002221 Print( "<!--%s-->", comment );
Lee Thomason5cae8972012-01-24 18:03:07 -08002222}
Lee Thomason751da522012-02-10 08:50:51 -08002223
2224
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002225void XMLPrinter::PushDeclaration( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002226{
Lee Thomason624d43f2012-10-12 10:58:48 -07002227 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002228 SealElement();
2229 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002230 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002231 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002232 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002233 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002234 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002235 Print( "<?%s?>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002236}
2237
2238
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002239void XMLPrinter::PushUnknown( const char* value )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002240{
Lee Thomason624d43f2012-10-12 10:58:48 -07002241 if ( _elementJustOpened ) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002242 SealElement();
2243 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002244 if ( _textDepth < 0 && !_firstElement && !_compactMode) {
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002245 Print( "\n" );
Lee Thomason624d43f2012-10-12 10:58:48 -07002246 PrintSpace( _depth );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002247 }
Lee Thomason624d43f2012-10-12 10:58:48 -07002248 _firstElement = false;
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002249 Print( "<!%s>", value );
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002250}
2251
2252
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002253bool XMLPrinter::VisitEnter( const XMLDocument& doc )
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002254{
Lee Thomason624d43f2012-10-12 10:58:48 -07002255 _processEntities = doc.ProcessEntities();
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002256 if ( doc.HasBOM() ) {
2257 PushHeader( true, false );
2258 }
2259 return true;
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08002260}
2261
2262
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002263bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
Lee Thomason751da522012-02-10 08:50:51 -08002264{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002265 const XMLElement* parentElem = element.Parent()->ToElement();
2266 bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;
2267 OpenElement( element.Name(), compactMode );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002268 while ( attribute ) {
2269 PushAttribute( attribute->Name(), attribute->Value() );
2270 attribute = attribute->Next();
2271 }
2272 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002273}
2274
2275
Uli Kustererca412e82014-02-01 13:35:05 +01002276bool XMLPrinter::VisitExit( const XMLElement& element )
Lee Thomason751da522012-02-10 08:50:51 -08002277{
Uli Kusterer5d1d27e2014-02-20 11:50:22 +01002278 CloseElement( CompactMode(element) );
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002279 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002280}
2281
2282
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002283bool XMLPrinter::Visit( const XMLText& text )
Lee Thomason751da522012-02-10 08:50:51 -08002284{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002285 PushText( text.Value(), text.CData() );
2286 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002287}
2288
2289
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002290bool XMLPrinter::Visit( const XMLComment& comment )
Lee Thomason751da522012-02-10 08:50:51 -08002291{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002292 PushComment( comment.Value() );
2293 return true;
Lee Thomason751da522012-02-10 08:50:51 -08002294}
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002295
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002296bool XMLPrinter::Visit( const XMLDeclaration& declaration )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002297{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002298 PushDeclaration( declaration.Value() );
2299 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002300}
2301
2302
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08002303bool XMLPrinter::Visit( const XMLUnknown& unknown )
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002304{
Lee Thomasona9cf3f92012-10-11 16:56:51 -07002305 PushUnknown( unknown.Value() );
2306 return true;
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08002307}
Kevin Wojniak04c22d22012-11-08 11:02:22 -08002308
Lee Thomason685b8952012-11-12 13:00:06 -08002309} // namespace tinyxml2
2310